diff options
author | Nick Kralevich <nnk@google.com> | 2014-02-12 11:05:59 -0800 |
---|---|---|
committer | Nick Kralevich <nnk@google.com> | 2014-02-12 11:05:59 -0800 |
commit | dd3d95f182a634acdcc1b1e8e4954234d048eb54 (patch) | |
tree | 989ee8d51a833038825dc36d38c9bdc7d1463917 | |
parent | aa318b2851042c6f98723446f33469a6545c7294 (diff) | |
parent | 4ad93639d210297764db3ffcd870ff38464943de (diff) | |
download | frameworks_base-dd3d95f182a634acdcc1b1e8e4954234d048eb54.zip frameworks_base-dd3d95f182a634acdcc1b1e8e4954234d048eb54.tar.gz frameworks_base-dd3d95f182a634acdcc1b1e8e4954234d048eb54.tar.bz2 |
resolved conflicts for merge of 4ad93639 to klp-modular-dev-plus-aosp
Change-Id: I7ad222301ec0b863d48a1a9a839469436c385ea0
-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 | ||||
-rw-r--r-- | include/androidfw/AssetManager.h | 26 | ||||
-rw-r--r-- | include/androidfw/ResourceTypes.h | 24 | ||||
-rw-r--r-- | libs/androidfw/AssetManager.cpp | 314 | ||||
-rw-r--r-- | libs/androidfw/ResourceTypes.cpp | 76 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/Installer.java | 11 | ||||
-rwxr-xr-x | services/core/java/com/android/server/pm/PackageManagerService.java | 100 |
16 files changed, 536 insertions, 220 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. --> diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h index e0c6183..ac47900 100644 --- a/include/androidfw/AssetManager.h +++ b/include/androidfw/AssetManager.h @@ -70,6 +70,12 @@ struct ResTable_config; class AssetManager : public AAssetManager { public: static const char* RESOURCES_FILENAME; + static const char* IDMAP_BIN; + static const char* OVERLAY_DIR; + static const char* TARGET_PACKAGE_NAME; + static const char* TARGET_APK_PATH; + static const char* IDMAP_DIR; + typedef enum CacheMode { CACHE_UNKNOWN = 0, CACHE_OFF, // don't try to cache file locations @@ -94,6 +100,7 @@ public: * newly-added asset source. */ bool addAssetPath(const String8& path, int32_t* cookie); + bool addOverlayPath(const String8& path, int32_t* cookie); /* * Convenience for adding the standard system assets. Uses the @@ -272,19 +279,14 @@ private: void setLocaleLocked(const char* locale); void updateResourceParamsLocked() const; - bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath); - - bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath); - Asset* openIdmapLocked(const struct asset_path& ap) const; - bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc); + void addSystemOverlays(const char* pathOverlaysList, const String8& targetPackagePath, + ResTable* sharedRes, size_t offset) const; class SharedZip : public RefBase { public: - static sp<SharedZip> get(const String8& path); + static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true); ZipFileRO* getZip(); @@ -295,6 +297,9 @@ private: ResTable* setResourceTable(ResTable* res); bool isUpToDate(); + + void addOverlay(const asset_path& ap); + bool getOverlay(size_t idx, asset_path* out) const; protected: ~SharedZip(); @@ -310,6 +315,8 @@ private: Asset* mResourceTableAsset; ResTable* mResourceTable; + Vector<asset_path> mOverlays; + static Mutex gLock; static DefaultKeyedVector<String8, wp<SharedZip> > gOpen; }; @@ -342,6 +349,9 @@ private: static String8 getPathName(const char* path); bool isUpToDate(); + + void addOverlay(const String8& path, const asset_path& overlay); + bool getOverlay(const String8& path, size_t idx, asset_path* out) const; private: void closeZip(int idx); diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h index 7779f7f..c022818 100644 --- a/include/androidfw/ResourceTypes.h +++ b/include/androidfw/ResourceTypes.h @@ -1545,39 +1545,21 @@ public: // Return value: on success: NO_ERROR; caller is responsible for free-ing // outData (using free(3)). On failure, any status_t value other than // NO_ERROR; the caller should not free outData. - status_t createIdmap(const ResTable& overlay, uint32_t targetCrc, uint32_t overlayCrc, - void** outData, size_t* outSize) const; - status_t createIdmap(const ResTable& overlay, uint32_t targetCrc, uint32_t overlayCrc, const char* targetPath, const char* overlayPath, - void** outData, uint32_t* outSize) const - { - (void)targetPath; - (void)overlayPath; - return createIdmap(overlay, targetCrc, overlayCrc, outData, outSize); - } + void** outData, uint32_t* outSize) const; enum { - IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t), + IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t) + 2 * 256, }; // Retrieve idmap meta-data. // // This function only requires the idmap header (the first // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file. static bool getIdmapInfo(const void* idmap, size_t size, - uint32_t* pTargetCrc, uint32_t* pOverlayCrc); - - static bool getIdmapInfo(const void* idmap, size_t size, uint32_t* pTargetCrc, uint32_t* pOverlayCrc, - String8* pTargetPath, String8* pOverlayPath) - { - if (*pTargetPath) - *pTargetPath = String8(); - if (*pOverlayPath) - *pOverlayPath = String8(); - return getIdmapInfo(idmap, size, pTargetCrc, pOverlayCrc); - } + String8* pTargetPath, String8* pOverlayPath); void print(bool inclValues) const; static String8 normalizeForOutput(const char* input); diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 251d47b..05a948d 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -41,10 +41,8 @@ #include <assert.h> #include <dirent.h> #include <errno.h> -#include <fcntl.h> +#include <string.h> // strerror #include <strings.h> -#include <sys/stat.h> -#include <unistd.h> #ifndef TEMP_FAILURE_RETRY /* Used to retry syscalls that can return EINTR. */ @@ -75,7 +73,7 @@ static const char* kDefaultVendor = "default"; static const char* kAssetsRoot = "assets"; static const char* kAppZipName = NULL; //"classes.jar"; static const char* kSystemAssets = "framework/framework-res.apk"; -static const char* kIdmapCacheDir = "resource-cache"; +static const char* kResourceCache = "resource-cache"; static const char* kExcludeExtension = ".EXCLUDE"; @@ -84,15 +82,19 @@ static Asset* const kExcludedAsset = (Asset*) 0xd000000d; static volatile int32_t gCount = 0; const char* AssetManager::RESOURCES_FILENAME = "resources.arsc"; +const char* AssetManager::IDMAP_BIN = "/system/bin/idmap"; +const char* AssetManager::OVERLAY_DIR = "/vendor/overlay"; +const char* AssetManager::TARGET_PACKAGE_NAME = "android"; +const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk"; +const char* AssetManager::IDMAP_DIR = "/data/resource-cache"; namespace { - // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap String8 idmapPathForPackagePath(const String8& pkgPath) { const char* root = getenv("ANDROID_DATA"); LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set"); String8 path(root); - path.appendPath(kIdmapCacheDir); + path.appendPath(kResourceCache); char buf[256]; // 256 chars should be enough for anyone... strncpy(buf, pkgPath.string(), 255); @@ -210,203 +212,99 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie) *cookie = static_cast<int32_t>(mAssetPaths.size()); } - // add overlay packages for /system/framework; apps are handled by the - // (Java) package manager - if (strncmp(path.string(), "/system/framework/", 18) == 0) { - // When there is an environment variable for /vendor, this - // should be changed to something similar to how ANDROID_ROOT - // and ANDROID_DATA are used in this file. - String8 overlayPath("/vendor/overlay/framework/"); - overlayPath.append(path.getPathLeaf()); - if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) { - asset_path oap; - oap.path = overlayPath; - oap.type = ::getFileType(overlayPath.string()); - bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay - if (addOverlay) { - oap.idmap = idmapPathForPackagePath(overlayPath); - - if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) { - addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap); - } - } - if (addOverlay) { - mAssetPaths.add(oap); - } else { - ALOGW("failed to add overlay package %s\n", overlayPath.string()); - } - } +#ifdef HAVE_ANDROID_OS + // Load overlays, if any + asset_path oap; + for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) { + mAssetPaths.add(oap); } +#endif return true; } -bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath, - uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, uint32_t* outSize) +bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie) { - AutoMutex _l(mLock); - const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) }; - ResTable tables[2]; + const String8 idmapPath = idmapPathForPackagePath(packagePath); - for (int i = 0; i < 2; ++i) { - asset_path ap; - ap.type = kFileTypeRegular; - ap.path = paths[i]; - Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap); - if (ass == NULL) { - ALOGW("failed to find resources.arsc in %s\n", ap.path.string()); - return false; - } - tables[i].add(ass, (void*)1, false); - } + AutoMutex _l(mLock); - return tables[0].createIdmap(tables[1], targetCrc, overlayCrc, - targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR; -} + for (size_t i = 0; i < mAssetPaths.size(); ++i) { + if (mAssetPaths[i].idmap == idmapPath) { + *cookie = static_cast<int32_t>(i + 1); + return true; + } + } -bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath) -{ - struct stat st; - if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) { - if (errno == ENOENT) { - return true; // non-existing idmap is always stale - } else { - ALOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno)); - return false; - } - } - if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) { - ALOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size); + Asset* idmap = NULL; + if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) { + ALOGW("failed to open idmap file %s\n", idmapPath.string()); return false; } - int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY)); - if (fd == -1) { - ALOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno)); - return false; - } - char buf[ResTable::IDMAP_HEADER_SIZE_BYTES]; - ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES; - for (;;) { - ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft, - bytesLeft)); - if (r < 0) { - TEMP_FAILURE_RETRY(close(fd)); - return false; - } - bytesLeft -= r; - if (bytesLeft == 0) { - break; - } - } - TEMP_FAILURE_RETRY(close(fd)); - uint32_t cachedOriginalCrc, cachedOverlayCrc; - if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES, - &cachedOriginalCrc, &cachedOverlayCrc)) { + String8 targetPath; + String8 overlayPath; + if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(), + NULL, NULL, &targetPath, &overlayPath)) { + ALOGW("failed to read idmap file %s\n", idmapPath.string()); + delete idmap; return false; } + delete idmap; - uint32_t actualOriginalCrc, actualOverlayCrc; - if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) { + if (overlayPath != packagePath) { + ALOGW("idmap file %s inconcistent: expected path %s does not match actual path %s\n", + idmapPath.string(), packagePath.string(), overlayPath.string()); return false; } - if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) { + if (access(targetPath.string(), R_OK) != 0) { + ALOGW("failed to access file %s: %s\n", targetPath.string(), strerror(errno)); return false; } - return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc; -} - -bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, - uint32_t* pCrc) -{ - asset_path ap; - ap.path = zipPath; - const ZipFileRO* zip = getZipFileLocked(ap); - if (zip == NULL) { + if (access(idmapPath.string(), R_OK) != 0) { + ALOGW("failed to access file %s: %s\n", idmapPath.string(), strerror(errno)); return false; } - const ZipEntryRO entry = zip->findEntryByName(entryFilename); - if (entry == NULL) { + if (access(overlayPath.string(), R_OK) != 0) { + ALOGW("failed to access file %s: %s\n", overlayPath.string(), strerror(errno)); return false; } - const bool gotInfo = zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc); - zip->releaseEntry(entry); + asset_path oap; + oap.path = overlayPath; + oap.type = ::getFileType(overlayPath.string()); + oap.idmap = idmapPath; +#if 0 + ALOGD("Overlay added: targetPath=%s overlayPath=%s idmapPath=%s\n", + targetPath.string(), overlayPath.string(), idmapPath.string()); +#endif + mAssetPaths.add(oap); + *cookie = static_cast<int32_t>(mAssetPaths.size()); - return gotInfo; -} + return true; + } -bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath, - const String8& idmapPath) +bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath, + uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, uint32_t* outSize) { - ALOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n", - __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string()); + AutoMutex _l(mLock); + const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) }; ResTable tables[2]; - const String8* paths[2] = { &originalPath, &overlayPath }; - uint32_t originalCrc, overlayCrc; - bool retval = false; - ssize_t offset = 0; - int fd = 0; - uint32_t* data = NULL; - size_t size; for (int i = 0; i < 2; ++i) { asset_path ap; ap.type = kFileTypeRegular; - ap.path = *paths[i]; + ap.path = paths[i]; Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap); if (ass == NULL) { ALOGW("failed to find resources.arsc in %s\n", ap.path.string()); - goto error; + return false; } tables[i].add(ass, 1, false /* copyData */, NULL /* idMap */); } - if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) { - ALOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string()); - goto error; - } - if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) { - ALOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string()); - goto error; - } - - if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc, - (void**)&data, &size) != NO_ERROR) { - ALOGW("failed to generate idmap data for file %s\n", idmapPath.string()); - goto error; - } - - // This should be abstracted (eg replaced by a stand-alone - // application like dexopt, triggered by something equivalent to - // installd). - fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644)); - if (fd == -1) { - ALOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno)); - goto error_free; - } - for (;;) { - ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size)); - if (written < 0) { - ALOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(), - strerror(errno)); - goto error_close; - } - size -= (size_t)written; - offset += written; - if (size == 0) { - break; - } - } - - retval = true; -error_close: - TEMP_FAILURE_RETRY(close(fd)); -error_free: - free(data); -error: - return retval; + return tables[0].createIdmap(tables[1], targetCrc, overlayCrc, + targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR; } bool AssetManager::addDefaultAssets() @@ -685,6 +583,10 @@ const ResTable* AssetManager::getResTable(bool required) const // which we want to avoid parsing every time. sharedRes = const_cast<AssetManager*>(this)-> mZipSet.getZipResourceTable(ap.path); + if (sharedRes != NULL) { + // skip ahead the number of system overlay packages preloaded + i += sharedRes->getTableCount() - 1; + } } if (sharedRes == NULL) { ass = const_cast<AssetManager*>(this)-> @@ -708,6 +610,14 @@ const ResTable* AssetManager::getResTable(bool required) const ALOGV("Creating shared resources for %s", ap.path.string()); sharedRes = new ResTable(); sharedRes->add(ass, i + 1, false, idmap); +#ifdef HAVE_ANDROID_OS + const char* data = getenv("ANDROID_DATA"); + LOG_ALWAYS_FATAL_IF(data == NULL, "ANDROID_DATA not set"); + String8 overlaysListPath(data); + overlaysListPath.appendPath(kResourceCache); + overlaysListPath.appendPath("overlays.list"); + addSystemOverlays(overlaysListPath.string(), ap.path, sharedRes, i); +#endif sharedRes = const_cast<AssetManager*>(this)-> mZipSet.setZipResourceTable(ap.path, sharedRes); } @@ -791,6 +701,46 @@ Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const return ass; } +void AssetManager::addSystemOverlays(const char* pathOverlaysList, + const String8& targetPackagePath, ResTable* sharedRes, size_t offset) const +{ + FILE* fin = fopen(pathOverlaysList, "r"); + if (fin == NULL) { + return; + } + + char buf[1024]; + while (fgets(buf, sizeof(buf), fin)) { + // format of each line: + // <path to apk><space><path to idmap><newline> + char* space = strchr(buf, ' '); + char* newline = strchr(buf, '\n'); + asset_path oap; + + if (space == NULL || newline == NULL || newline < space) { + continue; + } + + oap.path = String8(buf, space - buf); + oap.type = kFileTypeRegular; + oap.idmap = String8(space + 1, newline - space - 1); + + Asset* oass = const_cast<AssetManager*>(this)-> + openNonAssetInPathLocked("resources.arsc", + Asset::ACCESS_BUFFER, + oap); + + if (oass != NULL) { + Asset* oidmap = openIdmapLocked(oap); + offset++; + sharedRes->add(oass, offset + 1, false, oidmap); + const_cast<AssetManager*>(this)->mAssetPaths.add(oap); + const_cast<AssetManager*>(this)->mZipSet.addOverlay(targetPackagePath, oap); + } + } + fclose(fin); +} + const ResTable& AssetManager::getResources(bool required) const { const ResTable* rt = getResTable(required); @@ -1849,7 +1799,8 @@ AssetManager::SharedZip::SharedZip(const String8& path, time_t modWhen) } } -sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path) +sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path, + bool createIfNotPresent) { AutoMutex _l(gLock); time_t modWhen = getFileModDate(path); @@ -1857,6 +1808,9 @@ sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path) if (zip != NULL && zip->mModWhen == modWhen) { return zip; } + if (zip == NULL && !createIfNotPresent) { + return NULL; + } zip = new SharedZip(path, modWhen); gOpen.add(path, zip); return zip; @@ -1915,6 +1869,20 @@ bool AssetManager::SharedZip::isUpToDate() return mModWhen == modWhen; } +void AssetManager::SharedZip::addOverlay(const asset_path& ap) +{ + mOverlays.add(ap); +} + +bool AssetManager::SharedZip::getOverlay(size_t idx, asset_path* out) const +{ + if (idx >= mOverlays.size()) { + return false; + } + *out = mOverlays[idx]; + return true; +} + AssetManager::SharedZip::~SharedZip() { //ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath); @@ -2038,6 +2006,22 @@ bool AssetManager::ZipSet::isUpToDate() return true; } +void AssetManager::ZipSet::addOverlay(const String8& path, const asset_path& overlay) +{ + int idx = getIndex(path); + sp<SharedZip> zip = mZipFile[idx]; + zip->addOverlay(overlay); +} + +bool AssetManager::ZipSet::getOverlay(const String8& path, size_t idx, asset_path* out) const +{ + sp<SharedZip> zip = SharedZip::get(path, false); + if (zip == NULL) { + return false; + } + return zip->getOverlay(idx, out); +} + /* * Compute the zip file's index. * diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 609ad19..8cc98af 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -284,11 +284,37 @@ static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t if (!assertIdmapHeader(map, mapSize)) { return UNKNOWN_ERROR; } + if (mapSize <= IDMAP_HEADER_SIZE + 1) { + ALOGW("corrupt idmap: map size %d too short\n", mapSize); + return UNKNOWN_ERROR; + } + uint32_t typeCount = *(map + IDMAP_HEADER_SIZE); + if (typeCount == 0) { + ALOGW("corrupt idmap: no types\n"); + return UNKNOWN_ERROR; + } + if (IDMAP_HEADER_SIZE + 1 + typeCount > mapSize) { + ALOGW("corrupt idmap: number of types %d extends past idmap size %d\n", typeCount, mapSize); + return UNKNOWN_ERROR; + } const uint32_t* p = map + IDMAP_HEADER_SIZE + 1; + // find first defined type while (*p == 0) { ++p; + if (--typeCount == 0) { + ALOGW("corrupt idmap: types declared, none found\n"); + return UNKNOWN_ERROR; + } + } + + // determine package id from first entry of first type + const uint32_t offset = *p + IDMAP_HEADER_SIZE + 2; + if (offset > mapSize) { + ALOGW("corrupt idmap: entry offset %d points outside map size %d\n", offset, mapSize); + return UNKNOWN_ERROR; } - *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff; + *outId = (map[offset] >> 24) & 0x000000ff; + return NO_ERROR; } @@ -5334,23 +5360,30 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg, return NO_ERROR; } -status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc, - void** outData, size_t* outSize) const +status_t ResTable::createIdmap(const ResTable& overlay, + uint32_t targetCrc, uint32_t overlayCrc, + const char* targetPath, const char* overlayPath, + void** outData, size_t* outSize) const { // see README for details on the format of map if (mPackageGroups.size() == 0) { + ALOGW("idmap: target package has no package groups, cannot create idmap\n"); return UNKNOWN_ERROR; } if (mPackageGroups[0]->packages.size() == 0) { + ALOGW("idmap: target package has no packages in its first package group, " + "cannot create idmap\n"); return UNKNOWN_ERROR; } Vector<Vector<uint32_t> > map; + // overlaid packages are assumed to contain only one package group const PackageGroup* pg = mPackageGroups[0]; const Package* pkg = pg->packages[0]; size_t typeCount = pkg->types.size(); // starting size is header + first item (number of types in map) *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t); + // overlay packages are assumed to contain only one package group const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name); const uint32_t pkg_id = pkg->package->id << 24; @@ -5426,8 +5459,22 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui } uint32_t* data = (uint32_t*)*outData; *data++ = htodl(IDMAP_MAGIC); - *data++ = htodl(originalCrc); + *data++ = htodl(targetCrc); *data++ = htodl(overlayCrc); + const char* paths[] = { targetPath, overlayPath }; + for (int j = 0; j < 2; ++j) { + char* p = (char*)data; + const char* path = paths[j]; + const size_t I = strlen(path); + if (I > 255) { + ALOGV("path exceeds expected 255 characters: %s\n", path); + return UNKNOWN_ERROR; + } + for (size_t i = 0; i < 256; ++i) { + *p++ = i < I ? path[i] : '\0'; + } + data += 256 / sizeof(uint32_t); + } const size_t mapSize = map.size(); *data++ = htodl(mapSize); size_t offset = mapSize; @@ -5442,6 +5489,10 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui offset += N; } } + if (offset == mapSize) { + ALOGW("idmap: no resources in overlay package present in base package\n"); + return UNKNOWN_ERROR; + } for (size_t i = 0; i < mapSize; ++i) { const Vector<uint32_t>& vector = map.itemAt(i); const size_t N = vector.size(); @@ -5463,14 +5514,25 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui } bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes, - uint32_t* pOriginalCrc, uint32_t* pOverlayCrc) + uint32_t* pTargetCrc, uint32_t* pOverlayCrc, + String8* pTargetPath, String8* pOverlayPath) { const uint32_t* map = (const uint32_t*)idmap; if (!assertIdmapHeader(map, sizeBytes)) { return false; } - *pOriginalCrc = map[1]; - *pOverlayCrc = map[2]; + if (pTargetCrc) { + *pTargetCrc = map[1]; + } + if (pOverlayCrc) { + *pOverlayCrc = map[2]; + } + if (pTargetPath) { + pTargetPath->setTo(reinterpret_cast<const char*>(map + 3)); + } + if (pOverlayPath) { + pOverlayPath->setTo(reinterpret_cast<const char*>(map + 3 + 256 / sizeof(uint32_t))); + } return true; } diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 6185e50..ad6eabd 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -221,6 +221,17 @@ public final class Installer extends SystemService { return execute(builder.toString()); } + public int idmap(String targetApkPath, String overlayApkPath, int uid) { + StringBuilder builder = new StringBuilder("idmap"); + builder.append(' '); + builder.append(targetApkPath); + builder.append(' '); + builder.append(overlayApkPath); + builder.append(' '); + builder.append(uid); + return execute(builder.toString()); + } + public int movedex(String srcPath, String dstPath) { StringBuilder builder = new StringBuilder("movedex"); builder.append(' '); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ef1d258..0be8a4f 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -219,6 +219,7 @@ public class PackageManagerService extends IPackageManager.Stub { static final int SCAN_UPDATE_TIME = 1<<6; static final int SCAN_DEFER_DEX = 1<<7; static final int SCAN_BOOTING = 1<<8; + static final int SCAN_TRUSTED_OVERLAY = 1<<9; static final int REMOVE_CHATTY = 1<<16; @@ -259,9 +260,15 @@ public class PackageManagerService extends IPackageManager.Stub { private static final String LIB_DIR_NAME = "lib"; + private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay"; + static final String mTempContainerPrefix = "smdl2tmp"; final ServiceThread mHandlerThread; + + private static final String IDMAP_PREFIX = "/data/resource-cache/"; + private static final String IDMAP_SUFFIX = "@idmap"; + final PackageHandler mHandler; final int mSdkVersion = Build.VERSION.SDK_INT; @@ -297,6 +304,9 @@ public class PackageManagerService extends IPackageManager.Stub { // This is the object monitoring the system app dir. final FileObserver mVendorInstallObserver; + // This is the object monitoring the vendor overlay package dir. + final FileObserver mVendorOverlayInstallObserver; + // This is the object monitoring mAppInstallDir. final FileObserver mAppInstallObserver; @@ -344,6 +354,10 @@ public class PackageManagerService extends IPackageManager.Stub { final HashMap<String, PackageParser.Package> mPackages = new HashMap<String, PackageParser.Package>(); + // Tracks available target package names -> overlay package paths. + final HashMap<String, HashMap<String, PackageParser.Package>> mOverlays = + new HashMap<String, HashMap<String, PackageParser.Package>>(); + final Settings mSettings; boolean mRestoredSettings; @@ -1279,6 +1293,17 @@ public class PackageManagerService extends IPackageManager.Stub { } } + // Collect vendor overlay packages. + // (Do this before scanning any apps.) + // For security and version matching reason, only consider + // overlay packages if they reside in VENDOR_OVERLAY_DIR. + File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR); + mVendorOverlayInstallObserver = new AppDirObserver( + vendorOverlayDir.getPath(), OBSERVER_EVENTS, true, false); + mVendorOverlayInstallObserver.startWatching(); + scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM + | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_TRUSTED_OVERLAY, 0); + // Find base frameworks (resource packages without code). mFrameworkInstallObserver = new AppDirObserver( frameworkDir.getPath(), OBSERVER_EVENTS, true, false); @@ -3481,6 +3506,56 @@ public class PackageManagerService extends IPackageManager.Stub { return finalList; } + private void createIdmapsForPackageLI(PackageParser.Package pkg) { + HashMap<String, PackageParser.Package> overlays = mOverlays.get(pkg.packageName); + if (overlays == null) { + Slog.w(TAG, "Unable to create idmap for " + pkg.packageName + ": no overlay packages"); + return; + } + for (PackageParser.Package opkg : overlays.values()) { + // Not much to do if idmap fails: we already logged the error + // and we certainly don't want to abort installation of pkg simply + // because an overlay didn't fit properly. For these reasons, + // ignore the return value of createIdmapForPackagePairLI. + createIdmapForPackagePairLI(pkg, opkg); + } + } + + private boolean createIdmapForPackagePairLI(PackageParser.Package pkg, + PackageParser.Package opkg) { + if (!opkg.mTrustedOverlay) { + Slog.w(TAG, "Skipping target and overlay pair " + pkg.mScanPath + " and " + + opkg.mScanPath + ": overlay not trusted"); + return false; + } + HashMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName); + if (overlaySet == null) { + Slog.e(TAG, "was about to create idmap for " + pkg.mScanPath + " and " + + opkg.mScanPath + " but target package has no known overlays"); + return false; + } + final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + if (mInstaller.idmap(pkg.mScanPath, opkg.mScanPath, sharedGid) != 0) { + Slog.e(TAG, "Failed to generate idmap for " + pkg.mScanPath + " and " + opkg.mScanPath); + return false; + } + PackageParser.Package[] overlayArray = + overlaySet.values().toArray(new PackageParser.Package[0]); + Comparator<PackageParser.Package> cmp = new Comparator<PackageParser.Package>() { + public int compare(PackageParser.Package p1, PackageParser.Package p2) { + return p1.mOverlayPriority - p2.mOverlayPriority; + } + }; + Arrays.sort(overlayArray, cmp); + + pkg.applicationInfo.resourceDirs = new String[overlayArray.length]; + int i = 0; + for (PackageParser.Package p : overlayArray) { + pkg.applicationInfo.resourceDirs[i++] = p.applicationInfo.sourceDir; + } + return true; + } + private void scanDirLI(File dir, int flags, int scanMode, long currentTime) { String[] files = dir.list(); if (files == null) { @@ -3578,7 +3653,7 @@ public class PackageManagerService extends IPackageManager.Stub { pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); final PackageParser.Package pkg = pp.parsePackage(scanFile, - scanPath, mMetrics, parseFlags); + scanPath, mMetrics, parseFlags, (scanMode & SCAN_TRUSTED_OVERLAY) != 0); if (pkg == null) { mLastScanError = pp.getParseError(); @@ -5087,6 +5162,29 @@ public class PackageManagerService extends IPackageManager.Stub { } pkgSetting.setTimeStamp(scanFileTime); + + // Create idmap files for pairs of (packages, overlay packages). + // Note: "android", ie framework-res.apk, is handled by native layers. + if (pkg.mOverlayTarget != null) { + // This is an overlay package. + if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) { + if (!mOverlays.containsKey(pkg.mOverlayTarget)) { + mOverlays.put(pkg.mOverlayTarget, + new HashMap<String, PackageParser.Package>()); + } + HashMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget); + map.put(pkg.packageName, pkg); + PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget); + if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) { + mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE; + return null; + } + } + } else if (mOverlays.containsKey(pkg.packageName) && + !pkg.packageName.equals("android")) { + // This is a regular package, with one or more known overlay packages. + createIdmapsForPackageLI(pkg); + } } return pkg; |