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