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