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 struct AAssetManager { };
37 
38 /*
39  * Now the proper C++ android-namespace definitions
40  */
41 
42 namespace android {
43 
44 class Asset;        // fwd decl for things that include Asset.h first
45 class ResTable;
46 struct 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  */
58 class AssetManager : public AAssetManager {
59 public:
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 
212 private:
213     class SharedZip;
214 
215     struct asset_path
216     {
asset_pathasset_path217         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