resolved conflicts for merge of 4ad93639
to klp-modular-dev-plus-aosp
Change-Id: I7ad222301ec0b863d48a1a9a839469436c385ea0
This commit is contained in:
@ -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() {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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) {
|
||||
|
@ -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 },
|
||||
|
@ -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. -->
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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,37 +212,78 @@ 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::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,
|
||||
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());
|
||||
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,
|
||||
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()
|
||||
{
|
||||
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.
|
||||
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.
|
||||
*
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
*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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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(' ');
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user