AssetManager.h revision a982dc05d7ca919c07f50e446549ef9dceadf6bd
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 <utils/KeyedVector.h>
26#include <utils/SortedVector.h>
27#include <utils/String16.h>
28#include <utils/String8.h>
29#include <utils/threads.h>
30#include <utils/Vector.h>
31#include <utils/ZipFileRO.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    typedef enum CacheMode {
73        CACHE_UNKNOWN = 0,
74        CACHE_OFF,          // don't try to cache file locations
75        CACHE_DEFER,        // construct cache as pieces are needed
76        //CACHE_SCAN,         // scan full(!) asset hierarchy at init() time
77    } CacheMode;
78
79    AssetManager(CacheMode cacheMode = CACHE_OFF);
80    virtual ~AssetManager(void);
81
82    static int32_t getGlobalCount();
83
84    /*
85     * Add a new source for assets.  This can be called multiple times to
86     * look in multiple places for assets.  It can be either a directory (for
87     * finding assets as raw files on the disk) or a ZIP file.  This newly
88     * added asset path will be examined first when searching for assets,
89     * before any that were previously added.
90     *
91     * Returns "true" on success, "false" on failure.  If 'cookie' is non-NULL,
92     * then on success, *cookie is set to the value corresponding to the
93     * newly-added asset source.
94     */
95    bool addAssetPath(const String8& path, void** cookie);
96
97    /*
98     * Convenience for adding the standard system assets.  Uses the
99     * ANDROID_ROOT environment variable to find them.
100     */
101    bool addDefaultAssets();
102
103    /*
104     * Iterate over the asset paths in this manager.  (Previously
105     * added via addAssetPath() and addDefaultAssets().)  On first call,
106     * 'cookie' must be NULL, resulting in the first cookie being returned.
107     * Each next cookie will be returned there-after, until NULL indicating
108     * the end has been reached.
109     */
110    void* nextAssetPath(void* cookie) const;
111
112    /*
113     * Return an asset path in the manager.  'which' must be between 0 and
114     * countAssetPaths().
115     */
116    String8 getAssetPath(void* cookie) const;
117
118    /*
119     * Set the current locale and vendor.  The locale can change during
120     * the lifetime of an AssetManager if the user updates the device's
121     * language setting.  The vendor is less likely to change.
122     *
123     * Pass in NULL to indicate no preference.
124     */
125    void setLocale(const char* locale);
126    void setVendor(const char* vendor);
127
128    /*
129     * Choose screen orientation for resources values returned.
130     */
131    void setConfiguration(const ResTable_config& config, const char* locale = NULL);
132
133    void getConfiguration(ResTable_config* outConfig) const;
134
135    typedef Asset::AccessMode AccessMode;       // typing shortcut
136
137    /*
138     * Open an asset.
139     *
140     * This will search through locale-specific and vendor-specific
141     * directories and packages to find the file.
142     *
143     * The object returned does not depend on the AssetManager.  It should
144     * be freed by calling Asset::close().
145     */
146    Asset* open(const char* fileName, AccessMode mode);
147
148    /*
149     * Open a non-asset file as an asset.
150     *
151     * This is for opening files that are included in an asset package
152     * but aren't assets.  These sit outside the usual "locale/vendor"
153     * path hierarchy, and will not be seen by "AssetDir" or included
154     * in our filename cache.
155     */
156    Asset* openNonAsset(const char* fileName, AccessMode mode);
157
158    /*
159     * Explicit non-asset file.  The file explicitly named by the cookie (the
160     * resource set to look in) and fileName will be opened and returned.
161     */
162    Asset* openNonAsset(void* cookie, const char* fileName, AccessMode mode);
163
164    /*
165     * Open a directory within the asset hierarchy.
166     *
167     * The contents of the directory are an amalgam of vendor-specific,
168     * locale-specific, and generic assets stored loosely or in asset
169     * packages.  Depending on the cache setting and previous accesses,
170     * this call may incur significant disk overhead.
171     *
172     * To open the top-level directory, pass in "".
173     */
174    AssetDir* openDir(const char* dirName);
175
176    /*
177     * Open a directory within a particular path of the asset manager.
178     *
179     * The contents of the directory are an amalgam of vendor-specific,
180     * locale-specific, and generic assets stored loosely or in asset
181     * packages.  Depending on the cache setting and previous accesses,
182     * this call may incur significant disk overhead.
183     *
184     * To open the top-level directory, pass in "".
185     */
186    AssetDir* openNonAssetDir(void* cookie, const char* dirName);
187
188    /*
189     * Get the type of a file in the asset hierarchy.  They will either
190     * be "regular" or "directory".  [Currently only works for "regular".]
191     *
192     * Can also be used as a quick test for existence of a file.
193     */
194    FileType getFileType(const char* fileName);
195
196    /*
197     * Return the complete resource table to find things in the package.
198     */
199    const ResTable& getResources(bool required = true) const;
200
201    /*
202     * Discard cached filename information.  This only needs to be called
203     * if somebody has updated the set of "loose" files, and we want to
204     * discard our cached notion of what's where.
205     */
206    void purge(void) { purgeFileNameCacheLocked(); }
207
208    /*
209     * Return true if the files this AssetManager references are all
210     * up-to-date (have not been changed since it was created).  If false
211     * is returned, you will need to create a new AssetManager to get
212     * the current data.
213     */
214    bool isUpToDate();
215
216    /**
217     * Get the known locales for this asset manager object.
218     */
219    void getLocales(Vector<String8>* locales) const;
220
221private:
222    struct asset_path
223    {
224        String8 path;
225        FileType type;
226        String8 idmap;
227    };
228
229    Asset* openInPathLocked(const char* fileName, AccessMode mode,
230        const asset_path& path);
231    Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
232        const asset_path& path);
233    Asset* openInLocaleVendorLocked(const char* fileName, AccessMode mode,
234        const asset_path& path, const char* locale, const char* vendor);
235    String8 createPathNameLocked(const asset_path& path, const char* locale,
236        const char* vendor);
237    String8 createPathNameLocked(const asset_path& path, const char* rootDir);
238    String8 createZipSourceNameLocked(const String8& zipFileName,
239        const String8& dirName, const String8& fileName);
240
241    ZipFileRO* getZipFileLocked(const asset_path& path);
242    Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
243    Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
244        const ZipEntryRO entry, AccessMode mode, const String8& entryName);
245
246    bool scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
247        const asset_path& path, const char* rootDir, const char* dirName);
248    SortedVector<AssetDir::FileInfo>* scanDirLocked(const String8& path);
249    bool scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
250        const asset_path& path, const char* rootDir, const char* dirName);
251    void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
252        const SortedVector<AssetDir::FileInfo>* pContents);
253
254    void loadFileNameCacheLocked(void);
255    void fncScanLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
256        const char* dirName);
257    bool fncScanAndMergeDirLocked(
258        SortedVector<AssetDir::FileInfo>* pMergedInfo,
259        const asset_path& path, const char* locale, const char* vendor,
260        const char* dirName);
261    void purgeFileNameCacheLocked(void);
262
263    const ResTable* getResTable(bool required = true) const;
264    void setLocaleLocked(const char* locale);
265    void updateResourceParamsLocked() const;
266
267    bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
268                               const String8& idmapPath);
269
270    bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
271                            const String8& idmapPath);
272
273    Asset* openIdmapLocked(const struct asset_path& ap) const;
274
275    bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc);
276
277    class SharedZip : public RefBase {
278    public:
279        static sp<SharedZip> get(const String8& path);
280
281        ZipFileRO* getZip();
282
283        Asset* getResourceTableAsset();
284        Asset* setResourceTableAsset(Asset* asset);
285
286        ResTable* getResourceTable();
287        ResTable* setResourceTable(ResTable* res);
288
289        bool isUpToDate();
290
291    protected:
292        ~SharedZip();
293
294    private:
295        SharedZip(const String8& path, time_t modWhen);
296        SharedZip(); // <-- not implemented
297
298        String8 mPath;
299        ZipFileRO* mZipFile;
300        time_t mModWhen;
301
302        Asset* mResourceTableAsset;
303        ResTable* mResourceTable;
304
305        static Mutex gLock;
306        static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
307    };
308
309    /*
310     * Manage a set of Zip files.  For each file we need a pointer to the
311     * ZipFile and a time_t with the file's modification date.
312     *
313     * We currently only have two zip files (current app, "common" app).
314     * (This was originally written for 8, based on app/locale/vendor.)
315     */
316    class ZipSet {
317    public:
318        ZipSet(void);
319        ~ZipSet(void);
320
321        /*
322         * Return a ZipFileRO structure for a ZipFileRO with the specified
323         * parameters.
324         */
325        ZipFileRO* getZip(const String8& path);
326
327        Asset* getZipResourceTableAsset(const String8& path);
328        Asset* setZipResourceTableAsset(const String8& path, Asset* asset);
329
330        ResTable* getZipResourceTable(const String8& path);
331        ResTable* setZipResourceTable(const String8& path, ResTable* res);
332
333        // generate path, e.g. "common/en-US-noogle.zip"
334        static String8 getPathName(const char* path);
335
336        bool isUpToDate();
337
338    private:
339        void closeZip(int idx);
340
341        int getIndex(const String8& zip) const;
342        mutable Vector<String8> mZipPath;
343        mutable Vector<sp<SharedZip> > mZipFile;
344    };
345
346    // Protect all internal state.
347    mutable Mutex   mLock;
348
349    ZipSet          mZipSet;
350
351    Vector<asset_path> mAssetPaths;
352    char*           mLocale;
353    char*           mVendor;
354
355    mutable ResTable* mResources;
356    ResTable_config* mConfig;
357
358    /*
359     * Cached data for "loose" files.  This lets us avoid poking at the
360     * filesystem when searching for loose assets.  Each entry is the
361     * "extended partial" path, e.g. "default/default/foo/bar.txt".  The
362     * full set of files is present, including ".EXCLUDE" entries.
363     *
364     * We do not cache directory names.  We don't retain the ".gz",
365     * because to our clients "foo" and "foo.gz" both look like "foo".
366     */
367    CacheMode       mCacheMode;         // is the cache enabled?
368    bool            mCacheValid;        // clear when locale or vendor changes
369    SortedVector<AssetDir::FileInfo> mCache;
370};
371
372}; // namespace android
373
374#endif // __LIBS_ASSETMANAGER_H
375