1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2006 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker //
18*d57664e9SAndroid Build Coastguard Worker // Provide access to read-only assets.
19*d57664e9SAndroid Build Coastguard Worker //
20*d57664e9SAndroid Build Coastguard Worker
21*d57664e9SAndroid Build Coastguard Worker #define LOG_TAG "asset"
22*d57664e9SAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_RESOURCES
23*d57664e9SAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
24*d57664e9SAndroid Build Coastguard Worker
25*d57664e9SAndroid Build Coastguard Worker #include <androidfw/Asset.h>
26*d57664e9SAndroid Build Coastguard Worker #include <androidfw/AssetDir.h>
27*d57664e9SAndroid Build Coastguard Worker #include <androidfw/AssetManager.h>
28*d57664e9SAndroid Build Coastguard Worker #include <androidfw/misc.h>
29*d57664e9SAndroid Build Coastguard Worker #include <androidfw/PathUtils.h>
30*d57664e9SAndroid Build Coastguard Worker #include <androidfw/ResourceTypes.h>
31*d57664e9SAndroid Build Coastguard Worker #include <androidfw/ZipFileRO.h>
32*d57664e9SAndroid Build Coastguard Worker #include <cutils/atomic.h>
33*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
34*d57664e9SAndroid Build Coastguard Worker #include <utils/String8.h>
35*d57664e9SAndroid Build Coastguard Worker #include <utils/String8.h>
36*d57664e9SAndroid Build Coastguard Worker #include <utils/threads.h>
37*d57664e9SAndroid Build Coastguard Worker #include <utils/Timers.h>
38*d57664e9SAndroid Build Coastguard Worker #include <utils/Trace.h>
39*d57664e9SAndroid Build Coastguard Worker #ifndef _WIN32
40*d57664e9SAndroid Build Coastguard Worker #include <sys/file.h>
41*d57664e9SAndroid Build Coastguard Worker #endif
42*d57664e9SAndroid Build Coastguard Worker
43*d57664e9SAndroid Build Coastguard Worker #include <assert.h>
44*d57664e9SAndroid Build Coastguard Worker #include <dirent.h>
45*d57664e9SAndroid Build Coastguard Worker #include <errno.h>
46*d57664e9SAndroid Build Coastguard Worker #include <string.h> // strerror
47*d57664e9SAndroid Build Coastguard Worker #include <strings.h>
48*d57664e9SAndroid Build Coastguard Worker
49*d57664e9SAndroid Build Coastguard Worker #ifndef TEMP_FAILURE_RETRY
50*d57664e9SAndroid Build Coastguard Worker /* Used to retry syscalls that can return EINTR. */
51*d57664e9SAndroid Build Coastguard Worker #define TEMP_FAILURE_RETRY(exp) ({ \
52*d57664e9SAndroid Build Coastguard Worker typeof (exp) _rc; \
53*d57664e9SAndroid Build Coastguard Worker do { \
54*d57664e9SAndroid Build Coastguard Worker _rc = (exp); \
55*d57664e9SAndroid Build Coastguard Worker } while (_rc == -1 && errno == EINTR); \
56*d57664e9SAndroid Build Coastguard Worker _rc; })
57*d57664e9SAndroid Build Coastguard Worker #endif
58*d57664e9SAndroid Build Coastguard Worker
59*d57664e9SAndroid Build Coastguard Worker using namespace android;
60*d57664e9SAndroid Build Coastguard Worker
61*d57664e9SAndroid Build Coastguard Worker static const bool kIsDebug = false;
62*d57664e9SAndroid Build Coastguard Worker
63*d57664e9SAndroid Build Coastguard Worker static const char* kAssetsRoot = "assets";
64*d57664e9SAndroid Build Coastguard Worker static const char* kAppZipName = NULL; //"classes.jar";
65*d57664e9SAndroid Build Coastguard Worker static const char* kSystemAssets = "framework/framework-res.apk";
66*d57664e9SAndroid Build Coastguard Worker static const char* kResourceCache = "resource-cache";
67*d57664e9SAndroid Build Coastguard Worker
68*d57664e9SAndroid Build Coastguard Worker static const char* kExcludeExtension = ".EXCLUDE";
69*d57664e9SAndroid Build Coastguard Worker
70*d57664e9SAndroid Build Coastguard Worker static Asset* const kExcludedAsset = (Asset*) 0xd000000d;
71*d57664e9SAndroid Build Coastguard Worker
72*d57664e9SAndroid Build Coastguard Worker static volatile int32_t gCount = 0;
73*d57664e9SAndroid Build Coastguard Worker
74*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
75*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
76*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay";
77*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay";
78*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::SYSTEM_EXT_OVERLAY_DIR = "/system_ext/overlay";
79*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::ODM_OVERLAY_DIR = "/odm/overlay";
80*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::OEM_OVERLAY_DIR = "/oem/overlay";
81*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme";
82*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::TARGET_PACKAGE_NAME = "android";
83*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
84*d57664e9SAndroid Build Coastguard Worker const char* AssetManager::IDMAP_DIR = "/data/resource-cache";
85*d57664e9SAndroid Build Coastguard Worker
86*d57664e9SAndroid Build Coastguard Worker namespace {
87*d57664e9SAndroid Build Coastguard Worker
idmapPathForPackagePath(const String8 & pkgPath)88*d57664e9SAndroid Build Coastguard Worker String8 idmapPathForPackagePath(const String8& pkgPath) {
89*d57664e9SAndroid Build Coastguard Worker const char* root = getenv("ANDROID_DATA");
90*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
91*d57664e9SAndroid Build Coastguard Worker String8 path(root);
92*d57664e9SAndroid Build Coastguard Worker appendPath(path, kResourceCache);
93*d57664e9SAndroid Build Coastguard Worker
94*d57664e9SAndroid Build Coastguard Worker char buf[256]; // 256 chars should be enough for anyone...
95*d57664e9SAndroid Build Coastguard Worker strncpy(buf, pkgPath.c_str(), 255);
96*d57664e9SAndroid Build Coastguard Worker buf[255] = '\0';
97*d57664e9SAndroid Build Coastguard Worker char* filename = buf;
98*d57664e9SAndroid Build Coastguard Worker while (*filename && *filename == '/') {
99*d57664e9SAndroid Build Coastguard Worker ++filename;
100*d57664e9SAndroid Build Coastguard Worker }
101*d57664e9SAndroid Build Coastguard Worker char* p = filename;
102*d57664e9SAndroid Build Coastguard Worker while (*p) {
103*d57664e9SAndroid Build Coastguard Worker if (*p == '/') {
104*d57664e9SAndroid Build Coastguard Worker *p = '@';
105*d57664e9SAndroid Build Coastguard Worker }
106*d57664e9SAndroid Build Coastguard Worker ++p;
107*d57664e9SAndroid Build Coastguard Worker }
108*d57664e9SAndroid Build Coastguard Worker appendPath(path, filename);
109*d57664e9SAndroid Build Coastguard Worker path.append("@idmap");
110*d57664e9SAndroid Build Coastguard Worker
111*d57664e9SAndroid Build Coastguard Worker return path;
112*d57664e9SAndroid Build Coastguard Worker }
113*d57664e9SAndroid Build Coastguard Worker
114*d57664e9SAndroid Build Coastguard Worker /*
115*d57664e9SAndroid Build Coastguard Worker * Like strdup(), but uses C++ "new" operator instead of malloc.
116*d57664e9SAndroid Build Coastguard Worker */
strdupNew(const char * str)117*d57664e9SAndroid Build Coastguard Worker static char* strdupNew(const char* str) {
118*d57664e9SAndroid Build Coastguard Worker char* newStr;
119*d57664e9SAndroid Build Coastguard Worker int len;
120*d57664e9SAndroid Build Coastguard Worker
121*d57664e9SAndroid Build Coastguard Worker if (str == NULL)
122*d57664e9SAndroid Build Coastguard Worker return NULL;
123*d57664e9SAndroid Build Coastguard Worker
124*d57664e9SAndroid Build Coastguard Worker len = strlen(str);
125*d57664e9SAndroid Build Coastguard Worker newStr = new char[len+1];
126*d57664e9SAndroid Build Coastguard Worker memcpy(newStr, str, len+1);
127*d57664e9SAndroid Build Coastguard Worker
128*d57664e9SAndroid Build Coastguard Worker return newStr;
129*d57664e9SAndroid Build Coastguard Worker }
130*d57664e9SAndroid Build Coastguard Worker
131*d57664e9SAndroid Build Coastguard Worker } // namespace
132*d57664e9SAndroid Build Coastguard Worker
133*d57664e9SAndroid Build Coastguard Worker /*
134*d57664e9SAndroid Build Coastguard Worker * ===========================================================================
135*d57664e9SAndroid Build Coastguard Worker * AssetManager
136*d57664e9SAndroid Build Coastguard Worker * ===========================================================================
137*d57664e9SAndroid Build Coastguard Worker */
138*d57664e9SAndroid Build Coastguard Worker
getGlobalCount()139*d57664e9SAndroid Build Coastguard Worker int32_t AssetManager::getGlobalCount() {
140*d57664e9SAndroid Build Coastguard Worker return gCount;
141*d57664e9SAndroid Build Coastguard Worker }
142*d57664e9SAndroid Build Coastguard Worker
AssetManager()143*d57664e9SAndroid Build Coastguard Worker AssetManager::AssetManager() :
144*d57664e9SAndroid Build Coastguard Worker mLocale(NULL), mResources(NULL), mConfig(new ResTable_config) {
145*d57664e9SAndroid Build Coastguard Worker int count = android_atomic_inc(&gCount) + 1;
146*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
147*d57664e9SAndroid Build Coastguard Worker ALOGI("Creating AssetManager %p #%d\n", this, count);
148*d57664e9SAndroid Build Coastguard Worker }
149*d57664e9SAndroid Build Coastguard Worker memset(mConfig, 0, sizeof(ResTable_config));
150*d57664e9SAndroid Build Coastguard Worker }
151*d57664e9SAndroid Build Coastguard Worker
~AssetManager()152*d57664e9SAndroid Build Coastguard Worker AssetManager::~AssetManager() {
153*d57664e9SAndroid Build Coastguard Worker int count = android_atomic_dec(&gCount);
154*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
155*d57664e9SAndroid Build Coastguard Worker ALOGI("Destroying AssetManager in %p #%d\n", this, count);
156*d57664e9SAndroid Build Coastguard Worker } else {
157*d57664e9SAndroid Build Coastguard Worker ALOGV("Destroying AssetManager in %p #%d\n", this, count);
158*d57664e9SAndroid Build Coastguard Worker }
159*d57664e9SAndroid Build Coastguard Worker
160*d57664e9SAndroid Build Coastguard Worker // Manually close any fd paths for which we have not yet opened their zip (which
161*d57664e9SAndroid Build Coastguard Worker // will take ownership of the fd and close it when done).
162*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<mAssetPaths.size(); i++) {
163*d57664e9SAndroid Build Coastguard Worker ALOGV("Cleaning path #%d: fd=%d, zip=%p", (int)i, mAssetPaths[i].rawFd,
164*d57664e9SAndroid Build Coastguard Worker mAssetPaths[i].zip.get());
165*d57664e9SAndroid Build Coastguard Worker if (mAssetPaths[i].rawFd >= 0 && mAssetPaths[i].zip == NULL) {
166*d57664e9SAndroid Build Coastguard Worker close(mAssetPaths[i].rawFd);
167*d57664e9SAndroid Build Coastguard Worker }
168*d57664e9SAndroid Build Coastguard Worker }
169*d57664e9SAndroid Build Coastguard Worker
170*d57664e9SAndroid Build Coastguard Worker delete mConfig;
171*d57664e9SAndroid Build Coastguard Worker delete mResources;
172*d57664e9SAndroid Build Coastguard Worker
173*d57664e9SAndroid Build Coastguard Worker // don't have a String class yet, so make sure we clean up
174*d57664e9SAndroid Build Coastguard Worker delete[] mLocale;
175*d57664e9SAndroid Build Coastguard Worker }
176*d57664e9SAndroid Build Coastguard Worker
addAssetPath(const String8 & path,int32_t * cookie,bool appAsLib,bool isSystemAsset)177*d57664e9SAndroid Build Coastguard Worker bool AssetManager::addAssetPath(
178*d57664e9SAndroid Build Coastguard Worker const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset) {
179*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
180*d57664e9SAndroid Build Coastguard Worker
181*d57664e9SAndroid Build Coastguard Worker asset_path ap;
182*d57664e9SAndroid Build Coastguard Worker
183*d57664e9SAndroid Build Coastguard Worker String8 realPath(path);
184*d57664e9SAndroid Build Coastguard Worker if (kAppZipName) {
185*d57664e9SAndroid Build Coastguard Worker appendPath(realPath, kAppZipName);
186*d57664e9SAndroid Build Coastguard Worker }
187*d57664e9SAndroid Build Coastguard Worker ap.type = ::getFileType(realPath.c_str());
188*d57664e9SAndroid Build Coastguard Worker if (ap.type == kFileTypeRegular) {
189*d57664e9SAndroid Build Coastguard Worker ap.path = realPath;
190*d57664e9SAndroid Build Coastguard Worker } else {
191*d57664e9SAndroid Build Coastguard Worker ap.path = path;
192*d57664e9SAndroid Build Coastguard Worker ap.type = ::getFileType(path.c_str());
193*d57664e9SAndroid Build Coastguard Worker if (ap.type != kFileTypeDirectory && ap.type != kFileTypeRegular) {
194*d57664e9SAndroid Build Coastguard Worker ALOGW("Asset path %s is neither a directory nor file (type=%d).",
195*d57664e9SAndroid Build Coastguard Worker path.c_str(), (int)ap.type);
196*d57664e9SAndroid Build Coastguard Worker return false;
197*d57664e9SAndroid Build Coastguard Worker }
198*d57664e9SAndroid Build Coastguard Worker }
199*d57664e9SAndroid Build Coastguard Worker
200*d57664e9SAndroid Build Coastguard Worker // Skip if we have it already.
201*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<mAssetPaths.size(); i++) {
202*d57664e9SAndroid Build Coastguard Worker if (mAssetPaths[i].path == ap.path) {
203*d57664e9SAndroid Build Coastguard Worker if (cookie) {
204*d57664e9SAndroid Build Coastguard Worker *cookie = static_cast<int32_t>(i+1);
205*d57664e9SAndroid Build Coastguard Worker }
206*d57664e9SAndroid Build Coastguard Worker return true;
207*d57664e9SAndroid Build Coastguard Worker }
208*d57664e9SAndroid Build Coastguard Worker }
209*d57664e9SAndroid Build Coastguard Worker
210*d57664e9SAndroid Build Coastguard Worker ALOGV("In %p Asset %s path: %s", this,
211*d57664e9SAndroid Build Coastguard Worker ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.c_str());
212*d57664e9SAndroid Build Coastguard Worker
213*d57664e9SAndroid Build Coastguard Worker ap.isSystemAsset = isSystemAsset;
214*d57664e9SAndroid Build Coastguard Worker ssize_t apPos = mAssetPaths.add(ap);
215*d57664e9SAndroid Build Coastguard Worker
216*d57664e9SAndroid Build Coastguard Worker // new paths are always added at the end
217*d57664e9SAndroid Build Coastguard Worker if (cookie) {
218*d57664e9SAndroid Build Coastguard Worker *cookie = static_cast<int32_t>(mAssetPaths.size());
219*d57664e9SAndroid Build Coastguard Worker }
220*d57664e9SAndroid Build Coastguard Worker
221*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
222*d57664e9SAndroid Build Coastguard Worker // Load overlays, if any
223*d57664e9SAndroid Build Coastguard Worker asset_path oap;
224*d57664e9SAndroid Build Coastguard Worker for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
225*d57664e9SAndroid Build Coastguard Worker oap.isSystemAsset = isSystemAsset;
226*d57664e9SAndroid Build Coastguard Worker mAssetPaths.add(oap);
227*d57664e9SAndroid Build Coastguard Worker }
228*d57664e9SAndroid Build Coastguard Worker #endif
229*d57664e9SAndroid Build Coastguard Worker
230*d57664e9SAndroid Build Coastguard Worker if (mResources != NULL) {
231*d57664e9SAndroid Build Coastguard Worker appendPathToResTable(mAssetPaths.editItemAt(apPos), appAsLib);
232*d57664e9SAndroid Build Coastguard Worker }
233*d57664e9SAndroid Build Coastguard Worker
234*d57664e9SAndroid Build Coastguard Worker return true;
235*d57664e9SAndroid Build Coastguard Worker }
236*d57664e9SAndroid Build Coastguard Worker
addOverlayPath(const String8 & packagePath,int32_t * cookie)237*d57664e9SAndroid Build Coastguard Worker bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
238*d57664e9SAndroid Build Coastguard Worker {
239*d57664e9SAndroid Build Coastguard Worker const String8 idmapPath = idmapPathForPackagePath(packagePath);
240*d57664e9SAndroid Build Coastguard Worker
241*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
242*d57664e9SAndroid Build Coastguard Worker
243*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < mAssetPaths.size(); ++i) {
244*d57664e9SAndroid Build Coastguard Worker if (mAssetPaths[i].idmap == idmapPath) {
245*d57664e9SAndroid Build Coastguard Worker *cookie = static_cast<int32_t>(i + 1);
246*d57664e9SAndroid Build Coastguard Worker return true;
247*d57664e9SAndroid Build Coastguard Worker }
248*d57664e9SAndroid Build Coastguard Worker }
249*d57664e9SAndroid Build Coastguard Worker
250*d57664e9SAndroid Build Coastguard Worker Asset* idmap = NULL;
251*d57664e9SAndroid Build Coastguard Worker if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) {
252*d57664e9SAndroid Build Coastguard Worker ALOGW("failed to open idmap file %s\n", idmapPath.c_str());
253*d57664e9SAndroid Build Coastguard Worker return false;
254*d57664e9SAndroid Build Coastguard Worker }
255*d57664e9SAndroid Build Coastguard Worker
256*d57664e9SAndroid Build Coastguard Worker String8 targetPath;
257*d57664e9SAndroid Build Coastguard Worker String8 overlayPath;
258*d57664e9SAndroid Build Coastguard Worker if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(),
259*d57664e9SAndroid Build Coastguard Worker NULL, NULL, NULL, &targetPath, &overlayPath)) {
260*d57664e9SAndroid Build Coastguard Worker ALOGW("failed to read idmap file %s\n", idmapPath.c_str());
261*d57664e9SAndroid Build Coastguard Worker delete idmap;
262*d57664e9SAndroid Build Coastguard Worker return false;
263*d57664e9SAndroid Build Coastguard Worker }
264*d57664e9SAndroid Build Coastguard Worker delete idmap;
265*d57664e9SAndroid Build Coastguard Worker
266*d57664e9SAndroid Build Coastguard Worker if (overlayPath != packagePath) {
267*d57664e9SAndroid Build Coastguard Worker ALOGW("idmap file %s inconcistent: expected path %s does not match actual path %s\n",
268*d57664e9SAndroid Build Coastguard Worker idmapPath.c_str(), packagePath.c_str(), overlayPath.c_str());
269*d57664e9SAndroid Build Coastguard Worker return false;
270*d57664e9SAndroid Build Coastguard Worker }
271*d57664e9SAndroid Build Coastguard Worker if (access(targetPath.c_str(), R_OK) != 0) {
272*d57664e9SAndroid Build Coastguard Worker ALOGW("failed to access file %s: %s\n", targetPath.c_str(), strerror(errno));
273*d57664e9SAndroid Build Coastguard Worker return false;
274*d57664e9SAndroid Build Coastguard Worker }
275*d57664e9SAndroid Build Coastguard Worker if (access(idmapPath.c_str(), R_OK) != 0) {
276*d57664e9SAndroid Build Coastguard Worker ALOGW("failed to access file %s: %s\n", idmapPath.c_str(), strerror(errno));
277*d57664e9SAndroid Build Coastguard Worker return false;
278*d57664e9SAndroid Build Coastguard Worker }
279*d57664e9SAndroid Build Coastguard Worker if (access(overlayPath.c_str(), R_OK) != 0) {
280*d57664e9SAndroid Build Coastguard Worker ALOGW("failed to access file %s: %s\n", overlayPath.c_str(), strerror(errno));
281*d57664e9SAndroid Build Coastguard Worker return false;
282*d57664e9SAndroid Build Coastguard Worker }
283*d57664e9SAndroid Build Coastguard Worker
284*d57664e9SAndroid Build Coastguard Worker asset_path oap;
285*d57664e9SAndroid Build Coastguard Worker oap.path = overlayPath;
286*d57664e9SAndroid Build Coastguard Worker oap.type = ::getFileType(overlayPath.c_str());
287*d57664e9SAndroid Build Coastguard Worker oap.idmap = idmapPath;
288*d57664e9SAndroid Build Coastguard Worker #if 0
289*d57664e9SAndroid Build Coastguard Worker ALOGD("Overlay added: targetPath=%s overlayPath=%s idmapPath=%s\n",
290*d57664e9SAndroid Build Coastguard Worker targetPath.c_str(), overlayPath.c_str(), idmapPath.c_str());
291*d57664e9SAndroid Build Coastguard Worker #endif
292*d57664e9SAndroid Build Coastguard Worker mAssetPaths.add(oap);
293*d57664e9SAndroid Build Coastguard Worker *cookie = static_cast<int32_t>(mAssetPaths.size());
294*d57664e9SAndroid Build Coastguard Worker
295*d57664e9SAndroid Build Coastguard Worker if (mResources != NULL) {
296*d57664e9SAndroid Build Coastguard Worker appendPathToResTable(oap);
297*d57664e9SAndroid Build Coastguard Worker }
298*d57664e9SAndroid Build Coastguard Worker
299*d57664e9SAndroid Build Coastguard Worker return true;
300*d57664e9SAndroid Build Coastguard Worker }
301*d57664e9SAndroid Build Coastguard Worker
addAssetFd(int fd,const String8 & debugPathName,int32_t * cookie,bool appAsLib,bool assume_ownership)302*d57664e9SAndroid Build Coastguard Worker bool AssetManager::addAssetFd(
303*d57664e9SAndroid Build Coastguard Worker int fd, const String8& debugPathName, int32_t* cookie, bool appAsLib,
304*d57664e9SAndroid Build Coastguard Worker bool assume_ownership) {
305*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
306*d57664e9SAndroid Build Coastguard Worker
307*d57664e9SAndroid Build Coastguard Worker asset_path ap;
308*d57664e9SAndroid Build Coastguard Worker
309*d57664e9SAndroid Build Coastguard Worker ap.path = debugPathName;
310*d57664e9SAndroid Build Coastguard Worker ap.rawFd = fd;
311*d57664e9SAndroid Build Coastguard Worker ap.type = kFileTypeRegular;
312*d57664e9SAndroid Build Coastguard Worker ap.assumeOwnership = assume_ownership;
313*d57664e9SAndroid Build Coastguard Worker
314*d57664e9SAndroid Build Coastguard Worker ALOGV("In %p Asset fd %d name: %s", this, fd, ap.path.c_str());
315*d57664e9SAndroid Build Coastguard Worker
316*d57664e9SAndroid Build Coastguard Worker ssize_t apPos = mAssetPaths.add(ap);
317*d57664e9SAndroid Build Coastguard Worker
318*d57664e9SAndroid Build Coastguard Worker // new paths are always added at the end
319*d57664e9SAndroid Build Coastguard Worker if (cookie) {
320*d57664e9SAndroid Build Coastguard Worker *cookie = static_cast<int32_t>(mAssetPaths.size());
321*d57664e9SAndroid Build Coastguard Worker }
322*d57664e9SAndroid Build Coastguard Worker
323*d57664e9SAndroid Build Coastguard Worker if (mResources != NULL) {
324*d57664e9SAndroid Build Coastguard Worker appendPathToResTable(mAssetPaths.editItemAt(apPos), appAsLib);
325*d57664e9SAndroid Build Coastguard Worker }
326*d57664e9SAndroid Build Coastguard Worker
327*d57664e9SAndroid Build Coastguard Worker return true;
328*d57664e9SAndroid Build Coastguard Worker }
329*d57664e9SAndroid Build Coastguard Worker
createIdmap(const char * targetApkPath,const char * overlayApkPath,uint32_t targetCrc,uint32_t overlayCrc,uint32_t ** outData,size_t * outSize)330*d57664e9SAndroid Build Coastguard Worker bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath,
331*d57664e9SAndroid Build Coastguard Worker uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, size_t* outSize)
332*d57664e9SAndroid Build Coastguard Worker {
333*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
334*d57664e9SAndroid Build Coastguard Worker const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) };
335*d57664e9SAndroid Build Coastguard Worker Asset* assets[2] = {NULL, NULL};
336*d57664e9SAndroid Build Coastguard Worker bool ret = false;
337*d57664e9SAndroid Build Coastguard Worker {
338*d57664e9SAndroid Build Coastguard Worker ResTable tables[2];
339*d57664e9SAndroid Build Coastguard Worker
340*d57664e9SAndroid Build Coastguard Worker for (int i = 0; i < 2; ++i) {
341*d57664e9SAndroid Build Coastguard Worker asset_path ap;
342*d57664e9SAndroid Build Coastguard Worker ap.type = kFileTypeRegular;
343*d57664e9SAndroid Build Coastguard Worker ap.path = paths[i];
344*d57664e9SAndroid Build Coastguard Worker assets[i] = openNonAssetInPathLocked("resources.arsc",
345*d57664e9SAndroid Build Coastguard Worker Asset::ACCESS_BUFFER, ap);
346*d57664e9SAndroid Build Coastguard Worker if (assets[i] == NULL) {
347*d57664e9SAndroid Build Coastguard Worker ALOGW("failed to find resources.arsc in %s\n", ap.path.c_str());
348*d57664e9SAndroid Build Coastguard Worker goto exit;
349*d57664e9SAndroid Build Coastguard Worker }
350*d57664e9SAndroid Build Coastguard Worker if (tables[i].add(assets[i]) != NO_ERROR) {
351*d57664e9SAndroid Build Coastguard Worker ALOGW("failed to add %s to resource table", paths[i].c_str());
352*d57664e9SAndroid Build Coastguard Worker goto exit;
353*d57664e9SAndroid Build Coastguard Worker }
354*d57664e9SAndroid Build Coastguard Worker }
355*d57664e9SAndroid Build Coastguard Worker ret = tables[1].createIdmap(tables[0], targetCrc, overlayCrc,
356*d57664e9SAndroid Build Coastguard Worker targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
357*d57664e9SAndroid Build Coastguard Worker }
358*d57664e9SAndroid Build Coastguard Worker
359*d57664e9SAndroid Build Coastguard Worker exit:
360*d57664e9SAndroid Build Coastguard Worker delete assets[0];
361*d57664e9SAndroid Build Coastguard Worker delete assets[1];
362*d57664e9SAndroid Build Coastguard Worker return ret;
363*d57664e9SAndroid Build Coastguard Worker }
364*d57664e9SAndroid Build Coastguard Worker
addDefaultAssets()365*d57664e9SAndroid Build Coastguard Worker bool AssetManager::addDefaultAssets()
366*d57664e9SAndroid Build Coastguard Worker {
367*d57664e9SAndroid Build Coastguard Worker const char* root = getenv("ANDROID_ROOT");
368*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
369*d57664e9SAndroid Build Coastguard Worker
370*d57664e9SAndroid Build Coastguard Worker String8 path(root);
371*d57664e9SAndroid Build Coastguard Worker appendPath(path, kSystemAssets);
372*d57664e9SAndroid Build Coastguard Worker
373*d57664e9SAndroid Build Coastguard Worker return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
374*d57664e9SAndroid Build Coastguard Worker }
375*d57664e9SAndroid Build Coastguard Worker
nextAssetPath(const int32_t cookie) const376*d57664e9SAndroid Build Coastguard Worker int32_t AssetManager::nextAssetPath(const int32_t cookie) const
377*d57664e9SAndroid Build Coastguard Worker {
378*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
379*d57664e9SAndroid Build Coastguard Worker const size_t next = static_cast<size_t>(cookie) + 1;
380*d57664e9SAndroid Build Coastguard Worker return next > mAssetPaths.size() ? -1 : next;
381*d57664e9SAndroid Build Coastguard Worker }
382*d57664e9SAndroid Build Coastguard Worker
getAssetPath(const int32_t cookie) const383*d57664e9SAndroid Build Coastguard Worker String8 AssetManager::getAssetPath(const int32_t cookie) const
384*d57664e9SAndroid Build Coastguard Worker {
385*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
386*d57664e9SAndroid Build Coastguard Worker const size_t which = static_cast<size_t>(cookie) - 1;
387*d57664e9SAndroid Build Coastguard Worker if (which < mAssetPaths.size()) {
388*d57664e9SAndroid Build Coastguard Worker return mAssetPaths[which].path;
389*d57664e9SAndroid Build Coastguard Worker }
390*d57664e9SAndroid Build Coastguard Worker return String8();
391*d57664e9SAndroid Build Coastguard Worker }
392*d57664e9SAndroid Build Coastguard Worker
setLocaleLocked(const char * locale)393*d57664e9SAndroid Build Coastguard Worker void AssetManager::setLocaleLocked(const char* locale)
394*d57664e9SAndroid Build Coastguard Worker {
395*d57664e9SAndroid Build Coastguard Worker if (mLocale != NULL) {
396*d57664e9SAndroid Build Coastguard Worker delete[] mLocale;
397*d57664e9SAndroid Build Coastguard Worker }
398*d57664e9SAndroid Build Coastguard Worker
399*d57664e9SAndroid Build Coastguard Worker mLocale = strdupNew(locale);
400*d57664e9SAndroid Build Coastguard Worker updateResourceParamsLocked();
401*d57664e9SAndroid Build Coastguard Worker }
402*d57664e9SAndroid Build Coastguard Worker
setConfiguration(const ResTable_config & config,const char * locale)403*d57664e9SAndroid Build Coastguard Worker void AssetManager::setConfiguration(const ResTable_config& config, const char* locale)
404*d57664e9SAndroid Build Coastguard Worker {
405*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
406*d57664e9SAndroid Build Coastguard Worker *mConfig = config;
407*d57664e9SAndroid Build Coastguard Worker if (locale) {
408*d57664e9SAndroid Build Coastguard Worker setLocaleLocked(locale);
409*d57664e9SAndroid Build Coastguard Worker } else if (config.language[0] != 0) {
410*d57664e9SAndroid Build Coastguard Worker char spec[RESTABLE_MAX_LOCALE_LEN];
411*d57664e9SAndroid Build Coastguard Worker config.getBcp47Locale(spec);
412*d57664e9SAndroid Build Coastguard Worker setLocaleLocked(spec);
413*d57664e9SAndroid Build Coastguard Worker } else {
414*d57664e9SAndroid Build Coastguard Worker updateResourceParamsLocked();
415*d57664e9SAndroid Build Coastguard Worker }
416*d57664e9SAndroid Build Coastguard Worker }
417*d57664e9SAndroid Build Coastguard Worker
getConfiguration(ResTable_config * outConfig) const418*d57664e9SAndroid Build Coastguard Worker void AssetManager::getConfiguration(ResTable_config* outConfig) const
419*d57664e9SAndroid Build Coastguard Worker {
420*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
421*d57664e9SAndroid Build Coastguard Worker *outConfig = *mConfig;
422*d57664e9SAndroid Build Coastguard Worker }
423*d57664e9SAndroid Build Coastguard Worker
424*d57664e9SAndroid Build Coastguard Worker /*
425*d57664e9SAndroid Build Coastguard Worker * Open an asset.
426*d57664e9SAndroid Build Coastguard Worker *
427*d57664e9SAndroid Build Coastguard Worker * The data could be in any asset path. Each asset path could be:
428*d57664e9SAndroid Build Coastguard Worker * - A directory on disk.
429*d57664e9SAndroid Build Coastguard Worker * - A Zip archive, uncompressed or compressed.
430*d57664e9SAndroid Build Coastguard Worker *
431*d57664e9SAndroid Build Coastguard Worker * If the file is in a directory, it could have a .gz suffix, meaning it is compressed.
432*d57664e9SAndroid Build Coastguard Worker *
433*d57664e9SAndroid Build Coastguard Worker * We should probably reject requests for "illegal" filenames, e.g. those
434*d57664e9SAndroid Build Coastguard Worker * with illegal characters or "../" backward relative paths.
435*d57664e9SAndroid Build Coastguard Worker */
open(const char * fileName,AccessMode mode)436*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::open(const char* fileName, AccessMode mode)
437*d57664e9SAndroid Build Coastguard Worker {
438*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
439*d57664e9SAndroid Build Coastguard Worker
440*d57664e9SAndroid Build Coastguard Worker LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
441*d57664e9SAndroid Build Coastguard Worker
442*d57664e9SAndroid Build Coastguard Worker String8 assetName(kAssetsRoot);
443*d57664e9SAndroid Build Coastguard Worker appendPath(assetName, fileName);
444*d57664e9SAndroid Build Coastguard Worker
445*d57664e9SAndroid Build Coastguard Worker /*
446*d57664e9SAndroid Build Coastguard Worker * For each top-level asset path, search for the asset.
447*d57664e9SAndroid Build Coastguard Worker */
448*d57664e9SAndroid Build Coastguard Worker
449*d57664e9SAndroid Build Coastguard Worker size_t i = mAssetPaths.size();
450*d57664e9SAndroid Build Coastguard Worker while (i > 0) {
451*d57664e9SAndroid Build Coastguard Worker i--;
452*d57664e9SAndroid Build Coastguard Worker ALOGV("Looking for asset '%s' in '%s'\n",
453*d57664e9SAndroid Build Coastguard Worker assetName.c_str(), mAssetPaths.itemAt(i).path.c_str());
454*d57664e9SAndroid Build Coastguard Worker Asset* pAsset = openNonAssetInPathLocked(assetName.c_str(), mode,
455*d57664e9SAndroid Build Coastguard Worker mAssetPaths.editItemAt(i));
456*d57664e9SAndroid Build Coastguard Worker if (pAsset != NULL) {
457*d57664e9SAndroid Build Coastguard Worker return pAsset != kExcludedAsset ? pAsset : NULL;
458*d57664e9SAndroid Build Coastguard Worker }
459*d57664e9SAndroid Build Coastguard Worker }
460*d57664e9SAndroid Build Coastguard Worker
461*d57664e9SAndroid Build Coastguard Worker return NULL;
462*d57664e9SAndroid Build Coastguard Worker }
463*d57664e9SAndroid Build Coastguard Worker
464*d57664e9SAndroid Build Coastguard Worker /*
465*d57664e9SAndroid Build Coastguard Worker * Open a non-asset file as if it were an asset.
466*d57664e9SAndroid Build Coastguard Worker *
467*d57664e9SAndroid Build Coastguard Worker * The "fileName" is the partial path starting from the application name.
468*d57664e9SAndroid Build Coastguard Worker */
openNonAsset(const char * fileName,AccessMode mode,int32_t * outCookie)469*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::openNonAsset(const char* fileName, AccessMode mode, int32_t* outCookie)
470*d57664e9SAndroid Build Coastguard Worker {
471*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
472*d57664e9SAndroid Build Coastguard Worker
473*d57664e9SAndroid Build Coastguard Worker LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
474*d57664e9SAndroid Build Coastguard Worker
475*d57664e9SAndroid Build Coastguard Worker /*
476*d57664e9SAndroid Build Coastguard Worker * For each top-level asset path, search for the asset.
477*d57664e9SAndroid Build Coastguard Worker */
478*d57664e9SAndroid Build Coastguard Worker
479*d57664e9SAndroid Build Coastguard Worker size_t i = mAssetPaths.size();
480*d57664e9SAndroid Build Coastguard Worker while (i > 0) {
481*d57664e9SAndroid Build Coastguard Worker i--;
482*d57664e9SAndroid Build Coastguard Worker ALOGV("Looking for non-asset '%s' in '%s'\n", fileName, mAssetPaths.itemAt(i).path.c_str());
483*d57664e9SAndroid Build Coastguard Worker Asset* pAsset = openNonAssetInPathLocked(
484*d57664e9SAndroid Build Coastguard Worker fileName, mode, mAssetPaths.editItemAt(i));
485*d57664e9SAndroid Build Coastguard Worker if (pAsset != NULL) {
486*d57664e9SAndroid Build Coastguard Worker if (outCookie != NULL) *outCookie = static_cast<int32_t>(i + 1);
487*d57664e9SAndroid Build Coastguard Worker return pAsset != kExcludedAsset ? pAsset : NULL;
488*d57664e9SAndroid Build Coastguard Worker }
489*d57664e9SAndroid Build Coastguard Worker }
490*d57664e9SAndroid Build Coastguard Worker
491*d57664e9SAndroid Build Coastguard Worker return NULL;
492*d57664e9SAndroid Build Coastguard Worker }
493*d57664e9SAndroid Build Coastguard Worker
openNonAsset(const int32_t cookie,const char * fileName,AccessMode mode)494*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::openNonAsset(const int32_t cookie, const char* fileName, AccessMode mode)
495*d57664e9SAndroid Build Coastguard Worker {
496*d57664e9SAndroid Build Coastguard Worker const size_t which = static_cast<size_t>(cookie) - 1;
497*d57664e9SAndroid Build Coastguard Worker
498*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
499*d57664e9SAndroid Build Coastguard Worker
500*d57664e9SAndroid Build Coastguard Worker LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
501*d57664e9SAndroid Build Coastguard Worker
502*d57664e9SAndroid Build Coastguard Worker if (which < mAssetPaths.size()) {
503*d57664e9SAndroid Build Coastguard Worker ALOGV("Looking for non-asset '%s' in '%s'\n", fileName,
504*d57664e9SAndroid Build Coastguard Worker mAssetPaths.itemAt(which).path.c_str());
505*d57664e9SAndroid Build Coastguard Worker Asset* pAsset = openNonAssetInPathLocked(
506*d57664e9SAndroid Build Coastguard Worker fileName, mode, mAssetPaths.editItemAt(which));
507*d57664e9SAndroid Build Coastguard Worker if (pAsset != NULL) {
508*d57664e9SAndroid Build Coastguard Worker return pAsset != kExcludedAsset ? pAsset : NULL;
509*d57664e9SAndroid Build Coastguard Worker }
510*d57664e9SAndroid Build Coastguard Worker }
511*d57664e9SAndroid Build Coastguard Worker
512*d57664e9SAndroid Build Coastguard Worker return NULL;
513*d57664e9SAndroid Build Coastguard Worker }
514*d57664e9SAndroid Build Coastguard Worker
515*d57664e9SAndroid Build Coastguard Worker /*
516*d57664e9SAndroid Build Coastguard Worker * Get the type of a file in the asset namespace.
517*d57664e9SAndroid Build Coastguard Worker *
518*d57664e9SAndroid Build Coastguard Worker * This currently only works for regular files. All others (including
519*d57664e9SAndroid Build Coastguard Worker * directories) will return kFileTypeNonexistent.
520*d57664e9SAndroid Build Coastguard Worker */
getFileType(const char * fileName)521*d57664e9SAndroid Build Coastguard Worker FileType AssetManager::getFileType(const char* fileName)
522*d57664e9SAndroid Build Coastguard Worker {
523*d57664e9SAndroid Build Coastguard Worker Asset* pAsset = NULL;
524*d57664e9SAndroid Build Coastguard Worker
525*d57664e9SAndroid Build Coastguard Worker /*
526*d57664e9SAndroid Build Coastguard Worker * Open the asset. This is less efficient than simply finding the
527*d57664e9SAndroid Build Coastguard Worker * file, but it's not too bad (we don't uncompress or mmap data until
528*d57664e9SAndroid Build Coastguard Worker * the first read() call).
529*d57664e9SAndroid Build Coastguard Worker */
530*d57664e9SAndroid Build Coastguard Worker pAsset = open(fileName, Asset::ACCESS_STREAMING);
531*d57664e9SAndroid Build Coastguard Worker delete pAsset;
532*d57664e9SAndroid Build Coastguard Worker
533*d57664e9SAndroid Build Coastguard Worker if (pAsset == NULL) {
534*d57664e9SAndroid Build Coastguard Worker return kFileTypeNonexistent;
535*d57664e9SAndroid Build Coastguard Worker } else {
536*d57664e9SAndroid Build Coastguard Worker return kFileTypeRegular;
537*d57664e9SAndroid Build Coastguard Worker }
538*d57664e9SAndroid Build Coastguard Worker }
539*d57664e9SAndroid Build Coastguard Worker
appendPathToResTable(asset_path & ap,bool appAsLib) const540*d57664e9SAndroid Build Coastguard Worker bool AssetManager::appendPathToResTable(asset_path& ap, bool appAsLib) const {
541*d57664e9SAndroid Build Coastguard Worker // skip those ap's that correspond to system overlays
542*d57664e9SAndroid Build Coastguard Worker if (ap.isSystemOverlay) {
543*d57664e9SAndroid Build Coastguard Worker return true;
544*d57664e9SAndroid Build Coastguard Worker }
545*d57664e9SAndroid Build Coastguard Worker
546*d57664e9SAndroid Build Coastguard Worker Asset* ass = NULL;
547*d57664e9SAndroid Build Coastguard Worker ResTable* sharedRes = NULL;
548*d57664e9SAndroid Build Coastguard Worker bool shared = true;
549*d57664e9SAndroid Build Coastguard Worker bool onlyEmptyResources = true;
550*d57664e9SAndroid Build Coastguard Worker ATRACE_NAME(ap.path.c_str());
551*d57664e9SAndroid Build Coastguard Worker Asset* idmap = openIdmapLocked(ap);
552*d57664e9SAndroid Build Coastguard Worker size_t nextEntryIdx = mResources->getTableCount();
553*d57664e9SAndroid Build Coastguard Worker ALOGV("Looking for resource asset in '%s'\n", ap.path.c_str());
554*d57664e9SAndroid Build Coastguard Worker if (ap.type != kFileTypeDirectory && ap.rawFd < 0) {
555*d57664e9SAndroid Build Coastguard Worker if (nextEntryIdx == 0) {
556*d57664e9SAndroid Build Coastguard Worker // The first item is typically the framework resources,
557*d57664e9SAndroid Build Coastguard Worker // which we want to avoid parsing every time.
558*d57664e9SAndroid Build Coastguard Worker sharedRes = const_cast<AssetManager*>(this)->
559*d57664e9SAndroid Build Coastguard Worker mZipSet.getZipResourceTable(ap.path);
560*d57664e9SAndroid Build Coastguard Worker if (sharedRes != NULL) {
561*d57664e9SAndroid Build Coastguard Worker // skip ahead the number of system overlay packages preloaded
562*d57664e9SAndroid Build Coastguard Worker nextEntryIdx = sharedRes->getTableCount();
563*d57664e9SAndroid Build Coastguard Worker }
564*d57664e9SAndroid Build Coastguard Worker }
565*d57664e9SAndroid Build Coastguard Worker if (sharedRes == NULL) {
566*d57664e9SAndroid Build Coastguard Worker ass = const_cast<AssetManager*>(this)->
567*d57664e9SAndroid Build Coastguard Worker mZipSet.getZipResourceTableAsset(ap.path);
568*d57664e9SAndroid Build Coastguard Worker if (ass == NULL) {
569*d57664e9SAndroid Build Coastguard Worker ALOGV("loading resource table %s\n", ap.path.c_str());
570*d57664e9SAndroid Build Coastguard Worker ass = const_cast<AssetManager*>(this)->
571*d57664e9SAndroid Build Coastguard Worker openNonAssetInPathLocked("resources.arsc",
572*d57664e9SAndroid Build Coastguard Worker Asset::ACCESS_BUFFER,
573*d57664e9SAndroid Build Coastguard Worker ap);
574*d57664e9SAndroid Build Coastguard Worker if (ass != NULL && ass != kExcludedAsset) {
575*d57664e9SAndroid Build Coastguard Worker ass = const_cast<AssetManager*>(this)->
576*d57664e9SAndroid Build Coastguard Worker mZipSet.setZipResourceTableAsset(ap.path, ass);
577*d57664e9SAndroid Build Coastguard Worker }
578*d57664e9SAndroid Build Coastguard Worker }
579*d57664e9SAndroid Build Coastguard Worker
580*d57664e9SAndroid Build Coastguard Worker if (nextEntryIdx == 0 && ass != NULL) {
581*d57664e9SAndroid Build Coastguard Worker // If this is the first resource table in the asset
582*d57664e9SAndroid Build Coastguard Worker // manager, then we are going to cache it so that we
583*d57664e9SAndroid Build Coastguard Worker // can quickly copy it out for others.
584*d57664e9SAndroid Build Coastguard Worker ALOGV("Creating shared resources for %s", ap.path.c_str());
585*d57664e9SAndroid Build Coastguard Worker sharedRes = new ResTable();
586*d57664e9SAndroid Build Coastguard Worker sharedRes->add(ass, idmap, nextEntryIdx + 1, false);
587*d57664e9SAndroid Build Coastguard Worker #ifdef __ANDROID__
588*d57664e9SAndroid Build Coastguard Worker const char* data = getenv("ANDROID_DATA");
589*d57664e9SAndroid Build Coastguard Worker LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
590*d57664e9SAndroid Build Coastguard Worker String8 overlaysListPath(data);
591*d57664e9SAndroid Build Coastguard Worker appendPath(overlaysListPath, kResourceCache);
592*d57664e9SAndroid Build Coastguard Worker appendPath(overlaysListPath, "overlays.list");
593*d57664e9SAndroid Build Coastguard Worker addSystemOverlays(overlaysListPath.c_str(), ap.path, sharedRes, nextEntryIdx);
594*d57664e9SAndroid Build Coastguard Worker #endif
595*d57664e9SAndroid Build Coastguard Worker sharedRes = const_cast<AssetManager*>(this)->
596*d57664e9SAndroid Build Coastguard Worker mZipSet.setZipResourceTable(ap.path, sharedRes);
597*d57664e9SAndroid Build Coastguard Worker }
598*d57664e9SAndroid Build Coastguard Worker }
599*d57664e9SAndroid Build Coastguard Worker } else {
600*d57664e9SAndroid Build Coastguard Worker ALOGV("loading resource table %s\n", ap.path.c_str());
601*d57664e9SAndroid Build Coastguard Worker ass = const_cast<AssetManager*>(this)->
602*d57664e9SAndroid Build Coastguard Worker openNonAssetInPathLocked("resources.arsc",
603*d57664e9SAndroid Build Coastguard Worker Asset::ACCESS_BUFFER,
604*d57664e9SAndroid Build Coastguard Worker ap);
605*d57664e9SAndroid Build Coastguard Worker shared = false;
606*d57664e9SAndroid Build Coastguard Worker }
607*d57664e9SAndroid Build Coastguard Worker
608*d57664e9SAndroid Build Coastguard Worker if ((ass != NULL || sharedRes != NULL) && ass != kExcludedAsset) {
609*d57664e9SAndroid Build Coastguard Worker ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
610*d57664e9SAndroid Build Coastguard Worker if (sharedRes != NULL) {
611*d57664e9SAndroid Build Coastguard Worker ALOGV("Copying existing resources for %s", ap.path.c_str());
612*d57664e9SAndroid Build Coastguard Worker mResources->add(sharedRes, ap.isSystemAsset);
613*d57664e9SAndroid Build Coastguard Worker } else {
614*d57664e9SAndroid Build Coastguard Worker ALOGV("Parsing resources for %s", ap.path.c_str());
615*d57664e9SAndroid Build Coastguard Worker mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset);
616*d57664e9SAndroid Build Coastguard Worker }
617*d57664e9SAndroid Build Coastguard Worker onlyEmptyResources = false;
618*d57664e9SAndroid Build Coastguard Worker
619*d57664e9SAndroid Build Coastguard Worker if (!shared) {
620*d57664e9SAndroid Build Coastguard Worker delete ass;
621*d57664e9SAndroid Build Coastguard Worker }
622*d57664e9SAndroid Build Coastguard Worker } else {
623*d57664e9SAndroid Build Coastguard Worker ALOGV("Installing empty resources in to table %p\n", mResources);
624*d57664e9SAndroid Build Coastguard Worker mResources->addEmpty(nextEntryIdx + 1);
625*d57664e9SAndroid Build Coastguard Worker }
626*d57664e9SAndroid Build Coastguard Worker
627*d57664e9SAndroid Build Coastguard Worker if (idmap != NULL) {
628*d57664e9SAndroid Build Coastguard Worker delete idmap;
629*d57664e9SAndroid Build Coastguard Worker }
630*d57664e9SAndroid Build Coastguard Worker return onlyEmptyResources;
631*d57664e9SAndroid Build Coastguard Worker }
632*d57664e9SAndroid Build Coastguard Worker
getResTable(bool required) const633*d57664e9SAndroid Build Coastguard Worker const ResTable* AssetManager::getResTable(bool required) const
634*d57664e9SAndroid Build Coastguard Worker {
635*d57664e9SAndroid Build Coastguard Worker ResTable* rt = mResources;
636*d57664e9SAndroid Build Coastguard Worker if (rt) {
637*d57664e9SAndroid Build Coastguard Worker return rt;
638*d57664e9SAndroid Build Coastguard Worker }
639*d57664e9SAndroid Build Coastguard Worker
640*d57664e9SAndroid Build Coastguard Worker // Iterate through all asset packages, collecting resources from each.
641*d57664e9SAndroid Build Coastguard Worker
642*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
643*d57664e9SAndroid Build Coastguard Worker
644*d57664e9SAndroid Build Coastguard Worker if (mResources != NULL) {
645*d57664e9SAndroid Build Coastguard Worker return mResources;
646*d57664e9SAndroid Build Coastguard Worker }
647*d57664e9SAndroid Build Coastguard Worker
648*d57664e9SAndroid Build Coastguard Worker if (required) {
649*d57664e9SAndroid Build Coastguard Worker LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
650*d57664e9SAndroid Build Coastguard Worker }
651*d57664e9SAndroid Build Coastguard Worker
652*d57664e9SAndroid Build Coastguard Worker mResources = new ResTable();
653*d57664e9SAndroid Build Coastguard Worker updateResourceParamsLocked();
654*d57664e9SAndroid Build Coastguard Worker
655*d57664e9SAndroid Build Coastguard Worker bool onlyEmptyResources = true;
656*d57664e9SAndroid Build Coastguard Worker const size_t N = mAssetPaths.size();
657*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
658*d57664e9SAndroid Build Coastguard Worker bool empty = appendPathToResTable(
659*d57664e9SAndroid Build Coastguard Worker const_cast<AssetManager*>(this)->mAssetPaths.editItemAt(i));
660*d57664e9SAndroid Build Coastguard Worker onlyEmptyResources = onlyEmptyResources && empty;
661*d57664e9SAndroid Build Coastguard Worker }
662*d57664e9SAndroid Build Coastguard Worker
663*d57664e9SAndroid Build Coastguard Worker if (required && onlyEmptyResources) {
664*d57664e9SAndroid Build Coastguard Worker ALOGW("Unable to find resources file resources.arsc");
665*d57664e9SAndroid Build Coastguard Worker delete mResources;
666*d57664e9SAndroid Build Coastguard Worker mResources = NULL;
667*d57664e9SAndroid Build Coastguard Worker }
668*d57664e9SAndroid Build Coastguard Worker
669*d57664e9SAndroid Build Coastguard Worker return mResources;
670*d57664e9SAndroid Build Coastguard Worker }
671*d57664e9SAndroid Build Coastguard Worker
updateResourceParamsLocked() const672*d57664e9SAndroid Build Coastguard Worker void AssetManager::updateResourceParamsLocked() const
673*d57664e9SAndroid Build Coastguard Worker {
674*d57664e9SAndroid Build Coastguard Worker ATRACE_CALL();
675*d57664e9SAndroid Build Coastguard Worker ResTable* res = mResources;
676*d57664e9SAndroid Build Coastguard Worker if (!res) {
677*d57664e9SAndroid Build Coastguard Worker return;
678*d57664e9SAndroid Build Coastguard Worker }
679*d57664e9SAndroid Build Coastguard Worker
680*d57664e9SAndroid Build Coastguard Worker if (mLocale) {
681*d57664e9SAndroid Build Coastguard Worker mConfig->setBcp47Locale(mLocale);
682*d57664e9SAndroid Build Coastguard Worker } else {
683*d57664e9SAndroid Build Coastguard Worker mConfig->clearLocale();
684*d57664e9SAndroid Build Coastguard Worker }
685*d57664e9SAndroid Build Coastguard Worker
686*d57664e9SAndroid Build Coastguard Worker res->setParameters(mConfig);
687*d57664e9SAndroid Build Coastguard Worker }
688*d57664e9SAndroid Build Coastguard Worker
openIdmapLocked(const struct asset_path & ap) const689*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const
690*d57664e9SAndroid Build Coastguard Worker {
691*d57664e9SAndroid Build Coastguard Worker Asset* ass = NULL;
692*d57664e9SAndroid Build Coastguard Worker if (ap.idmap.size() != 0) {
693*d57664e9SAndroid Build Coastguard Worker ass = const_cast<AssetManager*>(this)->
694*d57664e9SAndroid Build Coastguard Worker openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER);
695*d57664e9SAndroid Build Coastguard Worker if (ass) {
696*d57664e9SAndroid Build Coastguard Worker ALOGV("loading idmap %s\n", ap.idmap.c_str());
697*d57664e9SAndroid Build Coastguard Worker } else {
698*d57664e9SAndroid Build Coastguard Worker ALOGW("failed to load idmap %s\n", ap.idmap.c_str());
699*d57664e9SAndroid Build Coastguard Worker }
700*d57664e9SAndroid Build Coastguard Worker }
701*d57664e9SAndroid Build Coastguard Worker return ass;
702*d57664e9SAndroid Build Coastguard Worker }
703*d57664e9SAndroid Build Coastguard Worker
addSystemOverlays(const char * pathOverlaysList,const String8 & targetPackagePath,ResTable * sharedRes,size_t offset) const704*d57664e9SAndroid Build Coastguard Worker void AssetManager::addSystemOverlays(const char* pathOverlaysList,
705*d57664e9SAndroid Build Coastguard Worker const String8& targetPackagePath, ResTable* sharedRes, size_t offset) const
706*d57664e9SAndroid Build Coastguard Worker {
707*d57664e9SAndroid Build Coastguard Worker FILE* fin = fopen(pathOverlaysList, "r");
708*d57664e9SAndroid Build Coastguard Worker if (fin == NULL) {
709*d57664e9SAndroid Build Coastguard Worker return;
710*d57664e9SAndroid Build Coastguard Worker }
711*d57664e9SAndroid Build Coastguard Worker
712*d57664e9SAndroid Build Coastguard Worker #ifndef _WIN32
713*d57664e9SAndroid Build Coastguard Worker if (TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_SH)) != 0) {
714*d57664e9SAndroid Build Coastguard Worker fclose(fin);
715*d57664e9SAndroid Build Coastguard Worker return;
716*d57664e9SAndroid Build Coastguard Worker }
717*d57664e9SAndroid Build Coastguard Worker #endif
718*d57664e9SAndroid Build Coastguard Worker char buf[1024];
719*d57664e9SAndroid Build Coastguard Worker while (fgets(buf, sizeof(buf), fin)) {
720*d57664e9SAndroid Build Coastguard Worker // format of each line:
721*d57664e9SAndroid Build Coastguard Worker // <path to apk><space><path to idmap><newline>
722*d57664e9SAndroid Build Coastguard Worker char* space = strchr(buf, ' ');
723*d57664e9SAndroid Build Coastguard Worker char* newline = strchr(buf, '\n');
724*d57664e9SAndroid Build Coastguard Worker asset_path oap;
725*d57664e9SAndroid Build Coastguard Worker
726*d57664e9SAndroid Build Coastguard Worker if (space == NULL || newline == NULL || newline < space) {
727*d57664e9SAndroid Build Coastguard Worker continue;
728*d57664e9SAndroid Build Coastguard Worker }
729*d57664e9SAndroid Build Coastguard Worker
730*d57664e9SAndroid Build Coastguard Worker oap.path = String8(buf, space - buf);
731*d57664e9SAndroid Build Coastguard Worker oap.type = kFileTypeRegular;
732*d57664e9SAndroid Build Coastguard Worker oap.idmap = String8(space + 1, newline - space - 1);
733*d57664e9SAndroid Build Coastguard Worker oap.isSystemOverlay = true;
734*d57664e9SAndroid Build Coastguard Worker
735*d57664e9SAndroid Build Coastguard Worker Asset* oass = const_cast<AssetManager*>(this)->
736*d57664e9SAndroid Build Coastguard Worker openNonAssetInPathLocked("resources.arsc",
737*d57664e9SAndroid Build Coastguard Worker Asset::ACCESS_BUFFER,
738*d57664e9SAndroid Build Coastguard Worker oap);
739*d57664e9SAndroid Build Coastguard Worker
740*d57664e9SAndroid Build Coastguard Worker if (oass != NULL) {
741*d57664e9SAndroid Build Coastguard Worker Asset* oidmap = openIdmapLocked(oap);
742*d57664e9SAndroid Build Coastguard Worker offset++;
743*d57664e9SAndroid Build Coastguard Worker sharedRes->add(oass, oidmap, offset + 1, false);
744*d57664e9SAndroid Build Coastguard Worker const_cast<AssetManager*>(this)->mAssetPaths.add(oap);
745*d57664e9SAndroid Build Coastguard Worker const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap);
746*d57664e9SAndroid Build Coastguard Worker delete oidmap;
747*d57664e9SAndroid Build Coastguard Worker }
748*d57664e9SAndroid Build Coastguard Worker }
749*d57664e9SAndroid Build Coastguard Worker
750*d57664e9SAndroid Build Coastguard Worker #ifndef _WIN32
751*d57664e9SAndroid Build Coastguard Worker TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_UN));
752*d57664e9SAndroid Build Coastguard Worker #endif
753*d57664e9SAndroid Build Coastguard Worker fclose(fin);
754*d57664e9SAndroid Build Coastguard Worker }
755*d57664e9SAndroid Build Coastguard Worker
getResources(bool required) const756*d57664e9SAndroid Build Coastguard Worker const ResTable& AssetManager::getResources(bool required) const
757*d57664e9SAndroid Build Coastguard Worker {
758*d57664e9SAndroid Build Coastguard Worker const ResTable* rt = getResTable(required);
759*d57664e9SAndroid Build Coastguard Worker return *rt;
760*d57664e9SAndroid Build Coastguard Worker }
761*d57664e9SAndroid Build Coastguard Worker
isUpToDate()762*d57664e9SAndroid Build Coastguard Worker bool AssetManager::isUpToDate()
763*d57664e9SAndroid Build Coastguard Worker {
764*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
765*d57664e9SAndroid Build Coastguard Worker return mZipSet.isUpToDate();
766*d57664e9SAndroid Build Coastguard Worker }
767*d57664e9SAndroid Build Coastguard Worker
getLocales(Vector<String8> * locales,bool includeSystemLocales) const768*d57664e9SAndroid Build Coastguard Worker void AssetManager::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
769*d57664e9SAndroid Build Coastguard Worker {
770*d57664e9SAndroid Build Coastguard Worker ResTable* res = mResources;
771*d57664e9SAndroid Build Coastguard Worker if (res != NULL) {
772*d57664e9SAndroid Build Coastguard Worker res->getLocales(locales, includeSystemLocales, true /* mergeEquivalentLangs */);
773*d57664e9SAndroid Build Coastguard Worker }
774*d57664e9SAndroid Build Coastguard Worker }
775*d57664e9SAndroid Build Coastguard Worker
776*d57664e9SAndroid Build Coastguard Worker /*
777*d57664e9SAndroid Build Coastguard Worker * Open a non-asset file as if it were an asset, searching for it in the
778*d57664e9SAndroid Build Coastguard Worker * specified app.
779*d57664e9SAndroid Build Coastguard Worker *
780*d57664e9SAndroid Build Coastguard Worker * Pass in a NULL values for "appName" if the common app directory should
781*d57664e9SAndroid Build Coastguard Worker * be used.
782*d57664e9SAndroid Build Coastguard Worker */
openNonAssetInPathLocked(const char * fileName,AccessMode mode,asset_path & ap)783*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::openNonAssetInPathLocked(const char* fileName, AccessMode mode,
784*d57664e9SAndroid Build Coastguard Worker asset_path& ap)
785*d57664e9SAndroid Build Coastguard Worker {
786*d57664e9SAndroid Build Coastguard Worker Asset* pAsset = NULL;
787*d57664e9SAndroid Build Coastguard Worker
788*d57664e9SAndroid Build Coastguard Worker ALOGV("openNonAssetInPath: name=%s type=%d fd=%d", fileName, ap.type, ap.rawFd);
789*d57664e9SAndroid Build Coastguard Worker
790*d57664e9SAndroid Build Coastguard Worker /* look at the filesystem on disk */
791*d57664e9SAndroid Build Coastguard Worker if (ap.type == kFileTypeDirectory) {
792*d57664e9SAndroid Build Coastguard Worker String8 path(ap.path);
793*d57664e9SAndroid Build Coastguard Worker appendPath(path, fileName);
794*d57664e9SAndroid Build Coastguard Worker
795*d57664e9SAndroid Build Coastguard Worker pAsset = openAssetFromFileLocked(path, mode);
796*d57664e9SAndroid Build Coastguard Worker
797*d57664e9SAndroid Build Coastguard Worker if (pAsset == NULL) {
798*d57664e9SAndroid Build Coastguard Worker /* try again, this time with ".gz" */
799*d57664e9SAndroid Build Coastguard Worker path.append(".gz");
800*d57664e9SAndroid Build Coastguard Worker pAsset = openAssetFromFileLocked(path, mode);
801*d57664e9SAndroid Build Coastguard Worker }
802*d57664e9SAndroid Build Coastguard Worker
803*d57664e9SAndroid Build Coastguard Worker if (pAsset != NULL) {
804*d57664e9SAndroid Build Coastguard Worker ALOGV("FOUND NA '%s' on disk", fileName);
805*d57664e9SAndroid Build Coastguard Worker pAsset->setAssetSource(path);
806*d57664e9SAndroid Build Coastguard Worker }
807*d57664e9SAndroid Build Coastguard Worker
808*d57664e9SAndroid Build Coastguard Worker /* look inside the zip file */
809*d57664e9SAndroid Build Coastguard Worker } else {
810*d57664e9SAndroid Build Coastguard Worker String8 path(fileName);
811*d57664e9SAndroid Build Coastguard Worker
812*d57664e9SAndroid Build Coastguard Worker /* check the appropriate Zip file */
813*d57664e9SAndroid Build Coastguard Worker ZipFileRO* pZip = getZipFileLocked(ap);
814*d57664e9SAndroid Build Coastguard Worker if (pZip != NULL) {
815*d57664e9SAndroid Build Coastguard Worker ALOGV("GOT zip, checking NA '%s'", path.c_str());
816*d57664e9SAndroid Build Coastguard Worker ZipEntryRO entry = pZip->findEntryByName(path.c_str());
817*d57664e9SAndroid Build Coastguard Worker if (entry != NULL) {
818*d57664e9SAndroid Build Coastguard Worker ALOGV("FOUND NA in Zip file for %s", path.c_str());
819*d57664e9SAndroid Build Coastguard Worker pAsset = openAssetFromZipLocked(pZip, entry, mode, path);
820*d57664e9SAndroid Build Coastguard Worker pZip->releaseEntry(entry);
821*d57664e9SAndroid Build Coastguard Worker }
822*d57664e9SAndroid Build Coastguard Worker }
823*d57664e9SAndroid Build Coastguard Worker
824*d57664e9SAndroid Build Coastguard Worker if (pAsset != NULL) {
825*d57664e9SAndroid Build Coastguard Worker /* create a "source" name, for debug/display */
826*d57664e9SAndroid Build Coastguard Worker pAsset->setAssetSource(
827*d57664e9SAndroid Build Coastguard Worker createZipSourceNameLocked(ZipSet::getPathName(ap.path.c_str()), String8(""),
828*d57664e9SAndroid Build Coastguard Worker String8(fileName)));
829*d57664e9SAndroid Build Coastguard Worker }
830*d57664e9SAndroid Build Coastguard Worker }
831*d57664e9SAndroid Build Coastguard Worker
832*d57664e9SAndroid Build Coastguard Worker return pAsset;
833*d57664e9SAndroid Build Coastguard Worker }
834*d57664e9SAndroid Build Coastguard Worker
835*d57664e9SAndroid Build Coastguard Worker /*
836*d57664e9SAndroid Build Coastguard Worker * Create a "source name" for a file from a Zip archive.
837*d57664e9SAndroid Build Coastguard Worker */
createZipSourceNameLocked(const String8 & zipFileName,const String8 & dirName,const String8 & fileName)838*d57664e9SAndroid Build Coastguard Worker String8 AssetManager::createZipSourceNameLocked(const String8& zipFileName,
839*d57664e9SAndroid Build Coastguard Worker const String8& dirName, const String8& fileName)
840*d57664e9SAndroid Build Coastguard Worker {
841*d57664e9SAndroid Build Coastguard Worker String8 sourceName("zip:");
842*d57664e9SAndroid Build Coastguard Worker sourceName.append(zipFileName);
843*d57664e9SAndroid Build Coastguard Worker sourceName.append(":");
844*d57664e9SAndroid Build Coastguard Worker if (dirName.length() > 0) {
845*d57664e9SAndroid Build Coastguard Worker appendPath(sourceName, dirName);
846*d57664e9SAndroid Build Coastguard Worker }
847*d57664e9SAndroid Build Coastguard Worker appendPath(sourceName, fileName);
848*d57664e9SAndroid Build Coastguard Worker return sourceName;
849*d57664e9SAndroid Build Coastguard Worker }
850*d57664e9SAndroid Build Coastguard Worker
851*d57664e9SAndroid Build Coastguard Worker /*
852*d57664e9SAndroid Build Coastguard Worker * Create a path to a loose asset (asset-base/app/rootDir).
853*d57664e9SAndroid Build Coastguard Worker */
createPathNameLocked(const asset_path & ap,const char * rootDir)854*d57664e9SAndroid Build Coastguard Worker String8 AssetManager::createPathNameLocked(const asset_path& ap, const char* rootDir)
855*d57664e9SAndroid Build Coastguard Worker {
856*d57664e9SAndroid Build Coastguard Worker String8 path(ap.path);
857*d57664e9SAndroid Build Coastguard Worker if (rootDir != NULL) appendPath(path, rootDir);
858*d57664e9SAndroid Build Coastguard Worker return path;
859*d57664e9SAndroid Build Coastguard Worker }
860*d57664e9SAndroid Build Coastguard Worker
861*d57664e9SAndroid Build Coastguard Worker /*
862*d57664e9SAndroid Build Coastguard Worker * Return a pointer to one of our open Zip archives. Returns NULL if no
863*d57664e9SAndroid Build Coastguard Worker * matching Zip file exists.
864*d57664e9SAndroid Build Coastguard Worker */
getZipFileLocked(asset_path & ap)865*d57664e9SAndroid Build Coastguard Worker ZipFileRO* AssetManager::getZipFileLocked(asset_path& ap)
866*d57664e9SAndroid Build Coastguard Worker {
867*d57664e9SAndroid Build Coastguard Worker ALOGV("getZipFileLocked() in %p: ap=%p zip=%p", this, &ap, ap.zip.get());
868*d57664e9SAndroid Build Coastguard Worker
869*d57664e9SAndroid Build Coastguard Worker if (ap.zip != NULL) {
870*d57664e9SAndroid Build Coastguard Worker return ap.zip->getZip();
871*d57664e9SAndroid Build Coastguard Worker }
872*d57664e9SAndroid Build Coastguard Worker
873*d57664e9SAndroid Build Coastguard Worker if (ap.rawFd < 0) {
874*d57664e9SAndroid Build Coastguard Worker ALOGV("getZipFileLocked: Creating new zip from path %s", ap.path.c_str());
875*d57664e9SAndroid Build Coastguard Worker ap.zip = mZipSet.getSharedZip(ap.path);
876*d57664e9SAndroid Build Coastguard Worker } else {
877*d57664e9SAndroid Build Coastguard Worker ALOGV("getZipFileLocked: Creating new zip from fd %d", ap.rawFd);
878*d57664e9SAndroid Build Coastguard Worker ap.zip = SharedZip::create(ap.rawFd, ap.path);
879*d57664e9SAndroid Build Coastguard Worker
880*d57664e9SAndroid Build Coastguard Worker }
881*d57664e9SAndroid Build Coastguard Worker return ap.zip != NULL ? ap.zip->getZip() : NULL;
882*d57664e9SAndroid Build Coastguard Worker }
883*d57664e9SAndroid Build Coastguard Worker
884*d57664e9SAndroid Build Coastguard Worker /*
885*d57664e9SAndroid Build Coastguard Worker * Try to open an asset from a file on disk.
886*d57664e9SAndroid Build Coastguard Worker *
887*d57664e9SAndroid Build Coastguard Worker * If the file is compressed with gzip, we seek to the start of the
888*d57664e9SAndroid Build Coastguard Worker * deflated data and pass that in (just like we would for a Zip archive).
889*d57664e9SAndroid Build Coastguard Worker *
890*d57664e9SAndroid Build Coastguard Worker * For uncompressed data, we may already have an mmap()ed version sitting
891*d57664e9SAndroid Build Coastguard Worker * around. If so, we want to hand that to the Asset instead.
892*d57664e9SAndroid Build Coastguard Worker *
893*d57664e9SAndroid Build Coastguard Worker * This returns NULL if the file doesn't exist, couldn't be opened, or
894*d57664e9SAndroid Build Coastguard Worker * claims to be a ".gz" but isn't.
895*d57664e9SAndroid Build Coastguard Worker */
openAssetFromFileLocked(const String8 & pathName,AccessMode mode)896*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::openAssetFromFileLocked(const String8& pathName,
897*d57664e9SAndroid Build Coastguard Worker AccessMode mode)
898*d57664e9SAndroid Build Coastguard Worker {
899*d57664e9SAndroid Build Coastguard Worker Asset* pAsset = NULL;
900*d57664e9SAndroid Build Coastguard Worker
901*d57664e9SAndroid Build Coastguard Worker if (strcasecmp(getPathExtension(pathName).c_str(), ".gz") == 0) {
902*d57664e9SAndroid Build Coastguard Worker //printf("TRYING '%s'\n", (const char*) pathName);
903*d57664e9SAndroid Build Coastguard Worker pAsset = Asset::createFromCompressedFile(pathName.c_str(), mode);
904*d57664e9SAndroid Build Coastguard Worker } else {
905*d57664e9SAndroid Build Coastguard Worker //printf("TRYING '%s'\n", (const char*) pathName);
906*d57664e9SAndroid Build Coastguard Worker pAsset = Asset::createFromFile(pathName.c_str(), mode);
907*d57664e9SAndroid Build Coastguard Worker }
908*d57664e9SAndroid Build Coastguard Worker
909*d57664e9SAndroid Build Coastguard Worker return pAsset;
910*d57664e9SAndroid Build Coastguard Worker }
911*d57664e9SAndroid Build Coastguard Worker
912*d57664e9SAndroid Build Coastguard Worker /*
913*d57664e9SAndroid Build Coastguard Worker * Given an entry in a Zip archive, create a new Asset object.
914*d57664e9SAndroid Build Coastguard Worker *
915*d57664e9SAndroid Build Coastguard Worker * If the entry is uncompressed, we may want to create or share a
916*d57664e9SAndroid Build Coastguard Worker * slice of shared memory.
917*d57664e9SAndroid Build Coastguard Worker */
openAssetFromZipLocked(const ZipFileRO * pZipFile,const ZipEntryRO entry,AccessMode mode,const String8 & entryName)918*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,
919*d57664e9SAndroid Build Coastguard Worker const ZipEntryRO entry, AccessMode mode, const String8& entryName)
920*d57664e9SAndroid Build Coastguard Worker {
921*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<Asset> pAsset;
922*d57664e9SAndroid Build Coastguard Worker
923*d57664e9SAndroid Build Coastguard Worker // TODO: look for previously-created shared memory slice?
924*d57664e9SAndroid Build Coastguard Worker uint16_t method;
925*d57664e9SAndroid Build Coastguard Worker uint32_t uncompressedLen;
926*d57664e9SAndroid Build Coastguard Worker
927*d57664e9SAndroid Build Coastguard Worker //printf("USING Zip '%s'\n", pEntry->getFileName());
928*d57664e9SAndroid Build Coastguard Worker
929*d57664e9SAndroid Build Coastguard Worker if (!pZipFile->getEntryInfo(entry, &method, &uncompressedLen, nullptr, nullptr,
930*d57664e9SAndroid Build Coastguard Worker nullptr, nullptr, nullptr))
931*d57664e9SAndroid Build Coastguard Worker {
932*d57664e9SAndroid Build Coastguard Worker ALOGW("getEntryInfo failed\n");
933*d57664e9SAndroid Build Coastguard Worker return NULL;
934*d57664e9SAndroid Build Coastguard Worker }
935*d57664e9SAndroid Build Coastguard Worker
936*d57664e9SAndroid Build Coastguard Worker std::optional<incfs::IncFsFileMap> dataMap = pZipFile->createEntryIncFsFileMap(entry);
937*d57664e9SAndroid Build Coastguard Worker if (!dataMap.has_value()) {
938*d57664e9SAndroid Build Coastguard Worker ALOGW("create map from entry failed\n");
939*d57664e9SAndroid Build Coastguard Worker return NULL;
940*d57664e9SAndroid Build Coastguard Worker }
941*d57664e9SAndroid Build Coastguard Worker
942*d57664e9SAndroid Build Coastguard Worker if (method == ZipFileRO::kCompressStored) {
943*d57664e9SAndroid Build Coastguard Worker pAsset = Asset::createFromUncompressedMap(std::move(*dataMap), mode);
944*d57664e9SAndroid Build Coastguard Worker ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.c_str(),
945*d57664e9SAndroid Build Coastguard Worker dataMap->file_name(), mode, pAsset.get());
946*d57664e9SAndroid Build Coastguard Worker } else {
947*d57664e9SAndroid Build Coastguard Worker pAsset = Asset::createFromCompressedMap(std::move(*dataMap),
948*d57664e9SAndroid Build Coastguard Worker static_cast<size_t>(uncompressedLen), mode);
949*d57664e9SAndroid Build Coastguard Worker ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.c_str(),
950*d57664e9SAndroid Build Coastguard Worker dataMap->file_name(), mode, pAsset.get());
951*d57664e9SAndroid Build Coastguard Worker }
952*d57664e9SAndroid Build Coastguard Worker if (pAsset == NULL) {
953*d57664e9SAndroid Build Coastguard Worker /* unexpected */
954*d57664e9SAndroid Build Coastguard Worker ALOGW("create from segment failed\n");
955*d57664e9SAndroid Build Coastguard Worker }
956*d57664e9SAndroid Build Coastguard Worker
957*d57664e9SAndroid Build Coastguard Worker return pAsset.release();
958*d57664e9SAndroid Build Coastguard Worker }
959*d57664e9SAndroid Build Coastguard Worker
960*d57664e9SAndroid Build Coastguard Worker /*
961*d57664e9SAndroid Build Coastguard Worker * Open a directory in the asset namespace.
962*d57664e9SAndroid Build Coastguard Worker *
963*d57664e9SAndroid Build Coastguard Worker * An "asset directory" is simply the combination of all asset paths' "assets/" directories.
964*d57664e9SAndroid Build Coastguard Worker *
965*d57664e9SAndroid Build Coastguard Worker * Pass in "" for the root dir.
966*d57664e9SAndroid Build Coastguard Worker */
openDir(const char * dirName)967*d57664e9SAndroid Build Coastguard Worker AssetDir* AssetManager::openDir(const char* dirName)
968*d57664e9SAndroid Build Coastguard Worker {
969*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
970*d57664e9SAndroid Build Coastguard Worker
971*d57664e9SAndroid Build Coastguard Worker AssetDir* pDir = NULL;
972*d57664e9SAndroid Build Coastguard Worker SortedVector<AssetDir::FileInfo>* pMergedInfo = NULL;
973*d57664e9SAndroid Build Coastguard Worker
974*d57664e9SAndroid Build Coastguard Worker LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
975*d57664e9SAndroid Build Coastguard Worker assert(dirName != NULL);
976*d57664e9SAndroid Build Coastguard Worker
977*d57664e9SAndroid Build Coastguard Worker //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
978*d57664e9SAndroid Build Coastguard Worker
979*d57664e9SAndroid Build Coastguard Worker pDir = new AssetDir;
980*d57664e9SAndroid Build Coastguard Worker
981*d57664e9SAndroid Build Coastguard Worker /*
982*d57664e9SAndroid Build Coastguard Worker * Scan the various directories, merging what we find into a single
983*d57664e9SAndroid Build Coastguard Worker * vector. We want to scan them in reverse priority order so that
984*d57664e9SAndroid Build Coastguard Worker * the ".EXCLUDE" processing works correctly. Also, if we decide we
985*d57664e9SAndroid Build Coastguard Worker * want to remember where the file is coming from, we'll get the right
986*d57664e9SAndroid Build Coastguard Worker * version.
987*d57664e9SAndroid Build Coastguard Worker *
988*d57664e9SAndroid Build Coastguard Worker * We start with Zip archives, then do loose files.
989*d57664e9SAndroid Build Coastguard Worker */
990*d57664e9SAndroid Build Coastguard Worker pMergedInfo = new SortedVector<AssetDir::FileInfo>;
991*d57664e9SAndroid Build Coastguard Worker
992*d57664e9SAndroid Build Coastguard Worker size_t i = mAssetPaths.size();
993*d57664e9SAndroid Build Coastguard Worker while (i > 0) {
994*d57664e9SAndroid Build Coastguard Worker i--;
995*d57664e9SAndroid Build Coastguard Worker const asset_path& ap = mAssetPaths.itemAt(i);
996*d57664e9SAndroid Build Coastguard Worker if (ap.type == kFileTypeRegular) {
997*d57664e9SAndroid Build Coastguard Worker ALOGV("Adding directory %s from zip %s", dirName, ap.path.c_str());
998*d57664e9SAndroid Build Coastguard Worker scanAndMergeZipLocked(pMergedInfo, ap, kAssetsRoot, dirName);
999*d57664e9SAndroid Build Coastguard Worker } else {
1000*d57664e9SAndroid Build Coastguard Worker ALOGV("Adding directory %s from dir %s", dirName, ap.path.c_str());
1001*d57664e9SAndroid Build Coastguard Worker scanAndMergeDirLocked(pMergedInfo, ap, kAssetsRoot, dirName);
1002*d57664e9SAndroid Build Coastguard Worker }
1003*d57664e9SAndroid Build Coastguard Worker }
1004*d57664e9SAndroid Build Coastguard Worker
1005*d57664e9SAndroid Build Coastguard Worker #if 0
1006*d57664e9SAndroid Build Coastguard Worker printf("FILE LIST:\n");
1007*d57664e9SAndroid Build Coastguard Worker for (i = 0; i < (size_t) pMergedInfo->size(); i++) {
1008*d57664e9SAndroid Build Coastguard Worker printf(" %d: (%d) '%s'\n", i,
1009*d57664e9SAndroid Build Coastguard Worker pMergedInfo->itemAt(i).getFileType(),
1010*d57664e9SAndroid Build Coastguard Worker (const char*) pMergedInfo->itemAt(i).getFileName());
1011*d57664e9SAndroid Build Coastguard Worker }
1012*d57664e9SAndroid Build Coastguard Worker #endif
1013*d57664e9SAndroid Build Coastguard Worker
1014*d57664e9SAndroid Build Coastguard Worker pDir->setFileList(pMergedInfo);
1015*d57664e9SAndroid Build Coastguard Worker return pDir;
1016*d57664e9SAndroid Build Coastguard Worker }
1017*d57664e9SAndroid Build Coastguard Worker
1018*d57664e9SAndroid Build Coastguard Worker /*
1019*d57664e9SAndroid Build Coastguard Worker * Open a directory in the non-asset namespace.
1020*d57664e9SAndroid Build Coastguard Worker *
1021*d57664e9SAndroid Build Coastguard Worker * An "asset directory" is simply the combination of all asset paths' "assets/" directories.
1022*d57664e9SAndroid Build Coastguard Worker *
1023*d57664e9SAndroid Build Coastguard Worker * Pass in "" for the root dir.
1024*d57664e9SAndroid Build Coastguard Worker */
openNonAssetDir(const int32_t cookie,const char * dirName)1025*d57664e9SAndroid Build Coastguard Worker AssetDir* AssetManager::openNonAssetDir(const int32_t cookie, const char* dirName)
1026*d57664e9SAndroid Build Coastguard Worker {
1027*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(mLock);
1028*d57664e9SAndroid Build Coastguard Worker
1029*d57664e9SAndroid Build Coastguard Worker AssetDir* pDir = NULL;
1030*d57664e9SAndroid Build Coastguard Worker SortedVector<AssetDir::FileInfo>* pMergedInfo = NULL;
1031*d57664e9SAndroid Build Coastguard Worker
1032*d57664e9SAndroid Build Coastguard Worker LOG_FATAL_IF(mAssetPaths.size() == 0, "No assets added to AssetManager");
1033*d57664e9SAndroid Build Coastguard Worker assert(dirName != NULL);
1034*d57664e9SAndroid Build Coastguard Worker
1035*d57664e9SAndroid Build Coastguard Worker //printf("+++ openDir(%s) in '%s'\n", dirName, (const char*) mAssetBase);
1036*d57664e9SAndroid Build Coastguard Worker
1037*d57664e9SAndroid Build Coastguard Worker pDir = new AssetDir;
1038*d57664e9SAndroid Build Coastguard Worker
1039*d57664e9SAndroid Build Coastguard Worker pMergedInfo = new SortedVector<AssetDir::FileInfo>;
1040*d57664e9SAndroid Build Coastguard Worker
1041*d57664e9SAndroid Build Coastguard Worker const size_t which = static_cast<size_t>(cookie) - 1;
1042*d57664e9SAndroid Build Coastguard Worker
1043*d57664e9SAndroid Build Coastguard Worker if (which < mAssetPaths.size()) {
1044*d57664e9SAndroid Build Coastguard Worker const asset_path& ap = mAssetPaths.itemAt(which);
1045*d57664e9SAndroid Build Coastguard Worker if (ap.type == kFileTypeRegular) {
1046*d57664e9SAndroid Build Coastguard Worker ALOGV("Adding directory %s from zip %s", dirName, ap.path.c_str());
1047*d57664e9SAndroid Build Coastguard Worker scanAndMergeZipLocked(pMergedInfo, ap, NULL, dirName);
1048*d57664e9SAndroid Build Coastguard Worker } else {
1049*d57664e9SAndroid Build Coastguard Worker ALOGV("Adding directory %s from dir %s", dirName, ap.path.c_str());
1050*d57664e9SAndroid Build Coastguard Worker scanAndMergeDirLocked(pMergedInfo, ap, NULL, dirName);
1051*d57664e9SAndroid Build Coastguard Worker }
1052*d57664e9SAndroid Build Coastguard Worker }
1053*d57664e9SAndroid Build Coastguard Worker
1054*d57664e9SAndroid Build Coastguard Worker #if 0
1055*d57664e9SAndroid Build Coastguard Worker printf("FILE LIST:\n");
1056*d57664e9SAndroid Build Coastguard Worker for (i = 0; i < (size_t) pMergedInfo->size(); i++) {
1057*d57664e9SAndroid Build Coastguard Worker printf(" %d: (%d) '%s'\n", i,
1058*d57664e9SAndroid Build Coastguard Worker pMergedInfo->itemAt(i).getFileType(),
1059*d57664e9SAndroid Build Coastguard Worker (const char*) pMergedInfo->itemAt(i).getFileName());
1060*d57664e9SAndroid Build Coastguard Worker }
1061*d57664e9SAndroid Build Coastguard Worker #endif
1062*d57664e9SAndroid Build Coastguard Worker
1063*d57664e9SAndroid Build Coastguard Worker pDir->setFileList(pMergedInfo);
1064*d57664e9SAndroid Build Coastguard Worker return pDir;
1065*d57664e9SAndroid Build Coastguard Worker }
1066*d57664e9SAndroid Build Coastguard Worker
1067*d57664e9SAndroid Build Coastguard Worker /*
1068*d57664e9SAndroid Build Coastguard Worker * Scan the contents of the specified directory and merge them into the
1069*d57664e9SAndroid Build Coastguard Worker * "pMergedInfo" vector, removing previous entries if we find "exclude"
1070*d57664e9SAndroid Build Coastguard Worker * directives.
1071*d57664e9SAndroid Build Coastguard Worker *
1072*d57664e9SAndroid Build Coastguard Worker * Returns "false" if we found nothing to contribute.
1073*d57664e9SAndroid Build Coastguard Worker */
scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo> * pMergedInfo,const asset_path & ap,const char * rootDir,const char * dirName)1074*d57664e9SAndroid Build Coastguard Worker bool AssetManager::scanAndMergeDirLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
1075*d57664e9SAndroid Build Coastguard Worker const asset_path& ap, const char* rootDir, const char* dirName)
1076*d57664e9SAndroid Build Coastguard Worker {
1077*d57664e9SAndroid Build Coastguard Worker assert(pMergedInfo != NULL);
1078*d57664e9SAndroid Build Coastguard Worker
1079*d57664e9SAndroid Build Coastguard Worker //printf("scanAndMergeDir: %s %s %s\n", ap.path.c_str(), rootDir, dirName);
1080*d57664e9SAndroid Build Coastguard Worker
1081*d57664e9SAndroid Build Coastguard Worker String8 path = createPathNameLocked(ap, rootDir);
1082*d57664e9SAndroid Build Coastguard Worker if (dirName[0] != '\0') appendPath(path, dirName);
1083*d57664e9SAndroid Build Coastguard Worker
1084*d57664e9SAndroid Build Coastguard Worker SortedVector<AssetDir::FileInfo>* pContents = scanDirLocked(path);
1085*d57664e9SAndroid Build Coastguard Worker if (pContents == NULL)
1086*d57664e9SAndroid Build Coastguard Worker return false;
1087*d57664e9SAndroid Build Coastguard Worker
1088*d57664e9SAndroid Build Coastguard Worker // if we wanted to do an incremental cache fill, we would do it here
1089*d57664e9SAndroid Build Coastguard Worker
1090*d57664e9SAndroid Build Coastguard Worker /*
1091*d57664e9SAndroid Build Coastguard Worker * Process "exclude" directives. If we find a filename that ends with
1092*d57664e9SAndroid Build Coastguard Worker * ".EXCLUDE", we look for a matching entry in the "merged" set, and
1093*d57664e9SAndroid Build Coastguard Worker * remove it if we find it. We also delete the "exclude" entry.
1094*d57664e9SAndroid Build Coastguard Worker */
1095*d57664e9SAndroid Build Coastguard Worker int i, count, exclExtLen;
1096*d57664e9SAndroid Build Coastguard Worker
1097*d57664e9SAndroid Build Coastguard Worker count = pContents->size();
1098*d57664e9SAndroid Build Coastguard Worker exclExtLen = strlen(kExcludeExtension);
1099*d57664e9SAndroid Build Coastguard Worker for (i = 0; i < count; i++) {
1100*d57664e9SAndroid Build Coastguard Worker const char* name;
1101*d57664e9SAndroid Build Coastguard Worker int nameLen;
1102*d57664e9SAndroid Build Coastguard Worker
1103*d57664e9SAndroid Build Coastguard Worker name = pContents->itemAt(i).getFileName().c_str();
1104*d57664e9SAndroid Build Coastguard Worker nameLen = strlen(name);
1105*d57664e9SAndroid Build Coastguard Worker if (nameLen > exclExtLen &&
1106*d57664e9SAndroid Build Coastguard Worker strcmp(name + (nameLen - exclExtLen), kExcludeExtension) == 0)
1107*d57664e9SAndroid Build Coastguard Worker {
1108*d57664e9SAndroid Build Coastguard Worker String8 match(name, nameLen - exclExtLen);
1109*d57664e9SAndroid Build Coastguard Worker int matchIdx;
1110*d57664e9SAndroid Build Coastguard Worker
1111*d57664e9SAndroid Build Coastguard Worker matchIdx = AssetDir::FileInfo::findEntry(pMergedInfo, match);
1112*d57664e9SAndroid Build Coastguard Worker if (matchIdx > 0) {
1113*d57664e9SAndroid Build Coastguard Worker ALOGV("Excluding '%s' [%s]\n",
1114*d57664e9SAndroid Build Coastguard Worker pMergedInfo->itemAt(matchIdx).getFileName().c_str(),
1115*d57664e9SAndroid Build Coastguard Worker pMergedInfo->itemAt(matchIdx).getSourceName().c_str());
1116*d57664e9SAndroid Build Coastguard Worker pMergedInfo->removeAt(matchIdx);
1117*d57664e9SAndroid Build Coastguard Worker } else {
1118*d57664e9SAndroid Build Coastguard Worker //printf("+++ no match on '%s'\n", (const char*) match);
1119*d57664e9SAndroid Build Coastguard Worker }
1120*d57664e9SAndroid Build Coastguard Worker
1121*d57664e9SAndroid Build Coastguard Worker ALOGD("HEY: size=%d removing %d\n", (int)pContents->size(), i);
1122*d57664e9SAndroid Build Coastguard Worker pContents->removeAt(i);
1123*d57664e9SAndroid Build Coastguard Worker i--; // adjust "for" loop
1124*d57664e9SAndroid Build Coastguard Worker count--; // and loop limit
1125*d57664e9SAndroid Build Coastguard Worker }
1126*d57664e9SAndroid Build Coastguard Worker }
1127*d57664e9SAndroid Build Coastguard Worker
1128*d57664e9SAndroid Build Coastguard Worker mergeInfoLocked(pMergedInfo, pContents);
1129*d57664e9SAndroid Build Coastguard Worker
1130*d57664e9SAndroid Build Coastguard Worker delete pContents;
1131*d57664e9SAndroid Build Coastguard Worker
1132*d57664e9SAndroid Build Coastguard Worker return true;
1133*d57664e9SAndroid Build Coastguard Worker }
1134*d57664e9SAndroid Build Coastguard Worker
1135*d57664e9SAndroid Build Coastguard Worker /*
1136*d57664e9SAndroid Build Coastguard Worker * Scan the contents of the specified directory, and stuff what we find
1137*d57664e9SAndroid Build Coastguard Worker * into a newly-allocated vector.
1138*d57664e9SAndroid Build Coastguard Worker *
1139*d57664e9SAndroid Build Coastguard Worker * Files ending in ".gz" will have their extensions removed.
1140*d57664e9SAndroid Build Coastguard Worker *
1141*d57664e9SAndroid Build Coastguard Worker * We should probably think about skipping files with "illegal" names,
1142*d57664e9SAndroid Build Coastguard Worker * e.g. illegal characters (/\:) or excessive length.
1143*d57664e9SAndroid Build Coastguard Worker *
1144*d57664e9SAndroid Build Coastguard Worker * Returns NULL if the specified directory doesn't exist.
1145*d57664e9SAndroid Build Coastguard Worker */
scanDirLocked(const String8 & path)1146*d57664e9SAndroid Build Coastguard Worker SortedVector<AssetDir::FileInfo>* AssetManager::scanDirLocked(const String8& path)
1147*d57664e9SAndroid Build Coastguard Worker {
1148*d57664e9SAndroid Build Coastguard Worker SortedVector<AssetDir::FileInfo>* pContents = NULL;
1149*d57664e9SAndroid Build Coastguard Worker DIR* dir;
1150*d57664e9SAndroid Build Coastguard Worker struct dirent* entry;
1151*d57664e9SAndroid Build Coastguard Worker FileType fileType;
1152*d57664e9SAndroid Build Coastguard Worker
1153*d57664e9SAndroid Build Coastguard Worker ALOGV("Scanning dir '%s'\n", path.c_str());
1154*d57664e9SAndroid Build Coastguard Worker
1155*d57664e9SAndroid Build Coastguard Worker dir = opendir(path.c_str());
1156*d57664e9SAndroid Build Coastguard Worker if (dir == NULL)
1157*d57664e9SAndroid Build Coastguard Worker return NULL;
1158*d57664e9SAndroid Build Coastguard Worker
1159*d57664e9SAndroid Build Coastguard Worker pContents = new SortedVector<AssetDir::FileInfo>;
1160*d57664e9SAndroid Build Coastguard Worker
1161*d57664e9SAndroid Build Coastguard Worker while (1) {
1162*d57664e9SAndroid Build Coastguard Worker entry = readdir(dir);
1163*d57664e9SAndroid Build Coastguard Worker if (entry == NULL)
1164*d57664e9SAndroid Build Coastguard Worker break;
1165*d57664e9SAndroid Build Coastguard Worker
1166*d57664e9SAndroid Build Coastguard Worker if (strcmp(entry->d_name, ".") == 0 ||
1167*d57664e9SAndroid Build Coastguard Worker strcmp(entry->d_name, "..") == 0)
1168*d57664e9SAndroid Build Coastguard Worker continue;
1169*d57664e9SAndroid Build Coastguard Worker
1170*d57664e9SAndroid Build Coastguard Worker #ifdef _DIRENT_HAVE_D_TYPE
1171*d57664e9SAndroid Build Coastguard Worker if (entry->d_type == DT_REG)
1172*d57664e9SAndroid Build Coastguard Worker fileType = kFileTypeRegular;
1173*d57664e9SAndroid Build Coastguard Worker else if (entry->d_type == DT_DIR)
1174*d57664e9SAndroid Build Coastguard Worker fileType = kFileTypeDirectory;
1175*d57664e9SAndroid Build Coastguard Worker else
1176*d57664e9SAndroid Build Coastguard Worker fileType = kFileTypeUnknown;
1177*d57664e9SAndroid Build Coastguard Worker #else
1178*d57664e9SAndroid Build Coastguard Worker // stat the file
1179*d57664e9SAndroid Build Coastguard Worker fileType = ::getFileType(appendPathCopy(path, entry->d_name).c_str());
1180*d57664e9SAndroid Build Coastguard Worker #endif
1181*d57664e9SAndroid Build Coastguard Worker
1182*d57664e9SAndroid Build Coastguard Worker if (fileType != kFileTypeRegular && fileType != kFileTypeDirectory)
1183*d57664e9SAndroid Build Coastguard Worker continue;
1184*d57664e9SAndroid Build Coastguard Worker
1185*d57664e9SAndroid Build Coastguard Worker AssetDir::FileInfo info;
1186*d57664e9SAndroid Build Coastguard Worker info.set(String8(entry->d_name), fileType);
1187*d57664e9SAndroid Build Coastguard Worker if (strcasecmp(getPathExtension(info.getFileName()).c_str(), ".gz") == 0)
1188*d57664e9SAndroid Build Coastguard Worker info.setFileName(getBasePath(info.getFileName()));
1189*d57664e9SAndroid Build Coastguard Worker info.setSourceName(appendPathCopy(path, info.getFileName()));
1190*d57664e9SAndroid Build Coastguard Worker pContents->add(info);
1191*d57664e9SAndroid Build Coastguard Worker }
1192*d57664e9SAndroid Build Coastguard Worker
1193*d57664e9SAndroid Build Coastguard Worker closedir(dir);
1194*d57664e9SAndroid Build Coastguard Worker return pContents;
1195*d57664e9SAndroid Build Coastguard Worker }
1196*d57664e9SAndroid Build Coastguard Worker
1197*d57664e9SAndroid Build Coastguard Worker /*
1198*d57664e9SAndroid Build Coastguard Worker * Scan the contents out of the specified Zip archive, and merge what we
1199*d57664e9SAndroid Build Coastguard Worker * find into "pMergedInfo". If the Zip archive in question doesn't exist,
1200*d57664e9SAndroid Build Coastguard Worker * we return immediately.
1201*d57664e9SAndroid Build Coastguard Worker *
1202*d57664e9SAndroid Build Coastguard Worker * Returns "false" if we found nothing to contribute.
1203*d57664e9SAndroid Build Coastguard Worker */
scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo> * pMergedInfo,const asset_path & ap,const char * rootDir,const char * baseDirName)1204*d57664e9SAndroid Build Coastguard Worker bool AssetManager::scanAndMergeZipLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
1205*d57664e9SAndroid Build Coastguard Worker const asset_path& ap, const char* rootDir, const char* baseDirName)
1206*d57664e9SAndroid Build Coastguard Worker {
1207*d57664e9SAndroid Build Coastguard Worker ZipFileRO* pZip;
1208*d57664e9SAndroid Build Coastguard Worker Vector<String8> dirs;
1209*d57664e9SAndroid Build Coastguard Worker AssetDir::FileInfo info;
1210*d57664e9SAndroid Build Coastguard Worker SortedVector<AssetDir::FileInfo> contents;
1211*d57664e9SAndroid Build Coastguard Worker String8 sourceName, zipName, dirName;
1212*d57664e9SAndroid Build Coastguard Worker
1213*d57664e9SAndroid Build Coastguard Worker pZip = mZipSet.getZip(ap.path);
1214*d57664e9SAndroid Build Coastguard Worker if (pZip == NULL) {
1215*d57664e9SAndroid Build Coastguard Worker ALOGW("Failure opening zip %s\n", ap.path.c_str());
1216*d57664e9SAndroid Build Coastguard Worker return false;
1217*d57664e9SAndroid Build Coastguard Worker }
1218*d57664e9SAndroid Build Coastguard Worker
1219*d57664e9SAndroid Build Coastguard Worker zipName = ZipSet::getPathName(ap.path.c_str());
1220*d57664e9SAndroid Build Coastguard Worker
1221*d57664e9SAndroid Build Coastguard Worker /* convert "sounds" to "rootDir/sounds" */
1222*d57664e9SAndroid Build Coastguard Worker if (rootDir != NULL) dirName = rootDir;
1223*d57664e9SAndroid Build Coastguard Worker appendPath(dirName, baseDirName);
1224*d57664e9SAndroid Build Coastguard Worker
1225*d57664e9SAndroid Build Coastguard Worker /*
1226*d57664e9SAndroid Build Coastguard Worker * Scan through the list of files, looking for a match. The files in
1227*d57664e9SAndroid Build Coastguard Worker * the Zip table of contents are not in sorted order, so we have to
1228*d57664e9SAndroid Build Coastguard Worker * process the entire list. We're looking for a string that begins
1229*d57664e9SAndroid Build Coastguard Worker * with the characters in "dirName", is followed by a '/', and has no
1230*d57664e9SAndroid Build Coastguard Worker * subsequent '/' in the stuff that follows.
1231*d57664e9SAndroid Build Coastguard Worker *
1232*d57664e9SAndroid Build Coastguard Worker * What makes this especially fun is that directories are not stored
1233*d57664e9SAndroid Build Coastguard Worker * explicitly in Zip archives, so we have to infer them from context.
1234*d57664e9SAndroid Build Coastguard Worker * When we see "sounds/foo.wav" we have to leave a note to ourselves
1235*d57664e9SAndroid Build Coastguard Worker * to insert a directory called "sounds" into the list. We store
1236*d57664e9SAndroid Build Coastguard Worker * these in temporary vector so that we only return each one once.
1237*d57664e9SAndroid Build Coastguard Worker *
1238*d57664e9SAndroid Build Coastguard Worker * Name comparisons are case-sensitive to match UNIX filesystem
1239*d57664e9SAndroid Build Coastguard Worker * semantics.
1240*d57664e9SAndroid Build Coastguard Worker */
1241*d57664e9SAndroid Build Coastguard Worker int dirNameLen = dirName.length();
1242*d57664e9SAndroid Build Coastguard Worker void *iterationCookie;
1243*d57664e9SAndroid Build Coastguard Worker if (!pZip->startIteration(&iterationCookie, dirName.c_str(), NULL)) {
1244*d57664e9SAndroid Build Coastguard Worker ALOGW("ZipFileRO::startIteration returned false");
1245*d57664e9SAndroid Build Coastguard Worker return false;
1246*d57664e9SAndroid Build Coastguard Worker }
1247*d57664e9SAndroid Build Coastguard Worker
1248*d57664e9SAndroid Build Coastguard Worker ZipEntryRO entry;
1249*d57664e9SAndroid Build Coastguard Worker while ((entry = pZip->nextEntry(iterationCookie)) != NULL) {
1250*d57664e9SAndroid Build Coastguard Worker char nameBuf[256];
1251*d57664e9SAndroid Build Coastguard Worker
1252*d57664e9SAndroid Build Coastguard Worker if (pZip->getEntryFileName(entry, nameBuf, sizeof(nameBuf)) != 0) {
1253*d57664e9SAndroid Build Coastguard Worker // TODO: fix this if we expect to have long names
1254*d57664e9SAndroid Build Coastguard Worker ALOGE("ARGH: name too long?\n");
1255*d57664e9SAndroid Build Coastguard Worker continue;
1256*d57664e9SAndroid Build Coastguard Worker }
1257*d57664e9SAndroid Build Coastguard Worker //printf("Comparing %s in %s?\n", nameBuf, dirName.c_str());
1258*d57664e9SAndroid Build Coastguard Worker if (dirNameLen == 0 || nameBuf[dirNameLen] == '/')
1259*d57664e9SAndroid Build Coastguard Worker {
1260*d57664e9SAndroid Build Coastguard Worker const char* cp;
1261*d57664e9SAndroid Build Coastguard Worker const char* nextSlash;
1262*d57664e9SAndroid Build Coastguard Worker
1263*d57664e9SAndroid Build Coastguard Worker cp = nameBuf + dirNameLen;
1264*d57664e9SAndroid Build Coastguard Worker if (dirNameLen != 0)
1265*d57664e9SAndroid Build Coastguard Worker cp++; // advance past the '/'
1266*d57664e9SAndroid Build Coastguard Worker
1267*d57664e9SAndroid Build Coastguard Worker nextSlash = strchr(cp, '/');
1268*d57664e9SAndroid Build Coastguard Worker //xxx this may break if there are bare directory entries
1269*d57664e9SAndroid Build Coastguard Worker if (nextSlash == NULL) {
1270*d57664e9SAndroid Build Coastguard Worker /* this is a file in the requested directory */
1271*d57664e9SAndroid Build Coastguard Worker
1272*d57664e9SAndroid Build Coastguard Worker info.set(getPathLeaf(String8(nameBuf)), kFileTypeRegular);
1273*d57664e9SAndroid Build Coastguard Worker
1274*d57664e9SAndroid Build Coastguard Worker info.setSourceName(
1275*d57664e9SAndroid Build Coastguard Worker createZipSourceNameLocked(zipName, dirName, info.getFileName()));
1276*d57664e9SAndroid Build Coastguard Worker
1277*d57664e9SAndroid Build Coastguard Worker contents.add(info);
1278*d57664e9SAndroid Build Coastguard Worker //printf("FOUND: file '%s'\n", info.getFileName().c_str());
1279*d57664e9SAndroid Build Coastguard Worker } else {
1280*d57664e9SAndroid Build Coastguard Worker /* this is a subdir; add it if we don't already have it*/
1281*d57664e9SAndroid Build Coastguard Worker String8 subdirName(cp, nextSlash - cp);
1282*d57664e9SAndroid Build Coastguard Worker size_t j;
1283*d57664e9SAndroid Build Coastguard Worker size_t N = dirs.size();
1284*d57664e9SAndroid Build Coastguard Worker
1285*d57664e9SAndroid Build Coastguard Worker for (j = 0; j < N; j++) {
1286*d57664e9SAndroid Build Coastguard Worker if (subdirName == dirs[j]) {
1287*d57664e9SAndroid Build Coastguard Worker break;
1288*d57664e9SAndroid Build Coastguard Worker }
1289*d57664e9SAndroid Build Coastguard Worker }
1290*d57664e9SAndroid Build Coastguard Worker if (j == N) {
1291*d57664e9SAndroid Build Coastguard Worker dirs.add(subdirName);
1292*d57664e9SAndroid Build Coastguard Worker }
1293*d57664e9SAndroid Build Coastguard Worker
1294*d57664e9SAndroid Build Coastguard Worker //printf("FOUND: dir '%s'\n", subdirName.c_str());
1295*d57664e9SAndroid Build Coastguard Worker }
1296*d57664e9SAndroid Build Coastguard Worker }
1297*d57664e9SAndroid Build Coastguard Worker }
1298*d57664e9SAndroid Build Coastguard Worker
1299*d57664e9SAndroid Build Coastguard Worker pZip->endIteration(iterationCookie);
1300*d57664e9SAndroid Build Coastguard Worker
1301*d57664e9SAndroid Build Coastguard Worker /*
1302*d57664e9SAndroid Build Coastguard Worker * Add the set of unique directories.
1303*d57664e9SAndroid Build Coastguard Worker */
1304*d57664e9SAndroid Build Coastguard Worker for (int i = 0; i < (int) dirs.size(); i++) {
1305*d57664e9SAndroid Build Coastguard Worker info.set(dirs[i], kFileTypeDirectory);
1306*d57664e9SAndroid Build Coastguard Worker info.setSourceName(
1307*d57664e9SAndroid Build Coastguard Worker createZipSourceNameLocked(zipName, dirName, info.getFileName()));
1308*d57664e9SAndroid Build Coastguard Worker contents.add(info);
1309*d57664e9SAndroid Build Coastguard Worker }
1310*d57664e9SAndroid Build Coastguard Worker
1311*d57664e9SAndroid Build Coastguard Worker mergeInfoLocked(pMergedInfo, &contents);
1312*d57664e9SAndroid Build Coastguard Worker
1313*d57664e9SAndroid Build Coastguard Worker return true;
1314*d57664e9SAndroid Build Coastguard Worker }
1315*d57664e9SAndroid Build Coastguard Worker
1316*d57664e9SAndroid Build Coastguard Worker
1317*d57664e9SAndroid Build Coastguard Worker /*
1318*d57664e9SAndroid Build Coastguard Worker * Merge two vectors of FileInfo.
1319*d57664e9SAndroid Build Coastguard Worker *
1320*d57664e9SAndroid Build Coastguard Worker * The merged contents will be stuffed into *pMergedInfo.
1321*d57664e9SAndroid Build Coastguard Worker *
1322*d57664e9SAndroid Build Coastguard Worker * If an entry for a file exists in both "pMergedInfo" and "pContents",
1323*d57664e9SAndroid Build Coastguard Worker * we use the newer "pContents" entry.
1324*d57664e9SAndroid Build Coastguard Worker */
mergeInfoLocked(SortedVector<AssetDir::FileInfo> * pMergedInfo,const SortedVector<AssetDir::FileInfo> * pContents)1325*d57664e9SAndroid Build Coastguard Worker void AssetManager::mergeInfoLocked(SortedVector<AssetDir::FileInfo>* pMergedInfo,
1326*d57664e9SAndroid Build Coastguard Worker const SortedVector<AssetDir::FileInfo>* pContents)
1327*d57664e9SAndroid Build Coastguard Worker {
1328*d57664e9SAndroid Build Coastguard Worker /*
1329*d57664e9SAndroid Build Coastguard Worker * Merge what we found in this directory with what we found in
1330*d57664e9SAndroid Build Coastguard Worker * other places.
1331*d57664e9SAndroid Build Coastguard Worker *
1332*d57664e9SAndroid Build Coastguard Worker * Two basic approaches:
1333*d57664e9SAndroid Build Coastguard Worker * (1) Create a new array that holds the unique values of the two
1334*d57664e9SAndroid Build Coastguard Worker * arrays.
1335*d57664e9SAndroid Build Coastguard Worker * (2) Take the elements from pContents and shove them into pMergedInfo.
1336*d57664e9SAndroid Build Coastguard Worker *
1337*d57664e9SAndroid Build Coastguard Worker * Because these are vectors of complex objects, moving elements around
1338*d57664e9SAndroid Build Coastguard Worker * inside the vector requires constructing new objects and allocating
1339*d57664e9SAndroid Build Coastguard Worker * storage for members. With approach #1, we're always adding to the
1340*d57664e9SAndroid Build Coastguard Worker * end, whereas with #2 we could be inserting multiple elements at the
1341*d57664e9SAndroid Build Coastguard Worker * front of the vector. Approach #1 requires a full copy of the
1342*d57664e9SAndroid Build Coastguard Worker * contents of pMergedInfo, but approach #2 requires the same copy for
1343*d57664e9SAndroid Build Coastguard Worker * every insertion at the front of pMergedInfo.
1344*d57664e9SAndroid Build Coastguard Worker *
1345*d57664e9SAndroid Build Coastguard Worker * (We should probably use a SortedVector interface that allows us to
1346*d57664e9SAndroid Build Coastguard Worker * just stuff items in, trusting us to maintain the sort order.)
1347*d57664e9SAndroid Build Coastguard Worker */
1348*d57664e9SAndroid Build Coastguard Worker SortedVector<AssetDir::FileInfo>* pNewSorted;
1349*d57664e9SAndroid Build Coastguard Worker int mergeMax, contMax;
1350*d57664e9SAndroid Build Coastguard Worker int mergeIdx, contIdx;
1351*d57664e9SAndroid Build Coastguard Worker
1352*d57664e9SAndroid Build Coastguard Worker pNewSorted = new SortedVector<AssetDir::FileInfo>;
1353*d57664e9SAndroid Build Coastguard Worker mergeMax = pMergedInfo->size();
1354*d57664e9SAndroid Build Coastguard Worker contMax = pContents->size();
1355*d57664e9SAndroid Build Coastguard Worker mergeIdx = contIdx = 0;
1356*d57664e9SAndroid Build Coastguard Worker
1357*d57664e9SAndroid Build Coastguard Worker while (mergeIdx < mergeMax || contIdx < contMax) {
1358*d57664e9SAndroid Build Coastguard Worker if (mergeIdx == mergeMax) {
1359*d57664e9SAndroid Build Coastguard Worker /* hit end of "merge" list, copy rest of "contents" */
1360*d57664e9SAndroid Build Coastguard Worker pNewSorted->add(pContents->itemAt(contIdx));
1361*d57664e9SAndroid Build Coastguard Worker contIdx++;
1362*d57664e9SAndroid Build Coastguard Worker } else if (contIdx == contMax) {
1363*d57664e9SAndroid Build Coastguard Worker /* hit end of "cont" list, copy rest of "merge" */
1364*d57664e9SAndroid Build Coastguard Worker pNewSorted->add(pMergedInfo->itemAt(mergeIdx));
1365*d57664e9SAndroid Build Coastguard Worker mergeIdx++;
1366*d57664e9SAndroid Build Coastguard Worker } else if (pMergedInfo->itemAt(mergeIdx) == pContents->itemAt(contIdx))
1367*d57664e9SAndroid Build Coastguard Worker {
1368*d57664e9SAndroid Build Coastguard Worker /* items are identical, add newer and advance both indices */
1369*d57664e9SAndroid Build Coastguard Worker pNewSorted->add(pContents->itemAt(contIdx));
1370*d57664e9SAndroid Build Coastguard Worker mergeIdx++;
1371*d57664e9SAndroid Build Coastguard Worker contIdx++;
1372*d57664e9SAndroid Build Coastguard Worker } else if (pMergedInfo->itemAt(mergeIdx) < pContents->itemAt(contIdx))
1373*d57664e9SAndroid Build Coastguard Worker {
1374*d57664e9SAndroid Build Coastguard Worker /* "merge" is lower, add that one */
1375*d57664e9SAndroid Build Coastguard Worker pNewSorted->add(pMergedInfo->itemAt(mergeIdx));
1376*d57664e9SAndroid Build Coastguard Worker mergeIdx++;
1377*d57664e9SAndroid Build Coastguard Worker } else {
1378*d57664e9SAndroid Build Coastguard Worker /* "cont" is lower, add that one */
1379*d57664e9SAndroid Build Coastguard Worker assert(pContents->itemAt(contIdx) < pMergedInfo->itemAt(mergeIdx));
1380*d57664e9SAndroid Build Coastguard Worker pNewSorted->add(pContents->itemAt(contIdx));
1381*d57664e9SAndroid Build Coastguard Worker contIdx++;
1382*d57664e9SAndroid Build Coastguard Worker }
1383*d57664e9SAndroid Build Coastguard Worker }
1384*d57664e9SAndroid Build Coastguard Worker
1385*d57664e9SAndroid Build Coastguard Worker /*
1386*d57664e9SAndroid Build Coastguard Worker * Overwrite the "merged" list with the new stuff.
1387*d57664e9SAndroid Build Coastguard Worker */
1388*d57664e9SAndroid Build Coastguard Worker *pMergedInfo = *pNewSorted;
1389*d57664e9SAndroid Build Coastguard Worker delete pNewSorted;
1390*d57664e9SAndroid Build Coastguard Worker
1391*d57664e9SAndroid Build Coastguard Worker #if 0 // for Vector, rather than SortedVector
1392*d57664e9SAndroid Build Coastguard Worker int i, j;
1393*d57664e9SAndroid Build Coastguard Worker for (i = pContents->size() -1; i >= 0; i--) {
1394*d57664e9SAndroid Build Coastguard Worker bool add = true;
1395*d57664e9SAndroid Build Coastguard Worker
1396*d57664e9SAndroid Build Coastguard Worker for (j = pMergedInfo->size() -1; j >= 0; j--) {
1397*d57664e9SAndroid Build Coastguard Worker /* case-sensitive comparisons, to behave like UNIX fs */
1398*d57664e9SAndroid Build Coastguard Worker if (strcmp(pContents->itemAt(i).mFileName,
1399*d57664e9SAndroid Build Coastguard Worker pMergedInfo->itemAt(j).mFileName) == 0)
1400*d57664e9SAndroid Build Coastguard Worker {
1401*d57664e9SAndroid Build Coastguard Worker /* match, don't add this entry */
1402*d57664e9SAndroid Build Coastguard Worker add = false;
1403*d57664e9SAndroid Build Coastguard Worker break;
1404*d57664e9SAndroid Build Coastguard Worker }
1405*d57664e9SAndroid Build Coastguard Worker }
1406*d57664e9SAndroid Build Coastguard Worker
1407*d57664e9SAndroid Build Coastguard Worker if (add)
1408*d57664e9SAndroid Build Coastguard Worker pMergedInfo->add(pContents->itemAt(i));
1409*d57664e9SAndroid Build Coastguard Worker }
1410*d57664e9SAndroid Build Coastguard Worker #endif
1411*d57664e9SAndroid Build Coastguard Worker }
1412*d57664e9SAndroid Build Coastguard Worker
1413*d57664e9SAndroid Build Coastguard Worker /*
1414*d57664e9SAndroid Build Coastguard Worker * ===========================================================================
1415*d57664e9SAndroid Build Coastguard Worker * AssetManager::SharedZip
1416*d57664e9SAndroid Build Coastguard Worker * ===========================================================================
1417*d57664e9SAndroid Build Coastguard Worker */
1418*d57664e9SAndroid Build Coastguard Worker
1419*d57664e9SAndroid Build Coastguard Worker
1420*d57664e9SAndroid Build Coastguard Worker Mutex AssetManager::SharedZip::gLock;
1421*d57664e9SAndroid Build Coastguard Worker DefaultKeyedVector<String8, wp<AssetManager::SharedZip> > AssetManager::SharedZip::gOpen;
1422*d57664e9SAndroid Build Coastguard Worker
SharedZip(const String8 & path,time_t modWhen)1423*d57664e9SAndroid Build Coastguard Worker AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen)
1424*d57664e9SAndroid Build Coastguard Worker : mPath(path), mZipFile(NULL), mModWhen(modWhen),
1425*d57664e9SAndroid Build Coastguard Worker mResourceTableAsset(NULL), mResourceTable(NULL)
1426*d57664e9SAndroid Build Coastguard Worker {
1427*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
1428*d57664e9SAndroid Build Coastguard Worker ALOGI("Creating SharedZip %p %s\n", this, mPath.c_str());
1429*d57664e9SAndroid Build Coastguard Worker }
1430*d57664e9SAndroid Build Coastguard Worker ALOGV("+++ opening zip '%s'\n", mPath.c_str());
1431*d57664e9SAndroid Build Coastguard Worker mZipFile = ZipFileRO::open(mPath.c_str());
1432*d57664e9SAndroid Build Coastguard Worker if (mZipFile == NULL) {
1433*d57664e9SAndroid Build Coastguard Worker ALOGD("failed to open Zip archive '%s'\n", mPath.c_str());
1434*d57664e9SAndroid Build Coastguard Worker }
1435*d57664e9SAndroid Build Coastguard Worker }
1436*d57664e9SAndroid Build Coastguard Worker
SharedZip(int fd,const String8 & path)1437*d57664e9SAndroid Build Coastguard Worker AssetManager::SharedZip::SharedZip(int fd, const String8& path)
1438*d57664e9SAndroid Build Coastguard Worker : mPath(path), mZipFile(NULL), mModWhen(0),
1439*d57664e9SAndroid Build Coastguard Worker mResourceTableAsset(NULL), mResourceTable(NULL)
1440*d57664e9SAndroid Build Coastguard Worker {
1441*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
1442*d57664e9SAndroid Build Coastguard Worker ALOGI("Creating SharedZip %p fd=%d %s\n", this, fd, mPath.c_str());
1443*d57664e9SAndroid Build Coastguard Worker }
1444*d57664e9SAndroid Build Coastguard Worker ALOGV("+++ opening zip fd=%d '%s'\n", fd, mPath.c_str());
1445*d57664e9SAndroid Build Coastguard Worker mZipFile = ZipFileRO::openFd(fd, mPath.c_str());
1446*d57664e9SAndroid Build Coastguard Worker if (mZipFile == NULL) {
1447*d57664e9SAndroid Build Coastguard Worker ::close(fd);
1448*d57664e9SAndroid Build Coastguard Worker ALOGD("failed to open Zip archive fd=%d '%s'\n", fd, mPath.c_str());
1449*d57664e9SAndroid Build Coastguard Worker }
1450*d57664e9SAndroid Build Coastguard Worker }
1451*d57664e9SAndroid Build Coastguard Worker
get(const String8 & path,bool createIfNotPresent)1452*d57664e9SAndroid Build Coastguard Worker sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path,
1453*d57664e9SAndroid Build Coastguard Worker bool createIfNotPresent)
1454*d57664e9SAndroid Build Coastguard Worker {
1455*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(gLock);
1456*d57664e9SAndroid Build Coastguard Worker time_t modWhen = getFileModDate(path.c_str());
1457*d57664e9SAndroid Build Coastguard Worker sp<SharedZip> zip = gOpen.valueFor(path).promote();
1458*d57664e9SAndroid Build Coastguard Worker if (zip != NULL && zip->mModWhen == modWhen) {
1459*d57664e9SAndroid Build Coastguard Worker return zip;
1460*d57664e9SAndroid Build Coastguard Worker }
1461*d57664e9SAndroid Build Coastguard Worker if (zip == NULL && !createIfNotPresent) {
1462*d57664e9SAndroid Build Coastguard Worker return NULL;
1463*d57664e9SAndroid Build Coastguard Worker }
1464*d57664e9SAndroid Build Coastguard Worker zip = new SharedZip(path, modWhen);
1465*d57664e9SAndroid Build Coastguard Worker gOpen.add(path, zip);
1466*d57664e9SAndroid Build Coastguard Worker return zip;
1467*d57664e9SAndroid Build Coastguard Worker }
1468*d57664e9SAndroid Build Coastguard Worker
create(int fd,const String8 & path)1469*d57664e9SAndroid Build Coastguard Worker sp<AssetManager::SharedZip> AssetManager::SharedZip::create(int fd, const String8& path)
1470*d57664e9SAndroid Build Coastguard Worker {
1471*d57664e9SAndroid Build Coastguard Worker return new SharedZip(fd, path);
1472*d57664e9SAndroid Build Coastguard Worker }
1473*d57664e9SAndroid Build Coastguard Worker
getZip()1474*d57664e9SAndroid Build Coastguard Worker ZipFileRO* AssetManager::SharedZip::getZip()
1475*d57664e9SAndroid Build Coastguard Worker {
1476*d57664e9SAndroid Build Coastguard Worker return mZipFile;
1477*d57664e9SAndroid Build Coastguard Worker }
1478*d57664e9SAndroid Build Coastguard Worker
getResourceTableAsset()1479*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::SharedZip::getResourceTableAsset()
1480*d57664e9SAndroid Build Coastguard Worker {
1481*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(gLock);
1482*d57664e9SAndroid Build Coastguard Worker ALOGV("Getting from SharedZip %p resource asset %p\n", this, mResourceTableAsset);
1483*d57664e9SAndroid Build Coastguard Worker return mResourceTableAsset;
1484*d57664e9SAndroid Build Coastguard Worker }
1485*d57664e9SAndroid Build Coastguard Worker
setResourceTableAsset(Asset * asset)1486*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::SharedZip::setResourceTableAsset(Asset* asset)
1487*d57664e9SAndroid Build Coastguard Worker {
1488*d57664e9SAndroid Build Coastguard Worker {
1489*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(gLock);
1490*d57664e9SAndroid Build Coastguard Worker if (mResourceTableAsset == NULL) {
1491*d57664e9SAndroid Build Coastguard Worker // This is not thread safe the first time it is called, so
1492*d57664e9SAndroid Build Coastguard Worker // do it here with the global lock held.
1493*d57664e9SAndroid Build Coastguard Worker asset->getBuffer(true);
1494*d57664e9SAndroid Build Coastguard Worker mResourceTableAsset = asset;
1495*d57664e9SAndroid Build Coastguard Worker return asset;
1496*d57664e9SAndroid Build Coastguard Worker }
1497*d57664e9SAndroid Build Coastguard Worker }
1498*d57664e9SAndroid Build Coastguard Worker delete asset;
1499*d57664e9SAndroid Build Coastguard Worker return mResourceTableAsset;
1500*d57664e9SAndroid Build Coastguard Worker }
1501*d57664e9SAndroid Build Coastguard Worker
getResourceTable()1502*d57664e9SAndroid Build Coastguard Worker ResTable* AssetManager::SharedZip::getResourceTable()
1503*d57664e9SAndroid Build Coastguard Worker {
1504*d57664e9SAndroid Build Coastguard Worker ALOGV("Getting from SharedZip %p resource table %p\n", this, mResourceTable);
1505*d57664e9SAndroid Build Coastguard Worker return mResourceTable;
1506*d57664e9SAndroid Build Coastguard Worker }
1507*d57664e9SAndroid Build Coastguard Worker
setResourceTable(ResTable * res)1508*d57664e9SAndroid Build Coastguard Worker ResTable* AssetManager::SharedZip::setResourceTable(ResTable* res)
1509*d57664e9SAndroid Build Coastguard Worker {
1510*d57664e9SAndroid Build Coastguard Worker {
1511*d57664e9SAndroid Build Coastguard Worker AutoMutex _l(gLock);
1512*d57664e9SAndroid Build Coastguard Worker if (mResourceTable == NULL) {
1513*d57664e9SAndroid Build Coastguard Worker mResourceTable = res;
1514*d57664e9SAndroid Build Coastguard Worker return res;
1515*d57664e9SAndroid Build Coastguard Worker }
1516*d57664e9SAndroid Build Coastguard Worker }
1517*d57664e9SAndroid Build Coastguard Worker delete res;
1518*d57664e9SAndroid Build Coastguard Worker return mResourceTable;
1519*d57664e9SAndroid Build Coastguard Worker }
1520*d57664e9SAndroid Build Coastguard Worker
isUpToDate()1521*d57664e9SAndroid Build Coastguard Worker bool AssetManager::SharedZip::isUpToDate()
1522*d57664e9SAndroid Build Coastguard Worker {
1523*d57664e9SAndroid Build Coastguard Worker time_t modWhen = getFileModDate(mPath.c_str());
1524*d57664e9SAndroid Build Coastguard Worker return mModWhen == modWhen;
1525*d57664e9SAndroid Build Coastguard Worker }
1526*d57664e9SAndroid Build Coastguard Worker
addOverlay(const asset_path & ap)1527*d57664e9SAndroid Build Coastguard Worker void AssetManager::SharedZip::addOverlay(const asset_path& ap)
1528*d57664e9SAndroid Build Coastguard Worker {
1529*d57664e9SAndroid Build Coastguard Worker mOverlays.add(ap);
1530*d57664e9SAndroid Build Coastguard Worker }
1531*d57664e9SAndroid Build Coastguard Worker
getOverlay(size_t idx,asset_path * out) const1532*d57664e9SAndroid Build Coastguard Worker bool AssetManager::SharedZip::getOverlay(size_t idx, asset_path* out) const
1533*d57664e9SAndroid Build Coastguard Worker {
1534*d57664e9SAndroid Build Coastguard Worker if (idx >= mOverlays.size()) {
1535*d57664e9SAndroid Build Coastguard Worker return false;
1536*d57664e9SAndroid Build Coastguard Worker }
1537*d57664e9SAndroid Build Coastguard Worker *out = mOverlays[idx];
1538*d57664e9SAndroid Build Coastguard Worker return true;
1539*d57664e9SAndroid Build Coastguard Worker }
1540*d57664e9SAndroid Build Coastguard Worker
~SharedZip()1541*d57664e9SAndroid Build Coastguard Worker AssetManager::SharedZip::~SharedZip()
1542*d57664e9SAndroid Build Coastguard Worker {
1543*d57664e9SAndroid Build Coastguard Worker if (kIsDebug) {
1544*d57664e9SAndroid Build Coastguard Worker ALOGI("Destroying SharedZip %p %s\n", this, mPath.c_str());
1545*d57664e9SAndroid Build Coastguard Worker }
1546*d57664e9SAndroid Build Coastguard Worker if (mResourceTable != NULL) {
1547*d57664e9SAndroid Build Coastguard Worker delete mResourceTable;
1548*d57664e9SAndroid Build Coastguard Worker }
1549*d57664e9SAndroid Build Coastguard Worker if (mResourceTableAsset != NULL) {
1550*d57664e9SAndroid Build Coastguard Worker delete mResourceTableAsset;
1551*d57664e9SAndroid Build Coastguard Worker }
1552*d57664e9SAndroid Build Coastguard Worker if (mZipFile != NULL) {
1553*d57664e9SAndroid Build Coastguard Worker delete mZipFile;
1554*d57664e9SAndroid Build Coastguard Worker ALOGV("Closed '%s'\n", mPath.c_str());
1555*d57664e9SAndroid Build Coastguard Worker }
1556*d57664e9SAndroid Build Coastguard Worker }
1557*d57664e9SAndroid Build Coastguard Worker
1558*d57664e9SAndroid Build Coastguard Worker /*
1559*d57664e9SAndroid Build Coastguard Worker * ===========================================================================
1560*d57664e9SAndroid Build Coastguard Worker * AssetManager::ZipSet
1561*d57664e9SAndroid Build Coastguard Worker * ===========================================================================
1562*d57664e9SAndroid Build Coastguard Worker */
1563*d57664e9SAndroid Build Coastguard Worker
1564*d57664e9SAndroid Build Coastguard Worker /*
1565*d57664e9SAndroid Build Coastguard Worker * Destructor. Close any open archives.
1566*d57664e9SAndroid Build Coastguard Worker */
~ZipSet(void)1567*d57664e9SAndroid Build Coastguard Worker AssetManager::ZipSet::~ZipSet(void)
1568*d57664e9SAndroid Build Coastguard Worker {
1569*d57664e9SAndroid Build Coastguard Worker size_t N = mZipFile.size();
1570*d57664e9SAndroid Build Coastguard Worker for (size_t i = 0; i < N; i++)
1571*d57664e9SAndroid Build Coastguard Worker closeZip(i);
1572*d57664e9SAndroid Build Coastguard Worker }
1573*d57664e9SAndroid Build Coastguard Worker
1574*d57664e9SAndroid Build Coastguard Worker /*
1575*d57664e9SAndroid Build Coastguard Worker * Close a Zip file and reset the entry.
1576*d57664e9SAndroid Build Coastguard Worker */
closeZip(int idx)1577*d57664e9SAndroid Build Coastguard Worker void AssetManager::ZipSet::closeZip(int idx)
1578*d57664e9SAndroid Build Coastguard Worker {
1579*d57664e9SAndroid Build Coastguard Worker mZipFile.editItemAt(idx) = NULL;
1580*d57664e9SAndroid Build Coastguard Worker }
1581*d57664e9SAndroid Build Coastguard Worker
1582*d57664e9SAndroid Build Coastguard Worker /*
1583*d57664e9SAndroid Build Coastguard Worker * Retrieve the appropriate Zip file from the set.
1584*d57664e9SAndroid Build Coastguard Worker */
getZip(const String8 & path)1585*d57664e9SAndroid Build Coastguard Worker ZipFileRO* AssetManager::ZipSet::getZip(const String8& path)
1586*d57664e9SAndroid Build Coastguard Worker {
1587*d57664e9SAndroid Build Coastguard Worker return getSharedZip(path)->getZip();
1588*d57664e9SAndroid Build Coastguard Worker }
1589*d57664e9SAndroid Build Coastguard Worker
getSharedZip(const String8 & path)1590*d57664e9SAndroid Build Coastguard Worker const sp<AssetManager::SharedZip> AssetManager::ZipSet::getSharedZip(const String8& path)
1591*d57664e9SAndroid Build Coastguard Worker {
1592*d57664e9SAndroid Build Coastguard Worker int idx = getIndex(path);
1593*d57664e9SAndroid Build Coastguard Worker sp<SharedZip> zip = mZipFile[idx];
1594*d57664e9SAndroid Build Coastguard Worker if (zip == NULL) {
1595*d57664e9SAndroid Build Coastguard Worker zip = SharedZip::get(path);
1596*d57664e9SAndroid Build Coastguard Worker mZipFile.editItemAt(idx) = zip;
1597*d57664e9SAndroid Build Coastguard Worker }
1598*d57664e9SAndroid Build Coastguard Worker return zip;
1599*d57664e9SAndroid Build Coastguard Worker }
1600*d57664e9SAndroid Build Coastguard Worker
getZipResourceTableAsset(const String8 & path)1601*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::ZipSet::getZipResourceTableAsset(const String8& path)
1602*d57664e9SAndroid Build Coastguard Worker {
1603*d57664e9SAndroid Build Coastguard Worker int idx = getIndex(path);
1604*d57664e9SAndroid Build Coastguard Worker sp<SharedZip> zip = mZipFile[idx];
1605*d57664e9SAndroid Build Coastguard Worker if (zip == NULL) {
1606*d57664e9SAndroid Build Coastguard Worker zip = SharedZip::get(path);
1607*d57664e9SAndroid Build Coastguard Worker mZipFile.editItemAt(idx) = zip;
1608*d57664e9SAndroid Build Coastguard Worker }
1609*d57664e9SAndroid Build Coastguard Worker return zip->getResourceTableAsset();
1610*d57664e9SAndroid Build Coastguard Worker }
1611*d57664e9SAndroid Build Coastguard Worker
setZipResourceTableAsset(const String8 & path,Asset * asset)1612*d57664e9SAndroid Build Coastguard Worker Asset* AssetManager::ZipSet::setZipResourceTableAsset(const String8& path,
1613*d57664e9SAndroid Build Coastguard Worker Asset* asset)
1614*d57664e9SAndroid Build Coastguard Worker {
1615*d57664e9SAndroid Build Coastguard Worker int idx = getIndex(path);
1616*d57664e9SAndroid Build Coastguard Worker sp<SharedZip> zip = mZipFile[idx];
1617*d57664e9SAndroid Build Coastguard Worker // doesn't make sense to call before previously accessing.
1618*d57664e9SAndroid Build Coastguard Worker return zip->setResourceTableAsset(asset);
1619*d57664e9SAndroid Build Coastguard Worker }
1620*d57664e9SAndroid Build Coastguard Worker
getZipResourceTable(const String8 & path)1621*d57664e9SAndroid Build Coastguard Worker ResTable* AssetManager::ZipSet::getZipResourceTable(const String8& path)
1622*d57664e9SAndroid Build Coastguard Worker {
1623*d57664e9SAndroid Build Coastguard Worker int idx = getIndex(path);
1624*d57664e9SAndroid Build Coastguard Worker sp<SharedZip> zip = mZipFile[idx];
1625*d57664e9SAndroid Build Coastguard Worker if (zip == NULL) {
1626*d57664e9SAndroid Build Coastguard Worker zip = SharedZip::get(path);
1627*d57664e9SAndroid Build Coastguard Worker mZipFile.editItemAt(idx) = zip;
1628*d57664e9SAndroid Build Coastguard Worker }
1629*d57664e9SAndroid Build Coastguard Worker return zip->getResourceTable();
1630*d57664e9SAndroid Build Coastguard Worker }
1631*d57664e9SAndroid Build Coastguard Worker
setZipResourceTable(const String8 & path,ResTable * res)1632*d57664e9SAndroid Build Coastguard Worker ResTable* AssetManager::ZipSet::setZipResourceTable(const String8& path,
1633*d57664e9SAndroid Build Coastguard Worker ResTable* res)
1634*d57664e9SAndroid Build Coastguard Worker {
1635*d57664e9SAndroid Build Coastguard Worker int idx = getIndex(path);
1636*d57664e9SAndroid Build Coastguard Worker sp<SharedZip> zip = mZipFile[idx];
1637*d57664e9SAndroid Build Coastguard Worker // doesn't make sense to call before previously accessing.
1638*d57664e9SAndroid Build Coastguard Worker return zip->setResourceTable(res);
1639*d57664e9SAndroid Build Coastguard Worker }
1640*d57664e9SAndroid Build Coastguard Worker
1641*d57664e9SAndroid Build Coastguard Worker /*
1642*d57664e9SAndroid Build Coastguard Worker * Generate the partial pathname for the specified archive. The caller
1643*d57664e9SAndroid Build Coastguard Worker * gets to prepend the asset root directory.
1644*d57664e9SAndroid Build Coastguard Worker *
1645*d57664e9SAndroid Build Coastguard Worker * Returns something like "common/en-US-noogle.jar".
1646*d57664e9SAndroid Build Coastguard Worker */
getPathName(const char * zipPath)1647*d57664e9SAndroid Build Coastguard Worker /*static*/ String8 AssetManager::ZipSet::getPathName(const char* zipPath)
1648*d57664e9SAndroid Build Coastguard Worker {
1649*d57664e9SAndroid Build Coastguard Worker return String8(zipPath);
1650*d57664e9SAndroid Build Coastguard Worker }
1651*d57664e9SAndroid Build Coastguard Worker
isUpToDate()1652*d57664e9SAndroid Build Coastguard Worker bool AssetManager::ZipSet::isUpToDate()
1653*d57664e9SAndroid Build Coastguard Worker {
1654*d57664e9SAndroid Build Coastguard Worker const size_t N = mZipFile.size();
1655*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
1656*d57664e9SAndroid Build Coastguard Worker if (mZipFile[i] != NULL && !mZipFile[i]->isUpToDate()) {
1657*d57664e9SAndroid Build Coastguard Worker return false;
1658*d57664e9SAndroid Build Coastguard Worker }
1659*d57664e9SAndroid Build Coastguard Worker }
1660*d57664e9SAndroid Build Coastguard Worker return true;
1661*d57664e9SAndroid Build Coastguard Worker }
1662*d57664e9SAndroid Build Coastguard Worker
addOverlay(const String8 & path,const asset_path & overlay)1663*d57664e9SAndroid Build Coastguard Worker void AssetManager::ZipSet::addOverlay(const String8& path, const asset_path& overlay)
1664*d57664e9SAndroid Build Coastguard Worker {
1665*d57664e9SAndroid Build Coastguard Worker int idx = getIndex(path);
1666*d57664e9SAndroid Build Coastguard Worker sp<SharedZip> zip = mZipFile[idx];
1667*d57664e9SAndroid Build Coastguard Worker zip->addOverlay(overlay);
1668*d57664e9SAndroid Build Coastguard Worker }
1669*d57664e9SAndroid Build Coastguard Worker
getOverlay(const String8 & path,size_t idx,asset_path * out) const1670*d57664e9SAndroid Build Coastguard Worker bool AssetManager::ZipSet::getOverlay(const String8& path, size_t idx, asset_path* out) const
1671*d57664e9SAndroid Build Coastguard Worker {
1672*d57664e9SAndroid Build Coastguard Worker sp<SharedZip> zip = SharedZip::get(path, false);
1673*d57664e9SAndroid Build Coastguard Worker if (zip == NULL) {
1674*d57664e9SAndroid Build Coastguard Worker return false;
1675*d57664e9SAndroid Build Coastguard Worker }
1676*d57664e9SAndroid Build Coastguard Worker return zip->getOverlay(idx, out);
1677*d57664e9SAndroid Build Coastguard Worker }
1678*d57664e9SAndroid Build Coastguard Worker
1679*d57664e9SAndroid Build Coastguard Worker /*
1680*d57664e9SAndroid Build Coastguard Worker * Compute the zip file's index.
1681*d57664e9SAndroid Build Coastguard Worker *
1682*d57664e9SAndroid Build Coastguard Worker * "appName", "locale", and "vendor" should be set to NULL to indicate the
1683*d57664e9SAndroid Build Coastguard Worker * default directory.
1684*d57664e9SAndroid Build Coastguard Worker */
getIndex(const String8 & zip) const1685*d57664e9SAndroid Build Coastguard Worker int AssetManager::ZipSet::getIndex(const String8& zip) const
1686*d57664e9SAndroid Build Coastguard Worker {
1687*d57664e9SAndroid Build Coastguard Worker const size_t N = mZipPath.size();
1688*d57664e9SAndroid Build Coastguard Worker for (size_t i=0; i<N; i++) {
1689*d57664e9SAndroid Build Coastguard Worker if (mZipPath[i] == zip) {
1690*d57664e9SAndroid Build Coastguard Worker return i;
1691*d57664e9SAndroid Build Coastguard Worker }
1692*d57664e9SAndroid Build Coastguard Worker }
1693*d57664e9SAndroid Build Coastguard Worker
1694*d57664e9SAndroid Build Coastguard Worker mZipPath.add(zip);
1695*d57664e9SAndroid Build Coastguard Worker mZipFile.add(NULL);
1696*d57664e9SAndroid Build Coastguard Worker
1697*d57664e9SAndroid Build Coastguard Worker return mZipPath.size()-1;
1698*d57664e9SAndroid Build Coastguard Worker }
1699