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