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.
54 *
55 * The asset hierarchy may be examined like a filesystem, using
56 * AssetDir objects to peruse a single directory.
57 */
58class AssetManager : public AAssetManager {
59public:
60    static const char* RESOURCES_FILENAME;
61    static const char* IDMAP_BIN;
62    static const char* OVERLAY_DIR;
63    /*
64     * If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay
65     * APKs in OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to
66     * OVERLAY_DIR.
67     */
68    static const char* OVERLAY_THEME_DIR_PROPERTY;
69    static const char* TARGET_PACKAGE_NAME;
70    static const char* TARGET_APK_PATH;
71    static const char* IDMAP_DIR;
72
73    AssetManager();
74    virtual ~AssetManager(void);
75
76    static int32_t getGlobalCount();
77
78    /*
79     * Add a new source for assets.  This can be called multiple times to
80     * look in multiple places for assets.  It can be either a directory (for
81     * finding assets as raw files on the disk) or a ZIP file.  This newly
82     * added asset path will be examined first when searching for assets,
83     * before any that were previously added, the assets are added as shared
84     * library if appAsLib is true.
85     *
86     * Returns "true" on success, "false" on failure.  If 'cookie' is non-NULL,
87     * then on success, *cookie is set to the value corresponding to the
88     * newly-added asset source.
89     */
90    bool addAssetPath(const String8& path, int32_t* cookie,
91        bool appAsLib=false, bool isSystemAsset=false);
92    bool addOverlayPath(const String8& path, int32_t* cookie);
93
94    /*
95     * Convenience for adding the standard system assets.  Uses the
96     * ANDROID_ROOT environment variable to find them.
97     */
98    bool addDefaultAssets();
99
100    /*
101     * Iterate over the asset paths in this manager.  (Previously
102     * added via addAssetPath() and addDefaultAssets().)  On first call,
103     * 'cookie' must be 0, resulting in the first cookie being returned.
104     * Each next cookie will be returned there-after, until -1 indicating
105     * the end has been reached.
106     */
107    int32_t nextAssetPath(const int32_t cookie) const;
108
109    /*
110     * Return an asset path in the manager.  'cookie' must be a non-negative value
111     * previously returned from addAssetPath() or nextAssetPath().
112     */
113    String8 getAssetPath(const int32_t cookie) const;
114
115    /*
116     * Sets various device configuration parameters, like screen orientation, layout,
117     * size, locale, etc.
118     * The optional 'locale' string takes precedence over the locale within 'config'
119     * and must be in bcp47 format.
120     */
121    void setConfiguration(const ResTable_config& config, const char* locale = NULL);
122
123    void getConfiguration(ResTable_config* outConfig) const;
124
125    typedef Asset::AccessMode AccessMode;       // typing shortcut
126
127    /*
128     * Open an asset.
129     *
130     * The object returned does not depend on the AssetManager.  It should
131     * be freed by calling Asset::close().
132     */
133    Asset* open(const char* fileName, AccessMode mode);
134
135    /*
136     * Open a non-asset file as an asset.
137     *
138     * This is for opening files that are included in an asset package
139     * but aren't assets.  These sit outside the usual "assets/"
140     * path hierarchy, and will not be seen by "AssetDir".
141     */
142    Asset* openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie = NULL);
143
144    /*
145     * Explicit non-asset file.  The file explicitly named by the cookie (the
146     * resource set to look in) and fileName will be opened and returned.
147     */
148    Asset* openNonAsset(const int32_t cookie, const char* fileName, AccessMode mode);
149
150    /*
151     * Open a directory within the asset hierarchy.
152     *
153     * To open the top-level directory, pass in "".
154     */
155    AssetDir* openDir(const char* dirName);
156
157    /*
158     * Open a directory within a particular path of the asset manager.
159     *
160     * To open the top-level directory, pass in "".
161     */
162    AssetDir* openNonAssetDir(const int32_t cookie, const char* dirName);
163
164    /*
165     * Get the type of a file in the asset hierarchy.  They will either
166     * be "regular" or "directory".  [Currently only works for "regular".]
167     *
168     * Can also be used as a quick test for existence of a file.
169     */
170    FileType getFileType(const char* fileName);
171
172    /*
173     * Return the complete resource table to find things in the package.
174     */
175    const ResTable& getResources(bool required = true) const;
176
177    /*
178     * Return true if the files this AssetManager references are all
179     * up-to-date (have not been changed since it was created).  If false
180     * is returned, you will need to create a new AssetManager to get
181     * the current data.
182     */
183    bool isUpToDate();
184
185    /**
186     * Get the known locales for this asset manager object.
187     */
188    void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
189
190    /**
191     * Generate idmap data to translate resources IDs between a package and a
192     * corresponding overlay package.
193     */
194    bool createIdmap(const char* targetApkPath, const char* overlayApkPath,
195        uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize);
196
197private:
198    struct asset_path
199    {
200        asset_path() : path(""), type(kFileTypeRegular), idmap(""),
201                       isSystemOverlay(false), isSystemAsset(false) {}
202        String8 path;
203        FileType type;
204        String8 idmap;
205        bool isSystemOverlay;
206        bool isSystemAsset;
207    };
208
209    Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
210        const asset_path& path);
211    String8 createPathNameLocked(const asset_path& path, const char* rootDir);
212    String8 createZipSourceNameLocked(const String8& zipFileName,
213        const String8& dirName, const String8& fileName);
214
215    ZipFileRO* getZipFileLocked(const asset_path& path);
216    Asset* openAssetFromFileLocked(const String8& fileName, AccessMode mode);
217    Asset* openAssetFromZipLocked(const ZipFileRO* pZipFile,
218        const ZipEntryRO entry, AccessMode mode, const String8& entryName);
219
220    bool scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
221        const asset_path& path, const char* rootDir, const char* dirName);
222    SortedVector<AssetDir::FileInfo>* scanDirLocked(const String8& path);
223    bool scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
224        const asset_path& path, const char* rootDir, const char* dirName);
225    void mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
226        const SortedVector<AssetDir::FileInfo>* pContents);
227
228    const ResTable* getResTable(bool required = true) const;
229    void setLocaleLocked(const char* locale);
230    void updateResourceParamsLocked() const;
231    bool appendPathToResTable(const asset_path& ap, bool appAsLib=false) const;
232
233    Asset* openIdmapLocked(const struct asset_path& ap) const;
234
235    void addSystemOverlays(const char* pathOverlaysList, const String8& targetPackagePath,
236            ResTable* sharedRes, size_t offset) const;
237
238    class SharedZip : public RefBase {
239    public:
240        static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true);
241
242        ZipFileRO* getZip();
243
244        Asset* getResourceTableAsset();
245        Asset* setResourceTableAsset(Asset* asset);
246
247        ResTable* getResourceTable();
248        ResTable* setResourceTable(ResTable* res);
249
250        bool isUpToDate();
251
252        void addOverlay(const asset_path& ap);
253        bool getOverlay(size_t idx, asset_path* out) const;
254
255    protected:
256        ~SharedZip();
257
258    private:
259        SharedZip(const String8& path, time_t modWhen);
260        SharedZip(); // <-- not implemented
261
262        String8 mPath;
263        ZipFileRO* mZipFile;
264        time_t mModWhen;
265
266        Asset* mResourceTableAsset;
267        ResTable* mResourceTable;
268
269        Vector<asset_path> mOverlays;
270
271        static Mutex gLock;
272        static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
273    };
274
275    /*
276     * Manage a set of Zip files.  For each file we need a pointer to the
277     * ZipFile and a time_t with the file's modification date.
278     *
279     * We currently only have two zip files (current app, "common" app).
280     * (This was originally written for 8, based on app/locale/vendor.)
281     */
282    class ZipSet {
283    public:
284        ZipSet() = default;
285        ~ZipSet();
286
287        /*
288         * Return a ZipFileRO structure for a ZipFileRO with the specified
289         * parameters.
290         */
291        ZipFileRO* getZip(const String8& path);
292
293        Asset* getZipResourceTableAsset(const String8& path);
294        Asset* setZipResourceTableAsset(const String8& path, Asset* asset);
295
296        ResTable* getZipResourceTable(const String8& path);
297        ResTable* setZipResourceTable(const String8& path, ResTable* res);
298
299        // generate path, e.g. "common/en-US-noogle.zip"
300        static String8 getPathName(const char* path);
301
302        bool isUpToDate();
303
304        void addOverlay(const String8& path, const asset_path& overlay);
305        bool getOverlay(const String8& path, size_t idx, asset_path* out) const;
306
307    private:
308        void closeZip(int idx);
309
310        int getIndex(const String8& zip) const;
311        mutable Vector<String8> mZipPath;
312        mutable Vector<sp<SharedZip> > mZipFile;
313    };
314
315    // Protect all internal state.
316    mutable Mutex   mLock;
317
318    ZipSet          mZipSet;
319
320    Vector<asset_path> mAssetPaths;
321    char*           mLocale;
322
323    mutable ResTable* mResources;
324    ResTable_config* mConfig;
325};
326
327}; // namespace android
328
329#endif // __LIBS_ASSETMANAGER_H
330