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