diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/app/ActivityThread.java | 6 | ||||
-rw-r--r-- | core/java/android/app/ApplicationPackageManager.java | 2 | ||||
-rw-r--r-- | core/java/android/app/ContextImpl.java | 9 | ||||
-rw-r--r-- | core/java/android/app/LoadedApk.java | 9 | ||||
-rw-r--r-- | core/java/android/app/ResourcesManager.java | 8 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageInfo.java | 10 | ||||
-rw-r--r-- | core/java/android/content/pm/PackageParser.java | 41 | ||||
-rw-r--r-- | core/java/android/content/res/AssetManager.java | 16 | ||||
-rw-r--r-- | core/jni/android_util_AssetManager.cpp | 94 | ||||
-rw-r--r-- | core/res/res/values/attrs_manifest.xml | 10 |
10 files changed, 187 insertions, 18 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 9f21a36..4b86b0c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -1541,11 +1541,11 @@ public final class ActivityThread { /** * Creates the top level resources for the given package. */ - Resources getTopLevelResources(String resDir, + Resources getTopLevelResources(String resDir, String[] overlayDirs, int displayId, Configuration overrideConfiguration, LoadedApk pkgInfo) { - return mResourcesManager.getTopLevelResources(resDir, displayId, overrideConfiguration, - pkgInfo.getCompatibilityInfo(), null); + return mResourcesManager.getTopLevelResources(resDir, overlayDirs, displayId, + overrideConfiguration, pkgInfo.getCompatibilityInfo(), null); } final Handler getHandler() { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index b505d4f..a280448 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -774,7 +774,7 @@ final class ApplicationPackageManager extends PackageManager { } Resources r = mContext.mMainThread.getTopLevelResources( app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir, - Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo); + app.resourceDirs, Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo); if (r != null) { return r; } diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 190ddb4..8d127c6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1911,8 +1911,8 @@ class ContextImpl extends Context { ContextImpl c = new ContextImpl(); c.init(mPackageInfo, null, mMainThread); c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - getDisplayId(), overrideConfiguration, mResources.getCompatibilityInfo(), - mActivityToken); + mPackageInfo.getOverlayDirs(), getDisplayId(), overrideConfiguration, + mResources.getCompatibilityInfo(), mActivityToken); return c; } @@ -1929,7 +1929,7 @@ class ContextImpl extends Context { context.mDisplay = display; DisplayAdjustments daj = getDisplayAdjustments(displayId); context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - displayId, null, daj.getCompatibilityInfo(), null); + mPackageInfo.getOverlayDirs(), displayId, null, daj.getCompatibilityInfo(), null); return context; } @@ -2041,7 +2041,8 @@ class ContextImpl extends Context { mDisplayAdjustments.setCompatibilityInfo(compatInfo); mDisplayAdjustments.setActivityToken(activityToken); mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(), - Display.DEFAULT_DISPLAY, null, compatInfo, activityToken); + mPackageInfo.getOverlayDirs(), Display.DEFAULT_DISPLAY, null, compatInfo, + activityToken); } else { mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo()); mDisplayAdjustments.setActivityToken(activityToken); diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 4239a5d..0115d1b 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -76,6 +76,7 @@ public final class LoadedApk { final String mPackageName; private final String mAppDir; private final String mResDir; + private final String[] mOverlayDirs; private final String[] mSharedLibraries; private final String mDataDir; private final String mLibDir; @@ -120,6 +121,7 @@ public final class LoadedApk { final int myUid = Process.myUid(); mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir; + mOverlayDirs = aInfo.resourceDirs; if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) { aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid), mPackageName); @@ -159,6 +161,7 @@ public final class LoadedApk { mPackageName = name; mAppDir = null; mResDir = null; + mOverlayDirs = null; mSharedLibraries = null; mDataDir = null; mDataDirFile = null; @@ -471,6 +474,10 @@ public final class LoadedApk { return mResDir; } + public String[] getOverlayDirs() { + return mOverlayDirs; + } + public String getDataDir() { return mDataDir; } @@ -485,7 +492,7 @@ public final class LoadedApk { public Resources getResources(ActivityThread mainThread) { if (mResources == null) { - mResources = mainThread.getTopLevelResources(mResDir, + mResources = mainThread.getTopLevelResources(mResDir, mOverlayDirs, Display.DEFAULT_DISPLAY, null, this); } return mResources; diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index f55dba4..728f372 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -147,7 +147,7 @@ public class ResourcesManager { * @param compatInfo the compability info. Must not be null. * @param token the application token for determining stack bounds. */ - public Resources getTopLevelResources(String resDir, int displayId, + public Resources getTopLevelResources(String resDir, String[] overlayDirs, int displayId, Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) { final float scale = compatInfo.applicationScale; ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale, @@ -180,6 +180,12 @@ public class ResourcesManager { return null; } + if (overlayDirs != null) { + for (String idmapPath : overlayDirs) { + assets.addOverlayPath(idmapPath); + } + } + //Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); DisplayMetrics dm = getDisplayMetricsLocked(displayId); Configuration config; diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java index af1a6d5..785f2b4 100644 --- a/core/java/android/content/pm/PackageInfo.java +++ b/core/java/android/content/pm/PackageInfo.java @@ -227,6 +227,14 @@ public class PackageInfo implements Parcelable { /** @hide */ public String requiredAccountType; + /** + * What package, if any, this package will overlay. + * + * Package name of target package, or null. + * @hide + */ + public String overlayTarget; + public PackageInfo() { } @@ -270,6 +278,7 @@ public class PackageInfo implements Parcelable { dest.writeInt(requiredForAllUsers ? 1 : 0); dest.writeString(restrictedAccountType); dest.writeString(requiredAccountType); + dest.writeString(overlayTarget); } public static final Parcelable.Creator<PackageInfo> CREATOR @@ -311,5 +320,6 @@ public class PackageInfo implements Parcelable { requiredForAllUsers = source.readInt() != 0; restrictedAccountType = source.readString(); requiredAccountType = source.readString(); + overlayTarget = source.readString(); } } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 4607902..52564eb 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -307,6 +307,7 @@ public class PackageParser { } pi.restrictedAccountType = p.mRestrictedAccountType; pi.requiredAccountType = p.mRequiredAccountType; + pi.overlayTarget = p.mOverlayTarget; pi.firstInstallTime = firstInstallTime; pi.lastUpdateTime = lastUpdateTime; if ((flags&PackageManager.GET_GIDS) != 0) { @@ -490,6 +491,11 @@ public class PackageParser { public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int flags) { + return parsePackage(sourceFile, destCodePath, metrics, flags, false); + } + + public Package parsePackage(File sourceFile, String destCodePath, + DisplayMetrics metrics, int flags, boolean trustedOverlay) { mParseError = PackageManager.INSTALL_SUCCEEDED; mArchiveSourcePath = sourceFile.getPath(); @@ -542,7 +548,7 @@ public class PackageParser { Exception errorException = null; try { // XXXX todo: need to figure out correct configuration. - pkg = parsePackage(res, parser, flags, errorText); + pkg = parsePackage(res, parser, flags, trustedOverlay, errorText); } catch (Exception e) { errorException = e; mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; @@ -951,8 +957,8 @@ public class PackageParser { } private Package parsePackage( - Resources res, XmlResourceParser parser, int flags, String[] outError) - throws XmlPullParserException, IOException { + Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay, + String[] outError) throws XmlPullParserException, IOException { AttributeSet attrs = parser; mParseInstrumentationArgs = null; @@ -1051,6 +1057,31 @@ public class PackageParser { if (!parseApplication(pkg, res, parser, attrs, flags, outError)) { return null; } + } else if (tagName.equals("overlay")) { + pkg.mTrustedOverlay = trustedOverlay; + + sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestResourceOverlay); + pkg.mOverlayTarget = sa.getString( + com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage); + pkg.mOverlayPriority = sa.getInt( + com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority, + -1); + sa.recycle(); + + if (pkg.mOverlayTarget == null) { + outError[0] = "<overlay> does not specify a target package"; + mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; + return null; + } + if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { + outError[0] = "<overlay> priority must be between 0 and 9999"; + mParseError = + PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; + return null; + } + XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("keys")) { if (!parseKeys(pkg, res, parser, attrs, outError)) { return null; @@ -3546,6 +3577,10 @@ public class PackageParser { */ public ManifestDigest manifestDigest; + public String mOverlayTarget; + public int mOverlayPriority; + public boolean mTrustedOverlay; + /** * Data used to feed the KeySetManager */ diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 780c4be..418bdda 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -90,7 +90,7 @@ public final class AssetManager { mNumRefs = 0; incRefsLocked(this.hashCode()); } - init(); + init(false); if (localLOGV) Log.v(TAG, "New asset manager: " + this); ensureSystemAssets(); } @@ -113,7 +113,7 @@ public final class AssetManager { incRefsLocked(this.hashCode()); } } - init(); + init(true); if (localLOGV) Log.v(TAG, "New asset manager: " + this); } @@ -615,6 +615,16 @@ public final class AssetManager { private native final int addAssetPathNative(String path); + /** + * Add a set of assets to overlay an already added set of assets. + * + * This is only intended for application resources. System wide resources + * are handled before any Java code is executed. + * + * {@hide} + */ + public native final int addOverlayPath(String idmapPath); + /** * Add multiple sets of assets to the asset manager at once. See * {@link #addAssetPath(String)} for more information. Returns array of @@ -752,7 +762,7 @@ public final class AssetManager { private native final int[] getArrayStringInfo(int arrayRes); /*package*/ native final int[] getArrayIntResource(int arrayRes); - private native final void init(); + private native final void init(boolean isSystem); private native final void destroy(); private final void incRefsLocked(long id) { diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index f96aef8..7162a1c 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -35,7 +35,16 @@ #include <androidfw/AssetManager.h> #include <androidfw/ResourceTypes.h> +#include <private/android_filesystem_config.h> // for AID_SYSTEM + #include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <linux/capability.h> +extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap); +extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap); + namespace android { @@ -100,6 +109,63 @@ jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table, return block; } +// This is called by zygote (running as user root) as part of preloadResources. +static void verifySystemIdmaps() +{ + pid_t pid; + char system_id[10]; + + snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM); + + switch (pid = fork()) { + case -1: + ALOGE("failed to fork for idmap: %s", strerror(errno)); + break; + case 0: // child + { + struct __user_cap_header_struct capheader; + struct __user_cap_data_struct capdata; + + memset(&capheader, 0, sizeof(capheader)); + memset(&capdata, 0, sizeof(capdata)); + + capheader.version = _LINUX_CAPABILITY_VERSION; + capheader.pid = 0; + + if (capget(&capheader, &capdata) != 0) { + ALOGE("capget: %s\n", strerror(errno)); + exit(1); + } + + capdata.effective = capdata.permitted; + if (capset(&capheader, &capdata) != 0) { + ALOGE("capset: %s\n", strerror(errno)); + exit(1); + } + + if (setgid(AID_SYSTEM) != 0) { + ALOGE("setgid: %s\n", strerror(errno)); + exit(1); + } + + if (setuid(AID_SYSTEM) != 0) { + ALOGE("setuid: %s\n", strerror(errno)); + exit(1); + } + + execl(AssetManager::IDMAP_BIN, AssetManager::IDMAP_BIN, "--scan", + AssetManager::OVERLAY_DIR, AssetManager::TARGET_PACKAGE_NAME, + AssetManager::TARGET_APK_PATH, AssetManager::IDMAP_DIR, (char*)NULL); + ALOGE("failed to execl for idmap: %s", strerror(errno)); + exit(1); // should never get here + } + break; + default: // parent + waitpid(pid, NULL, 0); + break; + } +} + // ---------------------------------------------------------------------------- // this guy is exported to other jni routines @@ -444,6 +510,25 @@ static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz return (res) ? static_cast<jint>(cookie) : 0; } +static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz, + jstring idmapPath) +{ + ScopedUtfChars idmapPath8(env, idmapPath); + if (idmapPath8.c_str() == NULL) { + return 0; + } + + AssetManager* am = assetManagerForJavaObject(env, clazz); + if (am == NULL) { + return 0; + } + + int32_t cookie; + bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie); + + return (res) ? (jint)cookie : 0; +} + static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz) { AssetManager* am = assetManagerForJavaObject(env, clazz); @@ -1579,8 +1664,11 @@ static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, j return array; } -static void android_content_AssetManager_init(JNIEnv* env, jobject clazz) +static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem) { + if (isSystem) { + verifySystemIdmaps(); + } AssetManager* am = new AssetManager(); if (am == NULL) { jniThrowException(env, "java/lang/OutOfMemoryError", ""); @@ -1658,6 +1746,8 @@ static JNINativeMethod gAssetManagerMethods[] = { (void*) android_content_AssetManager_getAssetRemainingLength }, { "addAssetPathNative", "(Ljava/lang/String;)I", (void*) android_content_AssetManager_addAssetPath }, + { "addOverlayPath", "(Ljava/lang/String;)I", + (void*) android_content_AssetManager_addOverlayPath }, { "isUpToDate", "()Z", (void*) android_content_AssetManager_isUpToDate }, @@ -1724,7 +1814,7 @@ static JNINativeMethod gAssetManagerMethods[] = { (void*) android_content_AssetManager_getArrayIntResource }, // Bookkeeping. - { "init", "()V", + { "init", "(Z)V", (void*) android_content_AssetManager_init }, { "destroy", "()V", (void*) android_content_AssetManager_destroy }, diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index b20f5ba..4647413 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -1777,6 +1777,16 @@ <attr name="publicKey" /> </declare-styleable> + <!-- Attributes relating to resource overlay packages. --> + <declare-styleable name="AndroidManifestResourceOverlay" parent="AndroidManifest"> + <!-- Package name of base package whose resources will be overlaid. --> + <attr name="targetPackage" /> + + <!-- Load order of overlay package. --> + <attr name="priority" /> + + </declare-styleable> + <!-- Declaration of an {@link android.content.Intent} object in XML. May also include zero or more {@link #IntentCategory <category> and {@link #Extra <extra>} tags. --> |