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