Merge "Runtime resource overlay, iteration 2"
This commit is contained in:
@ -1541,11 +1541,11 @@ public final class ActivityThread {
|
|||||||
/**
|
/**
|
||||||
* Creates the top level resources for the given package.
|
* Creates the top level resources for the given package.
|
||||||
*/
|
*/
|
||||||
Resources getTopLevelResources(String resDir,
|
Resources getTopLevelResources(String resDir, String[] overlayDirs,
|
||||||
int displayId, Configuration overrideConfiguration,
|
int displayId, Configuration overrideConfiguration,
|
||||||
LoadedApk pkgInfo) {
|
LoadedApk pkgInfo) {
|
||||||
return mResourcesManager.getTopLevelResources(resDir, displayId, overrideConfiguration,
|
return mResourcesManager.getTopLevelResources(resDir, overlayDirs, displayId,
|
||||||
pkgInfo.getCompatibilityInfo(), null);
|
overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
final Handler getHandler() {
|
final Handler getHandler() {
|
||||||
|
@ -774,7 +774,7 @@ final class ApplicationPackageManager extends PackageManager {
|
|||||||
}
|
}
|
||||||
Resources r = mContext.mMainThread.getTopLevelResources(
|
Resources r = mContext.mMainThread.getTopLevelResources(
|
||||||
app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir,
|
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) {
|
if (r != null) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -1911,8 +1911,8 @@ class ContextImpl extends Context {
|
|||||||
ContextImpl c = new ContextImpl();
|
ContextImpl c = new ContextImpl();
|
||||||
c.init(mPackageInfo, null, mMainThread);
|
c.init(mPackageInfo, null, mMainThread);
|
||||||
c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
|
c.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
|
||||||
getDisplayId(), overrideConfiguration, mResources.getCompatibilityInfo(),
|
mPackageInfo.getOverlayDirs(), getDisplayId(), overrideConfiguration,
|
||||||
mActivityToken);
|
mResources.getCompatibilityInfo(), mActivityToken);
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1929,7 +1929,7 @@ class ContextImpl extends Context {
|
|||||||
context.mDisplay = display;
|
context.mDisplay = display;
|
||||||
DisplayAdjustments daj = getDisplayAdjustments(displayId);
|
DisplayAdjustments daj = getDisplayAdjustments(displayId);
|
||||||
context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
|
context.mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
|
||||||
displayId, null, daj.getCompatibilityInfo(), null);
|
mPackageInfo.getOverlayDirs(), displayId, null, daj.getCompatibilityInfo(), null);
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2041,7 +2041,8 @@ class ContextImpl extends Context {
|
|||||||
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
|
mDisplayAdjustments.setCompatibilityInfo(compatInfo);
|
||||||
mDisplayAdjustments.setActivityToken(activityToken);
|
mDisplayAdjustments.setActivityToken(activityToken);
|
||||||
mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
|
mResources = mResourcesManager.getTopLevelResources(mPackageInfo.getResDir(),
|
||||||
Display.DEFAULT_DISPLAY, null, compatInfo, activityToken);
|
mPackageInfo.getOverlayDirs(), Display.DEFAULT_DISPLAY, null, compatInfo,
|
||||||
|
activityToken);
|
||||||
} else {
|
} else {
|
||||||
mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo());
|
mDisplayAdjustments.setCompatibilityInfo(packageInfo.getCompatibilityInfo());
|
||||||
mDisplayAdjustments.setActivityToken(activityToken);
|
mDisplayAdjustments.setActivityToken(activityToken);
|
||||||
|
@ -76,6 +76,7 @@ public final class LoadedApk {
|
|||||||
final String mPackageName;
|
final String mPackageName;
|
||||||
private final String mAppDir;
|
private final String mAppDir;
|
||||||
private final String mResDir;
|
private final String mResDir;
|
||||||
|
private final String[] mOverlayDirs;
|
||||||
private final String[] mSharedLibraries;
|
private final String[] mSharedLibraries;
|
||||||
private final String mDataDir;
|
private final String mDataDir;
|
||||||
private final String mLibDir;
|
private final String mLibDir;
|
||||||
@ -120,6 +121,7 @@ public final class LoadedApk {
|
|||||||
final int myUid = Process.myUid();
|
final int myUid = Process.myUid();
|
||||||
mResDir = aInfo.uid == myUid ? aInfo.sourceDir
|
mResDir = aInfo.uid == myUid ? aInfo.sourceDir
|
||||||
: aInfo.publicSourceDir;
|
: aInfo.publicSourceDir;
|
||||||
|
mOverlayDirs = aInfo.resourceDirs;
|
||||||
if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
|
if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
|
||||||
aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
|
aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
|
||||||
mPackageName);
|
mPackageName);
|
||||||
@ -159,6 +161,7 @@ public final class LoadedApk {
|
|||||||
mPackageName = name;
|
mPackageName = name;
|
||||||
mAppDir = null;
|
mAppDir = null;
|
||||||
mResDir = null;
|
mResDir = null;
|
||||||
|
mOverlayDirs = null;
|
||||||
mSharedLibraries = null;
|
mSharedLibraries = null;
|
||||||
mDataDir = null;
|
mDataDir = null;
|
||||||
mDataDirFile = null;
|
mDataDirFile = null;
|
||||||
@ -471,6 +474,10 @@ public final class LoadedApk {
|
|||||||
return mResDir;
|
return mResDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getOverlayDirs() {
|
||||||
|
return mOverlayDirs;
|
||||||
|
}
|
||||||
|
|
||||||
public String getDataDir() {
|
public String getDataDir() {
|
||||||
return mDataDir;
|
return mDataDir;
|
||||||
}
|
}
|
||||||
@ -485,7 +492,7 @@ public final class LoadedApk {
|
|||||||
|
|
||||||
public Resources getResources(ActivityThread mainThread) {
|
public Resources getResources(ActivityThread mainThread) {
|
||||||
if (mResources == null) {
|
if (mResources == null) {
|
||||||
mResources = mainThread.getTopLevelResources(mResDir,
|
mResources = mainThread.getTopLevelResources(mResDir, mOverlayDirs,
|
||||||
Display.DEFAULT_DISPLAY, null, this);
|
Display.DEFAULT_DISPLAY, null, this);
|
||||||
}
|
}
|
||||||
return mResources;
|
return mResources;
|
||||||
|
@ -147,7 +147,7 @@ public class ResourcesManager {
|
|||||||
* @param compatInfo the compability info. Must not be null.
|
* @param compatInfo the compability info. Must not be null.
|
||||||
* @param token the application token for determining stack bounds.
|
* @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) {
|
Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
|
||||||
final float scale = compatInfo.applicationScale;
|
final float scale = compatInfo.applicationScale;
|
||||||
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
|
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
|
||||||
@ -180,6 +180,12 @@ public class ResourcesManager {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (overlayDirs != null) {
|
||||||
|
for (String idmapPath : overlayDirs) {
|
||||||
|
assets.addOverlayPath(idmapPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
|
//Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
|
||||||
DisplayMetrics dm = getDisplayMetricsLocked(displayId);
|
DisplayMetrics dm = getDisplayMetricsLocked(displayId);
|
||||||
Configuration config;
|
Configuration config;
|
||||||
|
@ -227,6 +227,14 @@ public class PackageInfo implements Parcelable {
|
|||||||
/** @hide */
|
/** @hide */
|
||||||
public String requiredAccountType;
|
public String requiredAccountType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What package, if any, this package will overlay.
|
||||||
|
*
|
||||||
|
* Package name of target package, or null.
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public String overlayTarget;
|
||||||
|
|
||||||
public PackageInfo() {
|
public PackageInfo() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +278,7 @@ public class PackageInfo implements Parcelable {
|
|||||||
dest.writeInt(requiredForAllUsers ? 1 : 0);
|
dest.writeInt(requiredForAllUsers ? 1 : 0);
|
||||||
dest.writeString(restrictedAccountType);
|
dest.writeString(restrictedAccountType);
|
||||||
dest.writeString(requiredAccountType);
|
dest.writeString(requiredAccountType);
|
||||||
|
dest.writeString(overlayTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<PackageInfo> CREATOR
|
public static final Parcelable.Creator<PackageInfo> CREATOR
|
||||||
@ -311,5 +320,6 @@ public class PackageInfo implements Parcelable {
|
|||||||
requiredForAllUsers = source.readInt() != 0;
|
requiredForAllUsers = source.readInt() != 0;
|
||||||
restrictedAccountType = source.readString();
|
restrictedAccountType = source.readString();
|
||||||
requiredAccountType = source.readString();
|
requiredAccountType = source.readString();
|
||||||
|
overlayTarget = source.readString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,6 +307,7 @@ public class PackageParser {
|
|||||||
}
|
}
|
||||||
pi.restrictedAccountType = p.mRestrictedAccountType;
|
pi.restrictedAccountType = p.mRestrictedAccountType;
|
||||||
pi.requiredAccountType = p.mRequiredAccountType;
|
pi.requiredAccountType = p.mRequiredAccountType;
|
||||||
|
pi.overlayTarget = p.mOverlayTarget;
|
||||||
pi.firstInstallTime = firstInstallTime;
|
pi.firstInstallTime = firstInstallTime;
|
||||||
pi.lastUpdateTime = lastUpdateTime;
|
pi.lastUpdateTime = lastUpdateTime;
|
||||||
if ((flags&PackageManager.GET_GIDS) != 0) {
|
if ((flags&PackageManager.GET_GIDS) != 0) {
|
||||||
@ -490,6 +491,11 @@ public class PackageParser {
|
|||||||
|
|
||||||
public Package parsePackage(File sourceFile, String destCodePath,
|
public Package parsePackage(File sourceFile, String destCodePath,
|
||||||
DisplayMetrics metrics, int flags) {
|
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;
|
mParseError = PackageManager.INSTALL_SUCCEEDED;
|
||||||
|
|
||||||
mArchiveSourcePath = sourceFile.getPath();
|
mArchiveSourcePath = sourceFile.getPath();
|
||||||
@ -542,7 +548,7 @@ public class PackageParser {
|
|||||||
Exception errorException = null;
|
Exception errorException = null;
|
||||||
try {
|
try {
|
||||||
// XXXX todo: need to figure out correct configuration.
|
// XXXX todo: need to figure out correct configuration.
|
||||||
pkg = parsePackage(res, parser, flags, errorText);
|
pkg = parsePackage(res, parser, flags, trustedOverlay, errorText);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
errorException = e;
|
errorException = e;
|
||||||
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
|
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
|
||||||
@ -951,8 +957,8 @@ public class PackageParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Package parsePackage(
|
private Package parsePackage(
|
||||||
Resources res, XmlResourceParser parser, int flags, String[] outError)
|
Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay,
|
||||||
throws XmlPullParserException, IOException {
|
String[] outError) throws XmlPullParserException, IOException {
|
||||||
AttributeSet attrs = parser;
|
AttributeSet attrs = parser;
|
||||||
|
|
||||||
mParseInstrumentationArgs = null;
|
mParseInstrumentationArgs = null;
|
||||||
@ -1051,6 +1057,31 @@ public class PackageParser {
|
|||||||
if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
|
if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
|
||||||
return null;
|
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")) {
|
} else if (tagName.equals("keys")) {
|
||||||
if (!parseKeys(pkg, res, parser, attrs, outError)) {
|
if (!parseKeys(pkg, res, parser, attrs, outError)) {
|
||||||
return null;
|
return null;
|
||||||
@ -3546,6 +3577,10 @@ public class PackageParser {
|
|||||||
*/
|
*/
|
||||||
public ManifestDigest manifestDigest;
|
public ManifestDigest manifestDigest;
|
||||||
|
|
||||||
|
public String mOverlayTarget;
|
||||||
|
public int mOverlayPriority;
|
||||||
|
public boolean mTrustedOverlay;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data used to feed the KeySetManager
|
* Data used to feed the KeySetManager
|
||||||
*/
|
*/
|
||||||
|
@ -90,7 +90,7 @@ public final class AssetManager {
|
|||||||
mNumRefs = 0;
|
mNumRefs = 0;
|
||||||
incRefsLocked(this.hashCode());
|
incRefsLocked(this.hashCode());
|
||||||
}
|
}
|
||||||
init();
|
init(false);
|
||||||
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
|
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
|
||||||
ensureSystemAssets();
|
ensureSystemAssets();
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ public final class AssetManager {
|
|||||||
incRefsLocked(this.hashCode());
|
incRefsLocked(this.hashCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
init();
|
init(true);
|
||||||
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
|
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -615,6 +615,16 @@ public final class AssetManager {
|
|||||||
|
|
||||||
private native final int addAssetPathNative(String path);
|
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
|
* Add multiple sets of assets to the asset manager at once. See
|
||||||
* {@link #addAssetPath(String)} for more information. Returns array of
|
* {@link #addAssetPath(String)} for more information. Returns array of
|
||||||
@ -752,7 +762,7 @@ public final class AssetManager {
|
|||||||
private native final int[] getArrayStringInfo(int arrayRes);
|
private native final int[] getArrayStringInfo(int arrayRes);
|
||||||
/*package*/ native final int[] getArrayIntResource(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 native final void destroy();
|
||||||
|
|
||||||
private final void incRefsLocked(long id) {
|
private final void incRefsLocked(long id) {
|
||||||
|
@ -35,7 +35,16 @@
|
|||||||
#include <androidfw/AssetManager.h>
|
#include <androidfw/AssetManager.h>
|
||||||
#include <androidfw/ResourceTypes.h>
|
#include <androidfw/ResourceTypes.h>
|
||||||
|
|
||||||
|
#include <private/android_filesystem_config.h> // for AID_SYSTEM
|
||||||
|
|
||||||
#include <stdio.h>
|
#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 {
|
namespace android {
|
||||||
|
|
||||||
@ -100,6 +109,63 @@ jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
|
|||||||
return block;
|
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
|
// 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;
|
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)
|
static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
|
||||||
{
|
{
|
||||||
AssetManager* am = assetManagerForJavaObject(env, clazz);
|
AssetManager* am = assetManagerForJavaObject(env, clazz);
|
||||||
@ -1579,8 +1664,11 @@ static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, j
|
|||||||
return array;
|
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();
|
AssetManager* am = new AssetManager();
|
||||||
if (am == NULL) {
|
if (am == NULL) {
|
||||||
jniThrowException(env, "java/lang/OutOfMemoryError", "");
|
jniThrowException(env, "java/lang/OutOfMemoryError", "");
|
||||||
@ -1658,6 +1746,8 @@ static JNINativeMethod gAssetManagerMethods[] = {
|
|||||||
(void*) android_content_AssetManager_getAssetRemainingLength },
|
(void*) android_content_AssetManager_getAssetRemainingLength },
|
||||||
{ "addAssetPathNative", "(Ljava/lang/String;)I",
|
{ "addAssetPathNative", "(Ljava/lang/String;)I",
|
||||||
(void*) android_content_AssetManager_addAssetPath },
|
(void*) android_content_AssetManager_addAssetPath },
|
||||||
|
{ "addOverlayPath", "(Ljava/lang/String;)I",
|
||||||
|
(void*) android_content_AssetManager_addOverlayPath },
|
||||||
{ "isUpToDate", "()Z",
|
{ "isUpToDate", "()Z",
|
||||||
(void*) android_content_AssetManager_isUpToDate },
|
(void*) android_content_AssetManager_isUpToDate },
|
||||||
|
|
||||||
@ -1724,7 +1814,7 @@ static JNINativeMethod gAssetManagerMethods[] = {
|
|||||||
(void*) android_content_AssetManager_getArrayIntResource },
|
(void*) android_content_AssetManager_getArrayIntResource },
|
||||||
|
|
||||||
// Bookkeeping.
|
// Bookkeeping.
|
||||||
{ "init", "()V",
|
{ "init", "(Z)V",
|
||||||
(void*) android_content_AssetManager_init },
|
(void*) android_content_AssetManager_init },
|
||||||
{ "destroy", "()V",
|
{ "destroy", "()V",
|
||||||
(void*) android_content_AssetManager_destroy },
|
(void*) android_content_AssetManager_destroy },
|
||||||
|
@ -1777,6 +1777,16 @@
|
|||||||
<attr name="publicKey" />
|
<attr name="publicKey" />
|
||||||
</declare-styleable>
|
</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
|
<!-- Declaration of an {@link android.content.Intent} object in XML. May
|
||||||
also include zero or more {@link #IntentCategory <category> and
|
also include zero or more {@link #IntentCategory <category> and
|
||||||
{@link #Extra <extra>} tags. -->
|
{@link #Extra <extra>} tags. -->
|
||||||
|
@ -70,6 +70,12 @@ struct ResTable_config;
|
|||||||
class AssetManager : public AAssetManager {
|
class AssetManager : public AAssetManager {
|
||||||
public:
|
public:
|
||||||
static const char* RESOURCES_FILENAME;
|
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 {
|
typedef enum CacheMode {
|
||||||
CACHE_UNKNOWN = 0,
|
CACHE_UNKNOWN = 0,
|
||||||
CACHE_OFF, // don't try to cache file locations
|
CACHE_OFF, // don't try to cache file locations
|
||||||
@ -94,6 +100,7 @@ public:
|
|||||||
* newly-added asset source.
|
* newly-added asset source.
|
||||||
*/
|
*/
|
||||||
bool addAssetPath(const String8& path, int32_t* cookie);
|
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
|
* Convenience for adding the standard system assets. Uses the
|
||||||
@ -272,19 +279,14 @@ private:
|
|||||||
void setLocaleLocked(const char* locale);
|
void setLocaleLocked(const char* locale);
|
||||||
void updateResourceParamsLocked() const;
|
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;
|
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 {
|
class SharedZip : public RefBase {
|
||||||
public:
|
public:
|
||||||
static sp<SharedZip> get(const String8& path);
|
static sp<SharedZip> get(const String8& path, bool createIfNotPresent = true);
|
||||||
|
|
||||||
ZipFileRO* getZip();
|
ZipFileRO* getZip();
|
||||||
|
|
||||||
@ -295,6 +297,9 @@ private:
|
|||||||
ResTable* setResourceTable(ResTable* res);
|
ResTable* setResourceTable(ResTable* res);
|
||||||
|
|
||||||
bool isUpToDate();
|
bool isUpToDate();
|
||||||
|
|
||||||
|
void addOverlay(const asset_path& ap);
|
||||||
|
bool getOverlay(size_t idx, asset_path* out) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
~SharedZip();
|
~SharedZip();
|
||||||
@ -310,6 +315,8 @@ private:
|
|||||||
Asset* mResourceTableAsset;
|
Asset* mResourceTableAsset;
|
||||||
ResTable* mResourceTable;
|
ResTable* mResourceTable;
|
||||||
|
|
||||||
|
Vector<asset_path> mOverlays;
|
||||||
|
|
||||||
static Mutex gLock;
|
static Mutex gLock;
|
||||||
static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
|
static DefaultKeyedVector<String8, wp<SharedZip> > gOpen;
|
||||||
};
|
};
|
||||||
@ -342,6 +349,9 @@ private:
|
|||||||
static String8 getPathName(const char* path);
|
static String8 getPathName(const char* path);
|
||||||
|
|
||||||
bool isUpToDate();
|
bool isUpToDate();
|
||||||
|
|
||||||
|
void addOverlay(const String8& path, const asset_path& overlay);
|
||||||
|
bool getOverlay(const String8& path, size_t idx, asset_path* out) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void closeZip(int idx);
|
void closeZip(int idx);
|
||||||
|
@ -1545,39 +1545,21 @@ public:
|
|||||||
// Return value: on success: NO_ERROR; caller is responsible for free-ing
|
// Return value: on success: NO_ERROR; caller is responsible for free-ing
|
||||||
// outData (using free(3)). On failure, any status_t value other than
|
// outData (using free(3)). On failure, any status_t value other than
|
||||||
// NO_ERROR; the caller should not free outData.
|
// 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,
|
status_t createIdmap(const ResTable& overlay,
|
||||||
uint32_t targetCrc, uint32_t overlayCrc,
|
uint32_t targetCrc, uint32_t overlayCrc,
|
||||||
const char* targetPath, const char* overlayPath,
|
const char* targetPath, const char* overlayPath,
|
||||||
void** outData, uint32_t* outSize) const
|
void** outData, uint32_t* outSize) const;
|
||||||
{
|
|
||||||
(void)targetPath;
|
|
||||||
(void)overlayPath;
|
|
||||||
return createIdmap(overlay, targetCrc, overlayCrc, outData, outSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t),
|
IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t) + 2 * 256,
|
||||||
};
|
};
|
||||||
// Retrieve idmap meta-data.
|
// Retrieve idmap meta-data.
|
||||||
//
|
//
|
||||||
// This function only requires the idmap header (the first
|
// This function only requires the idmap header (the first
|
||||||
// IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file.
|
// 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,
|
static bool getIdmapInfo(const void* idmap, size_t size,
|
||||||
uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
|
uint32_t* pTargetCrc, uint32_t* pOverlayCrc,
|
||||||
String8* pTargetPath, String8* pOverlayPath)
|
String8* pTargetPath, String8* pOverlayPath);
|
||||||
{
|
|
||||||
if (*pTargetPath)
|
|
||||||
*pTargetPath = String8();
|
|
||||||
if (*pOverlayPath)
|
|
||||||
*pOverlayPath = String8();
|
|
||||||
return getIdmapInfo(idmap, size, pTargetCrc, pOverlayCrc);
|
|
||||||
}
|
|
||||||
|
|
||||||
void print(bool inclValues) const;
|
void print(bool inclValues) const;
|
||||||
static String8 normalizeForOutput(const char* input);
|
static String8 normalizeForOutput(const char* input);
|
||||||
|
@ -41,10 +41,8 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <string.h> // strerror
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#ifndef TEMP_FAILURE_RETRY
|
#ifndef TEMP_FAILURE_RETRY
|
||||||
/* Used to retry syscalls that can return EINTR. */
|
/* 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* kAssetsRoot = "assets";
|
||||||
static const char* kAppZipName = NULL; //"classes.jar";
|
static const char* kAppZipName = NULL; //"classes.jar";
|
||||||
static const char* kSystemAssets = "framework/framework-res.apk";
|
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";
|
static const char* kExcludeExtension = ".EXCLUDE";
|
||||||
|
|
||||||
@ -84,15 +82,19 @@ static Asset* const kExcludedAsset = (Asset*) 0xd000000d;
|
|||||||
static volatile int32_t gCount = 0;
|
static volatile int32_t gCount = 0;
|
||||||
|
|
||||||
const char* AssetManager::RESOURCES_FILENAME = "resources.arsc";
|
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 {
|
namespace {
|
||||||
// Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
|
|
||||||
String8 idmapPathForPackagePath(const String8& pkgPath)
|
String8 idmapPathForPackagePath(const String8& pkgPath)
|
||||||
{
|
{
|
||||||
const char* root = getenv("ANDROID_DATA");
|
const char* root = getenv("ANDROID_DATA");
|
||||||
LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
|
LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
|
||||||
String8 path(root);
|
String8 path(root);
|
||||||
path.appendPath(kIdmapCacheDir);
|
path.appendPath(kResourceCache);
|
||||||
|
|
||||||
char buf[256]; // 256 chars should be enough for anyone...
|
char buf[256]; // 256 chars should be enough for anyone...
|
||||||
strncpy(buf, pkgPath.string(), 255);
|
strncpy(buf, pkgPath.string(), 255);
|
||||||
@ -210,37 +212,78 @@ bool AssetManager::addAssetPath(const String8& path, int32_t* cookie)
|
|||||||
*cookie = static_cast<int32_t>(mAssetPaths.size());
|
*cookie = static_cast<int32_t>(mAssetPaths.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
// add overlay packages for /system/framework; apps are handled by the
|
#ifdef HAVE_ANDROID_OS
|
||||||
// (Java) package manager
|
// Load overlays, if any
|
||||||
if (strncmp(path.string(), "/system/framework/", 18) == 0) {
|
asset_path oap;
|
||||||
// When there is an environment variable for /vendor, this
|
for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
|
||||||
// should be changed to something similar to how ANDROID_ROOT
|
mAssetPaths.add(oap);
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie)
|
||||||
|
{
|
||||||
|
const String8 idmapPath = idmapPathForPackagePath(packagePath);
|
||||||
|
|
||||||
|
AutoMutex _l(mLock);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < mAssetPaths.size(); ++i) {
|
||||||
|
if (mAssetPaths[i].idmap == idmapPath) {
|
||||||
|
*cookie = static_cast<int32_t>(i + 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Asset* idmap = NULL;
|
||||||
|
if ((idmap = openAssetFromFileLocked(idmapPath, Asset::ACCESS_BUFFER)) == NULL) {
|
||||||
|
ALOGW("failed to open idmap file %s\n", idmapPath.string());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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 (access(targetPath.string(), R_OK) != 0) {
|
||||||
|
ALOGW("failed to access file %s: %s\n", targetPath.string(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (access(idmapPath.string(), R_OK) != 0) {
|
||||||
|
ALOGW("failed to access file %s: %s\n", idmapPath.string(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (access(overlayPath.string(), R_OK) != 0) {
|
||||||
|
ALOGW("failed to access file %s: %s\n", overlayPath.string(), strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 true;
|
||||||
|
}
|
||||||
|
|
||||||
bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath,
|
bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApkPath,
|
||||||
uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, uint32_t* outSize)
|
uint32_t targetCrc, uint32_t overlayCrc, uint32_t** outData, uint32_t* outSize)
|
||||||
{
|
{
|
||||||
@ -257,158 +300,13 @@ bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApk
|
|||||||
ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
|
ALOGW("failed to find resources.arsc in %s\n", ap.path.string());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tables[i].add(ass, (void*)1, false);
|
tables[i].add(ass, 1, false /* copyData */, NULL /* idMap */);
|
||||||
}
|
}
|
||||||
|
|
||||||
return tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
|
return tables[0].createIdmap(tables[1], targetCrc, overlayCrc,
|
||||||
targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
|
targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
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)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t actualOriginalCrc, actualOverlayCrc;
|
|
||||||
if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) {
|
|
||||||
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) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const ZipEntryRO entry = zip->findEntryByName(entryFilename);
|
|
||||||
if (entry == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const bool gotInfo = zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc);
|
|
||||||
zip->releaseEntry(entry);
|
|
||||||
|
|
||||||
return gotInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
|
|
||||||
const String8& idmapPath)
|
|
||||||
{
|
|
||||||
ALOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n",
|
|
||||||
__FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string());
|
|
||||||
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];
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetManager::addDefaultAssets()
|
bool AssetManager::addDefaultAssets()
|
||||||
{
|
{
|
||||||
const char* root = getenv("ANDROID_ROOT");
|
const char* root = getenv("ANDROID_ROOT");
|
||||||
@ -685,6 +583,10 @@ const ResTable* AssetManager::getResTable(bool required) const
|
|||||||
// which we want to avoid parsing every time.
|
// which we want to avoid parsing every time.
|
||||||
sharedRes = const_cast<AssetManager*>(this)->
|
sharedRes = const_cast<AssetManager*>(this)->
|
||||||
mZipSet.getZipResourceTable(ap.path);
|
mZipSet.getZipResourceTable(ap.path);
|
||||||
|
if (sharedRes != NULL) {
|
||||||
|
// skip ahead the number of system overlay packages preloaded
|
||||||
|
i += sharedRes->getTableCount() - 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (sharedRes == NULL) {
|
if (sharedRes == NULL) {
|
||||||
ass = const_cast<AssetManager*>(this)->
|
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());
|
ALOGV("Creating shared resources for %s", ap.path.string());
|
||||||
sharedRes = new ResTable();
|
sharedRes = new ResTable();
|
||||||
sharedRes->add(ass, i + 1, false, idmap);
|
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)->
|
sharedRes = const_cast<AssetManager*>(this)->
|
||||||
mZipSet.setZipResourceTable(ap.path, sharedRes);
|
mZipSet.setZipResourceTable(ap.path, sharedRes);
|
||||||
}
|
}
|
||||||
@ -791,6 +701,46 @@ Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const
|
|||||||
return ass;
|
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& AssetManager::getResources(bool required) const
|
||||||
{
|
{
|
||||||
const ResTable* rt = getResTable(required);
|
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);
|
AutoMutex _l(gLock);
|
||||||
time_t modWhen = getFileModDate(path);
|
time_t modWhen = getFileModDate(path);
|
||||||
@ -1857,6 +1808,9 @@ sp<AssetManager::SharedZip> AssetManager::SharedZip::get(const String8& path)
|
|||||||
if (zip != NULL && zip->mModWhen == modWhen) {
|
if (zip != NULL && zip->mModWhen == modWhen) {
|
||||||
return zip;
|
return zip;
|
||||||
}
|
}
|
||||||
|
if (zip == NULL && !createIfNotPresent) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
zip = new SharedZip(path, modWhen);
|
zip = new SharedZip(path, modWhen);
|
||||||
gOpen.add(path, zip);
|
gOpen.add(path, zip);
|
||||||
return zip;
|
return zip;
|
||||||
@ -1915,6 +1869,20 @@ bool AssetManager::SharedZip::isUpToDate()
|
|||||||
return mModWhen == modWhen;
|
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()
|
AssetManager::SharedZip::~SharedZip()
|
||||||
{
|
{
|
||||||
//ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
|
//ALOGI("Destroying SharedZip %p %s\n", this, (const char*)mPath);
|
||||||
@ -2038,6 +2006,22 @@ bool AssetManager::ZipSet::isUpToDate()
|
|||||||
return true;
|
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.
|
* Compute the zip file's index.
|
||||||
*
|
*
|
||||||
|
@ -284,11 +284,37 @@ static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t
|
|||||||
if (!assertIdmapHeader(map, mapSize)) {
|
if (!assertIdmapHeader(map, mapSize)) {
|
||||||
return UNKNOWN_ERROR;
|
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;
|
const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
|
||||||
|
// find first defined type
|
||||||
while (*p == 0) {
|
while (*p == 0) {
|
||||||
++p;
|
++p;
|
||||||
|
if (--typeCount == 0) {
|
||||||
|
ALOGW("corrupt idmap: types declared, none found\n");
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff;
|
|
||||||
|
// 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[offset] >> 24) & 0x000000ff;
|
||||||
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5334,23 +5360,30 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
|
|||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
|
status_t ResTable::createIdmap(const ResTable& overlay,
|
||||||
void** outData, size_t* outSize) const
|
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
|
// see README for details on the format of map
|
||||||
if (mPackageGroups.size() == 0) {
|
if (mPackageGroups.size() == 0) {
|
||||||
|
ALOGW("idmap: target package has no package groups, cannot create idmap\n");
|
||||||
return UNKNOWN_ERROR;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
if (mPackageGroups[0]->packages.size() == 0) {
|
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;
|
return UNKNOWN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<Vector<uint32_t> > map;
|
Vector<Vector<uint32_t> > map;
|
||||||
|
// overlaid packages are assumed to contain only one package group
|
||||||
const PackageGroup* pg = mPackageGroups[0];
|
const PackageGroup* pg = mPackageGroups[0];
|
||||||
const Package* pkg = pg->packages[0];
|
const Package* pkg = pg->packages[0];
|
||||||
size_t typeCount = pkg->types.size();
|
size_t typeCount = pkg->types.size();
|
||||||
// starting size is header + first item (number of types in map)
|
// starting size is header + first item (number of types in map)
|
||||||
*outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t);
|
*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 String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
|
||||||
const uint32_t pkg_id = pkg->package->id << 24;
|
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;
|
uint32_t* data = (uint32_t*)*outData;
|
||||||
*data++ = htodl(IDMAP_MAGIC);
|
*data++ = htodl(IDMAP_MAGIC);
|
||||||
*data++ = htodl(originalCrc);
|
*data++ = htodl(targetCrc);
|
||||||
*data++ = htodl(overlayCrc);
|
*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();
|
const size_t mapSize = map.size();
|
||||||
*data++ = htodl(mapSize);
|
*data++ = htodl(mapSize);
|
||||||
size_t offset = mapSize;
|
size_t offset = mapSize;
|
||||||
@ -5442,6 +5489,10 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui
|
|||||||
offset += N;
|
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) {
|
for (size_t i = 0; i < mapSize; ++i) {
|
||||||
const Vector<uint32_t>& vector = map.itemAt(i);
|
const Vector<uint32_t>& vector = map.itemAt(i);
|
||||||
const size_t N = vector.size();
|
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,
|
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;
|
const uint32_t* map = (const uint32_t*)idmap;
|
||||||
if (!assertIdmapHeader(map, sizeBytes)) {
|
if (!assertIdmapHeader(map, sizeBytes)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*pOriginalCrc = map[1];
|
if (pTargetCrc) {
|
||||||
*pOverlayCrc = map[2];
|
*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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +211,17 @@ public final class Installer {
|
|||||||
return execute(builder.toString());
|
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) {
|
public int movedex(String srcPath, String dstPath) {
|
||||||
StringBuilder builder = new StringBuilder("movedex");
|
StringBuilder builder = new StringBuilder("movedex");
|
||||||
builder.append(' ');
|
builder.append(' ');
|
||||||
|
@ -217,6 +217,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
static final int SCAN_UPDATE_TIME = 1<<6;
|
static final int SCAN_UPDATE_TIME = 1<<6;
|
||||||
static final int SCAN_DEFER_DEX = 1<<7;
|
static final int SCAN_DEFER_DEX = 1<<7;
|
||||||
static final int SCAN_BOOTING = 1<<8;
|
static final int SCAN_BOOTING = 1<<8;
|
||||||
|
static final int SCAN_TRUSTED_OVERLAY = 1<<9;
|
||||||
|
|
||||||
static final int REMOVE_CHATTY = 1<<16;
|
static final int REMOVE_CHATTY = 1<<16;
|
||||||
|
|
||||||
@ -257,8 +258,13 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
|
|
||||||
private static final String LIB_DIR_NAME = "lib";
|
private static final String LIB_DIR_NAME = "lib";
|
||||||
|
|
||||||
|
private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay";
|
||||||
|
|
||||||
static final String mTempContainerPrefix = "smdl2tmp";
|
static final String mTempContainerPrefix = "smdl2tmp";
|
||||||
|
|
||||||
|
private static final String IDMAP_PREFIX = "/data/resource-cache/";
|
||||||
|
private static final String IDMAP_SUFFIX = "@idmap";
|
||||||
|
|
||||||
final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
|
final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
|
||||||
Process.THREAD_PRIORITY_BACKGROUND);
|
Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
final PackageHandler mHandler;
|
final PackageHandler mHandler;
|
||||||
@ -296,6 +302,9 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
// This is the object monitoring the system app dir.
|
// This is the object monitoring the system app dir.
|
||||||
final FileObserver mVendorInstallObserver;
|
final FileObserver mVendorInstallObserver;
|
||||||
|
|
||||||
|
// This is the object monitoring the vendor overlay package dir.
|
||||||
|
final FileObserver mVendorOverlayInstallObserver;
|
||||||
|
|
||||||
// This is the object monitoring mAppInstallDir.
|
// This is the object monitoring mAppInstallDir.
|
||||||
final FileObserver mAppInstallObserver;
|
final FileObserver mAppInstallObserver;
|
||||||
|
|
||||||
@ -343,6 +352,10 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
final HashMap<String, PackageParser.Package> mPackages =
|
final HashMap<String, PackageParser.Package> mPackages =
|
||||||
new HashMap<String, PackageParser.Package>();
|
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;
|
final Settings mSettings;
|
||||||
boolean mRestoredSettings;
|
boolean mRestoredSettings;
|
||||||
|
|
||||||
@ -1273,6 +1286,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).
|
// Find base frameworks (resource packages without code).
|
||||||
mFrameworkInstallObserver = new AppDirObserver(
|
mFrameworkInstallObserver = new AppDirObserver(
|
||||||
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
|
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);
|
||||||
@ -3475,6 +3499,56 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
return finalList;
|
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) {
|
private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
|
||||||
String[] files = dir.list();
|
String[] files = dir.list();
|
||||||
if (files == null) {
|
if (files == null) {
|
||||||
@ -3572,7 +3646,7 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
pp.setSeparateProcesses(mSeparateProcesses);
|
pp.setSeparateProcesses(mSeparateProcesses);
|
||||||
pp.setOnlyCoreApps(mOnlyCore);
|
pp.setOnlyCoreApps(mOnlyCore);
|
||||||
final PackageParser.Package pkg = pp.parsePackage(scanFile,
|
final PackageParser.Package pkg = pp.parsePackage(scanFile,
|
||||||
scanPath, mMetrics, parseFlags);
|
scanPath, mMetrics, parseFlags, (scanMode & SCAN_TRUSTED_OVERLAY) != 0);
|
||||||
|
|
||||||
if (pkg == null) {
|
if (pkg == null) {
|
||||||
mLastScanError = pp.getParseError();
|
mLastScanError = pp.getParseError();
|
||||||
@ -5081,6 +5155,29 @@ public class PackageManagerService extends IPackageManager.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pkgSetting.setTimeStamp(scanFileTime);
|
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;
|
return pkg;
|
||||||
|
Reference in New Issue
Block a user