AssetManager.h revision 7df3625d5bb28d11cce9ac23429f5e3c6ebac030
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//
18// Asset management class.  AssetManager objects are thread-safe.
19//
20#ifndef __LIBS_ASSETMANAGER_H
21#define __LIBS_ASSETMANAGER_H
22
23#include <androidfw/Asset.h>
24#include <androidfw/AssetDir.h>
25#include <androidfw/ZipFileRO.h>
26#include <utils/KeyedVector.h>
27#include <utils/SortedVector.h>
28#include <utils/String16.h>
29#include <utils/String8.h>
30#include <utils/threads.h>
31#include <utils/Vector.h>
32
33/*
34 * Native-app access is via the opaque typedef struct AAssetManager in the C namespace.
35 */
36#ifdef __cplusplus
37extern "C" {
38#endif
39
40struct AAssetManager { };
41
42#ifdef __cplusplus
43};
44#endif
45
46
47/*
48 * Now the proper C++ android-namespace definitions
49 */
50
51namespace android {
52
53class Asset;        // fwd decl for things that include Asset.h first
54class ResTable;
55struct ResTable_config;
56
57/*
58 * Every application that uses assets needs one instance of this.  A
59 * single instance may be shared across multiple threads, and a single
60 * thread may have more than one instance (the latter is discouraged).
61 *
62 * The purpose of the AssetManager is to create Asset objects.  To do
63 * this efficiently it may cache information about the locations of
64 * files it has seen.  This can be controlled with the "cacheMode"
65 * argument.
66 *
67 * The asset hierarchy may be examined like a filesystem, using
68 * AssetDir objects to peruse a single directory.
69 */
70class AssetManager : public AAssetManager {
71public:
72    static const char* RESOURCES_FILENAME;
73    static const char* IDMAP_BIN;
74    static const char* OVERLAY_DIR;
75    static const char* TARGET_PACKAGE_NAME;
76    static const char* TARGET_APK_PATH;
77    static const char* IDMAP_DIR;
78
79    typedef enum CacheMode {
80        CACHE_UNKNOWN = 0,
81        CACHE_OFF,          // don't try to cache file locations
82        CACHE_DEFER,        // construct cache as pieces are needed
83        //CACHE_SCAN,         // scan full(!) asset hierarchy at init() time
84    } CacheMode;
85
86    AssetManager(CacheMode cacheMode = CACHE_OFF);
87    virtual ~AssetManager(void);
88
89    static int32_t getGlobalCount();
90
91    /*
92     * Add a new source for assets.  This can be called multiple times to
93     * look in multiple places for assets.  It can be either a directory (for
94     * finding assets as raw files on the disk) or a ZIP file.  This newly
95     * added asset path will be examined first when searching for assets,
96     * before any that were previously added.
97     *
98     * Returns "true" on success, "false" on failure.  If 'cookie' is non-NULL,
99     * then on success, *cookie is set to the value corresponding to the
100     * newly-added asset source.
101     */
102    bool addAssetPath(const String8& path, int32_t* cookie);
103    bool addOverlayPath(const String8& path, int32_t* cookie);
104
105    /*
106     * Convenience for adding the standard system assets.  Uses the
107     * ANDROID_ROOT environment variable to find them.
108     */
109    bool addDefaultAssets();
110
111    /*
112     * Iterate over the asset paths in this manager.  (Previously
113     * added via addAssetPath() and addDefaultAssets().)  On first call,
114     * 'cookie' must be 0, resulting in the first cookie being returned.
115     * Each next cookie will be returned there-after, until -1 indicating
116     * the end has been reached.
117     */
118    int32_t nextAssetPath(const int32_t cookie) const;
119
120    /*
121     * Return an asset path in the manager.  'which' must be between 0 and
122     * countAssetPaths().
123     */
124    String8 getAssetPath(const int32_t cookie) const;
125
126    /*
127     * Set the current locale and vendor.  The locale can change during
128     * the lifetime of an AssetManager if the user updates the device's
129     * language setting.  The vendor is less likely to change.
130     *
131     * Pass in NULL to indicate no preference.
132     */
133    void setLocale(const char* locale);
134    void setVendor(const char* vendor);
135
136    /*
137     * Choose screen orientation for resources values returned.
138     */
139    void setConfiguration(const ResTable_config& config, const char* locale = NULL);
140
141    void getConfiguration(ResTable_config* outConfig) const;
142
143    typedef Asset::AccessMode AccessMode;       // typing shortcut
144
145    /*
146     * Open an asset.
147     *
148     * This will search through locale-specific and vendor-specific
149     * directories and packages to find the file.
150     *
151     * The object returned does not depend on the AssetManager.  It should
152     * be freed by calling Asset::close().
153     */
154    Asset* open(const char* fileName, AccessMode mode);
155
156    /*
157     * Open a non-asset file as an asset.
158     *
159     * This is for opening files that are included in an asset package
160     * but aren't assets.  These sit outside the usual "locale/vendor"
161     * path hierarchy, and will not be seen by "AssetDir" or included
162     * in our filename cache.
163     */
164    Asset* openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie = NULL);
165
166    /*
167     * Explicit non-asset file.  The file explicitly named by the cookie (the
168     * resource set to look in) and fileName will be opened and returned.
169     */
170    Asset* openNonAsset(const int32_t cookie, const char* fileName, AccessMode mode);
171
172    /*
173     * Open a directory within the asset hierarchy.
174     *
175     * The contents of the directory are an amalgam of vendor-specific,
176     * locale-specific, and generic assets stored loosely or in asset
177     * packages.  Depending on the cache setting and previous accesses,
178     * this call may incur significant disk overhead.
179     *
180     * To open the top-level directory, pass in "".
181     */
182    AssetDir* openDir(const char* dirName);
183
184    /*
185     * Open a directory within a particular path of the asset manager.
186     *
187     * The contents of the directory are an amalgam of vendor-specific,
188     * locale-specific, and generic assets stored loosely or in asset
189     * packages.  Depending on the cache setting and previous accesses,
190     * this call may incur significant disk overhead.
191     *
192     * To open the top-level directory, pass in "".
193     */
194    AssetDir* openNonAssetDir(const int32_t cookie, const char* dirName);
195
196    /*
197     * Get the type of a file in the asset hierarchy.  They will either
198     * be "regular" or "directory".  [Currently only works for "regular".]
199     *
200     * Can also be used as a quick test for existence of a file.
201     */
202    FileType getFileType(const char* fileName);
203
204    /*
205     * Return the complete resource table to find things in the package.
206     */
207    const ResTable& getResources(bool required = true) const;
208
209    /*
210     * Discard cached filename information.  This only needs to be called
211     * if somebody has updated the set of "loose" files, and we want to
212     * discard our cached notion of what's where.
213     */
214    void purge(void) { purgeFileNameCacheLocked(); }
215
216    /*
217     * Return true if the files this AssetManager references are all
218     * up-to-date (have not been changed since it was created).  If false
219     * is returned, you will need to create a new AssetManager to get
220     * the current data.
221     */
222    bool isUpToDate();
223
224    /**
225     * Get the known locales for this asset manager object.
226     */
227    void getLocales(Vector<String8>* locales) const;
228
229    /**
230     * Generate idmap data to translate resources IDs between a package and a
231     * corresponding overlay package.
232     */
233    bool createIdmap(const char* targetApkPath, const char* overlayApkPath,
234        uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize);
235
236private:
237    struct asset_path
238    {
239        String8 path;
240        FileType type;
241        String8 idmap;
242    };
243
244    Asset* openInPathLocked(const char* fileName, AccessMode mode,
245        const asset_path& path);
246    Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
247        const asset_path& path);
248    Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
249        const asset_path& path, const char* locale, const char* vendor);
250    String8 createPathNameLocked(const asset_path& path, const char* locale,
251        const char* vendor);
252    String8 createPathNameLocked(const asset_path& path, const char* rootDir);
253    String8 createZipSourceNameLocked(const String8& zipFileName,
254        const String8& dirName, const String8& fileName);
255
256    ZipFileRO* getZipFileLocked(const asset_path& path);
257    Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
258    Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
259        const ZipEntryRO entry, AccessMode mode, const String8& entryName);
260
261    bool scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
262        const asset_path& path, const char* rootDir, const char* dirName);
263    SortedVector<AssetDir::FileInfo>* scanDirLocked(const String8& path);
264    bool scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
265        const asset_path& path, const char* rootDir, const char* dirName);
266    void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
267        const SortedVector<AssetDir::FileInfo>* pContents);
268
269    void loadFileNameCacheLocked(void);
270    void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
271        const char* dirName);
272    bool fncScanAndMergeDirLocked(
273        SortedVector<AssetDir::FileInfo>* pMergedInfo,
274        const asset_path& path, const char* locale, const char* vendor,
275        const char* dirName);
276    void purgeFileNameCacheLocked(void);
277
278    const ResTable* getResTable(bool required = true) const;
279    void setLocaleLocked(const char* locale);
280    void updateResourceParamsLocked() const;
281    bool appendPathToResTable(const asset_path& ap) const;
282
283    Asset* openIdmapLocked(const struct asset_path& ap) const;
284
285    void addSystemOverlays(const char* pathOverlaysList, const String8& targetPackagePath,
286            ResTable* sharedRes, size_t offset) const;
287
288    class SharedZip : public RefBase {
289    public:
290        static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true);
291
292        ZipFileRO* getZip();
293
294        Asset* getResourceTableAsset();
295        Asset* setResourceTableAsset(Asset* asset);
296
297        ResTable* getResourceTable();
298        ResTable* setResourceTable(ResTable* res);
299
300        bool isUpToDate();
301
302        void addOverlay(const asset_path& ap);
303        bool getOverlay(size_t idx, asset_path* out) const;
304
305    protected:
306        ~SharedZip();
307
308    private:
309        SharedZip(const String8& path, time_t modWhen);
310        SharedZip(); // <-- not implemented
311
312        String8 mPath;
313        ZipFileRO* mZipFile;
314        time_t mModWhen;
315
316        Asset* mResourceTableAsset;
317        ResTable* mResourceTable;
318
319        Vector<asset_path> mOverlays;
320
321        static Mutex gLock;
322        static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
323    };
324
325    /*
326     * Manage a set of Zip files.  For each file we need a pointer to the
327     * ZipFile and a time_t with the file's modification date.
328     *
329     * We currently only have two zip files (current app, "common" app).
330     * (This was originally written for 8, based on app/locale/vendor.)
331     */
332    class ZipSet {
333    public:
334        ZipSet(void);
335        ~ZipSet(void);
336
337        /*
338         * Return a ZipFileRO structure for a ZipFileRO with the specified
339         * parameters.
340         */
341        ZipFileRO* getZip(const String8& path);
342
343        Asset* getZipResourceTableAsset(const String8& path);
344        Asset* setZipResourceTableAsset(const String8& path, Asset* asset);
345
346        ResTable* getZipResourceTable(const String8& path);
347        ResTable* setZipResourceTable(const String8& path, ResTable* res);
348
349        // generate path, e.g. "common/en-US-noogle.zip"
350        static String8 getPathName(const char* path);
351
352        bool isUpToDate();
353
354        void addOverlay(const String8& path, const asset_path& overlay);
355        bool getOverlay(const String8& path, size_t idx, asset_path* out) const;
356
357    private:
358        void closeZip(int idx);
359
360        int getIndex(const String8& zip) const;
361        mutable Vector<String8> mZipPath;
362        mutable Vector<sp<SharedZip> > mZipFile;
363    };
364
365    // Protect all internal state.
366    mutable Mutex   mLock;
367
368    ZipSet          mZipSet;
369
370    Vector<asset_path> mAssetPaths;
371    char*           mLocale;
372    char*           mVendor;
373
374    mutable ResTable* mResources;
375    ResTable_config* mConfig;
376
377    /*
378     * Cached data for "loose" files.  This lets us avoid poking at the
379     * filesystem when searching for loose assets.  Each entry is the
380     * "extended partial" path, e.g. "default/default/foo/bar.txt".  The
381     * full set of files is present, including ".EXCLUDE" entries.
382     *
383     * We do not cache directory names.  We don't retain the ".gz",
384     * because to our clients "foo" and "foo.gz" both look like "foo".
385     */
386    CacheMode       mCacheMode;         // is the cache enabled?
387    bool            mCacheValid;        // clear when locale or vendor changes
388    SortedVector<AssetDir::FileInfo> mCache;
389};
390
391}; // namespace android
392
393#endif // __LIBS_ASSETMANAGER_H
394