resolved conflicts for merge of 4ad93639 to klp-modular-dev-plus-aosp

Change-Id: I7ad222301ec0b863d48a1a9a839469436c385ea0
This commit is contained in:
Nick Kralevich
2014-02-12 11:05:59 -08:00
16 changed files with 550 additions and 234 deletions

View File

@ -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() {

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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
*/

View File

@ -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) {

View File

@ -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 },

View File

@ -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. -->

View File

@ -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);

View File

@ -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);

View File

@ -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.
*

View File

@ -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;
}

View File

@ -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(' ');

View File

@ -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;