summaryrefslogtreecommitdiffstats
path: root/include/utils/AssetManager.h
blob: d8994e05a02727a661e616e5200ff300762d78c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//
// Asset management class.  AssetManager objects are thread-safe.
//
#ifndef __LIBS_ASSETMANAGER_H
#define __LIBS_ASSETMANAGER_H

#include <utils/Asset.h>
#include <utils/AssetDir.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/String16.h>
#include <utils/ZipFileRO.h>
#include <utils/threads.h>

namespace android {

class Asset;        // fwd decl for things that include Asset.h first
class ResTable;
struct ResTable_config;

/*
 * Every application that uses assets needs one instance of this.  A
 * single instance may be shared across multiple threads, and a single
 * thread may have more than one instance (the latter is discouraged).
 *
 * The purpose of the AssetManager is to create Asset objects.  To do
 * this efficiently it may cache information about the locations of
 * files it has seen.  This can be controlled with the "cacheMode"
 * argument.
 *
 * The asset hierarchy may be examined like a filesystem, using
 * AssetDir objects to peruse a single directory.
 */
class AssetManager {
public:
    typedef enum CacheMode {
        CACHE_UNKNOWN = 0,
        CACHE_OFF,          // don't try to cache file locations
        CACHE_DEFER,        // construct cache as pieces are needed
        //CACHE_SCAN,         // scan full(!) asset hierarchy at init() time
    } CacheMode;

    AssetManager(CacheMode cacheMode = CACHE_OFF);
    virtual ~AssetManager(void);

    static int32_t getGlobalCount();
    
    /*                                                                       
     * Add a new source for assets.  This can be called multiple times to
     * look in multiple places for assets.  It can be either a directory (for
     * finding assets as raw files on the disk) or a ZIP file.  This newly
     * added asset path will be examined first when searching for assets,
     * before any that were previously added.
     *
     * Returns "true" on success, "false" on failure.  If 'cookie' is non-NULL,
     * then on success, *cookie is set to the value corresponding to the
     * newly-added asset source.
     */
    bool addAssetPath(const String8& path, void** cookie);

    /*                                                                       
     * Convenience for adding the standard system assets.  Uses the
     * ANDROID_ROOT environment variable to find them.
     */
    bool addDefaultAssets();

    /*                                                                       
     * Iterate over the asset paths in this manager.  (Previously
     * added via addAssetPath() and addDefaultAssets().)  On first call,
     * 'cookie' must be NULL, resulting in the first cookie being returned.
     * Each next cookie will be returned there-after, until NULL indicating
     * the end has been reached.
     */
    void* nextAssetPath(void* cookie) const;

    /*                                                                       
     * Return an asset path in the manager.  'which' must be between 0 and
     * countAssetPaths().
     */
    String8 getAssetPath(void* cookie) const;

    /*
     * Set the current locale and vendor.  The locale can change during
     * the lifetime of an AssetManager if the user updates the device's
     * language setting.  The vendor is less likely to change.
     *
     * Pass in NULL to indicate no preference.
     */
    void setLocale(const char* locale);
    void setVendor(const char* vendor);

    /*
     * Choose screen orientation for resources values returned.
     */
    void setConfiguration(const ResTable_config& config, const char* locale = NULL);

    typedef Asset::AccessMode AccessMode;       // typing shortcut

    /*
     * Open an asset.
     *
     * This will search through locale-specific and vendor-specific
     * directories and packages to find the file.
     *
     * The object returned does not depend on the AssetManager.  It should
     * be freed by calling Asset::close().
     */
    Asset* open(const char* fileName, AccessMode mode);

    /*
     * Open a non-asset file as an asset.
     *
     * This is for opening files that are included in an asset package
     * but aren't assets.  These sit outside the usual "locale/vendor"
     * path hierarchy, and will not be seen by "AssetDir" or included
     * in our filename cache.
     */
    Asset* openNonAsset(const char* fileName, AccessMode mode);

    /*
     * Explicit non-asset file.  The file explicitly named by the cookie (the
     * resource set to look in) and fileName will be opened and returned.
     */
    Asset* openNonAsset(void* cookie, const char* fileName, AccessMode mode);

    /*
     * Open a directory within the asset hierarchy.
     *
     * The contents of the directory are an amalgam of vendor-specific,
     * locale-specific, and generic assets stored loosely or in asset
     * packages.  Depending on the cache setting and previous accesses,
     * this call may incur significant disk overhead.
     *
     * To open the top-level directory, pass in "".
     */
    AssetDir* openDir(const char* dirName);

    /*
     * Open a directory within a particular path of the asset manager.
     *
     * The contents of the directory are an amalgam of vendor-specific,
     * locale-specific, and generic assets stored loosely or in asset
     * packages.  Depending on the cache setting and previous accesses,
     * this call may incur significant disk overhead.
     *
     * To open the top-level directory, pass in "".
     */
    AssetDir* openNonAssetDir(void* cookie, const char* dirName);

    /*
     * Get the type of a file in the asset hierarchy.  They will either
     * be "regular" or "directory".  [Currently only works for "regular".]
     *
     * Can also be used as a quick test for existence of a file.
     */
    FileType getFileType(const char* fileName);

    /*                                                                       
     * Return the complete resource table to find things in the package.
     */
    const ResTable& getResources(bool required = true) const;

    /*
     * Discard cached filename information.  This only needs to be called
     * if somebody has updated the set of "loose" files, and we want to
     * discard our cached notion of what's where.
     */
    void purge(void) { purgeFileNameCacheLocked(); }

    /*
     * Return true if the files this AssetManager references are all
     * up-to-date (have not been changed since it was created).  If false
     * is returned, you will need to create a new AssetManager to get
     * the current data.
     */
    bool isUpToDate();
    
    /**
     * Get the known locales for this asset manager object.
     */
    void getLocales(Vector<String8>* locales) const;

private:
    struct asset_path
    {
        String8 path;
        FileType type;
    };

    Asset* openInPathLocked(const char* fileName, AccessMode mode,
        const asset_path& path);
    Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
        const asset_path& path);
    Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
        const asset_path& path, const char* locale, const char* vendor);
    String8 createPathNameLocked(const asset_path& path, const char* locale,
        const char* vendor);
    String8 createPathNameLocked(const asset_path& path, const char* rootDir);
    String8 createZipSourceNameLocked(const String8& zipFileName,
        const String8& dirName, const String8& fileName);

    ZipFileRO* getZipFileLocked(const asset_path& path);
    Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
    Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
        const ZipEntryRO entry, AccessMode mode, const String8& entryName);

    bool scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
        const asset_path& path, const char* rootDir, const char* dirName);
    SortedVector<AssetDir::FileInfo>* scanDirLocked(const String8& path);
    bool scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
        const asset_path& path, const char* rootDir, const char* dirName);
    void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
        const SortedVector<AssetDir::FileInfo>* pContents);

    void loadFileNameCacheLocked(void);
    void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
        const char* dirName);
    bool fncScanAndMergeDirLocked(
        SortedVector<AssetDir::FileInfo>* pMergedInfo,
        const asset_path& path, const char* locale, const char* vendor,
        const char* dirName);
    void purgeFileNameCacheLocked(void);

    const ResTable* getResTable(bool required = true) const;
    void setLocaleLocked(const char* locale);
    void updateResourceParamsLocked() const;

    class SharedZip : public RefBase {
    public:
        static sp<SharedZip> get(const String8& path);

        ZipFileRO* getZip();

        Asset* getResourceTableAsset();
        Asset* setResourceTableAsset(Asset* asset);

        ResTable* getResourceTable();
        ResTable* setResourceTable(ResTable* res);
        
        bool isUpToDate();
        
    protected:
        ~SharedZip();

    private:
        SharedZip(const String8& path, time_t modWhen);
        SharedZip(); // <-- not implemented

        String8 mPath;
        ZipFileRO* mZipFile;
        time_t mModWhen;

        Asset* mResourceTableAsset;
        ResTable* mResourceTable;

        static Mutex gLock;
        static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
    };

    /*
     * Manage a set of Zip files.  For each file we need a pointer to the
     * ZipFile and a time_t with the file's modification date.
     *
     * We currently only have two zip files (current app, "common" app).
     * (This was originally written for 8, based on app/locale/vendor.)
     */
    class ZipSet {
    public:
        ZipSet(void);
        ~ZipSet(void);

        /*
         * Return a ZipFileRO structure for a ZipFileRO with the specified
         * parameters.
         */
        ZipFileRO* getZip(const String8& path);

        Asset* getZipResourceTableAsset(const String8& path);
        Asset* setZipResourceTableAsset(const String8& path, Asset* asset);

        ResTable* getZipResourceTable(const String8& path);
        ResTable* setZipResourceTable(const String8& path, ResTable* res);

        // generate path, e.g. "common/en-US-noogle.zip"
        static String8 getPathName(const char* path);

        bool isUpToDate();
        
    private:
        void closeZip(int idx);

        int getIndex(const String8& zip) const;
        mutable Vector<String8> mZipPath;
        mutable Vector<sp<SharedZip> > mZipFile;
    };

    // Protect all internal state.
    mutable Mutex   mLock;

    ZipSet          mZipSet;

    Vector<asset_path> mAssetPaths;
    char*           mLocale;
    char*           mVendor;

    mutable ResTable* mResources;
    ResTable_config* mConfig;

    /*
     * Cached data for "loose" files.  This lets us avoid poking at the
     * filesystem when searching for loose assets.  Each entry is the
     * "extended partial" path, e.g. "default/default/foo/bar.txt".  The
     * full set of files is present, including ".EXCLUDE" entries.
     *
     * We do not cache directory names.  We don't retain the ".gz",
     * because to our clients "foo" and "foo.gz" both look like "foo".
     */
    CacheMode       mCacheMode;         // is the cache enabled?
    bool            mCacheValid;        // clear when locale or vendor changes
    SortedVector<AssetDir::FileInfo> mCache;
};

}; // namespace android

#endif // __LIBS_ASSETMANAGER_H