summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--core/java/android/app/ActivityThread.java113
-rw-r--r--core/java/android/content/res/AssetManager.java69
-rw-r--r--core/java/android/content/res/PackageRedirectionMap.aidl22
-rw-r--r--core/java/android/content/res/PackageRedirectionMap.java90
-rw-r--r--core/java/com/android/internal/app/IAssetRedirectionManager.aidl42
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp3
-rw-r--r--core/jni/android_util_AssetManager.cpp137
-rw-r--r--core/jni/android_util_PackageRedirectionMap.cpp176
-rw-r--r--include/utils/AssetManager.h17
-rw-r--r--include/utils/FileLock.h79
-rw-r--r--include/utils/PackageRedirectionMap.h68
-rw-r--r--include/utils/ResourceTypes.h40
-rw-r--r--libs/utils/Android.mk2
-rw-r--r--libs/utils/AssetManager.cpp406
-rw-r--r--libs/utils/FileLock.cpp96
-rw-r--r--libs/utils/PackageRedirectionMap.cpp191
-rw-r--r--libs/utils/ResourceTypes.cpp249
-rw-r--r--services/java/com/android/server/AssetRedirectionManagerService.java376
-rw-r--r--services/java/com/android/server/PackageManagerService.java114
-rw-r--r--services/java/com/android/server/SystemServer.java7
22 files changed, 1287 insertions, 1012 deletions
diff --git a/Android.mk b/Android.mk
index 83bdc0e..07d0caf 100644
--- a/Android.mk
+++ b/Android.mk
@@ -153,6 +153,7 @@ LOCAL_SRC_FILES += \
core/java/com/android/internal/app/IBatteryStats.aidl \
core/java/com/android/internal/app/IUsageStats.aidl \
core/java/com/android/internal/app/IMediaContainerService.aidl \
+ core/java/com/android/internal/app/IAssetRedirectionManager.aidl \
core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
core/java/com/android/internal/backup/IBackupTransport.aidl \
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 6955f41..650321e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -17,6 +17,7 @@
package android.app;
+import com.android.internal.app.IAssetRedirectionManager;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
@@ -41,11 +42,11 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
-import android.content.pm.ThemeInfo;
import android.content.res.AssetManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.CustomTheme;
+import android.content.res.PackageRedirectionMap;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDebug;
@@ -138,6 +139,7 @@ public final class ActivityThread {
static ContextImpl mSystemContext = null;
static IPackageManager sPackageManager;
+ static IAssetRedirectionManager sAssetRedirectionManager;
final ApplicationThread mAppThread = new ApplicationThread();
final Looper mLooper = Looper.myLooper();
@@ -1145,6 +1147,18 @@ public final class ActivityThread {
return sPackageManager;
}
+ // NOTE: this method can return null if the SystemServer is still
+ // initializing (for example, of another SystemServer component is accessing
+ // a resources object)
+ public static IAssetRedirectionManager getAssetRedirectionManager() {
+ if (sAssetRedirectionManager != null) {
+ return sAssetRedirectionManager;
+ }
+ IBinder b = ServiceManager.getService("assetredirection");
+ sAssetRedirectionManager = IAssetRedirectionManager.Stub.asInterface(b);
+ return sAssetRedirectionManager;
+ }
+
DisplayMetrics getDisplayMetricsLocked(boolean forceUpdate) {
if (mDisplayMetrics != null && !forceUpdate) {
return mDisplayMetrics;
@@ -1236,7 +1250,18 @@ public final class ActivityThread {
return r;
}
}
-
+
+ private void detachThemeAssets(AssetManager assets) {
+ String themePackageName = assets.getThemePackageName();
+ int themeCookie = assets.getThemeCookie();
+ if (!TextUtils.isEmpty(themePackageName) && themeCookie != 0) {
+ assets.removeAssetPath(themePackageName, themeCookie);
+ assets.setThemePackageName(null);
+ assets.setThemeCookie(0);
+ assets.clearRedirections();
+ }
+ }
+
/**
* Attach the necessary theme asset paths and meta information to convert an
* AssetManager to being globally "theme-aware".
@@ -1252,21 +1277,16 @@ public final class ActivityThread {
* the framework default.
*/
private boolean attachThemeAssets(AssetManager assets, CustomTheme theme, boolean updating) {
+ IAssetRedirectionManager rm = getAssetRedirectionManager();
+ if (rm == null) {
+ return false;
+ }
PackageInfo pi = null;
try {
pi = getPackageManager().getPackageInfo(theme.getThemePackageName(), 0);
} catch (RemoteException e) {
}
if (pi != null && pi.applicationInfo != null && pi.themeInfos != null) {
- /*
- * It's important that this is called before
- * updateResourcesWithAssetPath as it depends on the result of
- * getThemePackageName to figure out what to do with the resource
- * redirection table.
- */
- assets.setThemePackageInfo(theme.getThemePackageName(),
- findThemeResourceId(pi.themeInfos, theme));
-
String themeResDir = pi.applicationInfo.publicSourceDir;
int cookie;
if (updating) {
@@ -1275,44 +1295,47 @@ public final class ActivityThread {
cookie = assets.addAssetPath(themeResDir);
}
if (cookie != 0) {
+ String themePackageName = theme.getThemePackageName();
+ String themeId = theme.getThemeId();
+ int N = assets.getBasePackageCount();
+ for (int i = 0; i < N; i++) {
+ String packageName = assets.getBasePackageName(i);
+ int packageId = assets.getBasePackageId(i);
+
+ /*
+ * For now, we only consider redirections coming from the
+ * framework or regular android packages. This excludes
+ * themes and other specialty APKs we are not aware of.
+ */
+ if (packageId != 0x01 && packageId != 0x7f) {
+ continue;
+ }
+
+ try {
+ PackageRedirectionMap map = rm.getPackageRedirectionMap(themePackageName, themeId,
+ packageName);
+ if (map != null) {
+ assets.addRedirections(map);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failure accessing package redirection map, removing theme support.");
+ assets.removeAssetPath(themePackageName, cookie);
+ return false;
+ }
+ }
+
+ assets.setThemePackageName(theme.getThemePackageName());
assets.setThemeCookie(cookie);
return true;
} else {
Log.e(TAG, "Unable to " + (updating ? "update" : "add") + " theme assets at " +
themeResDir);
-
- /* Roll back the theme package info. */
- assets.setThemePackageInfo(null, 0);
}
}
return false;
}
/**
- * Searches for the high-level theme resource id for the specific
- * &lt;theme&gt; tag being applied.
- * <p>
- * An individual theme package can contain multiple &lt;theme&gt; tags, each
- * representing a separate theme choice from the user's perspective, even
- * though the most common case is for there to be only 1.
- *
- * @return The style resource id or 0 if no match was found.
- */
- private int findThemeResourceId(ThemeInfo[] themeInfos, CustomTheme theme) {
- String needle = theme.getThemeId();
- if (themeInfos != null && !TextUtils.isEmpty(needle)) {
- int n = themeInfos.length;
- for (int i = 0; i < n; i++) {
- ThemeInfo info = themeInfos[i];
- if (needle.equals(info.themeId)) {
- return info.styleResourceId;
- }
- }
- }
- return 0;
- }
-
- /**
* Creates the top level resources for the given package.
*/
Resources getTopLevelResources(String resDir, LoadedApk pkgInfo) {
@@ -3060,20 +3083,8 @@ public final class ActivityThread {
boolean themeChanged = (changes & ActivityInfo.CONFIG_THEME_RESOURCE) != 0;
if (themeChanged) {
AssetManager am = r.getAssets();
- /*
- * Dynamically modify the AssetManager object to
- * replace the old asset path with the new one. This
- * is made possibly by native layer changes made by
- * T-Mobile.
- */
if (am.hasThemeSupport()) {
- String oldThemePackage = am.getThemePackageName();
- int themeCookie = am.getThemeCookie();
- if (!TextUtils.isEmpty(oldThemePackage) && themeCookie != 0) {
- am.setThemePackageInfo(null, 0);
- am.removeAssetPath(oldThemePackage, themeCookie);
- am.setThemeCookie(0);
- }
+ detachThemeAssets(am);
if (!TextUtils.isEmpty(config.customTheme.getThemePackageName())) {
attachThemeAssets(am, config.customTheme, true);
}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 5a7734c..0b8c3ab 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -20,6 +20,7 @@ package android.content.res;
import android.os.ParcelFileDescriptor;
import android.util.Config;
import android.util.Log;
+import android.util.SparseArray;
import android.util.TypedValue;
import java.io.FileNotFoundException;
@@ -83,9 +84,17 @@ public final class AssetManager {
private String mAppName;
private boolean mThemeSupport;
+ private String mThemePackageName;
private int mThemeCookie;
/**
+ * Organize all added redirection maps using Java strong references to keep
+ * the native layer cleanup simple (that is, finalize() in Java will be
+ * responsible for delete in C++).
+ */
+ private SparseArray<PackageRedirectionMap> mRedirections;
+
+ /**
* Create a new AssetManager containing only the basic system assets.
* Applications will not generally use this method, instead retrieving the
* appropriate asset manager with {@link Resources#getAssets}. Not for
@@ -692,16 +701,30 @@ public final class AssetManager {
}
/**
+ * Apply a heuristic to match-up all attributes from the source style with
+ * attributes in the destination style. For each match, an entry in the
+ * package redirection map will be inserted.
+ *
+ * {@hide}
+ */
+ public native final boolean generateStyleRedirections(int resMapNative, int sourceStyle,
+ int destStyle);
+
+ /**
* Get package name of current theme (may return null).
* {@hide}
*/
- public native final String getThemePackageName();
+ public String getThemePackageName() {
+ return mThemePackageName;
+ }
/**
* Sets package name and highest level style id for current theme (null, 0 is allowed).
* {@hide}
*/
- public native final void setThemePackageInfo(String packageName, int styleId);
+ public void setThemePackageName(String packageName) {
+ mThemePackageName = packageName;
+ }
/**
* Get asset cookie for current theme (may return 0).
@@ -720,6 +743,30 @@ public final class AssetManager {
}
/**
+ * Add a redirection map to the asset manager. All future resource lookups
+ * will consult this map.
+ * {@hide}
+ */
+ public void addRedirections(PackageRedirectionMap map) {
+ if (mRedirections == null) {
+ mRedirections = new SparseArray<PackageRedirectionMap>(2);
+ }
+ mRedirections.append(map.getPackageId(), map);
+ addRedirectionsNative(map.getNativePointer());
+ }
+
+ /**
+ * Clear redirection map for the asset manager.
+ * {@hide}
+ */
+ public void clearRedirections() {
+ if (mRedirections != null) {
+ mRedirections.clear();
+ }
+ clearRedirectionsNative();
+ }
+
+ /**
* Determine whether the state in this asset manager is up-to-date with
* the files on the filesystem. If false is returned, you need to
* instantiate a new AssetManager class to see the new data.
@@ -837,6 +884,24 @@ public final class AssetManager {
private native final int splitThemePackage(String srcFileName, String dstFileName, String [] drmProtectedAssetNames);
+ /**
+ * {@hide}
+ */
+ public native final int getBasePackageCount();
+
+ /**
+ * {@hide}
+ */
+ public native final String getBasePackageName(int index);
+
+ /**
+ * {@hide}
+ */
+ public native final int getBasePackageId(int index);
+
+ private native final void addRedirectionsNative(int redirectionMapNativePointer);
+ private native final void clearRedirectionsNative();
+
private native final void init();
private native final void destroy();
diff --git a/core/java/android/content/res/PackageRedirectionMap.aidl b/core/java/android/content/res/PackageRedirectionMap.aidl
new file mode 100644
index 0000000..4f47525
--- /dev/null
+++ b/core/java/android/content/res/PackageRedirectionMap.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2011, T-Mobile USA, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+/**
+ * @hide
+ */
+parcelable PackageRedirectionMap;
diff --git a/core/java/android/content/res/PackageRedirectionMap.java b/core/java/android/content/res/PackageRedirectionMap.java
new file mode 100644
index 0000000..55c4282
--- /dev/null
+++ b/core/java/android/content/res/PackageRedirectionMap.java
@@ -0,0 +1,90 @@
+package android.content.res;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Native transport for package asset redirection information coming from the
+ * AssetRedirectionManagerService.
+ *
+ * @hide
+ */
+public class PackageRedirectionMap implements Parcelable {
+ private final int mNativePointer;
+
+ public static final Parcelable.Creator<PackageRedirectionMap> CREATOR
+ = new Parcelable.Creator<PackageRedirectionMap>() {
+ public PackageRedirectionMap createFromParcel(Parcel in) {
+ return new PackageRedirectionMap(in);
+ }
+
+ public PackageRedirectionMap[] newArray(int size) {
+ return new PackageRedirectionMap[size];
+ }
+ };
+
+ public PackageRedirectionMap() {
+ this(nativeConstructor());
+ }
+
+ private PackageRedirectionMap(Parcel in) {
+ this(nativeCreateFromParcel(in));
+ }
+
+ private PackageRedirectionMap(int nativePointer) {
+ if (nativePointer == 0) {
+ throw new RuntimeException();
+ }
+ mNativePointer = nativePointer;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ nativeDestructor(mNativePointer);
+ }
+
+ public int getNativePointer() {
+ return mNativePointer;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (!nativeWriteToParcel(mNativePointer, dest)) {
+ throw new RuntimeException();
+ }
+ }
+
+ public int getPackageId() {
+ return nativeGetPackageId(mNativePointer);
+ }
+
+ public void addRedirection(int fromIdent, int toIdent) {
+ nativeAddRedirection(mNativePointer, fromIdent, toIdent);
+ }
+
+ // Used for debugging purposes only.
+ public int[] getRedirectionKeys() {
+ return nativeGetRedirectionKeys(mNativePointer);
+ }
+
+ // Used for debugging purposes only.
+ public int lookupRedirection(int fromIdent) {
+ return nativeLookupRedirection(mNativePointer, fromIdent);
+ }
+
+ private static native int nativeConstructor();
+ private static native void nativeDestructor(int nativePointer);
+
+ private static native int nativeCreateFromParcel(Parcel p);
+ private static native boolean nativeWriteToParcel(int nativePointer, Parcel p);
+
+ private native void nativeAddRedirection(int nativePointer, int fromIdent, int toIdent);
+ private native int nativeGetPackageId(int nativePointer);
+ private native int[] nativeGetRedirectionKeys(int nativePointer);
+ private native int nativeLookupRedirection(int nativePointer, int fromIdent);
+}
diff --git a/core/java/com/android/internal/app/IAssetRedirectionManager.aidl b/core/java/com/android/internal/app/IAssetRedirectionManager.aidl
new file mode 100644
index 0000000..8b47f0b
--- /dev/null
+++ b/core/java/com/android/internal/app/IAssetRedirectionManager.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2011, T-Mobile USA, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.app;
+
+import android.content.res.PackageRedirectionMap;
+
+/**
+ * Interface used to interact with the AssetRedirectionManagerService.
+ */
+interface IAssetRedirectionManager {
+ /**
+ * Access the package redirection map for the supplied package name given a
+ * particular theme.
+ */
+ PackageRedirectionMap getPackageRedirectionMap(in String themePackageName,
+ String themeId, in String targetPackageName);
+
+ /**
+ * Clear all redirection maps for the given theme.
+ */
+ void clearRedirectionMapsByTheme(in String themePackageName,
+ in String themeId);
+
+ /**
+ * Clear all redirection maps for the given target package.
+ */
+ void clearPackageRedirectionMap(in String targetPackageName);
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c3f393d..69cb928 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -80,6 +80,7 @@ LOCAL_SRC_FILES:= \
android_util_Process.cpp \
android_util_StringBlock.cpp \
android_util_XmlBlock.cpp \
+ android_util_PackageRedirectionMap.cpp \
android/graphics/AutoDecodeCancel.cpp \
android/graphics/Bitmap.cpp \
android/graphics/BitmapFactory.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 648d93f..b22e611 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -170,6 +170,7 @@ extern int register_android_view_KeyEvent(JNIEnv* env);
extern int register_android_view_MotionEvent(JNIEnv* env);
extern int register_android_content_res_ObbScanner(JNIEnv* env);
extern int register_android_content_res_Configuration(JNIEnv* env);
+extern int register_android_content_res_PackageRedirectionMap(JNIEnv* env);
static AndroidRuntime* gCurRuntime = NULL;
@@ -1289,6 +1290,8 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_content_res_ObbScanner),
REG_JNI(register_android_content_res_Configuration),
+
+ REG_JNI(register_android_content_res_PackageRedirectionMap),
};
/*
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index c9f0ca7..b9ceeb7 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -33,6 +33,7 @@
#include <utils/Asset.h>
#include <utils/AssetManager.h>
#include <utils/ResourceTypes.h>
+#include <utils/PackageRedirectionMap.h>
#include <utils/ZipFile.h>
#include <stdio.h>
@@ -1802,36 +1803,128 @@ static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env,
return AssetManager::getGlobalCount();
}
-static void android_content_AssetManager_setThemePackageInfo(JNIEnv* env, jobject clazz,
- jstring packageName, jint styleId)
+static jint android_content_AssetManager_getBasePackageCount(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ return am->getResources().getBasePackageCount();
+}
+
+static jstring android_content_AssetManager_getBasePackageName(JNIEnv* env, jobject clazz, jint index)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ String16 packageName(am->getResources().getBasePackageName(index));
+ return env->NewString((const jchar*)packageName.string(), packageName.size());
+}
+
+static jint android_content_AssetManager_getBasePackageId(JNIEnv* env, jobject clazz, jint index)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return JNI_FALSE;
+ }
+
+ return am->getResources().getBasePackageId(index);
+}
+
+static void android_content_AssetManager_addRedirectionsNative(JNIEnv* env, jobject clazz,
+ PackageRedirectionMap* resMap)
{
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
return;
}
- if (packageName != NULL) {
- const char* packageName8 = env->GetStringUTFChars(packageName, NULL);
- am->setThemePackageInfo(packageName8, styleId);
- env->ReleaseStringUTFChars(packageName, packageName8);
- } else {
- am->setThemePackageInfo(NULL, styleId);
+ am->addRedirections(resMap);
+}
+
+static void android_content_AssetManager_clearRedirectionsNative(JNIEnv* env, jobject clazz)
+{
+ AssetManager* am = assetManagerForJavaObject(env, clazz);
+ if (am == NULL) {
+ return;
}
+
+ am->clearRedirections();
}
-static jstring android_content_AssetManager_getThemePackageName(JNIEnv* env, jobject clazz)
+static jboolean android_content_AssetManager_generateStyleRedirections(JNIEnv* env, jobject clazz,
+ PackageRedirectionMap* resMap, jint sourceStyle, jint destStyle)
{
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
- return NULL;
+ return JNI_FALSE;
}
- const char* packageName = am->getThemePackageName();
- if (packageName == NULL) {
- return NULL;
+ const ResTable& res(am->getResources());
+
+ res.lock();
+
+ // Load up a bag for the user-supplied theme.
+ const ResTable::bag_entry* themeEnt = NULL;
+ ssize_t N = res.getBagLocked(destStyle, &themeEnt);
+ const ResTable::bag_entry* endThemeEnt = themeEnt + (N >= 0 ? N : 0);
+
+ // ...and a bag for the framework default.
+ const ResTable::bag_entry* frameworkEnt = NULL;
+ N = res.getBagLocked(sourceStyle, &frameworkEnt);
+ const ResTable::bag_entry* endFrameworkEnt = frameworkEnt + (N >= 0 ? N : 0);
+
+ // Add the source => dest style redirection first.
+ jboolean ret = JNI_FALSE;
+ if (themeEnt < endThemeEnt && frameworkEnt < endFrameworkEnt) {
+ resMap->addRedirection(sourceStyle, destStyle);
+ ret = JNI_TRUE;
+ }
+
+ // Now compare them and infer resource redirections for attributes that
+ // remap to different styles. This works by essentially lining up all the
+ // sorted attributes from each theme and detected TYPE_REFERENCE entries
+ // that point to different resources. When we find such a mismatch, we'll
+ // create a resource redirection from the original framework resource ID to
+ // the one in the theme. This lets us do things like automatically find
+ // redirections for @android:style/Widget.Button by looking at how the
+ // theme overrides the android:attr/buttonStyle attribute.
+ REDIRECT_NOISY(LOGW("delta between 0x%08x and 0x%08x:\n", sourceStyle, destStyle));
+ for (; frameworkEnt < endFrameworkEnt; frameworkEnt++) {
+ if (frameworkEnt->map.value.dataType != Res_value::TYPE_REFERENCE) {
+ continue;
+ }
+
+ uint32_t curIdent = frameworkEnt->map.name.ident;
+
+ // Walk along the theme entry looking for a match.
+ while (themeEnt < endThemeEnt && curIdent > themeEnt->map.name.ident) {
+ themeEnt++;
+ }
+ // Match found, compare the references.
+ if (themeEnt < endThemeEnt && curIdent == themeEnt->map.name.ident) {
+ if (themeEnt->map.value.data != frameworkEnt->map.value.data) {
+ uint32_t fromIdent = frameworkEnt->map.value.data;
+ uint32_t toIdent = themeEnt->map.value.data;
+ REDIRECT_NOISY(LOGW(" generated mapping from 0x%08x => 0x%08x (by attr 0x%08x)\n",
+ fromIdent, toIdent, curIdent));
+ resMap->addRedirection(fromIdent, toIdent);
+ }
+ themeEnt++;
+ }
+
+ // Exhausted the theme, bail early.
+ if (themeEnt >= endThemeEnt) {
+ break;
+ }
}
- return env->NewStringUTF(packageName);
+ res.unlock();
+
+ return ret;
}
static jboolean android_content_AssetManager_removeAssetPath(JNIEnv* env, jobject clazz,
@@ -2001,16 +2094,24 @@ static JNINativeMethod gAssetManagerMethods[] = {
(void*) android_content_AssetManager_splitThemePackage },
// Dynamic theme package support.
- { "setThemePackageInfo", "(Ljava/lang/String;I)V",
- (void*) android_content_AssetManager_setThemePackageInfo },
- { "getThemePackageName", "()Ljava/lang/String;",
- (void*) android_content_AssetManager_getThemePackageName },
{ "removeAssetPath", "(Ljava/lang/String;I)Z",
(void*) android_content_AssetManager_removeAssetPath },
{ "updateResourcesWithAssetPath", "(Ljava/lang/String;)I",
(void*) android_content_AssetManager_updateResourcesWithAssetPath },
{ "dumpResources", "()V",
(void*) android_content_AssetManager_dumpRes },
+ { "getBasePackageCount", "()I",
+ (void*) android_content_AssetManager_getBasePackageCount },
+ { "getBasePackageName", "(I)Ljava/lang/String;",
+ (void*) android_content_AssetManager_getBasePackageName },
+ { "getBasePackageId", "(I)I",
+ (void*) android_content_AssetManager_getBasePackageId },
+ { "addRedirectionsNative", "(I)V",
+ (void*) android_content_AssetManager_addRedirectionsNative },
+ { "clearRedirectionsNative", "()V",
+ (void*) android_content_AssetManager_clearRedirectionsNative },
+ { "generateStyleRedirections", "(III)Z",
+ (void*) android_content_AssetManager_generateStyleRedirections },
};
int register_android_content_AssetManager(JNIEnv* env)
diff --git a/core/jni/android_util_PackageRedirectionMap.cpp b/core/jni/android_util_PackageRedirectionMap.cpp
new file mode 100644
index 0000000..2391edb
--- /dev/null
+++ b/core/jni/android_util_PackageRedirectionMap.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2011, T-Mobile USA, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/PackageRedirectionMap.h>
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include <utils/misc.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include "android_util_Binder.h"
+#include <binder/Parcel.h>
+
+#include <utils/ResourceTypes.h>
+
+#include <stdio.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+static PackageRedirectionMap* PackageRedirectionMap_constructor(JNIEnv* env, jobject clazz)
+{
+ return new PackageRedirectionMap;
+}
+
+static void PackageRedirectionMap_destructor(JNIEnv* env, jobject clazz,
+ PackageRedirectionMap* resMap)
+{
+ delete resMap;
+}
+
+static PackageRedirectionMap* PackageRedirectionMap_createFromParcel(JNIEnv* env, jobject clazz,
+ jobject parcel)
+{
+ if (parcel == NULL) {
+ return NULL;
+ }
+
+ Parcel* p = parcelForJavaObject(env, parcel);
+ PackageRedirectionMap* resMap = new PackageRedirectionMap;
+
+ int32_t entryCount = p->readInt32();
+ while (entryCount-- > 0) {
+ uint32_t fromIdent = (uint32_t)p->readInt32();
+ uint32_t toIdent = (uint32_t)p->readInt32();
+ resMap->addRedirection(fromIdent, toIdent);
+ }
+
+ return resMap;
+}
+
+static jboolean PackageRedirectionMap_writeToParcel(JNIEnv* env, jobject clazz,
+ PackageRedirectionMap* resMap, jobject parcel)
+{
+ if (parcel == NULL) {
+ return JNI_FALSE;
+ }
+
+ Parcel* p = parcelForJavaObject(env, parcel);
+
+ int package = resMap->getPackage();
+ size_t nTypes = resMap->getNumberOfTypes();
+ size_t entryCount = 0;
+ for (size_t type=0; type<nTypes; type++) {
+ entryCount += resMap->getNumberOfUsedEntries(type);
+ }
+ p->writeInt32(entryCount);
+ for (size_t type=0; type<nTypes; type++) {
+ size_t nEntries = resMap->getNumberOfEntries(type);
+ for (size_t entry=0; entry<nEntries; entry++) {
+ uint32_t toIdent = resMap->getEntry(type, entry);
+ if (toIdent != 0) {
+ uint32_t fromIdent = Res_MAKEID(package-1, type, entry);
+ p->writeInt32(fromIdent);
+ p->writeInt32(toIdent);
+ }
+ }
+ }
+
+ return JNI_TRUE;
+}
+
+static void PackageRedirectionMap_addRedirection(JNIEnv* env, jobject clazz,
+ PackageRedirectionMap* resMap, jint fromIdent, jint toIdent)
+{
+ resMap->addRedirection(fromIdent, toIdent);
+}
+
+static jint PackageRedirectionMap_getPackageId(JNIEnv* env, jobject clazz,
+ PackageRedirectionMap* resMap)
+{
+ return resMap->getPackage();
+}
+
+static jint PackageRedirectionMap_lookupRedirection(JNIEnv* env, jobject clazz,
+ PackageRedirectionMap* resMap, jint fromIdent)
+{
+ return resMap->lookupRedirection(fromIdent);
+}
+
+static jintArray PackageRedirectionMap_getRedirectionKeys(JNIEnv* env, jobject clazz,
+ PackageRedirectionMap* resMap)
+{
+ int package = resMap->getPackage();
+ size_t nTypes = resMap->getNumberOfTypes();
+ size_t entryCount = 0;
+ for (size_t type=0; type<nTypes; type++) {
+ size_t usedEntries = resMap->getNumberOfUsedEntries(type);
+ entryCount += usedEntries;
+ }
+ jintArray array = env->NewIntArray(entryCount);
+ if (array == NULL) {
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
+ return NULL;
+ }
+ jsize index = 0;
+ for (size_t type=0; type<nTypes; type++) {
+ size_t nEntries = resMap->getNumberOfEntries(type);
+ for (size_t entry=0; entry<nEntries; entry++) {
+ uint32_t toIdent = resMap->getEntry(type, entry);
+ if (toIdent != 0) {
+ jint fromIdent = (jint)Res_MAKEID(package-1, type, entry);
+ env->SetIntArrayRegion(array, index++, 1, &fromIdent);
+ }
+ }
+ }
+ return array;
+}
+
+// ----------------------------------------------------------------------------
+
+/*
+ * JNI registration.
+ */
+static JNINativeMethod gPackageRedirectionMapMethods[] = {
+ { "nativeConstructor", "()I",
+ (void*) PackageRedirectionMap_constructor },
+ { "nativeDestructor", "(I)V",
+ (void*) PackageRedirectionMap_destructor },
+ { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I",
+ (void*) PackageRedirectionMap_createFromParcel },
+ { "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z",
+ (void*) PackageRedirectionMap_writeToParcel },
+ { "nativeAddRedirection", "(III)V",
+ (void*) PackageRedirectionMap_addRedirection },
+ { "nativeGetPackageId", "(I)I",
+ (void*) PackageRedirectionMap_getPackageId },
+ { "nativeLookupRedirection", "(II)I",
+ (void*) PackageRedirectionMap_lookupRedirection },
+ { "nativeGetRedirectionKeys", "(I)[I",
+ (void*) PackageRedirectionMap_getRedirectionKeys },
+};
+
+int register_android_content_res_PackageRedirectionMap(JNIEnv* env)
+{
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/content/res/PackageRedirectionMap",
+ gPackageRedirectionMapMethods,
+ NELEM(gPackageRedirectionMapMethods));
+}
+
+}; // namespace android
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index 01179ed..f374cae 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -23,6 +23,7 @@
#include <utils/Asset.h>
#include <utils/AssetDir.h>
+#include <utils/PackageRedirectionMap.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/Vector.h>
@@ -218,9 +219,6 @@ public:
*/
void getLocales(Vector<String8>* locales) const;
- void setThemePackageInfo(const char* packageName, uint32_t styleId);
- const char* getThemePackageName();
-
/*
* Remove existing source for assets.
*
@@ -231,6 +229,8 @@ public:
bool removeAssetPath(const String8 &packageName, void *cookie);
bool updateWithAssetPath(const String8& path, void** cookie);
void dumpRes();
+ void addRedirections(PackageRedirectionMap* resMap);
+ void clearRedirections();
private:
struct asset_path
@@ -239,12 +239,6 @@ private:
FileType type;
};
- SharedBuffer* generateRedirections(SharedBuffer* entriesByTypeBuf, ResTable* rt,
- const char* themePackageName, const char16_t* resPackageName);
- bool generateAndWriteRedirections(ResTable* rt, const char* themePackageName,
- uint32_t themeStyleId, const char16_t* resPackageName, const char* redirPath,
- bool isFramework) const;
- void loadRedirectionMappings(ResTable* rt) const;
void updateResTableFromAssetPath(ResTable* rt, const asset_path& ap, void* cookie) const;
Asset* openInPathLocked(const char* fileName, AccessMode mode,
const asset_path& path);
@@ -362,11 +356,6 @@ private:
char* mLocale;
char* mVendor;
- // If non-null, represents the theme package from which to construct the
- // resource redirection map used by ResTable.
- char* mThemePackageName;
- uint32_t mThemeStyleId;
-
mutable ResTable* mResources;
ResTable_config* mConfig;
diff --git a/include/utils/FileLock.h b/include/utils/FileLock.h
deleted file mode 100644
index 2253cc2..0000000
--- a/include/utils/FileLock.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2010, T-Mobile USA, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __LIBS_FILE_LOCK_H
-#define __LIBS_FILE_LOCK_H
-
-#include <fcntl.h>
-
-namespace android {
-
-/*
- * Object oriented interface for flock. Implements reference counting so that
- * multiple levels of locks on the same object instance is possible.
- */
-class FileLock {
-public:
- FileLock(const char* fileName);
-
- /*
- * Lock the file. A balanced call to unlock is required even if the lock
- * fails.
- */
- bool lock(int openFlags=O_RDWR, mode_t fileCreateMode=0755) {
- mRefCount++;
- if (mFd == -1) {
- return doLock(openFlags, fileCreateMode);
- } else {
- return true;
- }
- }
-
- /*
- * Call this when mapping is no longer needed.
- */
- void unlock(void) {
- if (--mRefCount <= 0) {
- delete this;
- }
- }
-
- /*
- * Return the name of the file this map came from, if known.
- */
- const char* getFileName(void) const { return mFileName; }
-
- /*
- * Return the open file descriptor, if locked; -1 otherwise.
- */
- int getFileDescriptor(void) const { return mFd; }
-
-protected:
- // don't delete objects; call unlock()
- ~FileLock(void);
-
- bool doLock(int openFlags, mode_t fileCreateMode);
-
-private:
-
- int mRefCount; // reference count
- int mFd; // file descriptor, if locked
- char* mFileName; // original file name, if known
-};
-
-}; // namespace android
-
-#endif // __LIBS_FILE_LOCK_H
diff --git a/include/utils/PackageRedirectionMap.h b/include/utils/PackageRedirectionMap.h
new file mode 100644
index 0000000..9e6435b
--- /dev/null
+++ b/include/utils/PackageRedirectionMap.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PACKAGEREDIRECTIONMAP_H
+#define ANDROID_PACKAGEREDIRECTIONMAP_H
+
+#include <binder/Parcel.h>
+
+// ---------------------------------------------------------------------------
+
+namespace android {
+
+class PackageRedirectionMap
+{
+public:
+ PackageRedirectionMap();
+ ~PackageRedirectionMap();
+
+ bool addRedirection(uint32_t fromIdent, uint32_t toIdent);
+ uint32_t lookupRedirection(uint32_t fromIdent);
+
+ // If there are no redirections present in this map, this method will
+ // return -1.
+ int getPackage();
+
+ // Usage of the following methods is intended to be used only by the JNI
+ // methods for the purpose of parceling.
+ size_t getNumberOfTypes();
+ size_t getNumberOfUsedTypes();
+
+ size_t getNumberOfEntries(int type);
+ size_t getNumberOfUsedEntries(int type);
+
+ // Similar to lookupRedirection, but with no sanity checking.
+ uint32_t getEntry(int type, int entry);
+
+private:
+ int mPackage;
+
+ /*
+ * Sparse array organized into two layers: first by type, then by entry.
+ * The result of each lookup will be a qualified resource ID in the theme
+ * package scope.
+ *
+ * Underneath each layer is a SharedBuffer which
+ * indicates the array size.
+ */
+ uint32_t** mEntriesByType;
+};
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
+
+#endif // ANDROID_PACKAGEREDIRECTIONMAP_H
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index abdc00b..bae6b92 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -24,6 +24,7 @@
#include <utils/Asset.h>
#include <utils/ByteOrder.h>
#include <utils/Errors.h>
+#include <utils/PackageRedirectionMap.h>
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -1741,7 +1742,7 @@ public:
bool copyData=false);
status_t add(ResTable* src);
- status_t addRedirections(int package, const char* dataPath);
+ void addRedirections(PackageRedirectionMap* resMap);
void clearRedirections();
status_t getError() const;
@@ -2031,43 +2032,10 @@ private:
// package array.
uint8_t mPackageMap[256];
- // Represents the resource lookup table for a specific package.
- class PackageResMap {
- public:
- ~PackageResMap();
-
- int package;
-
- // Do the heavy lifting to read from a specific package resource map
- // file.
- static PackageResMap* createFromCache(int package, const char* cachePath);
-
- // Returns 0 if the lookup finds no mapping.
- uint32_t lookup(int type, int entry);
-
- // Inserts a SharedBuffer array into the res map structure.
- void insert(int type, const uint32_t* entries);
-
- private:
- PackageResMap();
-
- bool parseMap(const unsigned char* basePtr,
- const unsigned char* endPtr);
-
- uint32_t* parseMapType(const unsigned char* basePtr,
- const unsigned char* endPtr);
-
- // Sparse array representing all entries, organized into two layers:
- // first by type, then by entry id. The result of each lookup will be
- // a qualified resource ID in the theme package scope. Underneath is a
- // SharedBuffer on both layers which indicates the size.
- uint32_t** mEntriesByType;
- };
-
// Resource redirection mapping provided by the applied theme (if there is
- // any). Resources requested which are found in this map will be
+ // one). Resources requested which are found in this map will be
// automatically redirected to the appropriate themed value.
- Vector<PackageResMap*> mRedirectionMap;
+ Vector<PackageRedirectionMap*> mRedirectionMap;
};
} // namespace android
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index d077fec..2726cf2 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -25,10 +25,10 @@ commonSources:= \
CallStack.cpp \
Debug.cpp \
FileMap.cpp \
- FileLock.cpp \
Flattenable.cpp \
ObbFile.cpp \
Pool.cpp \
+ PackageRedirectionMap.cpp \
RefBase.cpp \
ResourceTypes.cpp \
SharedBuffer.cpp \
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 28dc6c0..4513a06 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -33,7 +33,6 @@
#include <utils/Log.h>
#include <utils/Timers.h>
#include <utils/threads.h>
-#include <utils/FileLock.h>
#include <dirent.h>
#include <sys/stat.h>
@@ -41,8 +40,6 @@
#include <errno.h>
#include <assert.h>
-#define REDIRECT_NOISY(x) //x
-
using namespace android;
/*
@@ -77,7 +74,6 @@ int32_t AssetManager::getGlobalCount()
AssetManager::AssetManager(CacheMode cacheMode)
: mLocale(NULL), mVendor(NULL),
- mThemePackageName(NULL),
mResources(NULL), mConfig(new ResTable_config),
mCacheMode(cacheMode), mCacheValid(false)
{
@@ -97,10 +93,6 @@ AssetManager::~AssetManager(void)
// don't have a String class yet, so make sure we clean up
delete[] mLocale;
delete[] mVendor;
-
- if (mThemePackageName != NULL) {
- delete[] mThemePackageName;
- }
}
bool AssetManager::addAssetPath(const String8& path, void** cookie)
@@ -438,365 +430,6 @@ static SharedBuffer* addToEntriesByTypeBuffer(SharedBuffer* buf, uint32_t from,
return buf;
}
-// TODO: Terrible, terrible I/O error handling here!
-static bool writeRedirections(const char* redirPath, SharedBuffer* entriesByTypeBuf)
-{
- REDIRECT_NOISY(LOGW("writing %s\n", redirPath));
-
- FILE* fp = fopen(redirPath, "w");
- if (!fp) {
- LOGE("fopen(%s,r) failed: %s\n", redirPath, strerror(errno));
- return false;
- }
-
- uint16_t version = 1;
- fwrite(&version, sizeof(version), 1, fp);
-
- uint16_t totalTypes = 0;
- size_t typeSize = (entriesByTypeBuf != NULL) ? entriesByTypeBuf->size() / sizeof(uint32_t*) : 0;
- uint32_t** entriesByType = (uint32_t**)entriesByTypeBuf->data();
- for (size_t i=0; i<typeSize; i++) {
- uint32_t* entries = entriesByType[i];
- if (entries != NULL) {
- totalTypes++;
- }
- }
-
- REDIRECT_NOISY(LOGW("writing %d total types\n", (int)totalTypes));
- fwrite(&totalTypes, sizeof(totalTypes), 1, fp);
-
- // Start offset for the first type table.
- uint32_t typeSectionOffset = 4 + (9 * totalTypes);
-
- for (size_t i=0; i<typeSize; i++) {
- uint32_t* entries = entriesByType[i];
- if (entries != NULL) {
- uint8_t type = i;
- fwrite(&type, sizeof(type), 1, fp);
- size_t entrySize = SharedBuffer::bufferFromData(entries)->size() / sizeof(uint32_t);
- size_t numEntries = 0;
- for (size_t j=0; j<entrySize; j++) {
- if (entries[j] != 0) {
- numEntries++;
- }
- }
- REDIRECT_NOISY(LOGW("%d entries for type %d\n", (int)numEntries, (int)type));
- fwrite(&typeSectionOffset, sizeof(typeSectionOffset), 1, fp);
- uint32_t typeSectionLength = numEntries * 6;
- fwrite(&typeSectionLength, sizeof(typeSectionLength), 1, fp);
- typeSectionOffset += typeSectionLength;
- }
- }
-
- for (size_t i=0; i<typeSize; i++) {
- uint32_t* entries = entriesByType[i];
- if (entries != NULL) {
- REDIRECT_NOISY(LOGW("writing for type %d...\n", i));
- size_t entrySize = SharedBuffer::bufferFromData(entries)->size() / sizeof(uint32_t);
- for (size_t j=0; j<entrySize; j++) {
- uint32_t resID = entries[j];
- if (resID != 0) {
- uint16_t entryIndex = j;
- REDIRECT_NOISY(LOGW("writing 0x%04x => 0x%08x\n", entryIndex, resID));
- fwrite(&entryIndex, sizeof(entryIndex), 1, fp);
- fwrite(&resID, sizeof(resID), 1, fp);
- }
- }
- SharedBuffer::bufferFromData(entries)->release();
- }
- }
-
- if (entriesByTypeBuf != NULL) {
- entriesByTypeBuf->release();
- }
-
- fclose(fp);
-
- REDIRECT_NOISY(LOGW("written...\n"));
-
- return true;
-}
-
-// Crude, lame brute force way to generate the initial framework redirections
-// for testing. This code should be generalized and follow a much better OO
-// structure.
-static SharedBuffer* generateFrameworkRedirections(SharedBuffer* entriesByTypeBuf, ResTable* rt,
- const char* themePackageName, uint32_t styleId, const char* redirPath)
-{
- REDIRECT_NOISY(LOGW("generateFrameworkRedirections: themePackageName=%s, styleId=0x%08x\n", themePackageName, styleId));
-
- rt->lock();
-
- // Load up a bag for the user-supplied theme.
- const ResTable::bag_entry* themeEnt = NULL;
- ssize_t N = rt->getBagLocked(styleId, &themeEnt);
- const ResTable::bag_entry* endThemeEnt = themeEnt + (N >= 0 ? N : 0);
-
- // ...and a bag for the framework default.
- const ResTable::bag_entry* frameworkEnt = NULL;
- N = rt->getBagLocked(0x01030005, &frameworkEnt);
- const ResTable::bag_entry* endFrameworkEnt = frameworkEnt + (N >= 0 ? N : 0);
-
- // The first entry should be for the theme itself.
- entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf, 0x01030005, styleId);
-
- // Now compare them and infer resource redirections for attributes that
- // remap to different styles. This works by essentially lining up all the
- // sorted attributes from each theme and detected TYPE_REFERENCE entries
- // that point to different resources. When we find such a mismatch, we'll
- // create a resource redirection from the original framework resource ID to
- // the one in the theme. This lets us do things like automatically find
- // redirections for @android:style/Widget.Button by looking at how the
- // theme overrides the android:attr/buttonStyle attribute.
- REDIRECT_NOISY(LOGW("delta between 0x01030005 and 0x%08x:\n", styleId));
- for (; frameworkEnt < endFrameworkEnt; frameworkEnt++) {
- if (frameworkEnt->map.value.dataType != Res_value::TYPE_REFERENCE) {
- continue;
- }
-
- uint32_t curIdent = frameworkEnt->map.name.ident;
-
- // Walk along the theme entry looking for a match.
- while (themeEnt < endThemeEnt && curIdent > themeEnt->map.name.ident) {
- themeEnt++;
- }
- // Match found, compare the references.
- if (themeEnt < endThemeEnt && curIdent == themeEnt->map.name.ident) {
- if (themeEnt->map.value.data != frameworkEnt->map.value.data) {
- entriesByTypeBuf = addToEntriesByTypeBuffer(entriesByTypeBuf,
- frameworkEnt->map.value.data, themeEnt->map.value.data);
- REDIRECT_NOISY(LOGW(" generated mapping from 0x%08x => 0x%08x (by attr 0x%08x)\n", frameworkEnt->map.value.data,
- themeEnt->map.value.data, curIdent));
- }
- themeEnt++;
- }
-
- // Exhausted the theme, bail early.
- if (themeEnt >= endThemeEnt) {
- break;
- }
- }
-
- rt->unlock();
-
- return entriesByTypeBuf;
-}
-
-static SharedBuffer* parseRedirections(SharedBuffer* buf, ResTable* rt,
- ResXMLTree& xml, String16& themePackage, String16& resPackage)
-{
- ResXMLTree::event_code_t eventType = xml.getEventType();
- REDIRECT_NOISY(LOGW("initial eventType=%d\n", (int)eventType));
- size_t len;
- while (eventType != ResXMLTree::END_DOCUMENT) {
- if (eventType == ResXMLTree::START_TAG) {
- String8 outerTag(xml.getElementName(&len));
- if (outerTag == "resource-redirections") {
- REDIRECT_NOISY(LOGW("got resource-redirections tag\n"));
- xml.next();
- while ((eventType = xml.getEventType()) != ResXMLTree::END_TAG) {
- if (eventType == ResXMLTree::START_TAG) {
- String8 itemTag(xml.getElementName(&len));
- if (itemTag == "item") {
- REDIRECT_NOISY(LOGW("got item tag\n"));
- ssize_t nameIdx = xml.indexOfAttribute(NULL, "name");
- size_t fromLen;
- const char16_t* fromName = NULL;
- size_t toLen;
- const char16_t* toName = NULL;
- if (nameIdx >= 0) {
- fromName = xml.getAttributeStringValue(nameIdx, &fromLen);
- REDIRECT_NOISY(LOGW(" got from %s\n", String8(fromName).string()));
- }
- if (xml.next() == ResXMLTree::TEXT) {
- toName = xml.getText(&toLen);
- REDIRECT_NOISY(LOGW(" got to %s\n", String8(toName).string()));
- xml.next();
- }
- if (toName != NULL && fromName != NULL) {
- // fromName should look "drawable/foo", so we'll
- // let identifierForName parse that part of it, but
- // make sure to provide the background ourselves.
- // TODO: we should check that the package isn't
- // already in the string and error out if it is...
- uint32_t fromIdent = rt->identifierForName(fromName, fromLen, NULL, 0,
- resPackage.string(), resPackage.size());
- if (fromIdent == 0) {
- LOGW("Failed to locate identifier for resource %s:%s\n",
- String8(fromName, fromLen).string(), String8(resPackage).string());
- } else {
- uint32_t toIdent = rt->identifierForName(toName, toLen, NULL, 0,
- themePackage.string(), themePackage.size());
- if (toIdent == 0) {
- LOGW("Failed to locate identifier for resource %s:%s\n",
- String8(toName, toLen).string(), String8(themePackage).string());
- } else {
- REDIRECT_NOISY(LOGW("adding fromIdent=0x%08x to toIdent=0x%08x\n", fromIdent, toIdent));
- buf = addToEntriesByTypeBuffer(buf, fromIdent, toIdent);
- }
- }
- }
- } else {
- REDIRECT_NOISY(LOGW("unexpected tag %s\n", itemTag.string()));
- }
- } else if (eventType == ResXMLTree::END_DOCUMENT) {
- return buf;
- }
- xml.next();
- }
- }
- }
-
- eventType = xml.next();
- }
-
- return buf;
-}
-
-// Generate redirections from XML meta data. This code should be moved into
-// the Java space at some point, generated by a special service.
-SharedBuffer* AssetManager::generateRedirections(SharedBuffer* entriesByTypeBuf,
- ResTable* rt, const char* themePackageName,
- const char16_t* resPackageName)
-{
- REDIRECT_NOISY(LOGW("generateRedirections: themePackageName=%s; resPackageName=%s\n",
- themePackageName, String8(resPackageName).string()));
-
- String16 type("xml");
- String16 name(resPackageName);
- name.replaceAll('.', '_');
- String16 package(themePackageName);
- uint32_t xmlIdent = rt->identifierForName(name.string(), name.size(), type.string(), type.size(),
- package.string(), package.size());
- REDIRECT_NOISY(LOGW("xmlIdent=0x%08x from %s:%s/%s\n", xmlIdent,
- String8(package).string(), String8(type).string(), String8(name).string()));
- if (xmlIdent != 0) {
- // All this junk is being simulated from the Java side implementation.
- // This is very clumsy and poorly thought through/tested. This code
- // will eventually be merged into the Java layer.
- Res_value value;
- ssize_t block = rt->getResource(xmlIdent, &value);
- block = rt->resolveReference(&value, block, &xmlIdent);
- if (block < 0 || value.dataType != Res_value::TYPE_STRING) {
- LOGE("Bad redirection XML resource #0x%08x\n", xmlIdent);
- } else {
- size_t len;
- const char16_t* str = rt->valueToString(&value, block, NULL, &len);
- void* cookie = rt->getTableCookie(block);
- const size_t whichAssetPath = ((size_t)cookie)-1;
- Asset* asset = openNonAssetInPathLocked(
- String8(str).string(), Asset::ACCESS_BUFFER,
- mAssetPaths.itemAt(whichAssetPath));
- if (asset == NULL || asset == kExcludedAsset) {
- LOGE("XML resource %s not found in package\n", String8(str).string());
- } else {
- ResXMLTree xml;
- status_t err = xml.setTo(asset->getBuffer(true), asset->getLength());
-
- xml.restart();
-
- String16 resPackage(resPackageName);
- entriesByTypeBuf = parseRedirections(entriesByTypeBuf, rt, xml,
- package, resPackage);
-
- xml.uninit();
-
- asset->close();
- delete asset;
- }
- }
- }
-
- return entriesByTypeBuf;
-}
-
-bool AssetManager::generateAndWriteRedirections(ResTable* rt,
- const char* themePackageName, uint32_t themeStyleId,
- const char16_t* resPackageName, const char* redirPath,
- bool isFramework) const
-{
- // FIXME: the const is a lie!!!
- AssetManager* am = (AssetManager*)this;
-
- SharedBuffer* buf = NULL;
- if (isFramework && themeStyleId != 0) {
- // Special framework theme heuristic...
- buf = generateFrameworkRedirections(buf, rt, themePackageName,
- themeStyleId, redirPath);
- }
- // Generate redirections from the package XML.
- buf = am->generateRedirections(buf, rt, themePackageName, resPackageName);
-
- return writeRedirections(redirPath, buf);
-}
-
-void AssetManager::loadRedirectionMappings(ResTable* rt) const
-{
- rt->clearRedirections();
-
- if (mThemePackageName != NULL) {
- const char* data = getenv("ANDROID_DATA");
- LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set");
-
- // Create the basic directory structure on demand.
- struct stat statbuf;
- String8 basePath(data);
- basePath.appendPath(kThemeResCacheDir);
- createDirIfNecessary(basePath.string(), 0777, &statbuf);
- basePath.appendPath(mThemePackageName);
- createDirIfNecessary(basePath.string(), 0777, &statbuf);
-
- String8 themeDirLockPath(basePath);
- themeDirLockPath.append(".lck");
-
- FileLock* themeDirLock = new FileLock(themeDirLockPath.string());
- themeDirLock->lock();
-
- // Load (generating if necessary) the cache files for each installed
- // package in this ResTable, excluding the framework's "android"
- // package.
- bool hasFramework = false;
- const size_t N = rt->getBasePackageCount();
- for (size_t i=0; i<N; i++) {
- uint32_t packageId = rt->getBasePackageId(i);
-
- // No need to regenerate the 0x01 framework resources.
- if (packageId == 0x7f) {
- String8 redirPath(basePath);
- const char16_t* resPackageName = rt->getBasePackageName(i);
- redirPath.appendPath(String8(resPackageName));
-
- if (lstat(redirPath.string(), &statbuf) != 0) {
- generateAndWriteRedirections(rt, mThemePackageName,
- mThemeStyleId, resPackageName, redirPath.string(),
- false);
- }
-
- rt->addRedirections(packageId, redirPath.string());
- } else if (packageId == 0x01) {
- hasFramework = true;
- }
- }
-
- // Handle the "android" package space as a special case using some
- // fancy heuristics.
- if (hasFramework) {
- String8 frameworkRedirPath(basePath);
- frameworkRedirPath.appendPath("android");
-
- if (lstat(frameworkRedirPath.string(), &statbuf) != 0) {
- generateAndWriteRedirections(rt, mThemePackageName,
- mThemeStyleId, String16("android").string(),
- frameworkRedirPath.string(), true);
- }
-
- rt->addRedirections(0x01, frameworkRedirPath.string());
- }
-
- themeDirLock->unlock();
- }
-}
-
const ResTable* AssetManager::getResTable(bool required) const
{
ResTable* rt = mResources;
@@ -827,7 +460,6 @@ const ResTable* AssetManager::getResTable(bool required) const
const asset_path& ap = mAssetPaths.itemAt(i);
updateResTableFromAssetPath(rt, ap, (void*)(i+1));
}
- loadRedirectionMappings(rt);
}
if (required && !rt) LOGW("Unable to find resources file resources.arsc");
@@ -2195,28 +1827,6 @@ int AssetManager::ZipSet::getIndex(const String8& zip) const
return mZipPath.size()-1;
}
-/*
- * Set the currently applied theme package name and the high-level theme style
- * identifier (the one to replace @android:style/Theme). May be set to NULL, 0
- * to indicate that this AssetManager does not have an added theme package.
- *
- * This information is used when constructing the ResTable's resource
- * redirection map.
- */
-void AssetManager::setThemePackageInfo(const char* packageName, uint32_t styleId)
-{
- if (mThemePackageName != NULL) {
- delete[] mThemePackageName;
- }
- mThemePackageName = strdupNew(packageName);
- mThemeStyleId = styleId;
-}
-
-const char* AssetManager::getThemePackageName()
-{
- return mThemePackageName;
-}
-
bool AssetManager::updateWithAssetPath(const String8& path, void** cookie)
{
bool res = addAssetPath(path, cookie);
@@ -2225,7 +1835,6 @@ bool AssetManager::updateWithAssetPath(const String8& path, void** cookie)
AutoMutex _l(mLock);
const asset_path& ap = mAssetPaths.itemAt((size_t)*cookie - 1);
updateResTableFromAssetPath(rt, ap, *cookie);
- loadRedirectionMappings(rt);
}
return res;
}
@@ -2240,7 +1849,6 @@ bool AssetManager::removeAssetPath(const String8 &packageName, void* cookie)
return false;
}
- rt->clearRedirections();
rt->removeAssetsByCookie(packageName, (void *)cookie);
return true;
@@ -2255,3 +1863,17 @@ void AssetManager::dumpRes()
}
rt->dump();
}
+
+void AssetManager::addRedirections(PackageRedirectionMap* resMap)
+{
+ getResources();
+ ResTable* rt = mResources;
+ rt->addRedirections(resMap);
+}
+
+void AssetManager::clearRedirections()
+{
+ getResources();
+ ResTable* rt = mResources;
+ rt->clearRedirections();
+}
diff --git a/libs/utils/FileLock.cpp b/libs/utils/FileLock.cpp
deleted file mode 100644
index a25a0e6..0000000
--- a/libs/utils/FileLock.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2010, T-Mobile USA, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//
-// File locking utility
-//
-
-#define LOG_TAG "filelock"
-
-#include <utils/FileLock.h>
-#include <utils/Log.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/file.h>
-#include <errno.h>
-#include <assert.h>
-
-using namespace android;
-
-/*
- * Constructor. Create an unlocked object.
- */
-FileLock::FileLock(const char* fileName)
- : mRefCount(0), mFd(-1), mFileName(strdup(fileName))
-{
- assert(mFileName != NULL);
-}
-
-static struct flock fullfileLock(short lockType)
-{
- struct flock lock;
- memset(&lock, 0, sizeof(lock));
-
- lock.l_type = lockType;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
-
- return lock;
-}
-
-/*
- * Destructor.
- */
-FileLock::~FileLock(void)
-{
- assert(mRefCount == 0);
-
- if (mFd >= 0) {
- struct flock lock(fullfileLock(F_UNLCK));
- if (fcntl(mFd, F_SETLK, &lock) == -1) {
- LOGE("error releasing write lock on %s: %s\n", mFileName, strerror(errno));
- }
- if (close(mFd) != 0) {
- LOGE("close(%s) failed: %s\n", mFileName, strerror(errno));
- }
- }
- if (mFileName != NULL) {
- free(mFileName);
- }
-}
-
-bool FileLock::doLock(int openFlags, mode_t fileCreateMode)
-{
- int fd = open(mFileName, openFlags | O_CREAT, fileCreateMode);
- if (fd == -1) {
- return false;
- }
-
- struct flock lock(fullfileLock(F_WRLCK));
- while (fcntl(fd, F_SETLKW, &lock) == -1) {
- if (errno != EINTR) {
- LOGE("error acquiring write lock on %s: %s\n", mFileName, strerror(errno));
- close(fd);
- return false;
- }
- }
-
- mFd = fd;
- return true;
-}
diff --git a/libs/utils/PackageRedirectionMap.cpp b/libs/utils/PackageRedirectionMap.cpp
new file mode 100644
index 0000000..bf1062a
--- /dev/null
+++ b/libs/utils/PackageRedirectionMap.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ * This code has been modified. Portions copyright (C) 2010, T-Mobile USA, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// Provide access to read-only assets.
+//
+
+#define LOG_TAG "packageresmap"
+
+#include <utils/PackageRedirectionMap.h>
+#include <utils/ResourceTypes.h>
+#include <utils/misc.h>
+
+using namespace android;
+
+PackageRedirectionMap::PackageRedirectionMap()
+ : mPackage(-1), mEntriesByType(NULL)
+{
+}
+
+static void clearEntriesByType(uint32_t** entriesByType)
+{
+ SharedBuffer* buf = SharedBuffer::bufferFromData(entriesByType);
+ const size_t N = buf->size() / sizeof(entriesByType[0]);
+ for (size_t i = 0; i < N; i++) {
+ uint32_t* entries = entriesByType[i];
+ if (entries != NULL) {
+ SharedBuffer::bufferFromData(entries)->release();
+ }
+ }
+ buf->release();
+}
+
+PackageRedirectionMap::~PackageRedirectionMap()
+{
+ if (mEntriesByType != NULL) {
+ clearEntriesByType(mEntriesByType);
+ }
+}
+
+static void* ensureCapacity(void* data, size_t nmemb, size_t size)
+{
+ SharedBuffer* buf;
+ size_t currentSize;
+
+ if (data != NULL) {
+ buf = SharedBuffer::bufferFromData(data);
+ currentSize = buf->size();
+ } else {
+ buf = NULL;
+ currentSize = 0;
+ }
+
+ size_t minSize = nmemb * size;
+ if (minSize > currentSize) {
+ unsigned int requestSize = roundUpPower2(minSize);
+ if (buf == NULL) {
+ buf = SharedBuffer::alloc(requestSize);
+ } else {
+ buf = buf->editResize(requestSize);
+ }
+ memset((unsigned char*)buf->data()+currentSize, 0, requestSize - currentSize);
+ }
+
+ return buf->data();
+}
+
+bool PackageRedirectionMap::addRedirection(uint32_t fromIdent, uint32_t toIdent)
+{
+ const int package = Res_GETPACKAGE(fromIdent);
+ const int type = Res_GETTYPE(fromIdent);
+ const int entry = Res_GETENTRY(fromIdent);
+
+ // The first time we add a redirection we can infer the package for all
+ // future redirections.
+ if (mPackage == -1) {
+ mPackage = package+1;
+ } else if (mPackage != (package+1)) {
+ LOGW("cannot add redirection for conflicting package 0x%02x (expecting package 0x%02x)\n", package+1, mPackage);
+ return false;
+ }
+
+ mEntriesByType = (uint32_t**)ensureCapacity(mEntriesByType, type + 1, sizeof(uint32_t*));
+ uint32_t* entries = mEntriesByType[type];
+ entries = (uint32_t*)ensureCapacity(entries, entry + 1, sizeof(uint32_t));
+ entries[entry] = toIdent;
+ mEntriesByType[type] = entries;
+
+ return true;
+}
+
+uint32_t PackageRedirectionMap::lookupRedirection(uint32_t fromIdent)
+{
+ if (mPackage == -1 || mEntriesByType == NULL || fromIdent == 0) {
+ return 0;
+ }
+
+ const int package = Res_GETPACKAGE(fromIdent);
+ const int type = Res_GETTYPE(fromIdent);
+ const int entry = Res_GETENTRY(fromIdent);
+
+ if (package+1 != mPackage) {
+ return 0;
+ }
+
+ size_t nTypes = getNumberOfTypes();
+ if (type < 0 || type >= nTypes) {
+ return 0;
+ }
+ uint32_t* entries = mEntriesByType[type];
+ if (entries == NULL) {
+ return 0;
+ }
+ size_t nEntries = getNumberOfEntries(type);
+ if (entry < 0 || entry >= nEntries) {
+ return 0;
+ }
+ return entries[entry];
+}
+
+int PackageRedirectionMap::getPackage()
+{
+ return mPackage;
+}
+
+size_t PackageRedirectionMap::getNumberOfTypes()
+{
+ if (mEntriesByType == NULL) {
+ return 0;
+ } else {
+ return SharedBuffer::bufferFromData(mEntriesByType)->size() /
+ sizeof(mEntriesByType[0]);
+ }
+}
+
+size_t PackageRedirectionMap::getNumberOfUsedTypes()
+{
+ uint32_t** entriesByType = mEntriesByType;
+ size_t N = getNumberOfTypes();
+ size_t count = 0;
+ for (size_t i=0; i<N; i++) {
+ if (entriesByType[i] != NULL) {
+ count++;
+ }
+ }
+ return count;
+}
+
+size_t PackageRedirectionMap::getNumberOfEntries(int type)
+{
+ uint32_t* entries = mEntriesByType[type];
+ if (entries == NULL) {
+ return 0;
+ } else {
+ return SharedBuffer::bufferFromData(entries)->size() /
+ sizeof(entries[0]);
+ }
+}
+
+size_t PackageRedirectionMap::getNumberOfUsedEntries(int type)
+{
+ size_t N = getNumberOfEntries(type);
+ uint32_t* entries = mEntriesByType[type];
+ size_t count = 0;
+ for (size_t i=0; i<N; i++) {
+ if (entries[i] != 0) {
+ count++;
+ }
+ }
+ return count;
+}
+
+uint32_t PackageRedirectionMap::getEntry(int type, int entry)
+{
+ uint32_t* entries = mEntriesByType[type];
+ return entries[entry];
+}
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index f7bee02..d9e5012 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -2057,14 +2057,12 @@ uint32_t ResTable::lookupRedirectionMap(uint32_t resID) const
}
const int p = Res_GETPACKAGE(resID)+1;
- const int t = Res_GETTYPE(resID)+1;
- const int e = Res_GETENTRY(resID);
const size_t N = mRedirectionMap.size();
for (size_t i=0; i<N; i++) {
- PackageResMap* resMap = mRedirectionMap[i];
- if (resMap->package == p) {
- return resMap->lookup(t, e);
+ PackageRedirectionMap* resMap = mRedirectionMap[i];
+ if (resMap->getPackage() == p) {
+ return resMap->lookupRedirection(resID);
}
}
return 0;
@@ -4096,127 +4094,6 @@ void ResTable::removeAssetsByCookie(const String8 &packageName, void* cookie)
}
}
-ResTable::PackageResMap::PackageResMap()
- : mEntriesByType(NULL)
-{
-}
-
-ResTable::PackageResMap::~PackageResMap()
-{
- if (mEntriesByType != NULL) {
- SharedBuffer* buf = SharedBuffer::bufferFromData(mEntriesByType);
- const size_t N = buf->size() / sizeof(mEntriesByType[0]);
- for (size_t i = 0; i < N; i++) {
- uint32_t* entries = mEntriesByType[i];
- if (entries != NULL) {
- SharedBuffer::bufferFromData(entries)->release();
- }
- }
- buf->release();
- }
-}
-
-uint32_t* ResTable::PackageResMap::parseMapType(const unsigned char* ptr, const unsigned char* end)
-{
- SharedBuffer* buf = NULL;
- for (; ptr + 6 <= end; ptr += 6) {
- uint16_t entry = *(uint16_t*)ptr;
- uint32_t resID = *(uint32_t*)(ptr + 2);
- REDIRECT_NOISY(LOGW("map type got entry=0x%04x, resID=0x%08x\n", entry, resID));
- size_t currentSize = (buf != NULL) ? buf->size() : 0;
- size_t entrySize = (entry+1) * sizeof(resID);
- if (entrySize > currentSize) {
- unsigned int requestSize = roundUpPower2(entrySize);
- REDIRECT_NOISY(LOGW("allocating buffer (%p) at requestSize=%d\n", buf, (int)requestSize));
- if (buf == NULL) {
- buf = SharedBuffer::alloc(requestSize);
- } else {
- buf = buf->editResize(requestSize);
- }
- memset((unsigned char*)buf->data()+currentSize, 0, requestSize - currentSize);
- REDIRECT_NOISY(LOGW("allocated buf=%p\n", buf));
- }
- uint32_t* entries = (uint32_t*)buf->data();
- entries[entry] = resID;
- }
- return (buf != NULL) ? (uint32_t*)buf->data() : NULL;
-}
-
-/*
- * Parse the resource mappings file.
- *
- * The format of this file begins with a simple header identifying the number
- * of types inside, followed by a table mapping each type to an offset further
- * in the file. At each offset mentioned is a set of resource ID mappings to
- * be parsed out and applied to a sparse array that is ultimately used to
- * lookup resource redirections (the indices are entries in the associated
- * package space and the values are the replacement resID's from the theme
- * itself)
- *
- * Detailed information of each section:
- *
- * | bytes | description
- * |-------+-----------------------
- * | 2 | file format version (first version is 1)
- * | 2 | number of resource types (think Res_GETTYPE) in the mapping
- *
- * For each resource type:
- *
- * +-------+-----------------------
- * | 1 | type identifier
- * | 4 | file offset containing the entry mapping
- * | 4 | length of the entry mapping section for this type
- * ...
- *
- * At each file offset mentioned in the type header:
- *
- * +-------+-----------------------
- * | 2 | entry id to be replaced (combined with the type and package this
- * | | forms a resID)
- * | 4 | resID in the theme space which is to replace the previous entry
- * ...
- */
-bool ResTable::PackageResMap::parseMap(const unsigned char* basePtr,
- const unsigned char* endPtr)
-{
- LOG_FATAL_IF(mEntriesByType != NULL, "parseMap must only be called once");
-
- if (basePtr + 4 > endPtr) {
- return false;
- }
- uint16_t version = *(uint16_t*)basePtr;
- uint16_t numTypes = *(uint16_t*)(basePtr + 2);
- const unsigned char* headerPtr = basePtr + 4;
-
- REDIRECT_NOISY(LOGW("file version=%d\n", version));
- REDIRECT_NOISY(LOGW("read %d numTypes\n", numTypes));
-
- while (numTypes-- > 0) {
- uint8_t type;
- uint32_t* entries = NULL;
- if (headerPtr + 9 < endPtr) {
- type = *(uint8_t*)headerPtr;
- uint32_t offset = *(uint32_t*)(headerPtr + 1);
- uint32_t length = *(uint32_t*)(headerPtr + 5);
- headerPtr += 9;
- REDIRECT_NOISY(LOGW("got type=0x%02x\n", type));
- if (basePtr + offset + length <= endPtr) {
- REDIRECT_NOISY(LOGW("parsing type...\n"));
- const unsigned char* entryStartPtr = basePtr + offset;
- const unsigned char* entryEndPtr = entryStartPtr + length;
- entries = parseMapType(entryStartPtr, entryEndPtr);
- }
- }
- if (entries == NULL) {
- return false;
- }
- REDIRECT_NOISY(LOGW("inserting type 0x%02x with %p\n", type, entries));
- insert(type, entries);
- }
-
- return true;
-}
-
/*
* Load the redirection map from the supplied map path.
*
@@ -4226,130 +4103,18 @@ bool ResTable::PackageResMap::parseMap(const unsigned char* basePtr,
* For this reason, this method should be called only after all resource
* bundles have been added to the table.
*/
-status_t ResTable::addRedirections(int package, const char* cachePath)
+void ResTable::addRedirections(PackageRedirectionMap* resMap)
{
- LOGV("Adding redirections for package 0x%02x at %s\n", package, cachePath);
-
- if (package != 0x01 && package != 0x7f) {
- REDIRECT_NOISY(LOGW("invalid package 0x%02x: should be either 0x01 (android) or 0x7f (application)\n", package));
- return BAD_TYPE;
- }
-
- ResTable::PackageResMap* resMap = ResTable::PackageResMap::createFromCache(package, cachePath);
- if (resMap != NULL) {
- REDIRECT_NOISY(LOGW("loaded cache stuff for cachePath=%s (package=%d)\n", cachePath, package));
- mRedirectionMap.add(resMap);
- return NO_ERROR;
- } else {
- REDIRECT_NOISY(LOGW("failed to parse redirection path at %s\n", cachePath));
- return BAD_TYPE;
- }
+ // TODO: Replace an existing entry matching the same package.
+ mRedirectionMap.add(resMap);
}
void ResTable::clearRedirections()
{
- const size_t N = mRedirectionMap.size();
- for (size_t i=0; i<N; i++) {
- PackageResMap* resMap = mRedirectionMap[i];
- delete resMap;
- }
+ /* This memory is being managed by strong references at the Java layer. */
mRedirectionMap.clear();
}
-ResTable::PackageResMap* ResTable::PackageResMap::createFromCache(int package, const char* cachePath)
-{
- FILE* cacheFile = fopen(cachePath, "r");
- if (cacheFile == NULL) {
- REDIRECT_NOISY(LOGW("unable to open resource mapping path %s: %s\n", cachePath, strerror(errno)));
- return NULL;
- }
-
- if (fseek(cacheFile, 0, SEEK_END) != 0) {
- fclose(cacheFile);
- return NULL;
- }
-
- long length = ftell(cacheFile);
- REDIRECT_NOISY(LOGW("file length is %d\n", (int)length));
- if (length < 4) {
- fclose(cacheFile);
- return NULL;
- }
-
- ResTable::PackageResMap* resMap = NULL;
- FileMap* fileMap = new FileMap;
- if (fileMap != NULL) {
- if (fileMap->create(cachePath, fileno(cacheFile), 0, length, true)) {
- REDIRECT_NOISY(LOGW("successfully mapped %s\n", cachePath));
- resMap = new ResTable::PackageResMap();
- if (resMap != NULL) {
- resMap->package = package;
- const unsigned char* ptr = (const unsigned char*)fileMap->getDataPtr();
- if (!resMap->parseMap(ptr, ptr + length)) {
- REDIRECT_NOISY(LOGW("failed to parse map!\n"));
- delete resMap;
- resMap = NULL;
- }
- }
- } else {
- REDIRECT_NOISY(LOGW("unable to map '%s': %s\n", cachePath, strerror(errno)));
- }
-
- fileMap->release();
- }
-
- fclose(cacheFile);
-
- return resMap;
-}
-
-uint32_t ResTable::PackageResMap::lookup(int type, int entry)
-{
- if (mEntriesByType == NULL) {
- return 0;
- }
- size_t maxTypes = SharedBuffer::bufferFromData(mEntriesByType)->size() /
- sizeof(mEntriesByType[0]);
- if (type < 0 || type >= maxTypes) {
- return 0;
- }
- uint32_t* entries = mEntriesByType[type];
- if (entries == NULL) {
- return 0;
- }
- size_t maxEntries = SharedBuffer::bufferFromData(entries)->size() /
- sizeof(entries[0]);
- if (entry < 0 || entry >= maxEntries) {
- return 0;
- }
- return entries[entry];
-}
-
-void ResTable::PackageResMap::insert(int type, const uint32_t* entries)
-{
- SharedBuffer* buf = NULL;
- size_t currentSize = 0;
- if (mEntriesByType != NULL) {
- buf = SharedBuffer::bufferFromData(mEntriesByType);
- currentSize = buf->size();
- }
- size_t typeSize = (type+1) * sizeof(uint32_t*);
- if (typeSize > currentSize) {
- unsigned int requestSize = roundUpPower2(typeSize);
- REDIRECT_NOISY(LOGW("allocating new type buffer (%p) at size requestSize=%d\n", buf, requestSize));
- if (buf == NULL) {
- buf = SharedBuffer::alloc(requestSize);
- } else {
- buf = buf->editResize(requestSize);
- }
- memset((unsigned char*)buf->data()+currentSize, 0, requestSize - currentSize);
- REDIRECT_NOISY(LOGW("allocated new type buffer %p\n", buf));
- }
- uint32_t** entriesByType = (uint32_t**)buf->data();
- entriesByType[type] = (uint32_t*)entries;
- mEntriesByType = entriesByType;
-}
-
#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
#ifndef HAVE_ANDROID_OS
diff --git a/services/java/com/android/server/AssetRedirectionManagerService.java b/services/java/com/android/server/AssetRedirectionManagerService.java
new file mode 100644
index 0000000..820c45c
--- /dev/null
+++ b/services/java/com/android/server/AssetRedirectionManagerService.java
@@ -0,0 +1,376 @@
+package com.android.server;
+
+import com.android.internal.app.IAssetRedirectionManager;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ThemeInfo;
+import android.content.res.AssetManager;
+import android.content.res.PackageRedirectionMap;
+import android.content.res.Resources;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public class AssetRedirectionManagerService extends IAssetRedirectionManager.Stub {
+ private static final String TAG = "AssetRedirectionManager";
+
+ private final Context mContext;
+
+ /*
+ * TODO: This data structure should have some way to expire very old cache
+ * entries. Would be nice to optimize for the removal path as well.
+ */
+ private final HashMap<RedirectionKey, PackageRedirectionMap> mRedirections =
+ new HashMap<RedirectionKey, PackageRedirectionMap>();
+
+ public AssetRedirectionManagerService(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void clearRedirectionMapsByTheme(String themePackageName, String themeId)
+ throws RemoteException {
+ synchronized (mRedirections) {
+ Set<RedirectionKey> keys = mRedirections.keySet();
+ Iterator<RedirectionKey> iter = keys.iterator();
+ while (iter.hasNext()) {
+ RedirectionKey key = iter.next();
+ if (themePackageName.equals(key.themePackageName) &&
+ (themeId == null || themeId.equals(key.themeId))) {
+ iter.remove();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void clearPackageRedirectionMap(String targetPackageName) throws RemoteException {
+ synchronized (mRedirections) {
+ Set<RedirectionKey> keys = mRedirections.keySet();
+ Iterator<RedirectionKey> iter = keys.iterator();
+ while (iter.hasNext()) {
+ RedirectionKey key = iter.next();
+ if (targetPackageName.equals(key.targetPackageName)) {
+ iter.remove();
+ }
+ }
+ }
+ }
+
+ @Override
+ public PackageRedirectionMap getPackageRedirectionMap(String themePackageName,
+ String themeId, String targetPackageName) throws RemoteException {
+ synchronized (mRedirections) {
+ RedirectionKey key = new RedirectionKey();
+ key.themePackageName = themePackageName;
+ key.themeId = themeId;
+ key.targetPackageName = targetPackageName;
+
+ PackageRedirectionMap map = mRedirections.get(key);
+ if (map != null) {
+ return map;
+ } else {
+ map = generatePackageRedirectionMap(key);
+ if (map != null) {
+ mRedirections.put(key, map);
+ }
+ return map;
+ }
+ }
+ }
+
+ private PackageRedirectionMap generatePackageRedirectionMap(RedirectionKey key) {
+ AssetManager assets = new AssetManager();
+
+ boolean frameworkAssets = key.targetPackageName.equals("android");
+
+ if (!frameworkAssets) {
+ PackageInfo pi = getPackageInfo(mContext, key.targetPackageName);
+ if (pi == null || pi.applicationInfo == null ||
+ assets.addAssetPath(pi.applicationInfo.publicSourceDir) == 0) {
+ Log.w(TAG, "Unable to attach target package assets for " + key.targetPackageName);
+ return null;
+ }
+ }
+
+ PackageInfo pi = getPackageInfo(mContext, key.themePackageName);
+ if (pi == null || pi.applicationInfo == null || pi.themeInfos == null ||
+ assets.addAssetPath(pi.applicationInfo.publicSourceDir) == 0) {
+ Log.w(TAG, "Unable to attach theme package assets from " + key.themePackageName);
+ return null;
+ }
+
+ PackageRedirectionMap resMap = new PackageRedirectionMap();
+
+ /*
+ * Apply a special redirection hack for the highest level <style>
+ * replacing @android:style/Theme.
+ */
+ if (frameworkAssets) {
+ int themeResourceId = findThemeResourceId(pi.themeInfos, key.themeId);
+ assets.generateStyleRedirections(resMap.getNativePointer(), android.R.style.Theme,
+ themeResourceId);
+ }
+
+ Resources res = new Resources(assets, null, null);
+ generateExplicitRedirections(resMap, res, key.themePackageName, key.targetPackageName);
+
+ return resMap;
+ }
+
+ private void generateExplicitRedirections(PackageRedirectionMap resMap, Resources res,
+ String themePackageName, String targetPackageName) {
+ /*
+ * XXX: We should be parsing the <theme> tag's <meta-data>! Instead,
+ * we're just assuming that res/xml/<package>.xml exists and describes
+ * the redirects we want!
+ */
+ String redirectXmlName = targetPackageName.replace('.', '_');
+ int redirectXmlResId = res.getIdentifier(redirectXmlName, "xml", themePackageName);
+ if (redirectXmlResId == 0) {
+ return;
+ }
+
+ ResourceRedirectionsProcessor processor = new ResourceRedirectionsProcessor(res,
+ redirectXmlResId, themePackageName, targetPackageName, resMap);
+ processor.process();
+ }
+
+ private static PackageInfo getPackageInfo(Context context, String packageName) {
+ try {
+ return context.getPackageManager().getPackageInfo(packageName, 0);
+ } catch (NameNotFoundException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Searches for the high-level theme resource id for the specific
+ * &lt;theme&gt; tag being applied.
+ * <p>
+ * An individual theme package can contain multiple &lt;theme&gt; tags, each
+ * representing a separate theme choice from the user's perspective, even
+ * though the most common case is for there to be only 1.
+ *
+ * @return The style resource id or 0 if no match was found.
+ */
+ private static int findThemeResourceId(ThemeInfo[] themeInfos, String needle) {
+ if (themeInfos != null && !TextUtils.isEmpty(needle)) {
+ int n = themeInfos.length;
+ for (int i = 0; i < n; i++) {
+ ThemeInfo info = themeInfos[i];
+ if (needle.equals(info.themeId)) {
+ return info.styleResourceId;
+ }
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ synchronized (mRedirections) {
+ final ArrayList<RedirectionKey> filteredKeySet = new ArrayList<RedirectionKey>();
+ for (Map.Entry<RedirectionKey, PackageRedirectionMap> entry: mRedirections.entrySet()) {
+ PackageRedirectionMap map = entry.getValue();
+ if (map != null && map.getPackageId() != -1) {
+ filteredKeySet.add(entry.getKey());
+ }
+ }
+ Collections.sort(filteredKeySet, new Comparator<RedirectionKey>() {
+ @Override
+ public int compare(RedirectionKey a, RedirectionKey b) {
+ int comp = a.themePackageName.compareTo(b.themePackageName);
+ if (comp != 0) {
+ return comp;
+ }
+ comp = a.themeId.compareTo(b.themeId);
+ if (comp != 0) {
+ return comp;
+ }
+ return a.targetPackageName.compareTo(b.targetPackageName);
+ }
+ });
+
+ pw.println("Theme asset redirections:");
+ String lastPackageName = null;
+ String lastId = null;
+ for (RedirectionKey key: filteredKeySet) {
+ if (lastPackageName == null || !lastPackageName.equals(key.themePackageName)) {
+ pw.println("* Theme package " + key.themePackageName + ":");
+ lastPackageName = key.themePackageName;
+ }
+ if (lastId == null || !lastId.equals(key.themeId)) {
+ pw.println(" theme id #" + key.themeId + ":");
+ lastId = key.themeId;
+ }
+ pw.println(" " + key.targetPackageName + ":");
+ PackageRedirectionMap resMap = mRedirections.get(key);
+ int[] fromIdents = resMap.getRedirectionKeys();
+ int N = fromIdents.length;
+ for (int i = 0; i < N; i++) {
+ int fromIdent = fromIdents[i];
+ pw.println(String.format(" 0x%08x => 0x%08x", fromIdent,
+ resMap.lookupRedirection(fromIdent)));
+ }
+ }
+ }
+ }
+
+ private static class RedirectionKey {
+ public String themePackageName;
+ public String themeId;
+ public String targetPackageName;
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (!(o instanceof RedirectionKey)) return false;
+ final RedirectionKey oo = (RedirectionKey)o;
+ if (!nullSafeEquals(themePackageName, oo.themePackageName)) {
+ return false;
+ }
+ if (!nullSafeEquals(themeId, oo.themeId)) {
+ return false;
+ }
+ if (!nullSafeEquals(targetPackageName, oo.targetPackageName)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return themePackageName.hashCode() +
+ themeId.hashCode() +
+ targetPackageName.hashCode();
+ }
+
+ private static boolean nullSafeEquals(Object a, Object b) {
+ if (a == null) {
+ return b == a;
+ } else if (b == null) {
+ return false;
+ } else {
+ return a.equals(b);
+ }
+ }
+ }
+
+ /**
+ * Parses and processes explicit redirection XML files.
+ */
+ private static class ResourceRedirectionsProcessor {
+ private final Resources mResources;
+ private final XmlPullParser mParser;
+ private final int mResourceId;
+ private final String mThemePackageName;
+ private final String mTargetPackageName;
+ private final PackageRedirectionMap mResMap;
+
+ public ResourceRedirectionsProcessor(Resources res, int resourceId,
+ String themePackageName, String targetPackageName,
+ PackageRedirectionMap outMap) {
+ mResources = res;
+ mParser = res.getXml(resourceId);
+ mResourceId = resourceId;
+ mThemePackageName = themePackageName;
+ mTargetPackageName = targetPackageName;
+ mResMap = outMap;
+ }
+
+ public void process() {
+ XmlPullParser parser = mParser;
+ int type;
+ try {
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // just loop...
+ }
+
+ String tagName = parser.getName();
+ if (parser.getName().equals("resource-redirections")) {
+ processResourceRedirectionsTag();
+ } else {
+ Log.w(TAG, "Unknown root element: " + tagName + " at " + getResourceLabel() + " " +
+ parser.getPositionDescription());
+ }
+ } catch (XmlPullParserException e) {
+ Log.w(TAG, "Malformed theme redirection meta at " + getResourceLabel());
+ } catch (IOException e) {
+ Log.w(TAG, "Unknown error reading redirection meta at " + getResourceLabel());
+ }
+ }
+
+ private void processResourceRedirectionsTag() throws XmlPullParserException, IOException {
+ XmlPullParser parser = mParser;
+ int type;
+ final int innerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
+ (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ String tagName = parser.getName();
+ if (tagName.equals("item")) {
+ processItemTag();
+ } else {
+ Log.w(TAG, "Unknown element under <resource-redirections>: " + tagName
+ + " at " + getResourceLabel() + " "
+ + parser.getPositionDescription());
+ XmlUtils.skipCurrentTag(parser);
+ continue;
+ }
+ }
+ }
+
+ private void processItemTag() throws XmlPullParserException, IOException {
+ XmlPullParser parser = mParser;
+ String fromName = parser.getAttributeValue(null, "name");
+ if (TextUtils.isEmpty(fromName)) {
+ Log.w(TAG, "Missing android:name attribute on <item> tag at " + getResourceLabel() + " " +
+ parser.getPositionDescription());
+ return;
+ }
+ String toName = parser.nextText();
+ if (TextUtils.isEmpty(toName)) {
+ Log.w(TAG, "Missing <item> text at " + getResourceLabel() + " " +
+ parser.getPositionDescription());
+ return;
+ }
+ int fromIdent = mResources.getIdentifier(fromName, null, mTargetPackageName);
+ if (fromIdent == 0) {
+ Log.w(TAG, "No such resource found for " + mTargetPackageName + ":" + fromName);
+ return;
+ }
+ int toIdent = mResources.getIdentifier(toName, null, mThemePackageName);
+ if (toIdent == 0) {
+ Log.w(TAG, "No such resource found for " + mThemePackageName + ":" + toName);
+ return;
+ }
+ mResMap.addRedirection(fromIdent, toIdent);
+ }
+
+ private String getResourceLabel() {
+ return "resource #0x" + Integer.toHexString(mResourceId);
+ }
+ }
+}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 79c8677..79f96bd 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -17,6 +17,7 @@
package com.android.server;
+import com.android.internal.app.IAssetRedirectionManager;
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
import com.android.internal.content.NativeLibraryHelper;
@@ -103,9 +104,6 @@ import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
-import java.io.RandomAccessFile;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -351,6 +349,8 @@ class PackageManagerService extends IPackageManager.Stub {
final ResolveInfo mResolveInfo = new ResolveInfo();
ComponentName mResolveComponentName;
PackageParser.Package mPlatformPackage;
+
+ IAssetRedirectionManager mAssetRedirectionManager;
// Set of pending broadcasts for aggregating enable/disable of components.
final HashMap<String, ArrayList<String>> mPendingBroadcasts
@@ -3682,16 +3682,38 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ // NOTE: this method can return null if the SystemServer is still
+ // initializing
+ public IAssetRedirectionManager getAssetRedirectionManager() {
+ if (mAssetRedirectionManager != null) {
+ return mAssetRedirectionManager;
+ }
+ IBinder b = ServiceManager.getService("assetredirection");
+ mAssetRedirectionManager = IAssetRedirectionManager.Stub.asInterface(b);
+ return mAssetRedirectionManager;
+ }
+
+ private void cleanAssetRedirections(PackageParser.Package pkg) {
+ IAssetRedirectionManager rm = getAssetRedirectionManager();
+ if (rm == null) {
+ return;
+ }
+ try {
+ if (pkg.mIsThemeApk) {
+ rm.clearRedirectionMapsByTheme(pkg.packageName, null);
+ } else {
+ rm.clearPackageRedirectionMap(pkg.packageName);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+
void removePackageLI(PackageParser.Package pkg, boolean chatty) {
if (chatty && Config.LOGD) Log.d(
TAG, "Removing package " + pkg.applicationInfo.packageName );
synchronized (mPackages) {
- if (pkg.mIsThemeApk) {
- deleteThemeResourceCache(pkg.packageName);
- } else {
- deleteThemeResourceCacheForApp(pkg.packageName);
- }
+ cleanAssetRedirections(pkg);
clearPackagePreferredActivitiesLP(pkg.packageName);
@@ -5848,12 +5870,10 @@ class PackageManagerService extends IPackageManager.Stub {
Log.d(TAG, "New package installed in " + newPackage.mPath);
}
- // DBS -- this changed a lot, hope it works
- if (newPackage.mIsThemeApk) {
- // Even though the package is still around, we'll delete the cache
- // and have it regenerated on demand by the AssetManager.
- deleteThemeResourceCache(newPackage.packageName);
+ cleanAssetRedirections(newPackage);
+ if (newPackage.mIsThemeApk) {
+ /* DBS-TODO
boolean isThemePackageDrmProtected = false;
int N = newPackage.mThemeInfos.size();
for (int i = 0; i < N; i++) {
@@ -5862,13 +5882,10 @@ class PackageManagerService extends IPackageManager.Stub {
break;
}
}
- /* DBS-TODO
if (isThemePackageDrmProtected) {
splitThemePackage(newPackage.mPath);
}
*/
- } else {
- deleteThemeResourceCacheForApp(newPackage.packageName);
}
synchronized (mPackages) {
@@ -5885,71 +5902,6 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
- /*
- * We currently synchronize with consumers of the theme redirections
- * cache by taking a file lock that is shared by that
- * implementation. This should ideally be replaced by centralizing
- * access through a service component that can rely on a simple
- * monitor lock to synchronize properly.
- */
- private FileLock lockThemeResourceDir(String themePackageName) throws IOException {
- RandomAccessFile lockFile = new RandomAccessFile(new File(mThemeResCacheDir,
- themePackageName + ".lck"), "rw");
- return lockFile.getChannel().lock();
- }
-
- private void deleteThemeResourceCache(String packageName) {
- Log.v(TAG, "deleteThemeResourceCache: packageName=" + packageName);
- try {
- FileLock lock = lockThemeResourceDir(packageName);
- try {
- File themeResDir = new File(mThemeResCacheDir, packageName);
- File[] files = themeResDir.listFiles();
- int n = files != null ? files.length : 0;
- Log.v(TAG, n + " files from " + themeResDir);
- for (int i = 0; i < n; i++) {
- File file = files[i];
- if (!file.delete()) {
- throw new IOException("Cannot delete " + file);
- }
- }
- if (themeResDir.exists() && !themeResDir.delete()) {
- throw new IOException("Cannot delete " + themeResDir);
- }
- } finally {
- lock.release();
- }
- } catch (IOException e) {
- Log.w(TAG, "Couldn't delete resource cache for theme package " + packageName +
- ":" + e.getMessage());
- }
- }
-
- private void deleteThemeResourceCacheForApp(String appPackageName) {
- Log.v(TAG, "deleteThemeResourceCacheForApp: appPackageName=" + appPackageName);
-
- // Unfortunately we must loop through all installed themes to make sure
- // we clear this package cache for each. Very lame.
- List<PackageInfo> themes = getInstalledThemePackages();
- for (PackageInfo theme: themes) {
- try {
- FileLock lock = lockThemeResourceDir(theme.packageName);
- try {
- File resCache = new File(new File(mThemeResCacheDir, theme.packageName),
- appPackageName);
- if (resCache.exists() && !resCache.delete()) {
- throw new IOException("Cannot delete " + resCache);
- }
- } finally {
- lock.release();
- }
- } catch (IOException e) {
- Log.w(TAG, "Couldn't delete app resource cache for " + appPackageName +
- " from theme " + theme.packageName);
- }
- }
- }
-
private void deleteLockedZipFileIfExists(String originalPackagePath) {
String lockedZipFilePath = PackageParser.getLockedZipFilePath(originalPackagePath);
File zipFile = new File(lockedZipFilePath);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cfd5311..73587b2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -443,6 +443,13 @@ class ServerThread extends Thread {
} catch (Throwable e) {
Slog.e(TAG, "Failure starting DiskStats Service", e);
}
+
+ try {
+ Slog.i(TAG, "AssetRedirectionManager Service");
+ ServiceManager.addService("assetredirection", new AssetRedirectionManagerService(context));
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting AssetRedirectionManager Service", e);
+ }
}
// make sure the ADB_ENABLED setting value matches the secure property value