From: LuK1337 Date: Tue, 14 Feb 2017 11:57:47 +0000 (+0100) Subject: oms-patches -> vendor/extra X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=efde2c6e560bdd74abc3d791da910f32960669f1;p=GitHub%2FStricted%2Fandroid_vendor_extra.git oms-patches -> vendor/extra Change-Id: Id57eaf3c592bb0d6b888bb38834c04f46a01b596 --- diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) diff --git a/build/0001-OMS-N-adb-shell-command-to-access-OverlayManagerServ.patch b/build/0001-OMS-N-adb-shell-command-to-access-OverlayManagerServ.patch deleted file mode 100644 index 80b0242..0000000 --- a/build/0001-OMS-N-adb-shell-command-to-access-OverlayManagerServ.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 9c60c359e98e9c862411c08e72bb7a1520b736d1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= -Date: Mon, 27 Jul 2015 12:24:40 +0200 -Subject: [PATCH] OMS-N: adb shell command to access OverlayManagerService - -Add a command to communicate with the OverlayManagerService for -debugging purposes. This mirrors the am and pm commands. - -This commit restores the functionality after the Nougat rebase from -Sony. - -Example use: - $ adb shell om list - com.android.systemui - [ ] com.test.awesome-home-button - - $ adb shell om enable com.test.awesome-home-button - - $ adb shell om list - com.android.systemui - [x] com.test.awesome-home-button - -Co-authored-by: Martin Wallgren -Signed-off-by: Zoran Jovanovic -Change-Id: If424b8ef6052e4121902b630279c0ebaf416203c ---- - target/product/base.mk | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/target/product/base.mk b/target/product/base.mk -index dcd48e7..a12f939 100644 ---- a/target/product/base.mk -+++ b/target/product/base.mk -@@ -108,6 +108,7 @@ PRODUCT_PACKAGES += \ - mtpd \ - ndc \ - netd \ -+ om \ - ping \ - ping6 \ - platform.xml \ --- -2.9.3 - diff --git a/extra.xml b/extra.xml new file mode 100644 index 0000000..edf9f07 --- /dev/null +++ b/extra.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/frameworks/base/0001-OMS7-N-Support-tagging-resources-as-OK-to-overlay-1-.patch b/frameworks/base/0001-OMS7-N-Support-tagging-resources-as-OK-to-overlay-1-.patch deleted file mode 100644 index 342173e..0000000 --- a/frameworks/base/0001-OMS7-N-Support-tagging-resources-as-OK-to-overlay-1-.patch +++ /dev/null @@ -1,474 +0,0 @@ -From 75d5463e848764c3255c32d126415faceca62023 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= -Date: Tue, 15 Dec 2015 16:08:31 +0100 -Subject: [PATCH 01/38] OMS7-N: Support tagging resources as OK to overlay - [1/11] - -This will allow applications to have a resource xml defining what -resources that are safe to overlay by third party overlay packages. -The format of the tag is and it will -result in the FLAG_OVELAY being set on the resource entry. - -An overlay package with resources that are not tagged as OK -to overlay by the target application, is considered to be a dangerous -overlay. - -Idmaps generated for dangerous overlays will be flagged as dangerous in -the idmap header. It is still possible to use both idmap and overlays that -are dangerous, but it might not be advisable. - -The intention is to allow dangerous overlays to be used if -they are pre-installed or if the signature of the overlay package -matches the signature of the target package. - -Change-Id: I08d11de845c1679017798ea1636ef4c36f820d8e ---- - cmds/idmap/create.cpp | 2 +- - cmds/idmap/inspect.cpp | 6 +++ - include/androidfw/ResourceTypes.h | 10 ++-- - libs/androidfw/AssetManager.cpp | 2 +- - libs/androidfw/ResourceTypes.cpp | 27 ++++++++--- - tools/aapt/ResourceTable.cpp | 96 ++++++++++++++++++++++++++++++++++++++- - tools/aapt/ResourceTable.h | 36 ++++++++++++++- - 7 files changed, 164 insertions(+), 15 deletions(-) - -diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp -index c13d318..8656b0e 100644 ---- a/cmds/idmap/create.cpp -+++ b/cmds/idmap/create.cpp -@@ -106,7 +106,7 @@ fail: - - uint32_t cached_target_crc, cached_overlay_crc; - String8 cached_target_path, cached_overlay_path; -- if (!ResTable::getIdmapInfo(buf, N, NULL, &cached_target_crc, &cached_overlay_crc, -+ if (!ResTable::getIdmapInfo(buf, N, NULL, NULL, &cached_target_crc, &cached_overlay_crc, - &cached_target_path, &cached_overlay_path)) { - return true; - } -diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp -index f6afc85..924090f 100644 ---- a/cmds/idmap/inspect.cpp -+++ b/cmds/idmap/inspect.cpp -@@ -192,6 +192,12 @@ namespace { - if (err != NO_ERROR) { - return err; - } -+ print("", "dangerous", i, ""); -+ -+ err = buf.nextUint32(&i); -+ if (err != NO_ERROR) { -+ return err; -+ } - print("", "base crc", i, ""); - - err = buf.nextUint32(&i); -diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h -index 12a6b0f..6094a57 100644 ---- a/include/androidfw/ResourceTypes.h -+++ b/include/androidfw/ResourceTypes.h -@@ -1382,7 +1382,11 @@ struct ResTable_entry - // If set, this is a weak resource and may be overriden by strong - // resources of the same name/type. This is only useful during - // linking with other resource tables. -- FLAG_WEAK = 0x0004 -+ FLAG_WEAK = 0x0004, -+ // If set, this resource has been declared OK to overlay, so overlay -+ // packages may be added to the resource table to provide alternative -+ // resource values. -+ FLAG_OVERLAY = 0x0008, - }; - uint16_t flags; - -@@ -1861,14 +1865,14 @@ public: - const char* targetPath, const char* overlayPath, - void** outData, size_t* outSize) const; - -- static const size_t IDMAP_HEADER_SIZE_BYTES = 4 * sizeof(uint32_t) + 2 * 256; -+ static const size_t IDMAP_HEADER_SIZE_BYTES = 5 * 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* pVersion, -+ uint32_t* pVersion, uint32_t* pDangerous, - uint32_t* pTargetCrc, uint32_t* pOverlayCrc, - String8* pTargetPath, String8* pOverlayPath); - -diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp -index fdd0caf..edc625b 100644 ---- a/libs/androidfw/AssetManager.cpp -+++ b/libs/androidfw/AssetManager.cpp -@@ -252,7 +252,7 @@ bool AssetManager::addOverlayPath(const String8& packagePath, int32_t* cookie) - String8 targetPath; - String8 overlayPath; - if (!ResTable::getIdmapInfo(idmap->getBuffer(false), idmap->getLength(), -- NULL, NULL, NULL, &targetPath, &overlayPath)) { -+ NULL, NULL, NULL, NULL, &targetPath, &overlayPath)) { - ALOGW("failed to read idmap file %s\n", idmapPath.string()); - delete idmap; - return false; -diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp -index e8c6fcf..022f19e 100644 ---- a/libs/androidfw/ResourceTypes.cpp -+++ b/libs/androidfw/ResourceTypes.cpp -@@ -59,7 +59,7 @@ namespace android { - #endif - - #define IDMAP_MAGIC 0x504D4449 --#define IDMAP_CURRENT_VERSION 0x00000001 -+#define IDMAP_CURRENT_VERSION 0x00000002 - - #define APP_PACKAGE_ID 0x7f - #define CMSDK_PACKAGE_ID 0x3f -@@ -6601,6 +6601,7 @@ status_t ResTable::createIdmap(const ResTable& overlay, - return UNKNOWN_ERROR; - } - -+ bool isDangerous = false; - KeyedVector map; - - // overlaid packages are assumed to contain only one package group -@@ -6675,6 +6676,13 @@ status_t ResTable::createIdmap(const ResTable& overlay, - } - } - typeMap.entryMap.add(Res_GETENTRY(overlayResID)); -+ -+ Entry entry; -+ if (getEntry(pg, typeIndex, entryIndex, NULL, &entry)) { -+ return UNKNOWN_ERROR; -+ } -+ isDangerous = isDangerous || -+ ((dtohs(entry.entry->flags) & ResTable_entry::FLAG_OVERLAY) == 0); - } - - if (!typeMap.entryMap.isEmpty()) { -@@ -6697,6 +6705,7 @@ status_t ResTable::createIdmap(const ResTable& overlay, - uint32_t* data = (uint32_t*)*outData; - *data++ = htodl(IDMAP_MAGIC); - *data++ = htodl(IDMAP_CURRENT_VERSION); -+ *data++ = htodl(isDangerous ? 1 : 0); - *data++ = htodl(targetCrc); - *data++ = htodl(overlayCrc); - const char* paths[] = { targetPath, overlayPath }; -@@ -6737,7 +6746,7 @@ status_t ResTable::createIdmap(const ResTable& overlay, - } - - bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes, -- uint32_t* pVersion, -+ uint32_t* pVersion, uint32_t* pDangerous, - uint32_t* pTargetCrc, uint32_t* pOverlayCrc, - String8* pTargetPath, String8* pOverlayPath) - { -@@ -6748,17 +6757,20 @@ bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes, - if (pVersion) { - *pVersion = dtohl(map[1]); - } -+ if (pDangerous) { -+ *pDangerous = dtohl(map[2]); -+ } - if (pTargetCrc) { -- *pTargetCrc = dtohl(map[2]); -+ *pTargetCrc = dtohl(map[3]); - } - if (pOverlayCrc) { -- *pOverlayCrc = dtohl(map[3]); -+ *pOverlayCrc = dtohl(map[4]); - } - if (pTargetPath) { -- pTargetPath->setTo(reinterpret_cast(map + 4)); -+ pTargetPath->setTo(reinterpret_cast(map + 5)); - } - if (pOverlayPath) { -- pOverlayPath->setTo(reinterpret_cast(map + 4 + 256 / sizeof(uint32_t))); -+ pOverlayPath->setTo(reinterpret_cast(map + 5 + 256 / sizeof(uint32_t))); - } - return true; - } -@@ -7085,6 +7097,9 @@ void ResTable::print(bool inclValues) const - if ((dtohs(ent->flags)&ResTable_entry::FLAG_PUBLIC) != 0) { - printf(" (PUBLIC)"); - } -+ if ((dtohs(ent->flags)&ResTable_entry::FLAG_OVERLAY) != 0) { -+ printf(" (OVERLAY)"); -+ } - printf("\n"); - - if (inclValues) { -diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp -index a1b1879..b2d0480 100644 ---- a/tools/aapt/ResourceTable.cpp -+++ b/tools/aapt/ResourceTable.cpp -@@ -800,6 +800,7 @@ status_t compileResourceFile(Bundle* bundle, - const String16 string_array16("string-array"); - const String16 integer_array16("integer-array"); - const String16 public16("public"); -+ const String16 overlay16("overlay"); - const String16 public_padding16("public-padding"); - const String16 private_symbols16("private-symbols"); - const String16 java_symbol16("java-symbol"); -@@ -1003,6 +1004,41 @@ status_t compileResourceFile(Bundle* bundle, - } - continue; - -+ } else if (strcmp16(block.getElementName(&len), overlay16.string()) == 0) { -+ SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); -+ -+ String16 type; -+ const ssize_t typeIdx = block.indexOfAttribute(NULL, "type"); -+ if (typeIdx < 0) { -+ srcPos.error("A 'type' attribute is required for \n"); -+ hasErrors = localHasErrors = true; -+ } -+ type = String16(block.getAttributeStringValue(typeIdx, &len)); -+ -+ String16 name; -+ const ssize_t nameIdx = block.indexOfAttribute(NULL, "name"); -+ if (nameIdx < 0) { -+ srcPos.error("A 'name' attribute is required for \n"); -+ hasErrors = localHasErrors = true; -+ } -+ name = String16(block.getAttributeStringValue(nameIdx, &len)); -+ -+ if (!localHasErrors) { -+ err = outTable->addOverlay(srcPos, myPackage, type, name); -+ if (err < NO_ERROR) { -+ hasErrors = localHasErrors = true; -+ } -+ } -+ -+ while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { -+ if (code == ResXMLTree::END_TAG) { -+ if (strcmp16(block.getElementName(&len), overlay16.string()) == 0) { -+ break; -+ } -+ } -+ } -+ continue; -+ - } else if (strcmp16(block.getElementName(&len), public_padding16.string()) == 0) { - SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); - -@@ -1865,6 +1901,29 @@ status_t ResourceTable::addPublic(const SourcePos& sourcePos, - return t->addPublic(sourcePos, name, ident); - } - -+status_t ResourceTable::addOverlay(const SourcePos& sourcePos, -+ const String16& package, -+ const String16& type, -+ const String16& name) -+{ -+ uint32_t rid = mAssets->getIncludedResources() -+ .identifierForName(name.string(), name.size(), -+ type.string(), type.size(), -+ package.string(), package.size()); -+ if (rid != 0) { -+ sourcePos.error("Error declaring overlay resource %s/%s for included package %s\n", -+ String8(type).string(), String8(name).string(), -+ String8(package).string()); -+ return UNKNOWN_ERROR; -+ } -+ -+ sp t = getType(package, type, sourcePos); -+ if (t == NULL) { -+ return UNKNOWN_ERROR; -+ } -+ return t->addOverlay(sourcePos, name); -+} -+ - status_t ResourceTable::addEntry(const SourcePos& sourcePos, - const String16& package, - const String16& type, -@@ -2665,6 +2724,11 @@ status_t ResourceTable::assignResourceIds() - firstError = err; - } - -+ err = t->applyOverlay(); -+ if (err != NO_ERROR && firstError == NO_ERROR) { -+ firstError = err; -+ } -+ - const size_t N = t->getOrderedConfigs().size(); - t->setIndex(ti + 1 + typeIdOffset); - -@@ -3254,7 +3318,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp& - index[ei] = htodl(data->getSize()-typeStart-typeSize); - - // Create the entry. -- ssize_t amt = e->flatten(bundle, data, cl->getPublic()); -+ ssize_t amt = e->flatten(bundle, data, cl->getPublic(), cl->getOverlay()); - if (amt < 0) { - return amt; - } -@@ -3759,7 +3823,8 @@ status_t ResourceTable::Entry::remapStringValue(StringPool* strings) - return NO_ERROR; - } - --ssize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp& data, bool isPublic) -+ssize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp& data, bool isPublic, -+ bool isOverlay) - { - size_t amt = 0; - ResTable_entry header; -@@ -3772,6 +3837,9 @@ ssize_t ResourceTable::Entry::flatten(Bundle* /* bundle */, const sp& - if (isPublic) { - header.flags |= htods(header.FLAG_PUBLIC); - } -+ if (isOverlay) { -+ header.flags |= htods(header.FLAG_OVERLAY); -+ } - header.key.index = htodl(mNameIndex); - if (ty != TYPE_BAG) { - status_t err = data->writeData(&header, sizeof(header)); -@@ -3912,6 +3980,13 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos, - return NO_ERROR; - } - -+status_t ResourceTable::Type::addOverlay(const SourcePos& sourcePos, -+ const String16& name) -+{ -+ mOverlay.add(name, Overlay(sourcePos, String16())); -+ return NO_ERROR; -+} -+ - void ResourceTable::Type::canAddEntry(const String16& name) - { - mCanAddEntries.add(name); -@@ -4014,6 +4089,7 @@ sp ResourceTable::Type::removeEntry(const String16& e - } - - mPublic.removeItem(entry); -+ mOverlay.removeItem(entry); - return removed; - } - -@@ -4115,6 +4191,22 @@ status_t ResourceTable::Type::applyPublicEntryOrder() - return hasError ? STATUST(UNKNOWN_ERROR) : NO_ERROR; - } - -+status_t ResourceTable::Type::applyOverlay() { -+ const size_t N = mOverlay.size(); -+ const size_t M = mOrderedConfigs.size(); -+ for (size_t i = 0; i < N; i++) { -+ const String16& name = mOverlay.keyAt(i); -+ for (size_t j = 0; j < M; j++) { -+ sp e = mOrderedConfigs.itemAt(j); -+ if (e->getName() == name) { -+ e->setOverlay(true); -+ break; -+ } -+ } -+ } -+ return NO_ERROR; -+} -+ - ResourceTable::Package::Package(const String16& name, size_t packageId) - : mName(name), mPackageId(packageId), - mTypeStringsMapping(0xffffffff), -diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h -index 54d56cf..7e9b044 100644 ---- a/tools/aapt/ResourceTable.h -+++ b/tools/aapt/ResourceTable.h -@@ -139,6 +139,11 @@ public: - const String16& name, - const uint32_t ident); - -+ status_t addOverlay(const SourcePos& pos, -+ const String16& package, -+ const String16& type, -+ const String16& name); -+ - status_t addEntry(const SourcePos& pos, - const String16& package, - const String16& type, -@@ -388,7 +393,7 @@ public: - - status_t remapStringValue(StringPool* strings); - -- ssize_t flatten(Bundle*, const sp& data, bool isPublic); -+ ssize_t flatten(Bundle*, const sp& data, bool isPublic, bool isOverlay); - - const SourcePos& getPos() const { return mPos; } - -@@ -407,7 +412,7 @@ public: - class ConfigList : public RefBase { - public: - ConfigList(const String16& name, const SourcePos& pos) -- : mName(name), mPos(pos), mPublic(false), mEntryIndex(-1) { } -+ : mName(name), mPos(pos), mPublic(false), mOverlay(false), mEntryIndex(-1) { } - virtual ~ConfigList() { } - - String16 getName() const { return mName; } -@@ -427,6 +432,9 @@ public: - bool getPublic() const { return mPublic; } - void setPublicSourcePos(const SourcePos& pos) { mPublicSourcePos = pos; } - const SourcePos& getPublicSourcePos() { return mPublicSourcePos; } -+ -+ void setOverlay(bool o) { mOverlay = o; } -+ bool getOverlay() const { return mOverlay; } - - void addEntry(const ResTable_config& config, const sp& entry) { - mEntries.add(config, entry); -@@ -440,6 +448,7 @@ public: - String16 mTypeComment; - bool mPublic; - SourcePos mPublicSourcePos; -+ bool mOverlay; - int32_t mEntryIndex; - DefaultKeyedVector > mEntries; - }; -@@ -467,6 +476,24 @@ public: - String16 comment; - uint32_t ident; - }; -+ -+ class Overlay { -+ public: -+ Overlay() : sourcePos() { } -+ Overlay(const SourcePos& pos, const String16& _comment) -+ : sourcePos(pos), comment(_comment) { } -+ Overlay(const Overlay& o) : sourcePos(o.sourcePos), comment(o.comment) { } -+ ~Overlay() { } -+ -+ Overlay& operator=(const Overlay& o) { -+ sourcePos = o.sourcePos; -+ comment = o.comment; -+ return *this; -+ } -+ -+ SourcePos sourcePos; -+ String16 comment; -+ }; - - class Type : public RefBase { - public: -@@ -478,6 +505,9 @@ public: - status_t addPublic(const SourcePos& pos, - const String16& name, - const uint32_t ident); -+ -+ status_t addOverlay(const SourcePos& pos, -+ const String16& name); - - void canAddEntry(const String16& name); - -@@ -505,6 +535,7 @@ public: - void setIndex(int32_t index) { mIndex = index; } - - status_t applyPublicEntryOrder(); -+ status_t applyOverlay(); - - const DefaultKeyedVector >& getConfigs() const { return mConfigs; } - const Vector >& getOrderedConfigs() const { return mOrderedConfigs; } -@@ -516,6 +547,7 @@ public: - String16 mName; - SourcePos* mFirstPublicSourcePos; - DefaultKeyedVector mPublic; -+ DefaultKeyedVector mOverlay; - DefaultKeyedVector > mConfigs; - Vector > mOrderedConfigs; - SortedVector mCanAddEntries; --- -2.9.3 - diff --git a/frameworks/base/0002-OMS7-N-Introduce-the-OverlayManagerService-2-11.patch b/frameworks/base/0002-OMS7-N-Introduce-the-OverlayManagerService-2-11.patch deleted file mode 100644 index 919e42c..0000000 --- a/frameworks/base/0002-OMS7-N-Introduce-the-OverlayManagerService-2-11.patch +++ /dev/null @@ -1,3082 +0,0 @@ -From 90815d5667efdc258011508a5599a45bd3d66756 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= -Date: Tue, 15 Dec 2015 16:40:23 +0100 -Subject: [PATCH 02/38] OMS7-N: Introduce the OverlayManagerService [2/11] - -Add a new system service to manage Runtime Resource Overlays. This will -offload the PackageManagerService and allow administration of overlay -packages while affected packages continue to execute. - -Overlays can be enabled or disabled during runtime. To the running -application the change is invisible. Technically, the overlay is added -or removed from the running application similarly to how multi-window -affects resources. - -Before an overlay can be enabled it has to be approved. This happens -during package installation or upgrade and if an error occurs, the -overlay is marked as not approved. - -The system performs the following security checks, in -the order listed, to determine if an overlay can be approved: - - 1. Is the overlay package pre-installed? If yes, OK to use. - - 2. Are the target and overlay packages signed with the same - certificate? If yes, OK to use. - - 3. Is the overlay dangerous? If no, OK to use. - -An overlay is said to be dangerous if it modifies resources not -explicitly specified by the target as OK to overlay. (This is done by -adding tags to the target's resources.) - -The decision to approve/not approve an overlay is not re-evaluated until -the next time either the overlay or its target package is changed. - -The order in which a set of overlays is loaded may also be changed -during runtime. The underlying mechanics are the same as for when an -overlay is enabled or disabled. - -When an overlay changes state, e.g. becomes enabled, the -OverlayManagerService will broadcast one of the new intents -android.intent.action.OVERLAY_ADDED, *_CHANGED, *_REMOVED or -*.OVERLAYS_REORDERED. - -Clients that wish to read information about overlays for users other -than themselves are required to hold the -android.permission.INTERACT_ACROSS_USERS_FULL permission. This mirrors -the protection level of PackageManager.getPackageInfo. - -Clients that wish to change the information are required to -hold the permission android.permission.CHANGE_CONFIGURATION. - -Each pair of overlay package and corresponding target package is -respresented by a new OverlayInfo class. This class mirrors the -existing PackageInfo class. - -Overlay packages are handled per Android user. The data is persisted in -/data/system/overlays.xml. - -Change-Id: Icc3c7daa25345d20bc5014b865024422eab72f5b ---- - Android.mk | 1 + - core/java/android/content/Context.java | 10 + - core/java/android/content/Intent.java | 34 + - core/java/android/content/om/IOverlayManager.aidl | 129 +++ - core/java/android/content/om/OverlayInfo.aidl | 19 + - core/java/android/content/om/OverlayInfo.java | 290 +++++++ - .../android/content/pm/PackageManagerInternal.java | 24 + - core/res/AndroidManifest.xml | 4 + - .../java/com/android/server/om/IdmapManager.java | 116 +++ - .../android/server/om/OverlayManagerService.java | 901 +++++++++++++++++++++ - .../server/om/OverlayManagerServiceImpl.java | 478 +++++++++++ - .../android/server/om/OverlayManagerSettings.java | 656 +++++++++++++++ - .../server/om/OverlayManagerShellCommand.java | 179 ++++ - .../android/server/pm/PackageManagerService.java | 41 + - 14 files changed, 2882 insertions(+) - create mode 100644 core/java/android/content/om/IOverlayManager.aidl - create mode 100644 core/java/android/content/om/OverlayInfo.aidl - create mode 100644 core/java/android/content/om/OverlayInfo.java - create mode 100644 services/core/java/com/android/server/om/IdmapManager.java - create mode 100644 services/core/java/com/android/server/om/OverlayManagerService.java - create mode 100644 services/core/java/com/android/server/om/OverlayManagerServiceImpl.java - create mode 100644 services/core/java/com/android/server/om/OverlayManagerSettings.java - create mode 100644 services/core/java/com/android/server/om/OverlayManagerShellCommand.java - -diff --git a/Android.mk b/Android.mk -index bdb4555..df42780 100644 ---- a/Android.mk -+++ b/Android.mk -@@ -137,6 +137,7 @@ LOCAL_SRC_FILES += \ - core/java/android/content/ISyncContext.aidl \ - core/java/android/content/ISyncServiceAdapter.aidl \ - core/java/android/content/ISyncStatusObserver.aidl \ -+ core/java/android/content/om/IOverlayManager.aidl \ - core/java/android/content/pm/ILauncherApps.aidl \ - core/java/android/content/pm/IOnAppsChangedListener.aidl \ - core/java/android/content/pm/IOtaDexopt.aidl \ -diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java -index 3a2f471..1ca44e0 100644 ---- a/core/java/android/content/Context.java -+++ b/core/java/android/content/Context.java -@@ -3656,6 +3656,16 @@ public abstract class Context { - public static final String GATEKEEPER_SERVICE = "android.service.gatekeeper.IGateKeeperService"; - - /** -+ * Use with {@link #getSystemService} to retrieve a {@link -+ * android.content.om.OverlayManager} for managing overlay packages. -+ * -+ * @see #getSystemService -+ * @see android.content.om.OverlayManager -+ * @hide -+ */ -+ public static final String OVERLAY_SERVICE = "overlay"; -+ -+ /** - * Determine whether the given permission is allowed for a particular - * process and user ID running in the system. - * -diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java -index 861aae5..1afae79 100644 ---- a/core/java/android/content/Intent.java -+++ b/core/java/android/content/Intent.java -@@ -3092,6 +3092,40 @@ public class Intent implements Parcelable, Cloneable { - "android.intent.action.MEDIA_RESOURCE_GRANTED"; - - /** -+ * Broadcast Action: An overlay package has been installed. The data -+ * contains the name of the added overlay package. -+ * @hide -+ */ -+ public static final String ACTION_OVERLAY_ADDED = "android.intent.action.OVERLAY_ADDED"; -+ -+ /** -+ * Broadcast Action: An overlay package has changed. The data contains the -+ * name of the overlay package which has changed. This is broadcast on all -+ * changes to the OverlayInfo returned by {@link -+ * android.content.om.IOverlayManager#getOverlayInfo(String, int)}. The -+ * most common change is a state change that will change whether the -+ * overlay is enabled or not. -+ * @hide -+ */ -+ public static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED"; -+ -+ /** -+ * Broadcast Action: An overlay package has been removed. The data contains -+ * the name of the overlay package which has been removed. -+ * @hide -+ */ -+ public static final String ACTION_OVERLAY_REMOVED = "android.intent.action.OVERLAY_REMOVED"; -+ -+ /** -+ * Broadcast Action: The order of a package's list of overlay packages has -+ * changed. The data contains the package name of the overlay package that -+ * had its position in the list adjusted. -+ * @hide -+ */ -+ public static final String -+ ACTION_OVERLAY_PRIORITY_CHANGED = "android.intent.action.OVERLAY_PRIORITY_CHANGED"; -+ -+ /** - * Activity Action: Allow the user to select and return one or more existing - * documents. When invoked, the system will display the various - * {@link DocumentsProvider} instances installed on the device, letting the -diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl -new file mode 100644 -index 0000000..4f5d960 ---- /dev/null -+++ b/core/java/android/content/om/IOverlayManager.aidl -@@ -0,0 +1,129 @@ -+/* -+ * Copyright (C) 2015 The Android Open Source Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package android.content.om; -+ -+import android.content.om.OverlayInfo; -+ -+/** -+ * Api for getting information about overlay packages. -+ * -+ * {@hide} -+ */ -+interface IOverlayManager { -+ /** -+ * Returns information about all installed overlay packages for the -+ * specified user. If there are no installed overlay packages for this user, -+ * an empty map is returned (i.e. null is never returned). The returned map is a -+ * mapping of target package names to lists of overlays. Each list for a -+ * given target package is sorted in priority order, with the overlay with -+ * the highest priority at the end of the list. -+ * -+ * @param userId The user to get the OverlayInfos for. -+ * @return A Map> with target package names -+ * mapped to lists of overlays; if no overlays exist for the -+ * requested user, an empty map is returned. -+ */ -+ Map getAllOverlays(in int userId); -+ -+ /** -+ * Returns information about all overlays for the given target package for -+ * the specified user. The returned list is ordered according to the -+ * overlay priority with the highest priority at the end of the list. -+ * -+ * @param targetPackageName The name of the target package. -+ * @param userId The user to get the OverlayInfos for. -+ * @return A list of OverlayInfo objects; if no overlays exist for the -+ * requested package, an empty list is returned. -+ */ -+ List getOverlayInfosForTarget(in String targetPackageName, in int userId); -+ -+ /** -+ * Returns information about the overlay with the given package name for the -+ * specified user. -+ * -+ * @param packageName The name of the overlay package. -+ * @param userId The user to get the OverlayInfo for. -+ * @return The OverlayInfo for the overlay package; or null if no such -+ * overlay package exists. -+ */ -+ OverlayInfo getOverlayInfo(in String packageName, in int userId); -+ -+ /** -+ * Request that an overlay package be enabled or disabled when possible to -+ * do so. -+ * -+ * It is always possible to disable an overlay, but due to technical and -+ * security reasons it may not always be possible to enable an overlay. An -+ * example of the latter is when the related target package is not -+ * installed. If the technical obstacle is later overcome, the overlay is -+ * automatically enabled at that point in time. -+ * -+ * An enabled overlay is a part of target package's resources, i.e. it will -+ * be part of any lookups performed via {@link android.content.res.Resources} -+ * and {@link android.content.res.AssetManager}. A disabled overlay will no -+ * longer affect the resources of the target package. If the target is -+ * currently running, its outdated resources will be replaced by new ones. -+ * This happens the same way as when an application enters or exits split -+ * window mode. -+ * -+ * @param packageName The name of the overlay package. -+ * @param enable true to enable the overlay, false to disable it. -+ * @param userId The user for which to change the overlay. -+ * @return true if the system successfully registered the request, false -+ * otherwise. -+ */ -+ boolean setEnabled(in String packageName, in boolean enable, in int userId); -+ -+ /** -+ * Change the priority of the given overlay to be just higher than the -+ * overlay with package name newParentPackageName. Both overlay packages -+ * must have the same target and user. -+ * -+ * @see getOverlayInfosForTarget -+ * -+ * @param packageName The name of the overlay package whose priority should -+ * be adjusted. -+ * @param newParentPackageName The name of the overlay package the newly -+ * adjusted overlay package should just outrank. -+ * @param userId The user for which to change the overlay. -+ */ -+ boolean setPriority(in String packageName, in String newParentPackageName, in int userId); -+ -+ /** -+ * Change the priority of the given overlay to the highest priority relative to -+ * the other overlays with the same target and user. -+ * -+ * @see getOverlayInfosForTarget -+ * -+ * @param packageName The name of the overlay package whose priority should -+ * be adjusted. -+ * @param userId The user for which to change the overlay. -+ */ -+ boolean setHighestPriority(in String packageName, in int userId); -+ -+ /** -+ * Change the priority of the overlay to the lowest priority relative to -+ * the other overlays for the same target and user. -+ * -+ * @see getOverlayInfosForTarget -+ * -+ * @param packageName The name of the overlay package whose priority should -+ * be adjusted. -+ * @param userId The user for which to change the overlay. -+ */ -+ boolean setLowestPriority(in String packageName, in int userId); -+} -diff --git a/core/java/android/content/om/OverlayInfo.aidl b/core/java/android/content/om/OverlayInfo.aidl -new file mode 100644 -index 0000000..e7d413d ---- /dev/null -+++ b/core/java/android/content/om/OverlayInfo.aidl -@@ -0,0 +1,19 @@ -+/* -+ * Copyright (C) 2015 The Android Open Source Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package android.content.om; -+ -+parcelable OverlayInfo; -diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java -new file mode 100644 -index 0000000..a25cf0c ---- /dev/null -+++ b/core/java/android/content/om/OverlayInfo.java -@@ -0,0 +1,290 @@ -+/* -+ * Copyright (C) 2015 The Android Open Source Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package android.content.om; -+ -+import android.annotation.NonNull; -+import android.os.Parcel; -+import android.os.Parcelable; -+ -+/** -+ * Immutable overlay information about a package. All PackageInfos that -+ * represent an overlay package will have a corresponding OverlayInfo. -+ * -+ * @hide -+ */ -+public final class OverlayInfo implements Parcelable { -+ /** -+ * An internal state used as the initial state of an overlay. OverlayInfo -+ * objects exposed outside the {@link -+ * com.android.server.om.OverlayManagerService} should never have this -+ * state. -+ */ -+ public static final int STATE_NOT_APPROVED_UNKNOWN = -1; -+ -+ /** -+ * The overlay package is disabled by the PackageManager. -+ */ -+ public static final int STATE_NOT_APPROVED_COMPONENT_DISABLED = 0; -+ -+ /** -+ * The target package of the overlay is not installed. -+ */ -+ public static final int STATE_NOT_APPROVED_MISSING_TARGET = 1; -+ -+ /** -+ * Creation of idmap file failed (e.g. no matching resources). -+ */ -+ public static final int STATE_NOT_APPROVED_NO_IDMAP = 2; -+ -+ /** -+ * The overlay package is dangerous, i.e. it touches resources not explicitly -+ * OK'd by the target package. -+ */ -+ public static final int STATE_NOT_APPROVED_DANGEROUS_OVERLAY = 3; -+ -+ /** -+ * The OverlayInfo is currently disabled but it is allowed to be enabled -+ * ({@link #STATE_APPROVED_ENABLED}) in the future. -+ */ -+ public static final int STATE_APPROVED_DISABLED = 4; -+ -+ /** -+ * The OverlayInfo is enabled but can be disabled -+ * ({@link #STATE_APPROVED_DISABLED}) in the future. -+ */ -+ public static final int STATE_APPROVED_ENABLED = 5; -+ -+ /** -+ * Package name of the overlay package -+ */ -+ public final String packageName; -+ -+ /** -+ * Package name of the target package -+ */ -+ public final String targetPackageName; -+ -+ /** -+ * Full path to the base APK for this overlay package -+ */ -+ public final String baseCodePath; -+ -+ /** -+ * The state of this OverlayInfo as defined by the STATE_* constants in this class. -+ *

-+ * The state of an OverlayInfo determines if it is approved and/or enabled. An OverlayInfo with -+ * one of the STATE_NOT_APPROVED_* states cannot be enabled, and can thus never be part of the -+ * best match in the resource lookup. -+ *

-+ * The only way to get an overlay package to be active and be part of the best matching in the -+ * resource lookup is if the corresponding OverlayInfo is in an STATE_*_ENABLED state. -+ * -+ * @see #STATE_NOT_APPROVED_COMPONENT_DISABLED -+ * @see #STATE_NOT_APPROVED_MISSING_TARGET -+ * @see #STATE_NOT_APPROVED_NO_IDMAP -+ * @see #STATE_NOT_APPROVED_DANGEROUS_OVERLAY -+ * @see #STATE_APPROVED_DISABLED -+ * @see #STATE_APPROVED_ENABLED -+ */ -+ public final int state; -+ -+ /** -+ * User handle for which this overlay applies -+ */ -+ public final int userId; -+ -+ /** -+ * Create a new OverlayInfo based on source with an updated state. -+ * -+ * @param source the source OverlayInfo to base the new instance on -+ * @param state the new state for the source OverlayInfo -+ */ -+ public OverlayInfo(@NonNull OverlayInfo source, int state) { -+ this(source.packageName, source.targetPackageName, source.baseCodePath, state, -+ source.userId); -+ } -+ -+ public OverlayInfo(@NonNull String packageName, @NonNull String targetPackageName, -+ @NonNull String baseCodePath, int state, int userId) { -+ this.packageName = packageName; -+ this.targetPackageName = targetPackageName; -+ this.baseCodePath = baseCodePath; -+ this.state = state; -+ this.userId = userId; -+ ensureValidState(); -+ } -+ -+ public OverlayInfo(Parcel source) { -+ packageName = source.readString(); -+ targetPackageName = source.readString(); -+ baseCodePath = source.readString(); -+ state = source.readInt(); -+ userId = source.readInt(); -+ ensureValidState(); -+ } -+ -+ private void ensureValidState() { -+ if (packageName == null) { -+ throw new IllegalArgumentException("packageName must not be null"); -+ } -+ if (targetPackageName == null) { -+ throw new IllegalArgumentException("targetPackageName must not be null"); -+ } -+ if (baseCodePath == null) { -+ throw new IllegalArgumentException("baseCodePath must not be null"); -+ } -+ switch (state) { -+ case STATE_NOT_APPROVED_UNKNOWN: -+ case STATE_NOT_APPROVED_COMPONENT_DISABLED: -+ case STATE_NOT_APPROVED_MISSING_TARGET: -+ case STATE_NOT_APPROVED_NO_IDMAP: -+ case STATE_NOT_APPROVED_DANGEROUS_OVERLAY: -+ case STATE_APPROVED_DISABLED: -+ case STATE_APPROVED_ENABLED: -+ break; -+ default: -+ throw new IllegalArgumentException("State " + state + " is not a valid state"); -+ } -+ } -+ -+ @Override -+ public int describeContents() { -+ return 0; -+ } -+ -+ @Override -+ public void writeToParcel(Parcel dest, int flags) { -+ dest.writeString(packageName); -+ dest.writeString(targetPackageName); -+ dest.writeString(baseCodePath); -+ dest.writeInt(state); -+ dest.writeInt(userId); -+ } -+ -+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { -+ @Override -+ public OverlayInfo createFromParcel(Parcel source) { -+ return new OverlayInfo(source); -+ } -+ -+ @Override -+ public OverlayInfo[] newArray(int size) { -+ return new OverlayInfo[size]; -+ } -+ }; -+ -+ /** -+ * Returns true if this overlay is enabled, i.e. should be used to overlay -+ * the resources in the target package. -+ * -+ * Disabled overlay packages are installed but are currently not in use. -+ * -+ * @return true if the overlay is enabled, else false. -+ */ -+ public boolean isEnabled() { -+ switch (state) { -+ case STATE_APPROVED_ENABLED: -+ return true; -+ default: -+ return false; -+ } -+ } -+ -+ /** -+ * Returns true if this overlay is approved. -+ * -+ * @return true if this overlay is approved, else false. -+ */ -+ public boolean isApproved() { -+ switch (state) { -+ case STATE_APPROVED_ENABLED: -+ case STATE_APPROVED_DISABLED: -+ return true; -+ default: -+ return false; -+ } -+ } -+ -+ public static String stateToString(int state) { -+ switch (state) { -+ case STATE_NOT_APPROVED_UNKNOWN: -+ return "STATE_NOT_APPROVED_UNKNOWN"; -+ case STATE_NOT_APPROVED_COMPONENT_DISABLED: -+ return "STATE_NOT_APPROVED_COMPONENT_DISABLED"; -+ case STATE_NOT_APPROVED_MISSING_TARGET: -+ return "STATE_NOT_APPROVED_MISSING_TARGET"; -+ case STATE_NOT_APPROVED_NO_IDMAP: -+ return "STATE_NOT_APPROVED_NO_IDMAP"; -+ case STATE_NOT_APPROVED_DANGEROUS_OVERLAY: -+ return "STATE_NOT_APPROVED_DANGEROUS_OVERLAY"; -+ case STATE_APPROVED_DISABLED: -+ return "STATE_APPROVED_DISABLED"; -+ case STATE_APPROVED_ENABLED: -+ return "STATE_APPROVED_ENABLED"; -+ default: -+ return ""; -+ } -+ } -+ -+ @Override -+ public int hashCode() { -+ final int prime = 31; -+ int result = 1; -+ result = prime * result + userId; -+ result = prime * result + state; -+ result = prime * result + ((packageName == null) ? 0 : packageName.hashCode()); -+ result = prime * result + ((targetPackageName == null) ? 0 : targetPackageName.hashCode()); -+ result = prime * result + ((baseCodePath == null) ? 0 : baseCodePath.hashCode()); -+ return result; -+ } -+ -+ @Override -+ public boolean equals(Object obj) { -+ if (this == obj) { -+ return true; -+ } -+ if (obj == null) { -+ return false; -+ } -+ if (getClass() != obj.getClass()) { -+ return false; -+ } -+ OverlayInfo other = (OverlayInfo) obj; -+ if (userId != other.userId) { -+ return false; -+ } -+ if (state != other.state) { -+ return false; -+ } -+ if (!packageName.equals(other.packageName)) { -+ return false; -+ } -+ if (!targetPackageName.equals(other.targetPackageName)) { -+ return false; -+ } -+ if (!baseCodePath.equals(other.baseCodePath)) { -+ return false; -+ } -+ return true; -+ } -+ -+ @Override -+ public String toString() { -+ return "OverlayInfo { overlay=" + packageName + ", target=" + targetPackageName + ", state=" -+ + state + " (" + stateToString(state) + "), userId=" + userId + " }"; -+ } -+} -diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java -index f5bcf64..bdbdd1e 100644 ---- a/core/java/android/content/pm/PackageManagerInternal.java -+++ b/core/java/android/content/pm/PackageManagerInternal.java -@@ -168,4 +168,28 @@ public abstract class PackageManagerInternal { - * @return Whether was launched. - */ - public abstract boolean wasPackageEverLaunched(String packageName, int userId); -+ -+ /** -+ * Get all overlay packages for a user. -+ * @param userId The user for which to get the overlays. -+ * @return A list of overlay packages. An empty list is returned if the -+ * user has no installed overlay packages. -+ */ -+ public abstract List getOverlayPackages(int userId); -+ -+ /** -+ * Get the names of all target packages for a user. -+ * @param userId The user for which to get the package names. -+ * @return A list of target package names. This list includes the "android" package. -+ */ -+ public abstract List getTargetPackageNames(int userId); -+ -+ /** -+ * Set which overlay to use for a package. -+ * @param userId The user for which to update the overlays. -+ * @param packageName The package name of the package for which to update the overlays. -+ * @param resourceDirs The paths to the overlay packages to use, ordered in the order in -+ * which to load the paths, or null if no overlays should be used. -+ */ -+ public abstract void setResourceDirs(int userId, String packageName, String[] resourceDirs); - } -diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml -index c2f12ef..986be28 100644 ---- a/core/res/AndroidManifest.xml -+++ b/core/res/AndroidManifest.xml -@@ -84,6 +84,10 @@ - - - -+ -+ -+ -+ - - - -diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java -new file mode 100644 -index 0000000..e2a3775 ---- /dev/null -+++ b/services/core/java/com/android/server/om/IdmapManager.java -@@ -0,0 +1,116 @@ -+/* -+ * Copyright (C) 2016 The Android Open Source Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package com.android.server.om; -+ -+import static com.android.server.om.OverlayManagerService.DEBUG; -+import static com.android.server.om.OverlayManagerService.TAG; -+ -+import android.annotation.NonNull; -+import android.content.om.OverlayInfo; -+import android.content.pm.PackageInfo; -+import android.os.UserHandle; -+import android.util.Slog; -+import com.android.internal.os.InstallerConnection.InstallerException; -+import com.android.server.pm.Installer; -+ -+import java.io.DataInputStream; -+import java.io.File; -+import java.io.FileInputStream; -+import java.io.IOException; -+ -+/** -+ * Handle the creation and deletion of idmap files. -+ * -+ * The actual work is performed by the idmap binary, launched through Installer -+ * and installd. -+ * -+ * Note: this class is subclassed in the OMS unit tests, and hence not marked as final. -+ */ -+class IdmapManager { -+ private final Installer mInstaller; -+ -+ IdmapManager(final Installer installer) { -+ mInstaller = installer; -+ } -+ -+ boolean createIdmap(@NonNull final PackageInfo targetPackage, -+ @NonNull final PackageInfo overlayPackage, int userId) { -+ // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible -+ if (DEBUG) { -+ Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and " + -+ overlayPackage.packageName); -+ } -+ final int sharedGid = UserHandle.getSharedAppGid(targetPackage.applicationInfo.uid); -+ final String targetPath = targetPackage.applicationInfo.getBaseCodePath(); -+ final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath(); -+ try { -+ mInstaller.idmap(targetPath, overlayPath, sharedGid); -+ } catch (InstallerException e) { -+ Slog.w(TAG, "failed to generate idmap for " + targetPath + " and " + -+ overlayPath + ": " + e.getMessage()); -+ return false; -+ } -+ return true; -+ } -+ -+ boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) { -+ // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible -+ if (DEBUG) { -+ Slog.d(TAG, "remove idmap for " + oi.baseCodePath); -+ } -+ try { -+ mInstaller.removeIdmap(oi.baseCodePath); -+ } catch (InstallerException e) { -+ Slog.w(TAG, "failed to remove idmap for " + oi.baseCodePath + ": " + e.getMessage()); -+ return false; -+ } -+ return true; -+ } -+ -+ boolean idmapExists(@NonNull final OverlayInfo oi) { -+ // unused OverlayInfo.userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible -+ return new File(getIdmapPath(oi.baseCodePath)).isFile(); -+ } -+ -+ boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) { -+ // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible -+ return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath())).isFile(); -+ } -+ -+ boolean isDangerous(@NonNull final PackageInfo overlayPackage, final int userId) { -+ // unused userId: see comment in OverlayManagerServiceImpl.removeIdmapIfPossible -+ return isDangerous(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath())); -+ } -+ -+ private String getIdmapPath(@NonNull final String baseCodePath) { -+ final StringBuilder sb = new StringBuilder("/data/resource-cache/"); -+ sb.append(baseCodePath.substring(1).replace('/', '@')); -+ sb.append("@idmap"); -+ return sb.toString(); -+ } -+ -+ private boolean isDangerous(@NonNull final String idmapPath) { -+ try (DataInputStream dis = new DataInputStream(new FileInputStream(idmapPath))) { -+ final int magic = dis.readInt(); -+ final int version = dis.readInt(); -+ final int dangerous = dis.readInt(); -+ return dangerous != 0; -+ } catch (IOException e) { -+ return true; -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java -new file mode 100644 -index 0000000..ec148dd ---- /dev/null -+++ b/services/core/java/com/android/server/om/OverlayManagerService.java -@@ -0,0 +1,901 @@ -+/* -+ * Copyright (C) 2016 The Android Open Source Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package com.android.server.om; -+ -+import static android.app.AppGlobals.getPackageManager; -+import static android.content.Intent.ACTION_PACKAGE_ADDED; -+import static android.content.Intent.ACTION_PACKAGE_CHANGED; -+import static android.content.Intent.ACTION_PACKAGE_REMOVED; -+import static android.content.Intent.ACTION_USER_REMOVED; -+import static android.content.pm.PackageManager.SIGNATURE_MATCH; -+ -+import android.annotation.NonNull; -+import android.annotation.Nullable; -+import android.app.ActivityManager; -+import android.app.ActivityManagerNative; -+import android.app.IActivityManager; -+import android.content.BroadcastReceiver; -+import android.content.Context; -+import android.content.Intent; -+import android.content.IntentFilter; -+import android.content.om.IOverlayManager; -+import android.content.om.OverlayInfo; -+import android.content.pm.IPackageManager; -+import android.content.pm.PackageInfo; -+import android.content.pm.PackageManagerInternal; -+import android.content.pm.UserInfo; -+import android.net.Uri; -+import android.os.Binder; -+import android.os.Environment; -+import android.os.IBinder; -+import android.os.Process; -+import android.os.RemoteException; -+import android.os.ResultReceiver; -+import android.os.UserHandle; -+import android.util.ArrayMap; -+import android.util.AtomicFile; -+import android.util.Slog; -+import android.util.SparseArray; -+ -+import com.android.server.FgThread; -+import com.android.server.IoThread; -+import com.android.server.LocalServices; -+import com.android.server.SystemService; -+import com.android.server.pm.Installer; -+import com.android.server.pm.UserManagerService; -+ -+import org.xmlpull.v1.XmlPullParserException; -+ -+import java.io.File; -+import java.io.FileDescriptor; -+import java.io.FileInputStream; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.PrintWriter; -+import java.util.ArrayList; -+import java.util.Collection; -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.Iterator; -+import java.util.List; -+import java.util.Map; -+import java.util.concurrent.atomic.AtomicBoolean; -+ -+/** -+ * Service to manage asset overlays. -+ * -+ *

Asset overlays are additional resources that come from apks loaded -+ * alongside the system and app apks. This service, the OverlayManagerService -+ * (OMS), tracks which installed overlays to use and provides methods to change -+ * this. Changes propagate to running applications as part of the Activity -+ * lifecycle. This allows Activities to reread their resources at a well -+ * defined point.

-+ * -+ *

By itself, the OMS will not change what overlays should be active. -+ * Instead, it is only responsible for making sure that overlays *can* be used -+ * from a technical and security point of view and to activate overlays in -+ * response to external requests. The responsibility to toggle overlays on and -+ * off lies within components that implement different use-cases such as themes -+ * or dynamic customization.

-+ * -+ *

The OMS receives input from three sources:

-+ * -+ *
    -+ *
  • Callbacks from the SystemService class, specifically when the -+ * Android framework is booting and when the end user switches Android -+ * users.
  • -+ * -+ *
  • Intents from the PackageManagerService (PMS). Overlays are regular -+ * apks, and whenever a package is installed (or removed, or has a -+ * component enabled or disabled), the PMS broadcasts this as an intent. -+ * When the OMS receives one of these intents, it updates its internal -+ * representation of the available overlays and, if there was a visible -+ * change, triggers an asset refresh in the affected apps.
  • -+ * -+ *
  • External requests via the {@link IOverlayManager AIDL interface}. -+ * The interface allows clients to read information about the currently -+ * available overlays, change whether an overlay should be used or not, and -+ * change the relative order in which overlay packages are loaded. -+ * Read-access is granted if the request targets the same Android user as -+ * the caller runs as, or if the caller holds the -+ * INTERACT_ACROSS_USERS_FULL permission. Write-access is granted if the -+ * caller is granted read-access and additionaly holds the -+ * CHANGE_CONFIGURATION permission.
  • -+ *
-+ * -+ *

The AIDL interface works with String package names, int user IDs, and -+ * {@link OverlayInfo} objects. OverlayInfo instances are used to track a -+ * specific pair of target and overlay packages and include information such as -+ * the current state of the overlay. OverlayInfo objects are immutable.

-+ * -+ *

Internally, OverlayInfo objects are maintained by the -+ * OverlayManagerSettings class. The OMS and its helper classes are notified of -+ * changes to the settings by the OverlayManagerSettings.ChangeListener -+ * callback interface. The file /data/system/overlays.xml is used to persist -+ * the settings.

-+ * -+ *

Creation and deletion of idmap files are handled by the IdmapManager -+ * class.

-+ * -+ *

The following is an overview of OMS and its related classes. Note how box -+ * (2) does the heavy lifting, box (1) interacts with the Android framework, -+ * and box (3) replaces box (1) during unit testing.

-+ * -+ *
-+ *         Android framework
-+ *            |         ^
-+ *      . . . | . . . . | . . . .
-+ *     .      |         |       .
-+ *     .    AIDL,   broadcasts  .
-+ *     .   intents      |       .
-+ *     .      |         |       . . . . . . . . . . . .
-+ *     .      v         |       .                     .
-+ *     .  OverlayManagerService . OverlayManagerTests .
-+ *     .                  \     .     /               .
-+ *     . (1)               \    .    /            (3) .
-+ *      . . . . . . . . . . \ . . . / . . . . . . . . .
-+ *     .                     \     /              .
-+ *     . (2)                  \   /               .
-+ *     .           OverlayManagerServiceImpl      .
-+ *     .                  |            |          .
-+ *     .                  |            |          .
-+ *     . OverlayManagerSettings     IdmapManager  .
-+ *     .                                          .
-+ *     . . . .  . . . . . . . . . . . . . . . . . .
-+ * 
-+ * -+ *

Finally, here is a list of keywords used in the OMS context.

-+ * -+ *
    -+ *
  • target [package] -- A regular apk that may have its resource -+ * pool extended by zero or more overlay packages.
  • -+ * -+ *
  • overlay [package] -- An apk that provides additional -+ * resources to another apk.
  • -+ * -+ *
  • OMS -- The OverlayManagerService, i.e. this class.
  • -+ * -+ *
  • approved -- An overlay is approved if the OMS has verified -+ * that it can be used technically speaking (its target package is -+ * installed, at least one resource name in both packages match, the -+ * idmap was created, etc) and that it is secure to do so. External -+ * clients can not change this state.
  • -+ * -+ *
  • not approved -- The opposite of approved.
  • -+ * -+ *
  • enabled -- An overlay currently in active use and thus part -+ * of resource lookups. This requires the overlay to be approved. Only -+ * external clients can change this state.
  • -+ * -+ *
  • disabled -- The opposite of enabled.
  • -+ * -+ *
  • idmap -- A mapping of resource IDs between target and overlay -+ * used during resource lookup. Also the name of the binary that creates -+ * the mapping.
  • -+ *
-+ */ -+public final class OverlayManagerService extends SystemService { -+ -+ static final String TAG = "OverlayManager"; -+ -+ static final boolean DEBUG = false; -+ -+ private final Object mLock = new Object(); -+ -+ private final AtomicFile mSettingsFile; -+ -+ private final PackageManagerHelper mPackageManager; -+ -+ private final UserManagerService mUserManager; -+ -+ private final OverlayManagerSettings mSettings; -+ -+ private final OverlayManagerServiceImpl mImpl; -+ -+ private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false); -+ -+ public OverlayManagerService(@NonNull final Context context, -+ @NonNull final Installer installer) { -+ super(context); -+ mSettingsFile = -+ new AtomicFile(new File(Environment.getDataSystemDirectory(), "overlays.xml")); -+ mPackageManager = new PackageManagerHelper(); -+ mUserManager = UserManagerService.getInstance(); -+ IdmapManager im = new IdmapManager(installer); -+ mSettings = new OverlayManagerSettings(); -+ mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings); -+ -+ final IntentFilter packageFilter = new IntentFilter(); -+ packageFilter.addAction(ACTION_PACKAGE_ADDED); -+ packageFilter.addAction(ACTION_PACKAGE_CHANGED); -+ packageFilter.addAction(ACTION_PACKAGE_REMOVED); -+ packageFilter.addDataScheme("package"); -+ getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, -+ packageFilter, null, null); -+ -+ final IntentFilter userFilter = new IntentFilter(); -+ userFilter.addAction(ACTION_USER_REMOVED); -+ getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL, -+ userFilter, null, null); -+ -+ restoreSettings(); -+ onSwitchUser(UserHandle.USER_SYSTEM); -+ schedulePersistSettings(); -+ -+ mSettings.addChangeListener(new OverlayChangeListener()); -+ -+ publishBinderService(Context.OVERLAY_SERVICE, mService); -+ publishLocalService(OverlayManagerService.class, this); -+ } -+ -+ @Override -+ public void onStart() { -+ // Intentionally left empty. -+ } -+ -+ @Override -+ public void onSwitchUser(final int newUserId) { -+ // ensure overlays in the settings are up-to-date, and propagate -+ // any asset changes to the rest of the system -+ final List targets; -+ synchronized (mLock) { -+ targets = mImpl.onSwitchUser(newUserId); -+ } -+ updateAssets(newUserId, targets); -+ } -+ -+ public List getEnabledOverlayPaths(@NonNull final String packageName, -+ final int userId) { -+ synchronized (mLock) { -+ return mImpl.onGetEnabledOverlayPaths(packageName, userId); -+ } -+ } -+ -+ private final class PackageReceiver extends BroadcastReceiver { -+ @Override -+ public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { -+ final Uri data = intent.getData(); -+ if (data == null) { -+ Slog.e(TAG, "Cannot handle package broadcast with null data"); -+ return; -+ } -+ final String packageName = data.getSchemeSpecificPart(); -+ -+ final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); -+ -+ final int[] userIds; -+ final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL); -+ if (extraUid == UserHandle.USER_NULL) { -+ userIds = mUserManager.getUserIds(); -+ } else { -+ userIds = new int[] { UserHandle.getUserId(extraUid) }; -+ } -+ -+ switch (intent.getAction()) { -+ case ACTION_PACKAGE_ADDED: -+ if (replacing) { -+ onPackageUpgraded(packageName, userIds); -+ } else { -+ onPackageAdded(packageName, userIds); -+ } -+ break; -+ case ACTION_PACKAGE_CHANGED: -+ onPackageChanged(packageName, userIds); -+ break; -+ case ACTION_PACKAGE_REMOVED: -+ if (replacing) { -+ onPackageUpgrading(packageName, userIds); -+ } else { -+ onPackageRemoved(packageName, userIds); -+ } -+ break; -+ default: -+ // do nothing -+ break; -+ } -+ } -+ -+ private void onPackageAdded(@NonNull final String packageName, -+ @NonNull final int[] userIds) { -+ for (final int userId : userIds) { -+ synchronized (mLock) { -+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false); -+ if (pi != null) { -+ mPackageManager.cachePackageInfo(packageName, userId, pi); -+ if (!isOverlayPackage(pi)) { -+ mImpl.onTargetPackageAdded(packageName, userId); -+ } else { -+ mImpl.onOverlayPackageAdded(packageName, userId); -+ } -+ } -+ } -+ } -+ } -+ -+ private void onPackageChanged(@NonNull final String packageName, -+ @NonNull final int[] userIds) { -+ for (int userId : userIds) { -+ synchronized (mLock) { -+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false); -+ if (pi != null) { -+ mPackageManager.cachePackageInfo(packageName, userId, pi); -+ if (!isOverlayPackage(pi)) { -+ mImpl.onTargetPackageChanged(packageName, userId); -+ } else { -+ mImpl.onOverlayPackageChanged(packageName, userId); -+ } -+ } -+ } -+ } -+ } -+ -+ private void onPackageUpgrading(@NonNull final String packageName, -+ @NonNull final int[] userIds) { -+ for (int userId : userIds) { -+ synchronized (mLock) { -+ mPackageManager.forgetPackageInfo(packageName, userId); -+ final OverlayInfo oi = mImpl.onGetOverlayInfo(packageName, userId); -+ if (oi == null) { -+ mImpl.onTargetPackageUpgrading(packageName, userId); -+ } else { -+ mImpl.onOverlayPackageUpgrading(packageName, userId); -+ } -+ } -+ } -+ } -+ -+ private void onPackageUpgraded(@NonNull final String packageName, -+ @NonNull final int[] userIds) { -+ for (int userId : userIds) { -+ synchronized (mLock) { -+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId, false); -+ if (pi != null) { -+ mPackageManager.cachePackageInfo(packageName, userId, pi); -+ if (!isOverlayPackage(pi)) { -+ mImpl.onTargetPackageUpgraded(packageName, userId); -+ } else { -+ mImpl.onOverlayPackageUpgraded(packageName, userId); -+ } -+ } -+ } -+ } -+ } -+ -+ private void onPackageRemoved(@NonNull final String packageName, -+ @NonNull final int[] userIds) { -+ for (int userId : userIds) { -+ synchronized (mLock) { -+ mPackageManager.forgetPackageInfo(packageName, userId); -+ final OverlayInfo oi = mImpl.onGetOverlayInfo(packageName, userId); -+ if (oi == null) { -+ mImpl.onTargetPackageRemoved(packageName, userId); -+ } else { -+ mImpl.onOverlayPackageRemoved(packageName, userId); -+ } -+ } -+ } -+ } -+ } -+ -+ private final class UserReceiver extends BroadcastReceiver { -+ @Override -+ public void onReceive(@NonNull final Context context, @NonNull final Intent intent) { -+ switch (intent.getAction()) { -+ case ACTION_USER_REMOVED: -+ final int userId = -+ intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); -+ if (userId != UserHandle.USER_NULL) { -+ synchronized (mLock) { -+ mImpl.onUserRemoved(userId); -+ mPackageManager.forgetAllPackageInfos(userId); -+ } -+ } -+ break; -+ default: -+ // do nothing -+ break; -+ } -+ } -+ } -+ -+ private final IBinder mService = new IOverlayManager.Stub() { -+ @Override -+ public Map> getAllOverlays(int userId) -+ throws RemoteException { -+ userId = handleIncomingUser(userId, "getAllOverlays"); -+ -+ synchronized (mLock) { -+ return mImpl.onGetOverlaysForUser(userId); -+ } -+ } -+ -+ @Override -+ public List getOverlayInfosForTarget(@Nullable final String targetPackageName, -+ int userId) throws RemoteException { -+ userId = handleIncomingUser(userId, "getOverlayInfosForTarget"); -+ if (targetPackageName == null) { -+ return Collections.emptyList(); -+ } -+ -+ synchronized (mLock) { -+ return mImpl.onGetOverlayInfosForTarget(targetPackageName, userId); -+ } -+ } -+ -+ @Override -+ public OverlayInfo getOverlayInfo(@Nullable final String packageName, -+ int userId) throws RemoteException { -+ userId = handleIncomingUser(userId, "getOverlayInfo"); -+ if (packageName == null) { -+ return null; -+ } -+ -+ synchronized (mLock) { -+ return mImpl.onGetOverlayInfo(packageName, userId); -+ } -+ } -+ -+ @Override -+ public boolean setEnabled(@Nullable final String packageName, final boolean enable, -+ int userId) throws RemoteException { -+ enforceChangeConfigurationPermission("setEnabled"); -+ userId = handleIncomingUser(userId, "setEnabled"); -+ if (packageName == null) { -+ return false; -+ } -+ -+ final long ident = Binder.clearCallingIdentity(); -+ try { -+ synchronized (mLock) { -+ return mImpl.onSetEnabled(packageName, enable, userId); -+ } -+ } finally { -+ Binder.restoreCallingIdentity(ident); -+ } -+ } -+ -+ @Override -+ public boolean setPriority(@Nullable final String packageName, -+ @Nullable final String parentPackageName, int userId) throws RemoteException { -+ enforceChangeConfigurationPermission("setPriority"); -+ userId = handleIncomingUser(userId, "setPriority"); -+ if (packageName == null || parentPackageName == null) { -+ return false; -+ } -+ -+ final long ident = Binder.clearCallingIdentity(); -+ try { -+ synchronized (mLock) { -+ return mImpl.onSetPriority(packageName, parentPackageName, userId); -+ } -+ } finally { -+ Binder.restoreCallingIdentity(ident); -+ } -+ } -+ -+ @Override -+ public boolean setHighestPriority(@Nullable final String packageName, int userId) -+ throws RemoteException { -+ enforceChangeConfigurationPermission("setHighestPriority"); -+ userId = handleIncomingUser(userId, "setHighestPriority"); -+ if (packageName == null) { -+ return false; -+ } -+ -+ final long ident = Binder.clearCallingIdentity(); -+ try { -+ synchronized (mLock) { -+ return mImpl.onSetHighestPriority(packageName, userId); -+ } -+ } finally { -+ Binder.restoreCallingIdentity(ident); -+ } -+ } -+ -+ @Override -+ public boolean setLowestPriority(@Nullable final String packageName, int userId) -+ throws RemoteException { -+ enforceChangeConfigurationPermission("setLowestPriority"); -+ userId = handleIncomingUser(userId, "setLowestPriority"); -+ if (packageName == null) { -+ return false; -+ } -+ -+ final long ident = Binder.clearCallingIdentity(); -+ try { -+ synchronized (mLock) { -+ return mImpl.onSetLowestPriority(packageName, userId); -+ } -+ } finally { -+ Binder.restoreCallingIdentity(ident); -+ } -+ } -+ -+ @Override -+ public void onShellCommand(@NonNull final FileDescriptor in, -+ @NonNull final FileDescriptor out, @NonNull final FileDescriptor err, -+ @NonNull final String[] args, @NonNull final ResultReceiver resultReceiver) { -+ (new OverlayManagerShellCommand(this)).exec( -+ this, in, out, err, args, resultReceiver); -+ } -+ -+ @Override -+ protected void dump(@NonNull final FileDescriptor fd, @NonNull final PrintWriter pw, -+ @NonNull final String[] argv) { -+ enforceDumpPermission("dump"); -+ -+ final boolean verbose = argv.length > 0 && "--verbose".equals(argv[0]); -+ -+ synchronized (mLock) { -+ mImpl.onDump(pw); -+ mPackageManager.dump(pw, verbose); -+ } -+ } -+ -+ /** -+ * Ensure that the caller has permission to interact with the given userId. -+ * If the calling user is not the same as the provided user, the caller needs -+ * to hold the INTERACT_ACROSS_USERS_FULL permission (or be system uid or -+ * root). -+ * -+ * @param userId the user to interact with -+ * @param message message for any SecurityException -+ */ -+ private int handleIncomingUser(final int userId, @NonNull final String message) { -+ return ActivityManager.handleIncomingUser(Binder.getCallingPid(), -+ Binder.getCallingUid(), userId, false, true, message, null); -+ } -+ -+ /** -+ * Enforce that the caller holds the CHANGE_CONFIGURATION permission (or is -+ * system or root). -+ * -+ * @param message used as message if SecurityException is thrown -+ * @throws SecurityException if the permission check fails -+ */ -+ private void enforceChangeConfigurationPermission(@NonNull final String message) { -+ final int callingUid = Binder.getCallingUid(); -+ -+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) { -+ getContext().enforceCallingOrSelfPermission( -+ android.Manifest.permission.CHANGE_CONFIGURATION, message); -+ } -+ } -+ -+ /** -+ * Enforce that the caller holds the DUMP permission (or is system or root). -+ * -+ * @param message used as message if SecurityException is thrown -+ * @throws SecurityException if the permission check fails -+ */ -+ private void enforceDumpPermission(@NonNull final String message) { -+ final int callingUid = Binder.getCallingUid(); -+ -+ if (callingUid != Process.SYSTEM_UID && callingUid != 0) { -+ getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, -+ message); -+ } -+ } -+ }; -+ -+ private boolean isOverlayPackage(@NonNull final PackageInfo pi) { -+ return pi != null && pi.overlayTarget != null; -+ } -+ -+ private final class OverlayChangeListener implements OverlayManagerSettings.ChangeListener { -+ @Override -+ public void onSettingsChanged() { -+ schedulePersistSettings(); -+ } -+ -+ @Override -+ public void onOverlayAdded(@NonNull final OverlayInfo oi) { -+ scheduleBroadcast(Intent.ACTION_OVERLAY_ADDED, oi, oi.isEnabled()); -+ } -+ -+ @Override -+ public void onOverlayRemoved(@NonNull final OverlayInfo oi) { -+ scheduleBroadcast(Intent.ACTION_OVERLAY_REMOVED, oi, oi.isEnabled()); -+ } -+ -+ @Override -+ public void onOverlayChanged(@NonNull final OverlayInfo oi, -+ @NonNull final OverlayInfo oldOi) { -+ scheduleBroadcast(Intent.ACTION_OVERLAY_CHANGED, oi, oi.isEnabled() != oldOi.isEnabled()); -+ } -+ -+ @Override -+ public void onOverlayPriorityChanged(@NonNull final OverlayInfo oi) { -+ scheduleBroadcast(Intent.ACTION_OVERLAY_PRIORITY_CHANGED, oi, oi.isEnabled()); -+ } -+ -+ private void scheduleBroadcast(@NonNull final String action, @NonNull final OverlayInfo oi, -+ final boolean doUpdate) { -+ FgThread.getHandler().post(new BroadcastRunnable(action, oi, doUpdate)); -+ } -+ -+ private final class BroadcastRunnable extends Thread { -+ private final String mAction; -+ private final OverlayInfo mOverlayInfo; -+ private final boolean mDoUpdate; -+ -+ public BroadcastRunnable(@NonNull final String action, @NonNull final OverlayInfo oi, -+ final boolean doUpdate) { -+ mAction = action; -+ mOverlayInfo = oi; -+ mDoUpdate = doUpdate; -+ } -+ -+ public void run() { -+ if (mDoUpdate) { -+ updateAssets(mOverlayInfo.userId, mOverlayInfo.targetPackageName); -+ } -+ sendBroadcast(mAction, mOverlayInfo.targetPackageName, mOverlayInfo.packageName, -+ mOverlayInfo.userId); -+ } -+ -+ private void sendBroadcast(@NonNull final String action, -+ @NonNull final String targetPackageName, @NonNull final String packageName, -+ final int userId) { -+ final Intent intent = new Intent(action, Uri.fromParts("package", -+ String.format("%s/%s", targetPackageName, packageName), null)); -+ intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); -+ if (DEBUG) { -+ Slog.d(TAG, String.format("send broadcast %s", intent)); -+ } -+ try { -+ ActivityManagerNative.getDefault().broadcastIntent(null, intent, null, null, 0, -+ null, null, null, android.app.AppOpsManager.OP_NONE, null, false, false, -+ userId); -+ } catch (RemoteException e) { -+ // Intentionally left empty. -+ } -+ } -+ -+ } -+ } -+ -+ private void updateAssets(final int userId, final String targetPackageName) { -+ final List list = new ArrayList<>(); -+ list.add(targetPackageName); -+ updateAssets(userId, list); -+ } -+ -+ private void updateAssets(final int userId, List targetPackageNames) { -+ // TODO: uncomment when we integrate OMS properly -+ // final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); -+ // final boolean updateFrameworkRes = targetPackageNames.contains("android"); -+ // if (updateFrameworkRes) { -+ // targetPackageNames = pm.getTargetPackageNames(userId); -+ // } -+ -+ // final Map allPaths = new ArrayMap<>(targetPackageNames.size()); -+ // synchronized (mLock) { -+ // final List frameworkPaths = mImpl.onGetEnabledOverlayPaths("android", userId); -+ // for (final String packageName : targetPackageNames) { -+ // final List paths = new ArrayList<>(); -+ // paths.addAll(frameworkPaths); -+ // if (!"android".equals(packageName)) { -+ // paths.addAll(mImpl.onGetEnabledOverlayPaths(packageName, userId)); -+ // } -+ // allPaths.put(packageName, -+ // paths.isEmpty() ? null : paths.toArray(new String[paths.size()])); -+ // } -+ // } -+ -+ // for (String packageName : targetPackageNames) { -+ // pm.setResourceDirs(userId, packageName, allPaths.get(packageName)); -+ // } -+ -+ // final IActivityManager am = ActivityManagerNative.getDefault(); -+ // try { -+ // am.updateAssets(userId, targetPackageNames); -+ // } catch (RemoteException e) { -+ // // Intentionally left empty. -+ // } -+ } -+ -+ private void schedulePersistSettings() { -+ if (mPersistSettingsScheduled.get()) { -+ return; -+ } -+ mPersistSettingsScheduled.set(true); -+ IoThread.getHandler().post(new Runnable() { -+ @Override -+ public void run() { -+ mPersistSettingsScheduled.set(false); -+ synchronized (mLock) { -+ FileOutputStream stream = null; -+ try { -+ stream = mSettingsFile.startWrite(); -+ mSettings.persist(stream); -+ mSettingsFile.finishWrite(stream); -+ } catch (IOException | XmlPullParserException e) { -+ mSettingsFile.failWrite(stream); -+ Slog.e(TAG, "failed to persist overlay state", e); -+ } -+ } -+ } -+ }); -+ } -+ -+ private void restoreSettings() { -+ synchronized (mLock) { -+ if (!mSettingsFile.getBaseFile().exists()) { -+ return; -+ } -+ try (final FileInputStream stream = mSettingsFile.openRead()) { -+ mSettings.restore(stream); -+ -+ // We might have data for dying users if the device was -+ // restarted before we received USER_REMOVED. Remove data for -+ // users that will not exist after the system is ready. -+ -+ for (final UserInfo deadUser : getDeadUsers()) { -+ final int userId = deadUser.getUserHandle().getIdentifier(); -+ mSettings.removeUser(userId); -+ } -+ } catch (IOException | XmlPullParserException e) { -+ Slog.e(TAG, "failed to restore overlay state", e); -+ } -+ } -+ } -+ -+ private List getDeadUsers() { -+ final List users = mUserManager.getUsers(false); -+ final List onlyLiveUsers = mUserManager.getUsers(true); -+ -+ // UserInfo doesn't implement equals, so we'll roll our own -+ // Collection.removeAll implementation -+ final Iterator iter = users.iterator(); -+ while (iter.hasNext()) { -+ final UserInfo ui = iter.next(); -+ for (final UserInfo live : onlyLiveUsers) { -+ if (ui.id == live.id) { -+ iter.remove(); -+ break; -+ } -+ } -+ } -+ -+ return users; -+ } -+ -+ private static final class PackageManagerHelper implements -+ OverlayManagerServiceImpl.PackageManagerHelper { -+ -+ private final IPackageManager mPackageManager; -+ private final PackageManagerInternal mPackageManagerInternal; -+ -+ // Use a cache for performance and for consistency within OMS: because -+ // additional PACKAGE_* intents may be delivered while we process an -+ // intent, querying the PackageManagerService for the actual current -+ // state may lead to contradictions within OMS. Better then to lag -+ // behind until all pending intents have been processed. -+ private final SparseArray> mCache = new SparseArray<>(); -+ -+ public PackageManagerHelper() { -+ mPackageManager = getPackageManager(); -+ mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); -+ } -+ -+ public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId, -+ final boolean useCache) { -+ if (useCache) { -+ final PackageInfo cachedPi = getCachedPackageInfo(packageName, userId); -+ if (cachedPi != null) { -+ return cachedPi; -+ } -+ } -+ try { -+ final PackageInfo pi = mPackageManager.getPackageInfo(packageName, 0, userId); -+ if (useCache && pi != null) { -+ cachePackageInfo(packageName, userId, pi); -+ } -+ return pi; -+ } catch (RemoteException e) { -+ // Intentionally left empty. -+ } -+ return null; -+ } -+ -+ @Override -+ public PackageInfo getPackageInfo(@NonNull final String packageName, final int userId) { -+ return getPackageInfo(packageName, userId, true); -+ } -+ -+ @Override -+ public boolean signaturesMatching(@NonNull final String packageName1, -+ @NonNull final String packageName2, final int userId) { -+ // The package manager does not support different versions of packages -+ // to be installed for different users: ignore userId for now. -+ try { -+ return mPackageManager.checkSignatures(packageName1, packageName2) == SIGNATURE_MATCH; -+ } catch (RemoteException e) { -+ // Intentionally left blank -+ } -+ return false; -+ } -+ -+ @Override -+ public List getOverlayPackages(final int userId) { -+ return mPackageManagerInternal.getOverlayPackages(userId); -+ } -+ -+ public PackageInfo getCachedPackageInfo(@NonNull final String packageName, -+ final int userId) { -+ final HashMap map = mCache.get(userId); -+ return map == null ? null : map.get(packageName); -+ } -+ -+ public void cachePackageInfo(@NonNull final String packageName, final int userId, -+ @NonNull final PackageInfo pi) { -+ HashMap map = mCache.get(userId); -+ if (map == null) { -+ map = new HashMap<>(); -+ mCache.put(userId, map); -+ } -+ map.put(packageName, pi); -+ } -+ -+ public void forgetPackageInfo(@NonNull final String packageName, final int userId) { -+ final HashMap map = mCache.get(userId); -+ if (map == null) { -+ return; -+ } -+ map.remove(packageName); -+ if (map.isEmpty()) { -+ mCache.delete(userId); -+ } -+ } -+ -+ public void forgetAllPackageInfos(final int userId) { -+ mCache.delete(userId); -+ } -+ -+ private static final String TAB1 = " "; -+ private static final String TAB2 = TAB1 + TAB1; -+ -+ public void dump(@NonNull final PrintWriter pw, final boolean verbose) { -+ pw.println("PackageInfo cache"); -+ -+ if (!verbose) { -+ int n = 0; -+ for (int i = 0; i < mCache.size(); i++) { -+ final int userId = mCache.keyAt(i); -+ n += mCache.get(userId).size(); -+ } -+ pw.println(TAB1 + n + " package(s)"); -+ return; -+ } -+ -+ if (mCache.size() == 0) { -+ pw.println(TAB1 + ""); -+ return; -+ } -+ -+ for (int i = 0; i < mCache.size(); i++) { -+ final int userId = mCache.keyAt(i); -+ pw.println(TAB1 + "User " + userId); -+ final HashMap map = mCache.get(userId); -+ for (Map.Entry entry : map.entrySet()) { -+ pw.println(TAB2 + entry.getKey() + ": " + entry.getValue()); -+ } -+ } -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java -new file mode 100644 -index 0000000..2a0d88b ---- /dev/null -+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java -@@ -0,0 +1,478 @@ -+/* -+ * Copyright (C) 2016 The Android Open Source Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package com.android.server.om; -+ -+import static android.content.om.OverlayInfo.STATE_APPROVED_DISABLED; -+import static android.content.om.OverlayInfo.STATE_APPROVED_ENABLED; -+import static android.content.om.OverlayInfo.STATE_NOT_APPROVED_COMPONENT_DISABLED; -+import static android.content.om.OverlayInfo.STATE_NOT_APPROVED_DANGEROUS_OVERLAY; -+import static android.content.om.OverlayInfo.STATE_NOT_APPROVED_MISSING_TARGET; -+import static android.content.om.OverlayInfo.STATE_NOT_APPROVED_NO_IDMAP; -+import static com.android.server.om.OverlayManagerService.DEBUG; -+import static com.android.server.om.OverlayManagerService.TAG; -+ -+import android.annotation.NonNull; -+import android.annotation.Nullable; -+import android.content.om.OverlayInfo; -+import android.content.pm.ApplicationInfo; -+import android.content.pm.PackageInfo; -+import android.util.ArrayMap; -+import android.util.ArraySet; -+import android.util.Slog; -+ -+import java.io.PrintWriter; -+import java.util.ArrayList; -+import java.util.Iterator; -+import java.util.List; -+import java.util.Map; -+import java.util.Set; -+ -+/** -+ * Internal implementation of OverlayManagerService. -+ * -+ * Methods in this class should only be called by the OverlayManagerService. -+ * This class is not thread-safe; the caller is expected to ensure the -+ * necessary thread synchronization. -+ * -+ * @see OverlayManagerService -+ */ -+final class OverlayManagerServiceImpl { -+ private final PackageManagerHelper mPackageManager; -+ private final IdmapManager mIdmapManager; -+ private final OverlayManagerSettings mSettings; -+ -+ OverlayManagerServiceImpl(@NonNull final PackageManagerHelper packageManager, -+ @NonNull final IdmapManager idmapManager, -+ @NonNull final OverlayManagerSettings settings) { -+ mPackageManager = packageManager; -+ mIdmapManager = idmapManager; -+ mSettings = settings; -+ } -+ -+ /* -+ * Call this when switching to a new Android user. Will return a list of -+ * target packages that must refresh their overlays. This list is the union -+ * of two sets: the set of targets with currently active overlays, and the -+ * set of targets that had, but no longer have, active overlays. -+ */ -+ List onSwitchUser(final int newUserId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onSwitchUser newUserId=" + newUserId); -+ } -+ -+ final Set packagesToUpdateAssets = new ArraySet<>(); -+ final Map> tmp = mSettings.getOverlaysForUser(newUserId); -+ final Map storedOverlayInfos = new ArrayMap<>(tmp.size()); -+ for (final List chunk: tmp.values()) { -+ for (final OverlayInfo oi: chunk) { -+ storedOverlayInfos.put(oi.packageName, oi); -+ } -+ } -+ -+ for (PackageInfo overlayPackage: mPackageManager.getOverlayPackages(newUserId)) { -+ final OverlayInfo oi = storedOverlayInfos.get(overlayPackage.packageName); -+ if (oi == null || !oi.targetPackageName.equals(overlayPackage.overlayTarget)) { -+ if (oi != null) { -+ packagesToUpdateAssets.add(oi.targetPackageName); -+ } -+ mSettings.init(overlayPackage.packageName, newUserId, -+ overlayPackage.overlayTarget, -+ overlayPackage.applicationInfo.getBaseCodePath()); -+ } -+ -+ try { -+ final PackageInfo targetPackage = -+ mPackageManager.getPackageInfo(overlayPackage.overlayTarget, newUserId); -+ updateState(targetPackage, overlayPackage, newUserId); -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ Slog.e(TAG, "failed to update settings", e); -+ mSettings.remove(overlayPackage.packageName, newUserId); -+ } -+ -+ packagesToUpdateAssets.add(overlayPackage.overlayTarget); -+ storedOverlayInfos.remove(overlayPackage.packageName); -+ } -+ -+ // any OverlayInfo left in storedOverlayInfos is no longer -+ // installed and should be removed -+ for (final OverlayInfo oi: storedOverlayInfos.values()) { -+ mSettings.remove(oi.packageName, oi.userId); -+ removeIdmapIfPossible(oi); -+ packagesToUpdateAssets.add(oi.targetPackageName); -+ } -+ -+ // remove target packages that are not installed -+ final Iterator iter = packagesToUpdateAssets.iterator(); -+ while (iter.hasNext()) { -+ String targetPackageName = iter.next(); -+ if (mPackageManager.getPackageInfo(targetPackageName, newUserId) == null) { -+ iter.remove(); -+ } -+ } -+ -+ return new ArrayList(packagesToUpdateAssets); -+ } -+ -+ void onUserRemoved(final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onUserRemoved userId=" + userId); -+ } -+ mSettings.removeUser(userId); -+ } -+ -+ void onTargetPackageAdded(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId); -+ } -+ -+ final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId); -+ updateAllOverlaysForTarget(packageName, userId, targetPackage); -+ } -+ -+ void onTargetPackageChanged(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId); -+ } -+ -+ final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId); -+ updateAllOverlaysForTarget(packageName, userId, targetPackage); -+ } -+ -+ void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId=" + userId); -+ } -+ -+ updateAllOverlaysForTarget(packageName, userId, null); -+ } -+ -+ void onTargetPackageUpgraded(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId); -+ } -+ -+ final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId); -+ updateAllOverlaysForTarget(packageName, userId, targetPackage); -+ } -+ -+ void onTargetPackageRemoved(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId); -+ } -+ -+ updateAllOverlaysForTarget(packageName, userId, null); -+ } -+ -+ private void updateAllOverlaysForTarget(@NonNull final String packageName, final int userId, -+ @Nullable final PackageInfo targetPackage) { -+ final List ois = mSettings.getOverlaysForTarget(packageName, userId); -+ for (final OverlayInfo oi : ois) { -+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName, userId); -+ if (overlayPackage == null) { -+ mSettings.remove(oi.packageName, oi.userId); -+ removeIdmapIfPossible(oi); -+ } else { -+ try { -+ updateState(targetPackage, overlayPackage, userId); -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ Slog.e(TAG, "failed to update settings", e); -+ mSettings.remove(oi.packageName, userId); -+ } -+ } -+ } -+ } -+ -+ void onOverlayPackageAdded(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onOverlayPackageAdded packageName=" + packageName + " userId=" + userId); -+ } -+ -+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); -+ if (overlayPackage == null) { -+ Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found"); -+ onOverlayPackageRemoved(packageName, userId); -+ return; -+ } -+ -+ final PackageInfo targetPackage = -+ mPackageManager.getPackageInfo(overlayPackage.overlayTarget, userId); -+ -+ mSettings.init(packageName, userId, overlayPackage.overlayTarget, -+ overlayPackage.applicationInfo.getBaseCodePath()); -+ try { -+ updateState(targetPackage, overlayPackage, userId); -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ Slog.e(TAG, "failed to update settings", e); -+ mSettings.remove(packageName, userId); -+ } -+ } -+ -+ void onOverlayPackageChanged(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId); -+ } -+ -+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); -+ if (overlayPackage == null) { -+ Slog.w(TAG, "overlay package " + packageName + " was changed, but couldn't be found"); -+ onOverlayPackageRemoved(packageName, userId); -+ return; -+ } -+ -+ final PackageInfo targetPackage = -+ mPackageManager.getPackageInfo(overlayPackage.overlayTarget, userId); -+ -+ try { -+ updateState(targetPackage, overlayPackage, userId); -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ Slog.e(TAG, "failed to update settings", e); -+ mSettings.remove(packageName, userId); -+ } -+ } -+ -+ void onOverlayPackageUpgrading(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onOverlayPackageUpgrading packageName=" + packageName + " userId=" + userId); -+ } -+ -+ try { -+ final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); -+ mSettings.setUpgrading(packageName, userId, true); -+ removeIdmapIfPossible(oi); -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ Slog.e(TAG, "failed to update settings", e); -+ mSettings.remove(packageName, userId); -+ } -+ } -+ -+ void onOverlayPackageUpgraded(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onOverlayPackageUpgraded packageName=" + packageName + " userId=" + userId); -+ } -+ -+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); -+ if (overlayPackage == null) { -+ Slog.w(TAG, "overlay package " + packageName + " was upgraded, but couldn't be found"); -+ onOverlayPackageRemoved(packageName, userId); -+ return; -+ } -+ -+ try { -+ final String storedTargetPackageName = mSettings.getTargetPackageName(packageName, userId); -+ if (!overlayPackage.overlayTarget.equals(storedTargetPackageName)) { -+ // Sneaky little hobbitses, changing the overlay's target package -+ // from one version to the next! We can't use the old version's -+ // state. -+ mSettings.remove(packageName, userId); -+ onOverlayPackageAdded(packageName, userId); -+ return; -+ } -+ -+ mSettings.setUpgrading(packageName, userId, false); -+ final PackageInfo targetPackage = -+ mPackageManager.getPackageInfo(overlayPackage.overlayTarget, userId); -+ updateState(targetPackage, overlayPackage, userId); -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ Slog.e(TAG, "failed to update settings", e); -+ mSettings.remove(packageName, userId); -+ } -+ } -+ -+ void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, "onOverlayPackageRemoved packageName=" + packageName + " userId=" + userId); -+ } -+ -+ try { -+ final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); -+ mSettings.remove(packageName, userId); -+ removeIdmapIfPossible(oi); -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ Slog.e(TAG, "failed to remove overlay package", e); -+ } -+ } -+ -+ OverlayInfo onGetOverlayInfo(@NonNull final String packageName, final int userId) { -+ try { -+ return mSettings.getOverlayInfo(packageName, userId); -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ return null; -+ } -+ } -+ -+ List onGetOverlayInfosForTarget(@NonNull final String targetPackageName, -+ final int userId) { -+ return mSettings.getOverlaysForTarget(targetPackageName, userId); -+ } -+ -+ Map> onGetOverlaysForUser(final int userId) { -+ return mSettings.getOverlaysForUser(userId); -+ } -+ -+ boolean onSetEnabled(@NonNull final String packageName, final boolean enable, -+ final int userId) { -+ if (DEBUG) { -+ Slog.d(TAG, String.format("onSetEnabled packageName=%s enable=%s userId=%d", -+ packageName, enable, userId)); -+ } -+ -+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); -+ if (overlayPackage == null) { -+ return false; -+ } -+ -+ try { -+ final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); -+ final PackageInfo targetPackage = -+ mPackageManager.getPackageInfo(oi.targetPackageName, userId); -+ mSettings.setEnabled(packageName, userId, enable); -+ updateState(targetPackage, overlayPackage, userId); -+ return true; -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ return false; -+ } -+ } -+ -+ boolean onSetPriority(@NonNull final String packageName, -+ @NonNull final String newParentPackageName, final int userId) { -+ return mSettings.setPriority(packageName, newParentPackageName, userId); -+ } -+ -+ boolean onSetHighestPriority(@NonNull final String packageName, final int userId) { -+ return mSettings.setHighestPriority(packageName, userId); -+ } -+ -+ boolean onSetLowestPriority(@NonNull final String packageName, final int userId) { -+ return mSettings.setLowestPriority(packageName, userId); -+ } -+ -+ void onDump(@NonNull final PrintWriter pw) { -+ mSettings.dump(pw); -+ } -+ -+ List onGetEnabledOverlayPaths(@NonNull final String targetPackageName, -+ final int userId) { -+ final List overlays = mSettings.getOverlaysForTarget(targetPackageName, userId); -+ final List paths = new ArrayList<>(overlays.size()); -+ for (final OverlayInfo oi : overlays) { -+ if (oi.isEnabled()) { -+ paths.add(oi.baseCodePath); -+ } -+ } -+ return paths; -+ } -+ -+ private void updateState(@Nullable final PackageInfo targetPackage, -+ @NonNull final PackageInfo overlayPackage, final int userId) -+ throws OverlayManagerSettings.BadKeyException { -+ if (targetPackage != null) { -+ mIdmapManager.createIdmap(targetPackage, overlayPackage, userId); -+ } -+ -+ mSettings.setBaseCodePath(overlayPackage.packageName, userId, -+ overlayPackage.applicationInfo.getBaseCodePath()); -+ -+ final int currentState = mSettings.getState(overlayPackage.packageName, userId); -+ final int newState = calculateNewState(targetPackage, overlayPackage, userId); -+ if (currentState != newState) { -+ if (DEBUG) { -+ Slog.d(TAG, String.format("%s:%d: %s -> %s", -+ overlayPackage.packageName, userId, -+ OverlayInfo.stateToString(currentState), -+ OverlayInfo.stateToString(newState))); -+ } -+ mSettings.setState(overlayPackage.packageName, userId, newState); -+ } -+ } -+ -+ private int calculateNewState(@Nullable final PackageInfo targetPackage, -+ @NonNull final PackageInfo overlayPackage, final int userId) -+ throws OverlayManagerSettings.BadKeyException { -+ if (!overlayPackage.applicationInfo.enabled) { -+ return STATE_NOT_APPROVED_COMPONENT_DISABLED; -+ } -+ -+ if (targetPackage == null) { -+ return STATE_NOT_APPROVED_MISSING_TARGET; -+ } -+ -+ if (!mIdmapManager.idmapExists(overlayPackage, userId)) { -+ return STATE_NOT_APPROVED_NO_IDMAP; -+ } -+ -+ final boolean enableIfApproved = mSettings.getEnabled(overlayPackage.packageName, userId); -+ -+ if (mPackageManager.signaturesMatching(targetPackage.packageName, -+ overlayPackage.packageName, userId)) { -+ return enableIfApproved ? STATE_APPROVED_ENABLED : STATE_APPROVED_DISABLED; -+ } -+ -+ if ((overlayPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { -+ return enableIfApproved ? STATE_APPROVED_ENABLED : STATE_APPROVED_DISABLED; -+ } -+ -+ if (!mIdmapManager.isDangerous(overlayPackage, userId)) { -+ return enableIfApproved ? STATE_APPROVED_ENABLED : STATE_APPROVED_DISABLED; -+ } -+ -+ return STATE_NOT_APPROVED_DANGEROUS_OVERLAY; -+ } -+ -+ private void removeIdmapIfPossible(@NonNull final OverlayInfo oi) { -+ // For a given package, all Android users share the same idmap file. -+ // This works because Android currently does not support users to -+ // install different versions of the same package. It also means we -+ // cannot remove an idmap file if any user still needs it. -+ // -+ // When/if the Android framework allows different versions of the same -+ // package to be installed for different users, idmap file handling -+ // should be revised: -+ // -+ // - an idmap file should be unique for each {user, package} pair -+ // -+ // - the path to the idmap file should be passed to the native Asset -+ // Manager layers, just like the path to the apk is passed today -+ // -+ // As part of that change, calls to this method should be replaced by -+ // direct calls to IdmapManager.removeIdmap, without looping over all -+ // users. -+ -+ if (!mIdmapManager.idmapExists(oi)) { -+ return; -+ } -+ final List userIds = mSettings.getUsers(); -+ for (final int userId : userIds) { -+ try { -+ final OverlayInfo tmp = mSettings.getOverlayInfo(oi.packageName, userId); -+ if (tmp != null && tmp.isEnabled()) { -+ // someone is still using the idmap file -> we cannot remove it -+ return; -+ } -+ } catch (OverlayManagerSettings.BadKeyException e) { -+ // intentionally left empty -+ } -+ } -+ mIdmapManager.removeIdmap(oi, oi.userId); -+ } -+ -+ interface PackageManagerHelper { -+ PackageInfo getPackageInfo(@NonNull String packageName, int userId); -+ boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2, -+ int userId); -+ List getOverlayPackages(int userId); -+ } -+} -diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java -new file mode 100644 -index 0000000..af0bb64 ---- /dev/null -+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java -@@ -0,0 +1,656 @@ -+/* -+ * Copyright (C) 2016 The Android Open Source Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package com.android.server.om; -+ -+import static android.content.om.OverlayInfo.STATE_NOT_APPROVED_UNKNOWN; -+import static com.android.server.om.OverlayManagerService.DEBUG; -+import static com.android.server.om.OverlayManagerService.TAG; -+ -+import android.annotation.NonNull; -+import android.annotation.Nullable; -+import android.content.om.OverlayInfo; -+import android.util.AndroidRuntimeException; -+import android.util.ArrayMap; -+import android.util.Slog; -+import android.util.Xml; -+ -+import com.android.internal.util.FastXmlSerializer; -+import com.android.internal.util.XmlUtils; -+ -+import org.xmlpull.v1.XmlPullParser; -+import org.xmlpull.v1.XmlPullParserException; -+ -+import java.io.IOException; -+import java.io.InputStream; -+import java.io.InputStreamReader; -+import java.io.OutputStream; -+import java.io.PrintWriter; -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.Iterator; -+import java.util.List; -+import java.util.ListIterator; -+import java.util.Map; -+ -+/** -+ * Data structure representing the current state of all overlay packages in the -+ * system. -+ * -+ * Modifications to the data are exposed through the ChangeListener interface. -+ * -+ * @see ChangeListener -+ * @see OverlayManagerService -+ */ -+final class OverlayManagerSettings { -+ private final List mListeners = new ArrayList<>(); -+ -+ private final ArrayList mItems = new ArrayList<>(); -+ -+ void init(@NonNull final String packageName, final int userId, -+ @NonNull final String targetPackageName, @NonNull final String baseCodePath) { -+ remove(packageName, userId); -+ final SettingsItem item = -+ new SettingsItem(packageName, userId, targetPackageName, baseCodePath); -+ mItems.add(item); -+ } -+ -+ void remove(@NonNull final String packageName, final int userId) { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ return; -+ } -+ final OverlayInfo oi = item.getOverlayInfo(); -+ mItems.remove(item); -+ if (oi != null) { -+ notifyOverlayRemoved(oi); -+ } -+ } -+ -+ boolean contains(@NonNull final String packageName, final int userId) { -+ return select(packageName, userId) != null; -+ } -+ -+ OverlayInfo getOverlayInfo(@NonNull final String packageName, final int userId) -+ throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ return item.getOverlayInfo(); -+ } -+ -+ String getTargetPackageName(@NonNull final String packageName, final int userId) -+ throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ return item.getTargetPackageName(); -+ } -+ -+ void setBaseCodePath(@NonNull final String packageName, final int userId, -+ @NonNull final String path) throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ item.setBaseCodePath(path); -+ notifySettingsChanged(); -+ } -+ -+ boolean getUpgrading(@NonNull final String packageName, final int userId) -+ throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ return item.isUpgrading(); -+ } -+ -+ void setUpgrading(@NonNull final String packageName, final int userId, final boolean newValue) -+ throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ if (newValue == item.isUpgrading()) { -+ return; // nothing to do -+ } -+ -+ if (newValue) { -+ final OverlayInfo oi = item.getOverlayInfo(); -+ item.setUpgrading(true); -+ item.setState(STATE_NOT_APPROVED_UNKNOWN); -+ notifyOverlayRemoved(oi); -+ } else { -+ item.setUpgrading(false); -+ } -+ notifySettingsChanged(); -+ } -+ -+ boolean getEnabled(@NonNull final String packageName, final int userId) throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ return item.isEnabled(); -+ } -+ -+ void setEnabled(@NonNull final String packageName, final int userId, final boolean enable) -+ throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ if (enable == item.isEnabled()) { -+ return; // nothing to do -+ } -+ -+ item.setEnabled(enable); -+ notifySettingsChanged(); -+ } -+ -+ int getState(@NonNull final String packageName, final int userId) throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ return item.getState(); -+ } -+ -+ void setState(@NonNull final String packageName, final int userId, final int state) -+ throws BadKeyException { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null) { -+ throw new BadKeyException(packageName, userId); -+ } -+ final OverlayInfo previous = item.getOverlayInfo(); -+ item.setState(state); -+ final OverlayInfo current = item.getOverlayInfo(); -+ if (previous.state == STATE_NOT_APPROVED_UNKNOWN) { -+ notifyOverlayAdded(current); -+ notifySettingsChanged(); -+ } else if (current.state != previous.state) { -+ notifyOverlayChanged(current, previous); -+ notifySettingsChanged(); -+ } -+ } -+ -+ List getOverlaysForTarget(@NonNull final String targetPackageName, -+ final int userId) { -+ final List items = selectWhereTarget(targetPackageName, userId); -+ if (items.isEmpty()) { -+ return Collections.emptyList(); -+ } -+ final List out = new ArrayList<>(items.size()); -+ for (final SettingsItem item : items) { -+ if (item.isUpgrading()) { -+ continue; -+ } -+ out.add(item.getOverlayInfo()); -+ } -+ return out; -+ } -+ -+ Map> getOverlaysForUser(final int userId) { -+ final List items = selectWhereUser(userId); -+ if (items.isEmpty()) { -+ return Collections.emptyMap(); -+ } -+ final Map> out = new ArrayMap<>(items.size()); -+ for (final SettingsItem item : items) { -+ if (item.isUpgrading()) { -+ continue; -+ } -+ final String targetPackageName = item.getTargetPackageName(); -+ if (!out.containsKey(targetPackageName)) { -+ out.put(targetPackageName, new ArrayList()); -+ } -+ final List overlays = out.get(targetPackageName); -+ overlays.add(item.getOverlayInfo()); -+ } -+ return out; -+ } -+ -+ List getTargetPackageNamesForUser(final int userId) { -+ final List items = selectWhereUser(userId); -+ if (items.isEmpty()) { -+ return Collections.emptyList(); -+ } -+ final List out = new ArrayList<>(); -+ for (final SettingsItem item : items) { -+ if (item.isUpgrading()) { -+ continue; -+ } -+ final String targetPackageName = item.getTargetPackageName(); -+ if (!out.contains(targetPackageName)) { -+ out.add(targetPackageName); -+ } -+ } -+ return out; -+ } -+ -+ List getUsers() { -+ final ArrayList users = new ArrayList<>(); -+ for (final SettingsItem item : mItems) { -+ if (!users.contains(item.userId)) { -+ users.add(item.userId); -+ } -+ } -+ return users; -+ } -+ -+ void removeUser(final int userId) { -+ final Iterator iter = mItems.iterator(); -+ while (iter.hasNext()) { -+ final SettingsItem item = iter.next(); -+ if (item.userId == userId) { -+ iter.remove(); -+ } -+ } -+ } -+ -+ boolean setPriority(@NonNull final String packageName, -+ @NonNull final String newParentPackageName, final int userId) { -+ if (packageName.equals(newParentPackageName)) { -+ return false; -+ } -+ final SettingsItem rowToMove = select(packageName, userId); -+ if (rowToMove == null || rowToMove.isUpgrading()) { -+ return false; -+ } -+ final SettingsItem newParentRow = select(newParentPackageName, userId); -+ if (newParentRow == null || newParentRow.isUpgrading()) { -+ return false; -+ } -+ if (!rowToMove.getTargetPackageName().equals(newParentRow.getTargetPackageName())) { -+ return false; -+ } -+ -+ mItems.remove(rowToMove); -+ final ListIterator iter = mItems.listIterator(); -+ while (iter.hasNext()) { -+ final SettingsItem item = iter.next(); -+ if (item.userId == userId && item.packageName.equals(newParentPackageName)) { -+ iter.add(rowToMove); -+ notifyOverlayPriorityChanged(rowToMove.getOverlayInfo()); -+ notifySettingsChanged(); -+ return true; -+ } -+ } -+ -+ Slog.wtf(TAG, "failed to find the parent item a second time"); -+ return false; -+ } -+ -+ boolean setLowestPriority(@NonNull final String packageName, final int userId) { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null || item.isUpgrading()) { -+ return false; -+ } -+ mItems.remove(item); -+ mItems.add(0, item); -+ notifyOverlayPriorityChanged(item.getOverlayInfo()); -+ notifySettingsChanged(); -+ return true; -+ } -+ -+ boolean setHighestPriority(@NonNull final String packageName, final int userId) { -+ final SettingsItem item = select(packageName, userId); -+ if (item == null || item.isUpgrading()) { -+ return false; -+ } -+ mItems.remove(item); -+ mItems.add(item); -+ notifyOverlayPriorityChanged(item.getOverlayInfo()); -+ notifySettingsChanged(); -+ return true; -+ } -+ -+ private static final String TAB1 = " "; -+ private static final String TAB2 = TAB1 + TAB1; -+ private static final String TAB3 = TAB2 + TAB1; -+ -+ void dump(@NonNull final PrintWriter pw) { -+ pw.println("Settings"); -+ dumpItems(pw); -+ dumpListeners(pw); -+ } -+ -+ private void dumpItems(@NonNull final PrintWriter pw) { -+ pw.println(TAB1 + "Items"); -+ -+ if (mItems.isEmpty()) { -+ pw.println(TAB2 + ""); -+ return; -+ } -+ -+ for (final SettingsItem item : mItems) { -+ final StringBuilder sb = new StringBuilder(); -+ sb.append(TAB2 + item.packageName + ":" + item.userId + " {\n"); -+ sb.append(TAB3 + "packageName.......: " + item.packageName + "\n"); -+ sb.append(TAB3 + "userId............: " + item.userId + "\n"); -+ sb.append(TAB3 + "targetPackageName.: " + item.getTargetPackageName() + "\n"); -+ sb.append(TAB3 + "baseCodePath......: " + item.getBaseCodePath() + "\n"); -+ sb.append(TAB3 + "state.............: " + OverlayInfo.stateToString(item.getState()) + "\n"); -+ sb.append(TAB3 + "isEnabled.........: " + item.isEnabled() + "\n"); -+ sb.append(TAB3 + "isUpgrading.......: " + item.isUpgrading() + "\n"); -+ sb.append(TAB2 + "}"); -+ pw.println(sb.toString()); -+ } -+ } -+ -+ private void dumpListeners(@NonNull final PrintWriter pw) { -+ pw.println(TAB1 + "Change listeners"); -+ -+ if (mListeners.isEmpty()) { -+ pw.println(TAB2 + ""); -+ return; -+ } -+ -+ for (ChangeListener ch : mListeners) { -+ pw.println(TAB2 + ch); -+ } -+ -+ } -+ -+ void restore(@NonNull final InputStream is) throws IOException, XmlPullParserException { -+ Serializer.restore(mItems, is); -+ } -+ -+ void persist(@NonNull final OutputStream os) throws IOException, XmlPullParserException { -+ Serializer.persist(mItems, os); -+ } -+ -+ private static final class Serializer { -+ private static final String TAG_OVERLAYS = "overlays"; -+ private static final String TAG_ITEM = "item"; -+ -+ private static final String ATTR_BASE_CODE_PATH = "baseCodePath"; -+ private static final String ATTR_IS_ENABLED = "isEnabled"; -+ private static final String ATTR_IS_UPGRADING = "isUpgrading"; -+ private static final String ATTR_PACKAGE_NAME = "packageName"; -+ private static final String ATTR_STATE = "state"; -+ private static final String ATTR_TARGET_PACKAGE_NAME = "targetPackageName"; -+ private static final String ATTR_USER_ID = "userId"; -+ private static final String ATTR_VERSION = "version"; -+ -+ private static final int CURRENT_VERSION = 1; -+ -+ public static void restore(@NonNull final ArrayList table, -+ @NonNull final InputStream is) throws IOException, XmlPullParserException { -+ -+ table.clear(); -+ final XmlPullParser parser = Xml.newPullParser(); -+ parser.setInput(new InputStreamReader(is)); -+ XmlUtils.beginDocument(parser, TAG_OVERLAYS); -+ int version = XmlUtils.readIntAttribute(parser, ATTR_VERSION); -+ if (version != CURRENT_VERSION) { -+ throw new XmlPullParserException("unrecognized version " + version); -+ } -+ int depth = parser.getDepth(); -+ -+ while (XmlUtils.nextElementWithin(parser, depth)) { -+ switch (parser.getName()) { -+ case TAG_ITEM: -+ final SettingsItem item = restoreRow(parser, depth + 1); -+ table.add(item); -+ break; -+ } -+ } -+ } -+ -+ private static SettingsItem restoreRow(@NonNull final XmlPullParser parser, final int depth) -+ throws IOException { -+ final String packageName = XmlUtils.readStringAttribute(parser, ATTR_PACKAGE_NAME); -+ final int userId = XmlUtils.readIntAttribute(parser, ATTR_USER_ID); -+ final String targetPackageName = XmlUtils.readStringAttribute(parser, -+ ATTR_TARGET_PACKAGE_NAME); -+ final String baseCodePath = XmlUtils.readStringAttribute(parser, ATTR_BASE_CODE_PATH); -+ final int state = XmlUtils.readIntAttribute(parser, ATTR_STATE); -+ final boolean isEnabled = XmlUtils.readBooleanAttribute(parser, ATTR_IS_ENABLED); -+ final boolean isUpgrading = XmlUtils.readBooleanAttribute(parser, ATTR_IS_UPGRADING); -+ -+ return new SettingsItem(packageName, userId, targetPackageName, baseCodePath, state, -+ isEnabled, isUpgrading); -+ } -+ -+ public static void persist(@NonNull final ArrayList table, -+ @NonNull final OutputStream os) throws IOException, XmlPullParserException { -+ final FastXmlSerializer xml = new FastXmlSerializer(); -+ xml.setOutput(os, "utf-8"); -+ xml.startDocument(null, true); -+ xml.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); -+ xml.startTag(null, TAG_OVERLAYS); -+ XmlUtils.writeIntAttribute(xml, ATTR_VERSION, CURRENT_VERSION); -+ -+ for (final SettingsItem item : table) { -+ persistRow(xml, item); -+ } -+ xml.endTag(null, TAG_OVERLAYS); -+ xml.endDocument(); -+ } -+ -+ private static void persistRow(@NonNull final FastXmlSerializer xml, -+ @NonNull final SettingsItem item) throws IOException { -+ xml.startTag(null, TAG_ITEM); -+ XmlUtils.writeStringAttribute(xml, ATTR_PACKAGE_NAME, item.packageName); -+ XmlUtils.writeIntAttribute(xml, ATTR_USER_ID, item.userId); -+ XmlUtils.writeStringAttribute(xml, ATTR_TARGET_PACKAGE_NAME, item.targetPackageName); -+ XmlUtils.writeStringAttribute(xml, ATTR_BASE_CODE_PATH, item.baseCodePath); -+ XmlUtils.writeIntAttribute(xml, ATTR_STATE, item.state); -+ XmlUtils.writeBooleanAttribute(xml, ATTR_IS_ENABLED, item.isEnabled); -+ XmlUtils.writeBooleanAttribute(xml, ATTR_IS_UPGRADING, item.isUpgrading); -+ xml.endTag(null, TAG_ITEM); -+ } -+ } -+ -+ private static final class SettingsItem { -+ private final int userId; -+ private final String packageName; -+ private final String targetPackageName; -+ private String baseCodePath; -+ private int state; -+ private boolean isEnabled; -+ private boolean isUpgrading; -+ private OverlayInfo cache; -+ -+ SettingsItem(@NonNull final String packageName, final int userId, -+ @NonNull final String targetPackageName, @NonNull final String baseCodePath, -+ final int state, final boolean isEnabled, final boolean isUpgrading) { -+ this.packageName = packageName; -+ this.userId = userId; -+ this.targetPackageName = targetPackageName; -+ this.baseCodePath = baseCodePath; -+ this.state = state; -+ this.isEnabled = isEnabled; -+ this.isUpgrading = isUpgrading; -+ cache = null; -+ } -+ -+ SettingsItem(@NonNull final String packageName, final int userId, -+ @NonNull final String targetPackageName, @NonNull final String baseCodePath) { -+ this(packageName, userId, targetPackageName, baseCodePath, STATE_NOT_APPROVED_UNKNOWN, -+ false, false); -+ } -+ -+ private String getTargetPackageName() { -+ return targetPackageName; -+ } -+ -+ private String getBaseCodePath() { -+ return baseCodePath; -+ } -+ -+ private void setBaseCodePath(@NonNull final String path) { -+ if (!baseCodePath.equals(path)) { -+ baseCodePath = path; -+ invalidateCache(); -+ } -+ } -+ -+ private int getState() { -+ return state; -+ } -+ -+ private void setState(final int state) { -+ if (this.state != state) { -+ this.state = state; -+ invalidateCache(); -+ } -+ } -+ -+ private boolean isEnabled() { -+ return isEnabled; -+ } -+ -+ private void setEnabled(final boolean enable) { -+ if (isEnabled != enable) { -+ isEnabled = enable; -+ invalidateCache(); -+ } -+ } -+ -+ private boolean isUpgrading() { -+ return isUpgrading; -+ } -+ -+ private void setUpgrading(final boolean upgrading) { -+ if (isUpgrading != upgrading) { -+ isUpgrading = upgrading; -+ invalidateCache(); -+ } -+ } -+ -+ private OverlayInfo getOverlayInfo() { -+ if (isUpgrading) { -+ return null; -+ } -+ if (cache == null) { -+ cache = new OverlayInfo(packageName, targetPackageName, baseCodePath, -+ state, userId); -+ } -+ return cache; -+ } -+ -+ private void invalidateCache() { -+ cache = null; -+ } -+ } -+ -+ private SettingsItem select(@NonNull final String packageName, final int userId) { -+ for (final SettingsItem item : mItems) { -+ if (item.userId == userId && item.packageName.equals(packageName)) { -+ return item; -+ } -+ } -+ return null; -+ } -+ -+ private List selectWhereUser(final int userId) { -+ final ArrayList items = new ArrayList<>(); -+ for (final SettingsItem item : mItems) { -+ if (item.userId == userId) { -+ items.add(item); -+ } -+ } -+ return items; -+ } -+ -+ private List selectWhereTarget(@NonNull final String targetPackageName, -+ final int userId) { -+ final ArrayList items = new ArrayList<>(); -+ for (final SettingsItem item : mItems) { -+ if (item.userId == userId && item.getTargetPackageName().equals(targetPackageName)) { -+ items.add(item); -+ } -+ } -+ return items; -+ } -+ -+ private void assertNotNull(@Nullable final Object o) { -+ if (o == null) { -+ throw new AndroidRuntimeException("object must not be null"); -+ } -+ } -+ -+ void addChangeListener(@NonNull final ChangeListener listener) { -+ mListeners.add(listener); -+ } -+ -+ void removeChangeListener(@NonNull final ChangeListener listener) { -+ mListeners.remove(listener); -+ } -+ -+ private void notifySettingsChanged() { -+ for (final ChangeListener listener : mListeners) { -+ listener.onSettingsChanged(); -+ } -+ } -+ -+ private void notifyOverlayAdded(@NonNull final OverlayInfo oi) { -+ if (DEBUG) { -+ assertNotNull(oi); -+ } -+ for (final ChangeListener listener : mListeners) { -+ listener.onOverlayAdded(oi); -+ } -+ } -+ -+ private void notifyOverlayRemoved(@NonNull final OverlayInfo oi) { -+ if (DEBUG) { -+ assertNotNull(oi); -+ } -+ for (final ChangeListener listener : mListeners) { -+ listener.onOverlayRemoved(oi); -+ } -+ } -+ -+ private void notifyOverlayChanged(@NonNull final OverlayInfo oi, -+ @NonNull final OverlayInfo oldOi) { -+ if (DEBUG) { -+ assertNotNull(oi); -+ assertNotNull(oldOi); -+ } -+ for (final ChangeListener listener : mListeners) { -+ listener.onOverlayChanged(oi, oldOi); -+ } -+ } -+ -+ private void notifyOverlayPriorityChanged(@NonNull final OverlayInfo oi) { -+ if (DEBUG) { -+ assertNotNull(oi); -+ } -+ for (final ChangeListener listener : mListeners) { -+ listener.onOverlayPriorityChanged(oi); -+ } -+ } -+ -+ interface ChangeListener { -+ void onSettingsChanged(); -+ void onOverlayAdded(@NonNull OverlayInfo oi); -+ void onOverlayRemoved(@NonNull OverlayInfo oi); -+ void onOverlayChanged(@NonNull OverlayInfo oi, @NonNull OverlayInfo oldOi); -+ void onOverlayPriorityChanged(@NonNull OverlayInfo oi); -+ } -+ -+ static final class BadKeyException extends RuntimeException { -+ public BadKeyException(@NonNull final String packageName, final int userId) { -+ super("Bad key packageName=" + packageName + " userId=" + userId); -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java -new file mode 100644 -index 0000000..d6f5373 ---- /dev/null -+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java -@@ -0,0 +1,179 @@ -+/* -+ * Copyright (C) 2016 The Android Open Source Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+package com.android.server.om; -+ -+import android.annotation.NonNull; -+import android.annotation.Nullable; -+import android.content.om.IOverlayManager; -+import android.content.om.OverlayInfo; -+import android.os.RemoteException; -+import android.os.ShellCommand; -+import android.os.UserHandle; -+ -+import java.io.PrintWriter; -+import java.util.List; -+import java.util.Map; -+ -+/** -+ * Implementation of 'cmd overlay' commands. -+ * -+ * This class provides an interface to the OverlayManagerService via adb. -+ * Intended only for manual debugging. Execute 'adb exec-out cmd overlay help' -+ * for a list of available commands. -+ */ -+final class OverlayManagerShellCommand extends ShellCommand { -+ private final IOverlayManager mInterface; -+ -+ OverlayManagerShellCommand(@NonNull final IOverlayManager iom) { -+ mInterface = iom; -+ } -+ -+ @Override -+ public int onCommand(@Nullable final String cmd) { -+ if (cmd == null) { -+ return handleDefaultCommands(cmd); -+ } -+ final PrintWriter err = getErrPrintWriter(); -+ try { -+ switch (cmd) { -+ case "list": -+ return runList(); -+ case "enable": -+ return runEnableDisable(true); -+ case "disable": -+ return runEnableDisable(false); -+ case "set-priority": -+ return runSetPriority(); -+ default: -+ return handleDefaultCommands(cmd); -+ } -+ } catch (IllegalArgumentException e) { -+ err.println("Error: " + e.getMessage()); -+ } catch (RemoteException e) { -+ err.println("Remote exception: " + e); -+ } -+ return -1; -+ } -+ -+ @Override -+ public void onHelp() { -+ final PrintWriter out = getOutPrintWriter(); -+ out.println("Overlay manager (overlay) commands:"); -+ out.println(" help"); -+ out.println(" Print this help text."); -+ out.println(" dump [--verbose] [--user USER_ID] [PACKAGE [PACKAGE [...]]]"); -+ out.println(" Print debugging information about the overlay manager."); -+ out.println(" list [--user USER_ID] [PACKAGE [PACKAGE [...]]]"); -+ out.println(" Print information about target and overlay packages."); -+ out.println(" Overlay packages are printed in priority order. With optional"); -+ out.println(" parameters PACKAGEs, limit output to the specified packages"); -+ out.println(" but include more information about each package."); -+ out.println(" enable [--user USER_ID] PACKAGE"); -+ out.println(" Enable overlay package PACKAGE."); -+ out.println(" disable [--user USER_ID] PACKAGE"); -+ out.println(" Disable overlay package PACKAGE."); -+ out.println(" set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest"); -+ out.println(" Change the priority of the overlay PACKAGE to be just higher than"); -+ out.println(" the priority of PACKAGE_PARENT If PARENT is the special keyword"); -+ out.println(" 'lowest', change priority of PACKAGE to the lowest priority."); -+ out.println(" If PARENT is the special keyword 'highest', change priority of"); -+ out.println(" PACKAGE to the highest priority."); -+ } -+ -+ private int runList() throws RemoteException { -+ final PrintWriter out = getOutPrintWriter(); -+ final PrintWriter err = getErrPrintWriter(); -+ -+ int userId = UserHandle.USER_SYSTEM; -+ String opt; -+ while ((opt = getNextOption()) != null) { -+ switch (opt) { -+ case "--user": -+ userId = UserHandle.parseUserArg(getNextArgRequired()); -+ break; -+ default: -+ err.println("Error: Unknown option: " + opt); -+ return 1; -+ } -+ } -+ -+ final Map> allOverlays = mInterface.getAllOverlays(userId); -+ for (final String targetPackageName : allOverlays.keySet()) { -+ out.println(targetPackageName); -+ for (final OverlayInfo oi : allOverlays.get(targetPackageName)) { -+ String status = "---"; -+ if (oi.isApproved()) { -+ status = "[ ]"; -+ } -+ if (oi.isEnabled()) { -+ status = "[x]"; -+ } -+ out.println(String.format("%s %s", status, oi.packageName)); -+ } -+ out.println(); -+ } -+ return 0; -+ } -+ -+ private int runEnableDisable(final boolean enable) throws RemoteException { -+ final PrintWriter err = getErrPrintWriter(); -+ -+ int userId = UserHandle.USER_SYSTEM; -+ String opt; -+ while ((opt = getNextOption()) != null) { -+ switch (opt) { -+ case "--user": -+ userId = UserHandle.parseUserArg(getNextArgRequired()); -+ break; -+ default: -+ err.println("Error: Unknown option: " + opt); -+ return 1; -+ } -+ } -+ -+ final String packageName = getNextArgRequired(); -+ return mInterface.setEnabled(packageName, enable, userId) ? 0 : 1; -+ } -+ -+ private int runSetPriority() throws RemoteException { -+ final PrintWriter err = getErrPrintWriter(); -+ -+ int userId = UserHandle.USER_SYSTEM; -+ String opt; -+ while ((opt = getNextOption()) != null) { -+ switch (opt) { -+ case "--user": -+ userId = UserHandle.parseUserArg(getNextArgRequired()); -+ break; -+ default: -+ err.println("Error: Unknown option: " + opt); -+ return 1; -+ } -+ } -+ -+ final String packageName = getNextArgRequired(); -+ final String newParentPackageName = getNextArgRequired(); -+ -+ if ("highest".equals(newParentPackageName)) { -+ return mInterface.setHighestPriority(packageName, userId) ? 0 : 1; -+ } else if ("lowest".equals(newParentPackageName)) { -+ return mInterface.setLowestPriority(packageName, userId) ? 0 : 1; -+ } else { -+ return mInterface.setPriority(packageName, newParentPackageName, userId) ? 0 : 1; -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java -index 583cb23..3892f8f 100644 ---- a/services/core/java/com/android/server/pm/PackageManagerService.java -+++ b/services/core/java/com/android/server/pm/PackageManagerService.java -@@ -21444,6 +21444,47 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); - return mSettings.wasPackageEverLaunchedLPr(packageName, userId); - } - } -+ -+ @Override -+ public List getOverlayPackages(int userId) { -+ final ArrayList overlayPackages = new ArrayList(); -+ synchronized (mPackages) { -+ for (PackageParser.Package p : mPackages.values()) { -+ if (p.mOverlayTarget != null) { -+ PackageInfo pkg = generatePackageInfo((PackageSetting)p.mExtras, 0, userId); -+ if (pkg != null) { -+ overlayPackages.add(pkg); -+ } -+ } -+ } -+ } -+ return overlayPackages; -+ } -+ -+ @Override -+ public List getTargetPackageNames(int userId) { -+ List targetPackages = new ArrayList<>(); -+ synchronized (mPackages) { -+ for (PackageParser.Package p : mPackages.values()) { -+ if (p.mOverlayTarget == null) { -+ targetPackages.add(p.packageName); -+ } -+ } -+ } -+ return targetPackages; -+ } -+ -+ @Override -+ public void setResourceDirs(int userId, String packageName, String[] resourceDirs) { -+ // TODO: uncomment when we integrate OMS properly -+ // synchronized (mPackages) { -+ // PackageSetting ps = mSettings.mPackages.get(packageName); -+ // if (ps == null) { -+ // return; -+ // } -+ // ps.setResourceDirs(resourceDirs, userId); -+ // } -+ } - } - - @Override --- -2.9.3 - diff --git a/frameworks/base/0003-OMS7-N-Integrate-OverlayManagerService-into-framewor.patch b/frameworks/base/0003-OMS7-N-Integrate-OverlayManagerService-into-framewor.patch deleted file mode 100644 index 5104306..0000000 --- a/frameworks/base/0003-OMS7-N-Integrate-OverlayManagerService-into-framewor.patch +++ /dev/null @@ -1,1473 +0,0 @@ -From 2a5bd30d939fd04580f162115ddba6c359290b6f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= -Date: Thu, 2 Jun 2016 09:35:31 +0200 -Subject: [PATCH 03/38] OMS7-N: Integrate OverlayManagerService into framework - [3/11] - -Hand over ownership of overlays to OverlayManagerService. - -Changes to a package's overlays are propagated using the activity life -cycle. Affected activities will be recreated as needed. This provides a -well-defined point to modify an application's assets while the -application is paused. - -Consolidate how overlays targeting the system and overlays targeting -regular applications are handled. Previously, system overlays were -handled as a special case. Now, everything is handled identically. As a -side effect, the call to idmap --scan during Zygote boot has become -obsolete and is removed. - -Deprecate and remove use of SCAN_TRUSTED_OVERLAY from -PackageManagerService. Previously, the flag was used to restrict what -paths overlays were allowed to be installed in. Now, overlay packages -are first class packages and it is up to the OverlayManagerService to -decide whether to use the overlay or not. - -Information on what overlays to use is recorded in -ApplicationInfo.resourceDirs. The PackageManagerService is responsible -for the creation of ApplicationInfo objects. The OverlayManagerService -is responsible for informing the PackageManagerService in advance about -what resourceDirs to use. - -When launching an application, the ApplicationInfo is already populated -with up-to-date information about overlays. - -When enabling or disabling an overlay for a running application, the -OverlayManagerService first notifies the OverlayManagerService about the -updated resourceDirs. It then tells the ActivityManagerService to push -the new ApplicationInfo object to the application's ActivityThread. -Finally the application requests its ResourcesManager to create new -ResourcesImpl objects based on the updated paths. - -Change-Id: If0b1eaa690c38f9c33f7c8dc981314205a73fa9c ---- - cmds/idmap/Android.mk | 2 +- - cmds/idmap/idmap.cpp | 55 --------- - cmds/idmap/idmap.h | 6 - - core/java/android/app/ActivityManagerNative.java | 30 +++++ - core/java/android/app/ActivityThread.java | 45 +++++++ - core/java/android/app/ApplicationThreadNative.java | 21 ++++ - core/java/android/app/IActivityManager.java | 2 + - core/java/android/app/IApplicationThread.java | 2 + - core/java/android/app/ResourcesManager.java | 119 ++++++++++++++---- - core/java/android/content/pm/PackageParser.java | 20 +-- - core/java/android/content/pm/PackageUserState.java | 6 + - core/jni/android_util_AssetManager.cpp | 95 --------------- - include/androidfw/AssetManager.h | 15 +-- - libs/androidfw/AssetManager.cpp | 104 ---------------- - .../com/android/server/SystemServiceManager.java | 24 ++-- - .../android/server/am/ActivityManagerService.java | 51 ++++++++ - .../android/server/om/OverlayManagerService.java | 61 +++++----- - .../android/server/pm/PackageManagerService.java | 134 ++++----------------- - .../com/android/server/pm/PackageSettingBase.java | 8 +- - .../core/java/com/android/server/pm/Settings.java | 4 +- - services/java/com/android/server/SystemServer.java | 4 + - 21 files changed, 335 insertions(+), 473 deletions(-) - -diff --git a/cmds/idmap/Android.mk b/cmds/idmap/Android.mk -index 50ccb07..eb6da18 100644 ---- a/cmds/idmap/Android.mk -+++ b/cmds/idmap/Android.mk -@@ -15,7 +15,7 @@ - LOCAL_PATH:= $(call my-dir) - include $(CLEAR_VARS) - --LOCAL_SRC_FILES := idmap.cpp create.cpp scan.cpp inspect.cpp -+LOCAL_SRC_FILES := idmap.cpp create.cpp inspect.cpp - - LOCAL_SHARED_LIBRARIES := liblog libutils libandroidfw - -diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp -index 3ab1915..d388977 100644 ---- a/cmds/idmap/idmap.cpp -+++ b/cmds/idmap/idmap.cpp -@@ -13,8 +13,6 @@ SYNOPSIS \n\ - idmap --help \n\ - idmap --fd target overlay fd \n\ - idmap --path target overlay idmap \n\ -- idmap --scan target-package-name-to-look-for path-to-target-apk dir-to-hold-idmaps \\\ -- dir-to-scan [additional-dir-to-scan [additional-dir-to-scan [...]]]\n\ - idmap --inspect idmap \n\ - \n\ - DESCRIPTION \n\ -@@ -49,11 +47,6 @@ OPTIONS \n\ - --path: create idmap for target package 'target' (path to apk) and overlay package \n\ - 'overlay' (path to apk); write results to 'idmap' (path). \n\ - \n\ -- --scan: non-recursively search directory 'dir-to-scan' (path) for overlay packages with \n\ -- target package 'target-package-name-to-look-for' (package name) present at\n\ -- 'path-to-target-apk' (path to apk). For each overlay package found, create an\n\ -- idmap file in 'dir-to-hold-idmaps' (path). \n\ --\n\ - --inspect: decode the binary format of 'idmap' (path) and display the contents in a \n\ - debug-friendly format. \n\ - \n\ -@@ -97,16 +90,6 @@ EXAMPLES \n\ - NOTES \n\ - This tool and its expected invocation from installd is modelled on dexopt."; - -- bool verify_directory_readable(const char *path) -- { -- return access(path, R_OK | X_OK) == 0; -- } -- -- bool verify_directory_writable(const char *path) -- { -- return access(path, W_OK) == 0; -- } -- - bool verify_file_readable(const char *path) - { - return access(path, R_OK) == 0; -@@ -167,36 +150,6 @@ NOTES \n\ - return idmap_create_path(target_apk_path, overlay_apk_path, idmap_path); - } - -- int maybe_scan(const char *target_package_name, const char *target_apk_path, -- const char *idmap_dir, const android::Vector *overlay_dirs) -- { -- if (!verify_root_or_system()) { -- fprintf(stderr, "error: permission denied: not user root or user system\n"); -- return -1; -- } -- -- if (!verify_file_readable(target_apk_path)) { -- ALOGD("error: failed to read apk %s: %s\n", target_apk_path, strerror(errno)); -- return -1; -- } -- -- if (!verify_directory_writable(idmap_dir)) { -- ALOGD("error: no write access to %s: %s\n", idmap_dir, strerror(errno)); -- return -1; -- } -- -- const size_t N = overlay_dirs->size(); -- for (size_t i = 0; i < N; i++) { -- const char *dir = overlay_dirs->itemAt(i); -- if (!verify_directory_readable(dir)) { -- ALOGD("error: no read access to %s: %s\n", dir, strerror(errno)); -- return -1; -- } -- } -- -- return idmap_scan(target_package_name, target_apk_path, idmap_dir, overlay_dirs); -- } -- - int maybe_inspect(const char *idmap_path) - { - // anyone (not just root or system) may do --inspect -@@ -235,14 +188,6 @@ int main(int argc, char **argv) - return maybe_create_path(argv[2], argv[3], argv[4]); - } - -- if (argc >= 6 && !strcmp(argv[1], "--scan")) { -- android::Vector v; -- for (int i = 5; i < argc; i++) { -- v.push(argv[i]); -- } -- return maybe_scan(argv[2], argv[3], argv[4], &v); -- } -- - if (argc == 3 && !strcmp(argv[1], "--inspect")) { - return maybe_inspect(argv[2]); - } -diff --git a/cmds/idmap/idmap.h b/cmds/idmap/idmap.h -index 8d4210b..5914de9 100644 ---- a/cmds/idmap/idmap.h -+++ b/cmds/idmap/idmap.h -@@ -25,12 +25,6 @@ int idmap_create_path(const char *target_apk_path, const char *overlay_apk_path, - - int idmap_create_fd(const char *target_apk_path, const char *overlay_apk_path, int fd); - --// Regarding target_package_name: the idmap_scan implementation should --// be able to extract this from the manifest in target_apk_path, --// simplifying the external API. --int idmap_scan(const char *target_package_name, const char *target_apk_path, -- const char *idmap_dir, const android::Vector *overlay_dirs); -- - int idmap_inspect(const char *idmap_path); - - #endif // _IDMAP_H_ -diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java -index 50479c8..389f342 100644 ---- a/core/java/android/app/ActivityManagerNative.java -+++ b/core/java/android/app/ActivityManagerNative.java -@@ -16,6 +16,7 @@ - - package android.app; - -+import android.annotation.NonNull; - import android.annotation.UserIdInt; - import android.app.ActivityManager.StackInfo; - import android.app.assist.AssistContent; -@@ -1226,6 +1227,19 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM - return true; - } - -+ case UPDATE_ASSETS_TRANSACTION: { -+ data.enforceInterface(IActivityManager.descriptor); -+ final int userId = data.readInt(); -+ final int N = data.readInt(); -+ final List packageNames = new ArrayList<>(); -+ for (int i = 0; i < N; i++) { -+ packageNames.add(data.readString()); -+ } -+ updateAssets(userId, packageNames); -+ reply.writeNoException(); -+ return true; -+ } -+ - case SET_REQUESTED_ORIENTATION_TRANSACTION: { - data.enforceInterface(IActivityManager.descriptor); - IBinder token = data.readStrongBinder(); -@@ -4586,6 +4600,22 @@ class ActivityManagerProxy implements IActivityManager - data.recycle(); - reply.recycle(); - } -+ public void updateAssets(final int userId, @NonNull final List packageNames) -+ throws RemoteException -+ { -+ final Parcel data = Parcel.obtain(); -+ final Parcel reply = Parcel.obtain(); -+ data.writeInterfaceToken(IActivityManager.descriptor); -+ data.writeInt(userId); -+ data.writeInt(packageNames.size()); -+ for (int i = 0; i < packageNames.size(); i++) { -+ data.writeString(packageNames.get(i)); -+ } -+ mRemote.transact(UPDATE_ASSETS_TRANSACTION, data, reply, 0); -+ reply.readException(); -+ data.recycle(); -+ reply.recycle(); -+ } - public void setRequestedOrientation(IBinder token, int requestedOrientation) - throws RemoteException { - Parcel data = Parcel.obtain(); -diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java -index 2d22f26..55fc25d 100644 ---- a/core/java/android/app/ActivityThread.java -+++ b/core/java/android/app/ActivityThread.java -@@ -897,6 +897,14 @@ public final class ActivityThread { - sendMessage(H.CONFIGURATION_CHANGED, config); - } - -+ public void scheduleAssetsChanged(@NonNull final String packageName, -+ @NonNull final ApplicationInfo ai) { -+ final SomeArgs args = SomeArgs.obtain(); -+ args.arg1 = packageName; -+ args.arg2 = ai; -+ sendMessage(H.ASSETS_CHANGED, args); -+ } -+ - public void updateTimeZone() { - TimeZone.setDefault(null); - } -@@ -1405,6 +1413,7 @@ public final class ActivityThread { - public static final int MULTI_WINDOW_MODE_CHANGED = 152; - public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153; - public static final int LOCAL_VOICE_INTERACTION_STARTED = 154; -+ public static final int ASSETS_CHANGED = 155; - - String codeToString(int code) { - if (DEBUG_MESSAGES) { -@@ -1461,6 +1470,7 @@ public final class ActivityThread { - case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED"; - case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED"; - case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED"; -+ case ASSETS_CHANGED: return "ASSETS_CHANGED"; - } - } - return Integer.toString(code); -@@ -1716,6 +1726,10 @@ public final class ActivityThread { - handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1, - (IVoiceInteractor) ((SomeArgs) msg.obj).arg2); - break; -+ case ASSETS_CHANGED: -+ handleAssetsChanged((String)((SomeArgs)msg.obj).arg1, -+ (ApplicationInfo)((SomeArgs)msg.obj).arg2); -+ break; - } - Object obj = msg.obj; - if (obj instanceof SomeArgs) { -@@ -4803,6 +4817,37 @@ public final class ActivityThread { - } - } - -+ final void handleAssetsChanged(@NonNull final String packageToUpdate, -+ @NonNull final ApplicationInfo ai) { -+ synchronized (mResourcesManager) { -+ // Update all affected loaded packages with new overlay package information -+ final ArrayList> loadedPackages = new ArrayList<>(); -+ loadedPackages.addAll(mPackages.values()); -+ loadedPackages.addAll(mResourcePackages.values()); -+ for (final WeakReference ref : loadedPackages) { -+ final LoadedApk apk = ref.get(); -+ if (apk != null) { -+ final String packageName = apk.getPackageName(); -+ if (packageToUpdate.equals(packageName)) { -+ apk.updateApplicationInfo(ai, null); -+ } -+ } -+ } -+ -+ // Update all affected Resources objects to use new ResourcesImpl -+ mResourcesManager.applyNewResourceDirsLocked(ai.sourceDir, ai.resourceDirs); -+ } -+ -+ // Schedule all activities to reload -+ for (final Map.Entry entry : mActivities.entrySet()) { -+ final Activity activity = entry.getValue().activity; -+ if (!activity.mFinished) { -+ requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false, -+ false); -+ } -+ } -+ } -+ - static void freeTextLayoutCachesIfNeeded(int configDiff) { - if (configDiff != 0) { - // Ask text layout engine to free its caches if there is a locale change -diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java -index 05d9d7e..47b05ee 100644 ---- a/core/java/android/app/ApplicationThreadNative.java -+++ b/core/java/android/app/ApplicationThreadNative.java -@@ -16,6 +16,7 @@ - - package android.app; - -+import android.annotation.NonNull; - import android.content.ComponentName; - import android.content.Intent; - import android.content.IIntentReceiver; -@@ -331,6 +332,15 @@ public abstract class ApplicationThreadNative extends Binder - return true; - } - -+ case SCHEDULE_ASSETS_CHANGED_TRANSACTION: -+ { -+ data.enforceInterface(IApplicationThread.descriptor); -+ final String packageName = data.readString(); -+ final ApplicationInfo ai = ApplicationInfo.CREATOR.createFromParcel(data); -+ scheduleAssetsChanged(packageName, ai); -+ return true; -+ } -+ - case UPDATE_TIME_ZONE_TRANSACTION: { - data.enforceInterface(IApplicationThread.descriptor); - updateTimeZone(); -@@ -1126,6 +1136,17 @@ class ApplicationThreadProxy implements IApplicationThread { - data.recycle(); - } - -+ public final void scheduleAssetsChanged(@NonNull final String packageName, -+ @NonNull final ApplicationInfo ai) throws RemoteException { -+ final Parcel data = Parcel.obtain(); -+ data.writeInterfaceToken(IApplicationThread.descriptor); -+ data.writeString(packageName); -+ ai.writeToParcel(data, 0); -+ mRemote.transact(SCHEDULE_ASSETS_CHANGED_TRANSACTION, data, null, -+ IBinder.FLAG_ONEWAY); -+ data.recycle(); -+ } -+ - public void updateTimeZone() throws RemoteException { - Parcel data = Parcel.obtain(); - data.writeInterfaceToken(IApplicationThread.descriptor); -diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java -index 5a4470b..c7522b9 100644 ---- a/core/java/android/app/IActivityManager.java -+++ b/core/java/android/app/IActivityManager.java -@@ -266,6 +266,7 @@ public interface IActivityManager extends IInterface { - - public Configuration getConfiguration() throws RemoteException; - public void updateConfiguration(Configuration values) throws RemoteException; -+ public void updateAssets(int userId, List packageNames) throws RemoteException; - public void setRequestedOrientation(IBinder token, - int requestedOrientation) throws RemoteException; - public int getRequestedOrientation(IBinder token) throws RemoteException; -@@ -1075,4 +1076,5 @@ public interface IActivityManager extends IInterface { - int SET_RENDER_THREAD_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 378; - int SET_HAS_TOP_UI = IBinder.FIRST_CALL_TRANSACTION + 379; - int CAN_BYPASS_WORK_CHALLENGE = IBinder.FIRST_CALL_TRANSACTION + 380; -+ int UPDATE_ASSETS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 381; - } -diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java -index 3fa88ae..fcc97e3 100644 ---- a/core/java/android/app/IApplicationThread.java -+++ b/core/java/android/app/IApplicationThread.java -@@ -104,6 +104,7 @@ public interface IApplicationThread extends IInterface { - void scheduleExit() throws RemoteException; - void scheduleSuicide() throws RemoteException; - void scheduleConfigurationChanged(Configuration config) throws RemoteException; -+ void scheduleAssetsChanged(String packageName, ApplicationInfo ai) throws RemoteException; - void updateTimeZone() throws RemoteException; - void clearDnsCache() throws RemoteException; - void setHttpProxy(String proxy, String port, String exclList, -@@ -225,4 +226,5 @@ public interface IApplicationThread extends IInterface { - int SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58; - int SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59; - int SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+60; -+ int SCHEDULE_ASSETS_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+61; - } -diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java -index 4916c1c..8cbca31 100644 ---- a/core/java/android/app/ResourcesManager.java -+++ b/core/java/android/app/ResourcesManager.java -@@ -29,6 +29,7 @@ import android.content.res.ResourcesImpl; - import android.content.res.ResourcesKey; - import android.hardware.display.DisplayManagerGlobal; - import android.os.IBinder; -+import android.os.Process; - import android.os.Trace; - import android.util.ArrayMap; - import android.util.DisplayMetrics; -@@ -52,6 +53,8 @@ public class ResourcesManager { - static final String TAG = "ResourcesManager"; - private static final boolean DEBUG = false; - -+ private static final String FRAMEWORK_RESOURCES_PATH = "/system/framework/framework-res.apk"; -+ - private static ResourcesManager sResourcesManager; - - /** -@@ -916,44 +919,108 @@ public class ResourcesManager { - } - } - -- // Bail early if there is no work to do. -- if (updatedResourceKeys.isEmpty()) { -- return; -+ redirectResourcesToNewImplLocked(updatedResourceKeys); -+ } -+ } -+ -+ final void applyNewResourceDirsLocked(@NonNull final String baseCodePath, -+ @NonNull final String[] newResourceDirs) { -+ try { -+ Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, -+ "ResourcesManager#applyNewResourceDirsLocked"); -+ -+ ApplicationPackageManager.configurationChanged(); -+ -+ if (Process.myUid() == Process.SYSTEM_UID) { -+ // Resources.getSystem Resources are created on request and aren't tracked by -+ // mResourceReferences. -+ // -+ // If overlays targeting "android" are to be used, we must create the system -+ // resources regardless of whether they already exist, since otherwise the -+ // information on what overlays to use would be lost. This is wasteful for most -+ // applications, so limit this operation to the system user only. (This means -+ // Resources.getSystem() will *not* use overlays for applications.) -+ if (FRAMEWORK_RESOURCES_PATH.equals(baseCodePath)) { -+ final ResourcesKey key = new ResourcesKey( -+ FRAMEWORK_RESOURCES_PATH, -+ null, -+ newResourceDirs, -+ null, -+ Display.DEFAULT_DISPLAY, -+ null, -+ null); -+ final ResourcesImpl impl = createResourcesImpl(key); -+ Resources.getSystem().setImpl(impl); -+ } - } - -- // Update any references to ResourcesImpl that require reloading. -- final int resourcesCount = mResourceReferences.size(); -- for (int i = 0; i < resourcesCount; i++) { -- final Resources r = mResourceReferences.get(i).get(); -+ -+ final ArrayMap updatedResourceKeys = new ArrayMap<>(); -+ final int implCount = mResourceImpls.size(); -+ for (int i = 0; i < implCount; i++) { -+ final ResourcesImpl impl = mResourceImpls.valueAt(i).get(); -+ final ResourcesKey key = mResourceImpls.keyAt(i); -+ if (impl != null && key.mResDir != null && key.mResDir.equals(baseCodePath)) { -+ -+ updatedResourceKeys.put(impl, new ResourcesKey( -+ key.mResDir, -+ key.mSplitResDirs, -+ newResourceDirs, -+ key.mLibDirs, -+ key.mDisplayId, -+ key.mOverrideConfiguration, -+ key.mCompatInfo)); -+ } -+ } -+ -+ invalidatePath("/"); -+ -+ redirectResourcesToNewImplLocked(updatedResourceKeys); -+ } finally { -+ Trace.traceEnd(Trace.TRACE_TAG_RESOURCES); -+ } -+ } -+ -+ private void redirectResourcesToNewImplLocked( -+ @NonNull final ArrayMap updatedResourceKeys) { -+ -+ // Bail early if there is no work to do. -+ if (updatedResourceKeys.isEmpty()) { -+ return; -+ } -+ -+ // Update any references to ResourcesImpl that require reloading. -+ final int resourcesCount = mResourceReferences.size(); -+ for (int i = 0; i < resourcesCount; i++) { -+ final Resources r = mResourceReferences.get(i).get(); -+ if (r != null) { -+ final ResourcesKey key = updatedResourceKeys.get(r.getImpl()); -+ if (key != null) { -+ final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key); -+ if (impl == null) { -+ throw new Resources.NotFoundException("failed to load"); -+ } -+ r.setImpl(impl); -+ } -+ } -+ } -+ -+ // Update any references to ResourcesImpl that require reloading for each Activity. -+ for (final ActivityResources activityResources : mActivityResourceReferences.values()) { -+ final int resCount = activityResources.activityResources.size(); -+ for (int i = 0; i < resCount; i++) { -+ final Resources r = activityResources.activityResources.get(i).get(); - if (r != null) { - final ResourcesKey key = updatedResourceKeys.get(r.getImpl()); - if (key != null) { - final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key); - if (impl == null) { -- throw new Resources.NotFoundException("failed to load " + libAsset); -+ throw new Resources.NotFoundException("failed to load"); - } - r.setImpl(impl); - } - } - } -- -- // Update any references to ResourcesImpl that require reloading for each Activity. -- for (ActivityResources activityResources : mActivityResourceReferences.values()) { -- final int resCount = activityResources.activityResources.size(); -- for (int i = 0; i < resCount; i++) { -- final Resources r = activityResources.activityResources.get(i).get(); -- if (r != null) { -- final ResourcesKey key = updatedResourceKeys.get(r.getImpl()); -- if (key != null) { -- final ResourcesImpl impl = findOrCreateResourcesImplForKeyLocked(key); -- if (impl == null) { -- throw new Resources.NotFoundException("failed to load " + libAsset); -- } -- r.setImpl(impl); -- } -- } -- } -- } - } - } - } -diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java -index f2e3333..8d42d2c 100644 ---- a/core/java/android/content/pm/PackageParser.java -+++ b/core/java/android/content/pm/PackageParser.java -@@ -668,10 +668,9 @@ public class PackageParser { - public final static int PARSE_IS_SYSTEM_DIR = 1<<6; - public final static int PARSE_IS_PRIVILEGED = 1<<7; - public final static int PARSE_COLLECT_CERTIFICATES = 1<<8; -- public final static int PARSE_TRUSTED_OVERLAY = 1<<9; -- public final static int PARSE_ENFORCE_CODE = 1<<10; -- public final static int PARSE_IS_EPHEMERAL = 1<<11; -- public final static int PARSE_FORCE_SDK = 1<<12; -+ public final static int PARSE_ENFORCE_CODE = 1<<9; -+ public final static int PARSE_IS_EPHEMERAL = 1<<10; -+ public final static int PARSE_FORCE_SDK = 1<<11; - - private static final Comparator sSplitNameComparator = new SplitNameComparator(); - -@@ -1806,9 +1805,6 @@ public class PackageParser { - 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) { -@@ -1816,14 +1812,7 @@ public class PackageParser { - mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; - return null; - } -- if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) { -- outError[0] = " priority must be between 0 and 9999"; -- mParseError = -- PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; -- return null; -- } - XmlUtils.skipCurrentTag(parser); -- - } else if (tagName.equals(TAG_KEY_SETS)) { - if (!parseKeySets(pkg, res, parser, outError)) { - return null; -@@ -4913,8 +4902,6 @@ public class PackageParser { - public String mRequiredAccountType; - - public String mOverlayTarget; -- public int mOverlayPriority; -- public boolean mTrustedOverlay; - - /** - * Data used to feed the KeySetManagerService -@@ -5455,6 +5442,7 @@ public class PackageParser { - ai.enabled = false; - } - ai.enabledSetting = state.enabled; -+ ai.resourceDirs = state.resourceDirs; - if (state.protectedComponents != null) { - ai.protect = state.protectedComponents.size() > 0; - } -diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java -index e64e4c4..4b276fb 100644 ---- a/core/java/android/content/pm/PackageUserState.java -+++ b/core/java/android/content/pm/PackageUserState.java -@@ -31,6 +31,8 @@ import android.util.ArraySet; - - import com.android.internal.util.ArrayUtils; - -+import java.util.Arrays; -+ - /** - * Per-user state information about a package. - * @hide -@@ -53,6 +55,8 @@ public class PackageUserState { - public ArraySet protectedComponents; - public ArraySet visibleComponents; - -+ public String[] resourceDirs; -+ - public PackageUserState() { - installed = true; - hidden = false; -@@ -76,6 +80,8 @@ public class PackageUserState { - appLinkGeneration = o.appLinkGeneration; - disabledComponents = ArrayUtils.cloneOrNull(o.disabledComponents); - enabledComponents = ArrayUtils.cloneOrNull(o.enabledComponents); -+ resourceDirs = -+ o.resourceDirs == null ? null : Arrays.copyOf(o.resourceDirs, o.resourceDirs.length); - protectedComponents = o.protectedComponents != null - ? new ArraySet(o.protectedComponents) : null; - visibleComponents = o.visibleComponents != null -diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp -index 1a7294f..6c5a88f 100644 ---- a/core/jni/android_util_AssetManager.cpp -+++ b/core/jni/android_util_AssetManager.cpp -@@ -129,85 +129,6 @@ 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(const char* overlay_dir) --{ -- 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); -- } -- -- // Generic idmap parameters -- const char* argv[7]; -- int argc = 0; -- struct stat st; -- -- memset(argv, NULL, sizeof(argv)); -- argv[argc++] = AssetManager::IDMAP_BIN; -- argv[argc++] = "--scan"; -- argv[argc++] = AssetManager::TARGET_PACKAGE_NAME; -- argv[argc++] = AssetManager::TARGET_APK_PATH; -- argv[argc++] = AssetManager::IDMAP_DIR; -- -- // Directories to scan for overlays -- // /vendor/overlay -- -- if (stat(overlay_dir, &st) == 0) { -- argv[argc++] = overlay_dir; -- } -- -- // Finally, invoke idmap (if any overlay directory exists) -- if (argc > 5) { -- execv(AssetManager::IDMAP_BIN, (char* const*)argv); -- ALOGE("failed to execl for idmap: %s", strerror(errno)); -- exit(1); // should never get here -- } else { -- exit(0); -- } -- } -- break; -- default: // parent -- waitpid(pid, NULL, 0); -- break; -- } --} -- - // ---------------------------------------------------------------------------- - - // this guy is exported to other jni routines -@@ -2078,22 +1999,6 @@ static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jo - - static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem) - { -- if (isSystem) { -- // Load frameworks-res.apk's overlay through regionalization environment -- if (Environment::isSupported()) { -- Environment* environment = new Environment(); -- if (environment != NULL) { -- const char* overlay_dir = environment->getOverlayDir(); -- if (overlay_dir != NULL && strcmp(overlay_dir, "") != 0) { -- ALOGD("Regionalization - getOverlayDir:%s", overlay_dir); -- verifySystemIdmaps(overlay_dir); -- } -- delete environment; -- } -- } -- -- verifySystemIdmaps(AssetManager::OVERLAY_DIR); -- } - AssetManager* am = new AssetManager(); - if (am == NULL) { - jniThrowException(env, "java/lang/OutOfMemoryError", ""); -diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h -index 914ac3d..651765b 100644 ---- a/include/androidfw/AssetManager.h -+++ b/include/androidfw/AssetManager.h -@@ -238,12 +238,10 @@ public: - private: - struct asset_path - { -- asset_path() : path(""), type(kFileTypeRegular), idmap(""), -- isSystemOverlay(false), isSystemAsset(false) {} -+ asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemAsset(false) {} - String8 path; - FileType type; - String8 idmap; -- bool isSystemOverlay; - bool isSystemAsset; - }; - -@@ -288,9 +286,6 @@ private: - - Asset* openIdmapLocked(const struct asset_path& ap) const; - -- void addSystemOverlays(const char* pathOverlaysList, const String8& targetPackagePath, -- ResTable* sharedRes, size_t offset) const; -- - class SharedZip : public RefBase { - public: - static sp get(const String8& path, bool createIfNotPresent = true); -@@ -305,9 +300,6 @@ private: - - bool isUpToDate(); - -- void addOverlay(const asset_path& ap); -- bool getOverlay(size_t idx, asset_path* out) const; -- - protected: - ~SharedZip(); - -@@ -322,8 +314,6 @@ private: - Asset* mResourceTableAsset; - ResTable* mResourceTable; - -- Vector mOverlays; -- - static Mutex gLock; - static DefaultKeyedVector > gOpen; - }; -@@ -356,9 +346,6 @@ private: - static String8 getPathName(const char* path); - - bool isUpToDate(); -- -- void addOverlay(const String8& path, const asset_path& overlay); -- bool getOverlay(const String8& path, size_t idx, asset_path* out) const; - - private: - void closeZip(int idx); -diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp -index edc625b..924b230 100644 ---- a/libs/androidfw/AssetManager.cpp -+++ b/libs/androidfw/AssetManager.cpp -@@ -214,15 +214,6 @@ bool AssetManager::addAssetPath( - *cookie = static_cast(mAssetPaths.size()); - } - --#ifdef __ANDROID__ -- // Load overlays, if any -- asset_path oap; -- for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) { -- oap.isSystemAsset = isSystemAsset; -- mAssetPaths.add(oap); -- } --#endif -- - if (mResources != NULL) { - appendPathToResTable(ap, appAsLib); - } -@@ -606,11 +597,6 @@ FileType AssetManager::getFileType(const char* fileName) - } - - bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) const { -- // skip those ap's that correspond to system overlays -- if (ap.isSystemOverlay) { -- return true; -- } -- - Asset* ass = NULL; - ResTable* sharedRes = NULL; - bool shared = true; -@@ -652,14 +638,6 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con - ALOGV("Creating shared resources for %s", ap.path.string()); - sharedRes = new ResTable(); - sharedRes->add(ass, idmap, nextEntryIdx + 1, false); --#ifdef __ANDROID__ -- 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, nextEntryIdx); --#endif - sharedRes = const_cast(this)-> - mZipSet.setZipResourceTable(ap.path, sharedRes); - } -@@ -772,58 +750,6 @@ 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; -- } -- --#ifndef _WIN32 -- if (TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_SH)) != 0) { -- fclose(fin); -- return; -- } --#endif -- char buf[1024]; -- while (fgets(buf, sizeof(buf), fin)) { -- // format of each line: -- // -- 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); -- oap.isSystemOverlay = true; -- -- Asset* oass = const_cast(this)-> -- openNonAssetInPathLocked("resources.arsc", -- Asset::ACCESS_BUFFER, -- oap); -- -- if (oass != NULL) { -- Asset* oidmap = openIdmapLocked(oap); -- offset++; -- sharedRes->add(oass, oidmap, offset + 1, false); -- const_cast(this)->mAssetPaths.add(oap); -- const_cast(this)->mZipSet.addOverlay(targetPackagePath, oap); -- delete oidmap; -- } -- } -- --#ifndef _WIN32 -- TEMP_FAILURE_RETRY(flock(fileno(fin), LOCK_UN)); --#endif -- fclose(fin); --} -- - const ResTable& AssetManager::getResources(bool required) const - { - const ResTable* rt = getResTable(required); -@@ -1962,20 +1888,6 @@ 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() - { - if (kIsDebug) { -@@ -2101,22 +2013,6 @@ bool AssetManager::ZipSet::isUpToDate() - return true; - } - --void AssetManager::ZipSet::addOverlay(const String8& path, const asset_path& overlay) --{ -- int idx = getIndex(path); -- sp zip = mZipFile[idx]; -- zip->addOverlay(overlay); --} -- --bool AssetManager::ZipSet::getOverlay(const String8& path, size_t idx, asset_path* out) const --{ -- sp zip = SharedZip::get(path, false); -- if (zip == NULL) { -- return false; -- } -- return zip->getOverlay(idx, out); --} -- - /* - * Compute the zip file's index. - * -diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java -index 90f507c..904c967 100644 ---- a/services/core/java/com/android/server/SystemServiceManager.java -+++ b/services/core/java/com/android/server/SystemServiceManager.java -@@ -16,6 +16,7 @@ - - package com.android.server; - -+import android.annotation.NonNull; - import android.content.Context; - import android.os.Trace; - import android.util.Slog; -@@ -104,22 +105,25 @@ public class SystemServiceManager { - + ": service constructor threw an exception", ex); - } - -- // Register it. -- mServices.add(service); -- -- // Start it. -- try { -- service.onStart(); -- } catch (RuntimeException ex) { -- throw new RuntimeException("Failed to start service " + name -- + ": onStart threw an exception", ex); -- } -+ startService(service); - return service; - } finally { - Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); - } - } - -+ public void startService(@NonNull final SystemService service) { -+ // Register it. -+ mServices.add(service); -+ // Start it. -+ try { -+ service.onStart(); -+ } catch (RuntimeException ex) { -+ throw new RuntimeException("Failed to start service " + service.getClass().getName() -+ + ": onStart threw an exception", ex); -+ } -+ } -+ - /** - * Starts the specified boot phase for all system services that have been started up to - * this point. -diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java -index e31b409..2822dc9 100644 ---- a/services/core/java/com/android/server/am/ActivityManagerService.java -+++ b/services/core/java/com/android/server/am/ActivityManagerService.java -@@ -19297,6 +19297,57 @@ public final class ActivityManagerService extends ActivityManagerNative - } - - /** -+ * @hide -+ */ -+ @Override -+ public void updateAssets(final int userId, @NonNull final List packageNames) { -+ enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION, "updateAssets()"); -+ -+ synchronized(this) { -+ final long origId = Binder.clearCallingIdentity(); -+ try { -+ updateAssetsLocked(userId, packageNames); -+ } finally { -+ Binder.restoreCallingIdentity(origId); -+ } -+ } -+ } -+ -+ void updateAssetsLocked(final int userId, @NonNull final List packagesToUpdate) { -+ final IPackageManager pm = AppGlobals.getPackageManager(); -+ final Map cache = new ArrayMap<>(); -+ -+ final boolean updateFrameworkRes = packagesToUpdate.contains("android"); -+ for (int i = mLruProcesses.size() - 1; i >= 0; i--) { -+ final ProcessRecord app = mLruProcesses.get(i); -+ if (app.userId != userId || app.thread == null) { -+ continue; -+ } -+ -+ for (final String packageName : app.pkgList.keySet()) { -+ if (updateFrameworkRes || packagesToUpdate.contains(packageName)) { -+ try { -+ final ApplicationInfo ai; -+ if (cache.containsKey(packageName)) { -+ ai = cache.get(packageName); -+ } else { -+ ai = pm.getApplicationInfo(packageName, 0, userId); -+ cache.put(packageName, ai); -+ } -+ -+ if (ai != null) { -+ app.thread.scheduleAssetsChanged(packageName, ai); -+ } -+ } catch (RemoteException e) { -+ Slog.w(TAG, String.format("Failed to update %s assets for %s", -+ packageName, app)); -+ } -+ } -+ } -+ } -+ } -+ -+ /** - * Decide based on the configuration whether we should shouw the ANR, - * crash, etc dialogs. The idea is that if there is no affordence to - * press the on-screen buttons, or the user experience would be more -diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java -index ec148dd..761ef52 100644 ---- a/services/core/java/com/android/server/om/OverlayManagerService.java -+++ b/services/core/java/com/android/server/om/OverlayManagerService.java -@@ -676,37 +676,36 @@ public final class OverlayManagerService extends SystemService { - } - - private void updateAssets(final int userId, List targetPackageNames) { -- // TODO: uncomment when we integrate OMS properly -- // final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); -- // final boolean updateFrameworkRes = targetPackageNames.contains("android"); -- // if (updateFrameworkRes) { -- // targetPackageNames = pm.getTargetPackageNames(userId); -- // } -- -- // final Map allPaths = new ArrayMap<>(targetPackageNames.size()); -- // synchronized (mLock) { -- // final List frameworkPaths = mImpl.onGetEnabledOverlayPaths("android", userId); -- // for (final String packageName : targetPackageNames) { -- // final List paths = new ArrayList<>(); -- // paths.addAll(frameworkPaths); -- // if (!"android".equals(packageName)) { -- // paths.addAll(mImpl.onGetEnabledOverlayPaths(packageName, userId)); -- // } -- // allPaths.put(packageName, -- // paths.isEmpty() ? null : paths.toArray(new String[paths.size()])); -- // } -- // } -- -- // for (String packageName : targetPackageNames) { -- // pm.setResourceDirs(userId, packageName, allPaths.get(packageName)); -- // } -- -- // final IActivityManager am = ActivityManagerNative.getDefault(); -- // try { -- // am.updateAssets(userId, targetPackageNames); -- // } catch (RemoteException e) { -- // // Intentionally left empty. -- // } -+ final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); -+ final boolean updateFrameworkRes = targetPackageNames.contains("android"); -+ if (updateFrameworkRes) { -+ targetPackageNames = pm.getTargetPackageNames(userId); -+ } -+ -+ final Map allPaths = new ArrayMap<>(targetPackageNames.size()); -+ synchronized (mLock) { -+ final List frameworkPaths = mImpl.onGetEnabledOverlayPaths("android", userId); -+ for (final String packageName : targetPackageNames) { -+ final List paths = new ArrayList<>(); -+ paths.addAll(frameworkPaths); -+ if (!"android".equals(packageName)) { -+ paths.addAll(mImpl.onGetEnabledOverlayPaths(packageName, userId)); -+ } -+ allPaths.put(packageName, -+ paths.isEmpty() ? null : paths.toArray(new String[paths.size()])); -+ } -+ } -+ -+ for (String packageName : targetPackageNames) { -+ pm.setResourceDirs(userId, packageName, allPaths.get(packageName)); -+ } -+ -+ final IActivityManager am = ActivityManagerNative.getDefault(); -+ try { -+ am.updateAssets(userId, targetPackageNames); -+ } catch (RemoteException e) { -+ // Intentionally left empty. -+ } - } - - private void schedulePersistSettings() { -diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java -index 3892f8f..f700522 100644 ---- a/services/core/java/com/android/server/pm/PackageManagerService.java -+++ b/services/core/java/com/android/server/pm/PackageManagerService.java -@@ -399,17 +399,16 @@ 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 SCAN_DELETE_DATA_ON_FAILURES = 1<<10; -- static final int SCAN_REPLACING = 1<<11; -- static final int SCAN_REQUIRE_KNOWN = 1<<12; -- static final int SCAN_MOVE = 1<<13; -- static final int SCAN_INITIAL = 1<<14; -- static final int SCAN_CHECK_ONLY = 1<<15; -- static final int SCAN_DONT_KILL_APP = 1<<17; -- static final int SCAN_IGNORE_FROZEN = 1<<18; -- -- static final int REMOVE_CHATTY = 1<<16; -+ static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<9; -+ static final int SCAN_REPLACING = 1<<10; -+ static final int SCAN_REQUIRE_KNOWN = 1<<11; -+ static final int SCAN_MOVE = 1<<12; -+ static final int SCAN_INITIAL = 1<<13; -+ static final int SCAN_CHECK_ONLY = 1<<14; -+ static final int SCAN_DONT_KILL_APP = 1<<15; -+ static final int SCAN_IGNORE_FROZEN = 1<<16; -+ -+ static final int REMOVE_CHATTY = 1<<17; - - private static final int[] EMPTY_INT_ARRAY = new int[0]; - -@@ -600,10 +599,6 @@ public class PackageManagerService extends IPackageManager.Stub { - final ArrayMap> mKnownCodebase = - new ArrayMap>(); - -- // Tracks available target package names -> overlay package paths. -- final ArrayMap> mOverlays = -- new ArrayMap>(); -- - /** - * Tracks new system packages [received in an OTA] that we expect to - * find updated user-installed versions. Keys are package name, values -@@ -2342,8 +2337,8 @@ public class PackageManagerService extends IPackageManager.Stub { - File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR); - scanDirTracedLI(vendorOverlayDir, mDefParseFlags - | PackageParser.PARSE_IS_SYSTEM -- | PackageParser.PARSE_IS_SYSTEM_DIR -- | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0); -+ | PackageParser.PARSE_IS_SYSTEM_DIR, -+ scanFlags, 0); - - // Find base frameworks (resource packages without code). - scanDirTracedLI(frameworkDir, mDefParseFlags -@@ -2400,7 +2395,7 @@ public class PackageManagerService extends IPackageManager.Stub { - // Collect overlay in /system/vendor - scanDirLI(new File(RegionalizationSystemDir, "vendor/overlay"), - PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, -- scanFlags | SCAN_TRUSTED_OVERLAY, 0); -+ scanFlags, 0); - } - } - -@@ -6723,60 +6718,6 @@ public class PackageManagerService extends IPackageManager.Stub { - return finalList; - } - -- private void createIdmapsForPackageLI(PackageParser.Package pkg) { -- ArrayMap 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.baseCodePath + " and " + -- opkg.baseCodePath + ": overlay not trusted"); -- return false; -- } -- ArrayMap overlaySet = mOverlays.get(pkg.packageName); -- if (overlaySet == null) { -- Slog.e(TAG, "was about to create idmap for " + pkg.baseCodePath + " and " + -- opkg.baseCodePath + " but target package has no known overlays"); -- return false; -- } -- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); -- // TODO: generate idmap for split APKs -- try { -- mInstaller.idmap(pkg.baseCodePath, opkg.baseCodePath, sharedGid); -- } catch (InstallerException e) { -- Slog.e(TAG, "Failed to generate idmap for " + pkg.baseCodePath + " and " -- + opkg.baseCodePath); -- return false; -- } -- PackageParser.Package[] overlayArray = -- overlaySet.values().toArray(new PackageParser.Package[0]); -- Comparator cmp = new Comparator() { -- 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.baseCodePath; -- } -- return true; -- } -- - private void scanDirTracedLI(File dir, final int parseFlags, int scanFlags, long currentTime) { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir"); - try { -@@ -6964,10 +6905,6 @@ public class PackageManagerService extends IPackageManager.Stub { - pp.setOnlyPowerOffAlarmApps(mOnlyPowerOffAlarm); - pp.setDisplayMetrics(mMetrics); - -- if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) { -- parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY; -- } -- - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage"); - final PackageParser.Package pkg; - try { -@@ -8200,7 +8137,6 @@ public class PackageManagerService extends IPackageManager.Stub { - pkg.applicationInfo.privateFlags &= - ~ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; - } -- pkg.mTrustedOverlay = (policyFlags&PackageParser.PARSE_TRUSTED_OVERLAY) != 0; - - if ((policyFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; -@@ -8795,7 +8731,6 @@ public class PackageManagerService extends IPackageManager.Stub { - // writer - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings"); - -- boolean createIdmapFailed = false; - synchronized (mPackages) { - // We don't expect installation to fail beyond this point - -@@ -9142,36 +9077,10 @@ 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 ArrayMap()); -- } -- ArrayMap map = mOverlays.get(pkg.mOverlayTarget); -- map.put(pkg.packageName, pkg); -- PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget); -- if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) { -- createIdmapFailed = true; -- } -- } -- } else if (mOverlays.containsKey(pkg.packageName) && -- !pkg.packageName.equals("android")) { -- // This is a regular package, with one or more known overlay packages. -- createIdmapsForPackageLI(pkg); -- } - } - - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - -- if (createIdmapFailed) { -- throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, -- "scanPackageLI failed to createIdmap"); -- } - return pkg; - } - -@@ -16618,7 +16527,7 @@ public class PackageManagerService extends IPackageManager.Stub { - false /*hidden*/, false /*suspended*/, null, null, null, - false /*blockUninstall*/, - ps.readUserState(nextUserId).domainVerificationStatus, 0, -- null, null); -+ null, null, null); - } - } - -@@ -21476,14 +21385,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); - - @Override - public void setResourceDirs(int userId, String packageName, String[] resourceDirs) { -- // TODO: uncomment when we integrate OMS properly -- // synchronized (mPackages) { -- // PackageSetting ps = mSettings.mPackages.get(packageName); -- // if (ps == null) { -- // return; -- // } -- // ps.setResourceDirs(resourceDirs, userId); -- // } -+ synchronized (mPackages) { -+ final PackageSetting ps = mSettings.mPackages.get(packageName); -+ if (ps == null) { -+ return; -+ } -+ ps.setResourceDirs(resourceDirs, userId); -+ } - } - } - -diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java -index 75427a8..18c79cd 100644 ---- a/services/core/java/com/android/server/pm/PackageSettingBase.java -+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java -@@ -21,6 +21,7 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED - import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; - import static android.content.pm.PackageManager.COMPONENT_VISIBLE_STATUS; - -+import android.annotation.NonNull; - import android.content.pm.IntentFilterVerificationInfo; - import android.content.pm.PackageManager; - import android.content.pm.PackageUserState; -@@ -379,7 +380,7 @@ abstract class PackageSettingBase extends SettingBase { - boolean notLaunched, boolean hidden, boolean suspended, - String lastDisableAppCaller, ArraySet enabledComponents, - ArraySet disabledComponents, boolean blockUninstall, int domainVerifState, -- int linkGeneration, -+ int linkGeneration, String[] resourceDirs, - ArraySet protectedComponents, ArraySet visibleComponents) { - PackageUserState state = modifyUserState(userId); - state.ceDataInode = ceDataInode; -@@ -395,6 +396,7 @@ abstract class PackageSettingBase extends SettingBase { - state.blockUninstall = blockUninstall; - state.domainVerificationStatus = domainVerifState; - state.appLinkGeneration = linkGeneration; -+ state.resourceDirs = resourceDirs; - state.protectedComponents = protectedComponents; - state.visibleComponents = visibleComponents; - } -@@ -455,6 +457,10 @@ abstract class PackageSettingBase extends SettingBase { - modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName); - } - -+ void setResourceDirs(@NonNull final String[] resourceDirs, final int userId) { -+ modifyUserState(userId).resourceDirs = resourceDirs; -+ } -+ - boolean enableComponentLPw(String componentClassName, int userId) { - PackageUserState state = modifyUserStateComponents(userId, false, true); - boolean changed = state.disabledComponents != null -diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java -index 285b5bb..2b36e0e 100755 ---- a/services/core/java/com/android/server/pm/Settings.java -+++ b/services/core/java/com/android/server/pm/Settings.java -@@ -813,6 +813,7 @@ final class Settings { - false, // blockUninstall - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0, - null, -+ null, - null - ); - writePackageRestrictionsLPr(user.id); -@@ -1617,6 +1618,7 @@ final class Settings { - false, // blockUninstall - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED, 0, - null, -+ null, - null - ); - } -@@ -1726,7 +1728,7 @@ final class Settings { - - ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched, - hidden, suspended, enabledCaller, enabledComponents, disabledComponents, -- blockUninstall, verifState, linkGeneration, -+ blockUninstall, verifState, linkGeneration, null, - protectedComponents, visibleComponents); - } else if (tagName.equals("preferred-activities")) { - readPreferredActivitiesLPw(parser, userId); -diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java -index 3e16338..010aaa1 100644 ---- a/services/java/com/android/server/SystemServer.java -+++ b/services/java/com/android/server/SystemServer.java -@@ -84,6 +84,7 @@ import com.android.server.media.projection.MediaProjectionManagerService; - import com.android.server.net.NetworkPolicyManagerService; - import com.android.server.net.NetworkStatsService; - import com.android.server.notification.NotificationManagerService; -+import com.android.server.om.OverlayManagerService; - import com.android.server.os.RegionalizationService; - import com.android.server.os.SchedulingPolicyService; - import com.android.server.pm.BackgroundDexOptService; -@@ -530,6 +531,9 @@ public final class SystemServer { - // Set up the Application instance for the system process and get started. - mActivityManagerService.setSystemProcess(); - -+ // Manages Overlay packages -+ mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer)); -+ - // The sensor service needs access to package manager service, app ops - // service, and permissions service, therefore we start it after them. - startSensorService(); --- -2.9.3 - diff --git a/frameworks/base/0004-OMS7-N-Set-EXTRA_REPLACING-correctly-in-ACTION_PACKA.patch b/frameworks/base/0004-OMS7-N-Set-EXTRA_REPLACING-correctly-in-ACTION_PACKA.patch deleted file mode 100644 index 5ce4094..0000000 --- a/frameworks/base/0004-OMS7-N-Set-EXTRA_REPLACING-correctly-in-ACTION_PACKA.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 06912868733feadee85507d9f40ede2468a9a496 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= -Date: Mon, 25 Apr 2016 16:29:22 +0200 -Subject: [PATCH 04/38] OMS7-N: Set EXTRA_REPLACING correctly in - ACTION_PACKAGE_ADDED [4/11] - -When broadcasting ACTION_PACKAGE_ADDED the recipients of the Intent are -split into two groups: the first group hasn't seen the new package -before and the Intent should have EXTRA_REPLACING set to false; and vice -versa for the second group. - -The package manager schedules these Intent broadcasts on a background -thread by posting Runnable objects to a handler. Each Runnable holds -references to objects used to construct the Intents, one of which is a -Bundle used to create the Intent extras. - -If the same Bundle object is used for both recipient groups, any -modification to the object made for one group will unintentionally -propagate to the other. To prevent this a separate Bundle is now created -for each group. - -Prior to this patch, the following scenario would fail: - - 1. Install a package P for user owner - 2. Create and switch to a secondary user - 3. Install a new version of package P (for all users) - -In step 3, the secondary user was expected to receive -ACTION_PACKAGE_ADDED with EXTRA_REPLACING set to false, but instead it -was set to true. The bug was initially introduced in commit bd0e9e49. - -Change-Id: Icf869013d5d652de4bf0f6df4529b7a68d35a25c ---- - services/core/java/com/android/server/pm/PackageManagerService.java | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java -index f700522..7277f6a 100644 ---- a/services/core/java/com/android/server/pm/PackageManagerService.java -+++ b/services/core/java/com/android/server/pm/PackageManagerService.java -@@ -1714,6 +1714,7 @@ public class PackageManagerService extends IPackageManager.Stub { - - // Send added for users that don't see the package for the first time - if (update) { -+ extras = new Bundle(extras); - extras.putBoolean(Intent.EXTRA_REPLACING, true); - } - sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, --- -2.9.3 - diff --git a/frameworks/base/0005-OMS7-N-idmap-suppress-print-for-padded-resources-5-1.patch b/frameworks/base/0005-OMS7-N-idmap-suppress-print-for-padded-resources-5-1.patch deleted file mode 100644 index 31ebb89..0000000 --- a/frameworks/base/0005-OMS7-N-idmap-suppress-print-for-padded-resources-5-1.patch +++ /dev/null @@ -1,29 +0,0 @@ -From ee6f42041d3c77be1151d82898ee5626633cf9fa Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= -Date: Mon, 29 Feb 2016 14:12:35 +0100 -Subject: [PATCH 05/38] OMS7-N: idmap: suppress print for padded resources - [5/11] - -Change-Id: I565ccf515068b96927e4317cc9c06543415bb324 ---- - cmds/idmap/inspect.cpp | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp -index 924090f..cb52a39 100644 ---- a/cmds/idmap/inspect.cpp -+++ b/cmds/idmap/inspect.cpp -@@ -289,7 +289,9 @@ namespace { - if (err != NO_ERROR) { - return err; - } -- print("", "entry", data32, "%s/%s", type.string(), name.string()); -+ if (data32 != ResTable_type::NO_ENTRY) { -+ print("", "entry", data32, "%s/%s", type.string(), name.string()); -+ } - } - } - --- -2.9.3 - diff --git a/frameworks/base/0006-OMS7-N-Fix-memory-leak-during-idmap-creation-6-11.patch b/frameworks/base/0006-OMS7-N-Fix-memory-leak-during-idmap-creation-6-11.patch deleted file mode 100644 index 9eb37d8..0000000 --- a/frameworks/base/0006-OMS7-N-Fix-memory-leak-during-idmap-creation-6-11.patch +++ /dev/null @@ -1,67 +0,0 @@ -From a2ce720b5bfca010dc28ab9cd79e9a8d94f981b3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= -Date: Thu, 2 Jun 2016 09:34:36 +0200 -Subject: [PATCH 06/38] OMS7-N: Fix memory leak during idmap creation [6/11] - -Plug a memory leak in AssetManager::createIdmap. - -Change-Id: Ieed805c596df931e2167ebb47c1b2907d6bf67f4 ---- - libs/androidfw/AssetManager.cpp | 38 +++++++++++++++++++++++++------------- - 1 file changed, 25 insertions(+), 13 deletions(-) - -diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp -index 924b230..c501e8b 100644 ---- a/libs/androidfw/AssetManager.cpp -+++ b/libs/androidfw/AssetManager.cpp -@@ -291,22 +291,34 @@ bool AssetManager::createIdmap(const char* targetApkPath, const char* overlayApk - { - AutoMutex _l(mLock); - const String8 paths[2] = { String8(targetApkPath), String8(overlayApkPath) }; -- ResTable tables[2]; -- -- for (int i = 0; i < 2; ++i) { -- asset_path ap; -- ap.type = kFileTypeRegular; -- ap.path = paths[i]; -- Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap); -- if (ass == NULL) { -- ALOGW("failed to find resources.arsc in %s\n", ap.path.string()); -- return false; -+ Asset* assets[2] = {NULL, NULL}; -+ bool ret = false; -+ { -+ ResTable tables[2]; -+ -+ for (int i = 0; i < 2; ++i) { -+ asset_path ap; -+ ap.type = kFileTypeRegular; -+ ap.path = paths[i]; -+ assets[i] = openNonAssetInPathLocked("resources.arsc", -+ Asset::ACCESS_BUFFER, ap); -+ if (assets[i] == NULL) { -+ ALOGW("failed to find resources.arsc in %s\n", ap.path.string()); -+ goto exit; -+ } -+ if (tables[i].add(assets[i]) != NO_ERROR) { -+ ALOGW("failed to add %s to resource table", paths[i].string()); -+ goto exit; -+ } - } -- tables[i].add(ass); -+ ret = tables[0].createIdmap(tables[1], targetCrc, overlayCrc, -+ targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR; - } - -- return tables[0].createIdmap(tables[1], targetCrc, overlayCrc, -- targetApkPath, overlayApkPath, (void**)outData, outSize) == NO_ERROR; -+exit: -+ delete assets[0]; -+ delete assets[1]; -+ return ret; - } - - bool AssetManager::addDefaultAssets() --- -2.9.3 - diff --git a/frameworks/base/0007-OMS7-N-installd-add-command-rmidmap-7-11.patch b/frameworks/base/0007-OMS7-N-installd-add-command-rmidmap-7-11.patch deleted file mode 100644 index 209f9e3..0000000 --- a/frameworks/base/0007-OMS7-N-installd-add-command-rmidmap-7-11.patch +++ /dev/null @@ -1,38 +0,0 @@ -From b14c245ca8e1b2fa9665ef8cde29eeafaeba282f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= -Date: Thu, 2 Jun 2016 09:35:09 +0200 -Subject: [PATCH 07/38] OMS7-N: installd: add command 'rmidmap' [7/11] - -Add an installd command to remove an idmap file. This is the inverse of -the 'idmap' command and is intended for clean-up once an idmap file is -no longer needed because an APK was removed, etc. - -This commit depends on a corresponding commit in frameworks/native (with -the same Change-Id). - -Change-Id: I58f55f643da99c0bd69136ee43c1c8c70c352797 ---- - services/core/java/com/android/server/pm/Installer.java | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java -index 2e18b1c..7f618b8 100644 ---- a/services/core/java/com/android/server/pm/Installer.java -+++ b/services/core/java/com/android/server/pm/Installer.java -@@ -170,6 +170,13 @@ public final class Installer extends SystemService { - mInstaller.execute("idmap", targetApkPath, overlayApkPath, uid); - } - -+ public void removeIdmap(String overlayApkPath) throws InstallerException { -+ StringBuilder builder = new StringBuilder("rmidmap"); -+ builder.append(' '); -+ builder.append(overlayApkPath); -+ mInstaller.execute(builder.toString()); -+ } -+ - public void rmdex(String codePath, String instructionSet) throws InstallerException { - assertValidInstructionSet(instructionSet); - mInstaller.execute("rmdex", codePath, instructionSet); --- -2.9.3 - diff --git a/frameworks/base/0008-OMS7-N-Disable-Zygote-preloaded-drawables-8-11.patch b/frameworks/base/0008-OMS7-N-Disable-Zygote-preloaded-drawables-8-11.patch deleted file mode 100644 index fd22568..0000000 --- a/frameworks/base/0008-OMS7-N-Disable-Zygote-preloaded-drawables-8-11.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 5e8fc3854ee67ed15983c460b390d0cff1dde775 Mon Sep 17 00:00:00 2001 -From: Josh Guilfoyle -Date: Wed, 26 Jan 2011 23:28:43 -0800 -Subject: [PATCH 08/38] OMS7-N: Disable Zygote preloaded drawables [8/11] - -With a theme applied, most of these preloaded drawables go unused. Any -assets the theme has redirected will need to be loaded with each app -process regardless. Worse, preloads make it impossible to do asset -redirection for constituent parts of a preloaded drawable (for instance, -individual states of a StateListDrawable cannot be redirected). - -Some day it might be nice to revisit this and see if there's a way to -reintroduce the drawable cache in a way that can be altered at runtime -without significant complexity or runtime penalty. - -Change-Id: I253b1a22482ac664c196533a4c2fcd88ae84b996 ---- - core/java/com/android/internal/os/ZygoteInit.java | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java -index 20f84b5..455849e 100644 ---- a/core/java/com/android/internal/os/ZygoteInit.java -+++ b/core/java/com/android/internal/os/ZygoteInit.java -@@ -108,7 +108,7 @@ public class ZygoteInit { - private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes"; - - /** Controls whether we should preload resources during zygote init. */ -- public static final boolean PRELOAD_RESOURCES = true; -+ public static final boolean PRELOAD_RESOURCES = false; - - /** - * Registers a server socket for zygote command connections -@@ -437,6 +437,8 @@ public class ZygoteInit { - Log.i(TAG, "...preloaded " + N + " resource in " - + (SystemClock.uptimeMillis() - startTime) + "ms."); - } -+ } else { -+ Log.i(TAG, "Preload resources disabled, skipped."); - } - mResources.finishPreloading(); - } catch (RuntimeException e) { --- -2.9.3 - diff --git a/frameworks/base/0009-OMS7-N-Persistence-on-boot-through-OverlayManagerSer.patch b/frameworks/base/0009-OMS7-N-Persistence-on-boot-through-OverlayManagerSer.patch deleted file mode 100644 index 16c58d4..0000000 --- a/frameworks/base/0009-OMS7-N-Persistence-on-boot-through-OverlayManagerSer.patch +++ /dev/null @@ -1,78 +0,0 @@ -From fc7d694af82449a4d4a3456ffd486a5afa30a2ef Mon Sep 17 00:00:00 2001 -From: Nicholas Chum -Date: Sun, 19 Jun 2016 10:37:13 -0400 -Subject: [PATCH 09/38] OMS7-N: Persistence on boot through - OverlayManagerServiceImpl [9/11] - -Overlays should not be enforced by the traditional OverlayManagerService -by Sony, but instead, it shouldn't be enforced at all to allow third -party overlays from the community to boot up with the device. - -Change-Id: Ic6eeb38b5e7bcec4211405d4504ba37a75738227 ---- - .../server/om/OverlayManagerServiceImpl.java | 31 +++++++++++++++------- - 1 file changed, 21 insertions(+), 10 deletions(-) - -diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java -index 2a0d88b..4c61968 100644 ---- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java -+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java -@@ -402,34 +402,45 @@ final class OverlayManagerServiceImpl { - private int calculateNewState(@Nullable final PackageInfo targetPackage, - @NonNull final PackageInfo overlayPackage, final int userId) - throws OverlayManagerSettings.BadKeyException { -+ -+ // STATE 0 CHECK: Check if the overlay package is disabled by PackageManager - if (!overlayPackage.applicationInfo.enabled) { - return STATE_NOT_APPROVED_COMPONENT_DISABLED; - } - -+ // OVERLAY STATE CHECK: Check the current overlay's activation -+ boolean stateCheck = mSettings.getEnabled(overlayPackage.packageName, userId); -+ -+ // STATE 1 CHECK: Check if the overlay's target package is missing from the device - if (targetPackage == null) { - return STATE_NOT_APPROVED_MISSING_TARGET; - } - -+ // STATE 2 CHECK: Check if the overlay has an existing idmap file created. Perhaps -+ // there were no matching resources between the two packages? (Overlay & Target) - if (!mIdmapManager.idmapExists(overlayPackage, userId)) { - return STATE_NOT_APPROVED_NO_IDMAP; - } - -- final boolean enableIfApproved = mSettings.getEnabled(overlayPackage.packageName, userId); -- -- if (mPackageManager.signaturesMatching(targetPackage.packageName, -- overlayPackage.packageName, userId)) { -- return enableIfApproved ? STATE_APPROVED_ENABLED : STATE_APPROVED_DISABLED; -- } -- -+ // STATE 6 CHECK: System Overlays, also known as RRO overlay files, work the same -+ // as OMS, but with enable/disable limitations. A system overlay resides in the -+ // directory "/vendor/overlay" depending on your device. -+ // -+ // Team Substratum: Disable this as this is a security vulnerability and a -+ // memory-limited partition. - if ((overlayPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { -- return enableIfApproved ? STATE_APPROVED_ENABLED : STATE_APPROVED_DISABLED; -+ return STATE_NOT_APPROVED_COMPONENT_DISABLED; - } - -+ // STATE 3 CHECK: If the overlay only modifies resources explicitly granted by the -+ // target, we approve it. -+ // -+ // Team Substratum: Always approve dangerous packages but disabled state - if (!mIdmapManager.isDangerous(overlayPackage, userId)) { -- return enableIfApproved ? STATE_APPROVED_ENABLED : STATE_APPROVED_DISABLED; -+ return STATE_APPROVED_DISABLED; - } - -- return STATE_NOT_APPROVED_DANGEROUS_OVERLAY; -+ return stateCheck ? STATE_APPROVED_ENABLED : STATE_APPROVED_DISABLED; - } - - private void removeIdmapIfPossible(@NonNull final OverlayInfo oi) { --- -2.9.3 - diff --git a/frameworks/base/0010-OMS7-N-Do-not-enforce-code-policy-limiting-overlay-i.patch b/frameworks/base/0010-OMS7-N-Do-not-enforce-code-policy-limiting-overlay-i.patch deleted file mode 100644 index abf34be..0000000 --- a/frameworks/base/0010-OMS7-N-Do-not-enforce-code-policy-limiting-overlay-i.patch +++ /dev/null @@ -1,29 +0,0 @@ -From c41b5f7552e5ef1f221d1f755b37501037463c66 Mon Sep 17 00:00:00 2001 -From: Nicholas Chum -Date: Thu, 27 Oct 2016 07:08:00 +0200 -Subject: [PATCH 10/38] OMS7-N: Do not enforce code policy limiting overlay - installation [10/11] - -Change-Id: Iea317f3771f25dbfcbf4938e88cace12fd97d7eb ---- - services/core/java/com/android/server/pm/PackageManagerService.java | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java -index 7277f6a..46679e5 100644 ---- a/services/core/java/com/android/server/pm/PackageManagerService.java -+++ b/services/core/java/com/android/server/pm/PackageManagerService.java -@@ -8143,10 +8143,6 @@ public class PackageManagerService extends IPackageManager.Stub { - pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; - } - -- if ((policyFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) { -- enforceCodePolicy(pkg); -- } -- - if (mCustomResolverComponentName != null && - mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) { - setUpCustomResolverActivity(pkg); --- -2.9.3 - diff --git a/frameworks/base/0011-OMS7-N-Implement-multi-target-enable-disable-and-dis.patch b/frameworks/base/0011-OMS7-N-Implement-multi-target-enable-disable-and-dis.patch deleted file mode 100644 index c155b92..0000000 --- a/frameworks/base/0011-OMS7-N-Implement-multi-target-enable-disable-and-dis.patch +++ /dev/null @@ -1,470 +0,0 @@ -From 61a04ac0c542521026b925d35faf4244e6ea2810 Mon Sep 17 00:00:00 2001 -From: Jacob McSwain -Date: Sun, 26 Jun 2016 15:21:52 -0500 -Subject: [PATCH 11/38] OMS7-N: Implement multi-target enable/disable and - disable-all [11/11] - -Just use the enable option like normal, but you can add more arguments -for more packages. Also add a feature that allows the client to disable -all of the current user's overlays. - -Multiple targets example: - om enable android.AkZent com.android.systemui.AkZent - -Works the same as: - om enable android.AkZent && om enable com.android.systemui.AkZent - -Original implementation for M by @USA-RedDragon -Current and further development by @nicholaschum - -Change-Id: I04a595084a87b8260b5c534c4f5f111adbe154d7 ---- - core/java/android/content/om/IOverlayManager.aidl | 10 +- - .../android/server/om/OverlayManagerService.java | 48 ++++++---- - .../server/om/OverlayManagerServiceImpl.java | 12 ++- - .../android/server/om/OverlayManagerSettings.java | 31 +++--- - .../server/om/OverlayManagerShellCommand.java | 104 +++++++++++++++++++-- - 5 files changed, 161 insertions(+), 44 deletions(-) - -diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl -index 4f5d960..8e349dc 100644 ---- a/core/java/android/content/om/IOverlayManager.aidl -+++ b/core/java/android/content/om/IOverlayManager.aidl -@@ -83,10 +83,12 @@ interface IOverlayManager { - * @param packageName The name of the overlay package. - * @param enable true to enable the overlay, false to disable it. - * @param userId The user for which to change the overlay. -+ * @param shouldWait true to wait to reload resources until refresh is called - * @return true if the system successfully registered the request, false - * otherwise. - */ -- boolean setEnabled(in String packageName, in boolean enable, in int userId); -+ boolean setEnabled(in String packageName, in boolean enable, in int userId, -+ in boolean shouldWait); - - /** - * Change the priority of the given overlay to be just higher than the -@@ -126,4 +128,10 @@ interface IOverlayManager { - * @param userId The user for which to change the overlay. - */ - boolean setLowestPriority(in String packageName, in int userId); -+ -+ /** -+ * Refresh assets -+ * @param uid the user to refresh assets for -+ */ -+ void refresh(in int uid); - } -diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java -index 761ef52..deb9046 100644 ---- a/services/core/java/com/android/server/om/OverlayManagerService.java -+++ b/services/core/java/com/android/server/om/OverlayManagerService.java -@@ -255,7 +255,7 @@ public final class OverlayManagerService extends SystemService { - synchronized (mLock) { - targets = mImpl.onSwitchUser(newUserId); - } -- updateAssets(newUserId, targets); -+ updateSelectedAssets(newUserId, targets); - } - - public List getEnabledOverlayPaths(@NonNull final String packageName, -@@ -451,7 +451,7 @@ public final class OverlayManagerService extends SystemService { - - @Override - public boolean setEnabled(@Nullable final String packageName, final boolean enable, -- int userId) throws RemoteException { -+ int userId, final boolean shouldWait) throws RemoteException { - enforceChangeConfigurationPermission("setEnabled"); - userId = handleIncomingUser(userId, "setEnabled"); - if (packageName == null) { -@@ -461,7 +461,7 @@ public final class OverlayManagerService extends SystemService { - final long ident = Binder.clearCallingIdentity(); - try { - synchronized (mLock) { -- return mImpl.onSetEnabled(packageName, enable, userId); -+ return mImpl.onSetEnabled(packageName, enable, userId, shouldWait); - } - } finally { - Binder.restoreCallingIdentity(ident); -@@ -590,6 +590,15 @@ public final class OverlayManagerService extends SystemService { - message); - } - } -+ -+ public void refresh(int uid) { -+ Collection targets; -+ synchronized (mLock) { -+ targets = mImpl.onSwitchUser(uid); -+ } -+ List targeted = new ArrayList(targets); -+ updateSelectedAssets(uid, targeted); -+ } - }; - - private boolean isOverlayPackage(@NonNull final PackageInfo pi) { -@@ -603,45 +612,48 @@ public final class OverlayManagerService extends SystemService { - } - - @Override -- public void onOverlayAdded(@NonNull final OverlayInfo oi) { -- scheduleBroadcast(Intent.ACTION_OVERLAY_ADDED, oi, oi.isEnabled()); -+ public void onOverlayAdded(@NonNull final OverlayInfo oi, final boolean shouldWait) { -+ scheduleBroadcast(Intent.ACTION_OVERLAY_ADDED, oi, oi.isEnabled(), shouldWait); - } - - @Override -- public void onOverlayRemoved(@NonNull final OverlayInfo oi) { -- scheduleBroadcast(Intent.ACTION_OVERLAY_REMOVED, oi, oi.isEnabled()); -+ public void onOverlayRemoved(@NonNull final OverlayInfo oi, final boolean shouldWait) { -+ scheduleBroadcast(Intent.ACTION_OVERLAY_REMOVED, oi, oi.isEnabled(), shouldWait); - } - - @Override -- public void onOverlayChanged(@NonNull final OverlayInfo oi, -- @NonNull final OverlayInfo oldOi) { -- scheduleBroadcast(Intent.ACTION_OVERLAY_CHANGED, oi, oi.isEnabled() != oldOi.isEnabled()); -+ public void onOverlayChanged(@NonNull final OverlayInfo oi, @NonNull OverlayInfo oldOi, -+ final boolean shouldWait) { -+ scheduleBroadcast(Intent.ACTION_OVERLAY_CHANGED, oi, -+ oi.isEnabled() != oldOi.isEnabled(), shouldWait); - } - - @Override - public void onOverlayPriorityChanged(@NonNull final OverlayInfo oi) { -- scheduleBroadcast(Intent.ACTION_OVERLAY_PRIORITY_CHANGED, oi, oi.isEnabled()); -+ scheduleBroadcast(Intent.ACTION_OVERLAY_PRIORITY_CHANGED, oi, oi.isEnabled(), false); - } - - private void scheduleBroadcast(@NonNull final String action, @NonNull final OverlayInfo oi, -- final boolean doUpdate) { -- FgThread.getHandler().post(new BroadcastRunnable(action, oi, doUpdate)); -+ final boolean doUpdate, final boolean shouldWait) { -+ FgThread.getHandler().post(new BroadcastRunnable(action, oi, doUpdate, shouldWait)); - } - - private final class BroadcastRunnable extends Thread { - private final String mAction; - private final OverlayInfo mOverlayInfo; - private final boolean mDoUpdate; -+ private final boolean shouldWait; - -- public BroadcastRunnable(@NonNull final String action, @NonNull final OverlayInfo oi, -- final boolean doUpdate) { -+ public BroadcastRunnable(@NonNull final String action, @NonNull final OverlayInfo oi, -+ final boolean doUpdate, final boolean shouldWait) { - mAction = action; - mOverlayInfo = oi; - mDoUpdate = doUpdate; -+ this.shouldWait = shouldWait; - } - - public void run() { -- if (mDoUpdate) { -+ if (mDoUpdate && !shouldWait) { - updateAssets(mOverlayInfo.userId, mOverlayInfo.targetPackageName); - } - sendBroadcast(mAction, mOverlayInfo.targetPackageName, mOverlayInfo.packageName, -@@ -672,10 +684,10 @@ public final class OverlayManagerService extends SystemService { - private void updateAssets(final int userId, final String targetPackageName) { - final List list = new ArrayList<>(); - list.add(targetPackageName); -- updateAssets(userId, list); -+ updateSelectedAssets(userId, list); - } - -- private void updateAssets(final int userId, List targetPackageNames) { -+ private void updateSelectedAssets(final int userId, List targetPackageNames) { - final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class); - final boolean updateFrameworkRes = targetPackageNames.contains("android"); - if (updateFrameworkRes) { -diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java -index 4c61968..c515640 100644 ---- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java -+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java -@@ -324,7 +324,7 @@ final class OverlayManagerServiceImpl { - } - - boolean onSetEnabled(@NonNull final String packageName, final boolean enable, -- final int userId) { -+ final int userId, final boolean shouldWait) { - if (DEBUG) { - Slog.d(TAG, String.format("onSetEnabled packageName=%s enable=%s userId=%d", - packageName, enable, userId)); -@@ -340,7 +340,7 @@ final class OverlayManagerServiceImpl { - final PackageInfo targetPackage = - mPackageManager.getPackageInfo(oi.targetPackageName, userId); - mSettings.setEnabled(packageName, userId, enable); -- updateState(targetPackage, overlayPackage, userId); -+ updateState(targetPackage, overlayPackage, userId, shouldWait); - return true; - } catch (OverlayManagerSettings.BadKeyException e) { - return false; -@@ -379,6 +379,12 @@ final class OverlayManagerServiceImpl { - private void updateState(@Nullable final PackageInfo targetPackage, - @NonNull final PackageInfo overlayPackage, final int userId) - throws OverlayManagerSettings.BadKeyException { -+ updateState(targetPackage, overlayPackage, userId, false); -+ } -+ -+ private void updateState(@Nullable final PackageInfo targetPackage, -+ @NonNull final PackageInfo overlayPackage, final int userId, -+ final boolean shouldWait) throws OverlayManagerSettings.BadKeyException { - if (targetPackage != null) { - mIdmapManager.createIdmap(targetPackage, overlayPackage, userId); - } -@@ -395,7 +401,7 @@ final class OverlayManagerServiceImpl { - OverlayInfo.stateToString(currentState), - OverlayInfo.stateToString(newState))); - } -- mSettings.setState(overlayPackage.packageName, userId, newState); -+ mSettings.setState(overlayPackage.packageName, userId, newState, shouldWait); - } - } - -diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java -index af0bb64..935ea02 100644 ---- a/services/core/java/com/android/server/om/OverlayManagerSettings.java -+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java -@@ -76,7 +76,7 @@ final class OverlayManagerSettings { - final OverlayInfo oi = item.getOverlayInfo(); - mItems.remove(item); - if (oi != null) { -- notifyOverlayRemoved(oi); -+ notifyOverlayRemoved(oi, false); - } - } - -@@ -135,7 +135,7 @@ final class OverlayManagerSettings { - final OverlayInfo oi = item.getOverlayInfo(); - item.setUpgrading(true); - item.setState(STATE_NOT_APPROVED_UNKNOWN); -- notifyOverlayRemoved(oi); -+ notifyOverlayRemoved(oi, false); - } else { - item.setUpgrading(false); - } -@@ -172,8 +172,8 @@ final class OverlayManagerSettings { - return item.getState(); - } - -- void setState(@NonNull final String packageName, final int userId, final int state) -- throws BadKeyException { -+ void setState(@NonNull final String packageName, final int userId, final int state, -+ final boolean shouldWait) throws BadKeyException { - final SettingsItem item = select(packageName, userId); - if (item == null) { - throw new BadKeyException(packageName, userId); -@@ -182,10 +182,10 @@ final class OverlayManagerSettings { - item.setState(state); - final OverlayInfo current = item.getOverlayInfo(); - if (previous.state == STATE_NOT_APPROVED_UNKNOWN) { -- notifyOverlayAdded(current); -+ notifyOverlayAdded(current, shouldWait); - notifySettingsChanged(); - } else if (current.state != previous.state) { -- notifyOverlayChanged(current, previous); -+ notifyOverlayChanged(current, previous, shouldWait); - notifySettingsChanged(); - } - } -@@ -602,32 +602,32 @@ final class OverlayManagerSettings { - } - } - -- private void notifyOverlayAdded(@NonNull final OverlayInfo oi) { -+ private void notifyOverlayAdded(@NonNull final OverlayInfo oi, final boolean shouldWait) { - if (DEBUG) { - assertNotNull(oi); - } - for (final ChangeListener listener : mListeners) { -- listener.onOverlayAdded(oi); -+ listener.onOverlayAdded(oi, shouldWait); - } - } - -- private void notifyOverlayRemoved(@NonNull final OverlayInfo oi) { -+ private void notifyOverlayRemoved(@NonNull final OverlayInfo oi, final boolean shouldWait) { - if (DEBUG) { - assertNotNull(oi); - } - for (final ChangeListener listener : mListeners) { -- listener.onOverlayRemoved(oi); -+ listener.onOverlayRemoved(oi, shouldWait); - } - } - - private void notifyOverlayChanged(@NonNull final OverlayInfo oi, -- @NonNull final OverlayInfo oldOi) { -+ @NonNull final OverlayInfo oldOi, final boolean shouldWait) { - if (DEBUG) { - assertNotNull(oi); - assertNotNull(oldOi); - } - for (final ChangeListener listener : mListeners) { -- listener.onOverlayChanged(oi, oldOi); -+ listener.onOverlayChanged(oi, oldOi, shouldWait); - } - } - -@@ -642,9 +642,10 @@ final class OverlayManagerSettings { - - interface ChangeListener { - void onSettingsChanged(); -- void onOverlayAdded(@NonNull OverlayInfo oi); -- void onOverlayRemoved(@NonNull OverlayInfo oi); -- void onOverlayChanged(@NonNull OverlayInfo oi, @NonNull OverlayInfo oldOi); -+ void onOverlayAdded(@NonNull OverlayInfo oi, boolean shouldWait); -+ void onOverlayRemoved(@NonNull OverlayInfo oi, boolean shouldWait); -+ void onOverlayChanged(@NonNull OverlayInfo oi, @NonNull OverlayInfo oldOi, -+ boolean shouldWait); - void onOverlayPriorityChanged(@NonNull OverlayInfo oi); - } - -diff --git a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java -index d6f5373..44004c1 100644 ---- a/services/core/java/com/android/server/om/OverlayManagerShellCommand.java -+++ b/services/core/java/com/android/server/om/OverlayManagerShellCommand.java -@@ -25,8 +25,10 @@ import android.os.ShellCommand; - import android.os.UserHandle; - - import java.io.PrintWriter; -+import java.util.ArrayList; - import java.util.List; - import java.util.Map; -+import java.util.Map.Entry; - - /** - * Implementation of 'cmd overlay' commands. -@@ -45,7 +47,9 @@ final class OverlayManagerShellCommand extends ShellCommand { - @Override - public int onCommand(@Nullable final String cmd) { - if (cmd == null) { -- return handleDefaultCommands(cmd); -+ final PrintWriter out = getOutPrintWriter(); -+ out.println("The overlay manager has already been initialized."); -+ return -1; - } - final PrintWriter err = getErrPrintWriter(); - try { -@@ -56,6 +60,8 @@ final class OverlayManagerShellCommand extends ShellCommand { - return runEnableDisable(true); - case "disable": - return runEnableDisable(false); -+ case "disable-all": -+ return runDisableAll(); - case "set-priority": - return runSetPriority(); - default: -@@ -82,10 +88,12 @@ final class OverlayManagerShellCommand extends ShellCommand { - out.println(" Overlay packages are printed in priority order. With optional"); - out.println(" parameters PACKAGEs, limit output to the specified packages"); - out.println(" but include more information about each package."); -- out.println(" enable [--user USER_ID] PACKAGE"); -- out.println(" Enable overlay package PACKAGE."); -- out.println(" disable [--user USER_ID] PACKAGE"); -- out.println(" Disable overlay package PACKAGE."); -+ out.println(" enable [--user USER_ID] [PACKAGE [PACKAGE [...]]]"); -+ out.println(" Enable overlay package PACKAGE or subsequent counts of PACKAGE."); -+ out.println(" disable [--user USER_ID] [PACKAGE [PACKAGE [...]]]"); -+ out.println(" Disable overlay package PACKAGE or subsequent counts of PACKAGE."); -+ out.println(" disable-all [--user USER_ID]"); -+ out.println(" Disable all overlay packages."); - out.println(" set-priority [--user USER_ID] PACKAGE PARENT|lowest|highest"); - out.println(" Change the priority of the overlay PACKAGE to be just higher than"); - out.println(" the priority of PACKAGE_PARENT If PARENT is the special keyword"); -@@ -145,8 +153,90 @@ final class OverlayManagerShellCommand extends ShellCommand { - } - } - -- final String packageName = getNextArgRequired(); -- return mInterface.setEnabled(packageName, enable, userId) ? 0 : 1; -+ int argc = 0; -+ String packageName = getNextArgRequired(); -+ ArrayList packages = new ArrayList<>(); -+ if (packageName == null) { -+ System.err.println("Error: no packages specified"); -+ return 1; -+ } -+ while (packageName != null) { -+ argc++; -+ packages.add(packageName); -+ packageName = getNextArg(); -+ } -+ if (argc > 1) { -+ for (String pkg : packages) { -+ boolean ret = mInterface.setEnabled(pkg, enable, userId, false); -+ if (!ret) { -+ System.err.println("Error: Failed to " + ((enable) ? "enable ": "disable ") + pkg); -+ } -+ } -+ return 0; -+ } else if (argc == 1) { -+ return mInterface.setEnabled(packages.get(0), enable, userId, false) ? 0 : 1; -+ } else { -+ System.err.println("Error: A fatal exception has occurred."); -+ return 1; -+ } -+ } -+ -+ private int runDisableAll() { -+ int userId = UserHandle.USER_OWNER; -+ String opt; -+ while ((opt = getNextOption()) != null) { -+ switch (opt) { -+ case "--user": -+ userId = UserHandle.parseUserArg(getNextArgRequired()); -+ break; -+ default: -+ System.err.println("Error: Unknown option: " + opt); -+ return 1; -+ } -+ } -+ -+ try { -+ Map> targetsAndOverlays = mInterface.getAllOverlays(userId); -+ int iterator = 0; -+ int overlaySize = targetsAndOverlays.entrySet().size(); -+ for (Entry> targetEntry : targetsAndOverlays.entrySet()) { -+ int iterator_nested = 0; -+ int targetSize_nested = targetEntry.getValue().size(); -+ iterator++; -+ for (OverlayInfo oi : targetEntry.getValue()) { -+ if (iterator_nested < targetSize_nested) { -+ if (oi.isEnabled()) { -+ boolean worked = mInterface.setEnabled(oi.packageName, false, userId, true); -+ if (!worked) { -+ System.err.println("Failed to disable " + oi.packageName); -+ } -+ } -+ } else { -+ if (iterator == overlaySize) { -+ if (oi.isEnabled()) { -+ boolean worked = mInterface.setEnabled(oi.packageName, false, userId, false); -+ if (!worked) { -+ System.err.println("Failed to disable " + oi.packageName); -+ } -+ } -+ } else { -+ if (oi.isEnabled()) { -+ boolean worked = mInterface.setEnabled(oi.packageName, false, userId, true); -+ if (!worked) { -+ System.err.println("Failed to disable " + oi.packageName); -+ } -+ } -+ } -+ } -+ iterator_nested++; -+ } -+ } -+ mInterface.refresh(userId); -+ } catch (RemoteException re) { -+ System.err.println(re.toString()); -+ System.err.println("Error: A fatal exception has occurred."); -+ } -+ return 0; - } - - private int runSetPriority() throws RemoteException { --- -2.9.3 - diff --git a/frameworks/base/0012-Themes-Expose-resolver-hardcoded-colors.patch b/frameworks/base/0012-Themes-Expose-resolver-hardcoded-colors.patch deleted file mode 100644 index 618f62d..0000000 --- a/frameworks/base/0012-Themes-Expose-resolver-hardcoded-colors.patch +++ /dev/null @@ -1,200 +0,0 @@ -From 68105cc059781ce4d0948cfe6d34511da24079d2 Mon Sep 17 00:00:00 2001 -From: Dave Kover -Date: Fri, 9 Dec 2016 10:47:17 -0700 -Subject: [PATCH 12/38] Themes: Expose resolver hardcoded colors - -commit dbbd5e70cc65002df41561474b03362022dd6716 -Author: Dave Kover -Date: Wed Feb 18 16:11:14 2015 -0800 - - Themes: Expose resolver hardcoded colors - - Expose background colors of the resolver list. - - Change-Id: I3a0a460c5ffe0f5057b3b9ec92faa7a3e09c9e01 - -commit 0343eb126f3901a3857791137f74fa805bb9d75c -Author: Thyrus11 -Date: Sat Feb 21 07:19:42 2015 +0100 - - Themes: Make resolver list fully themeable - - Follow-up on commit cc9e3b8fcba95b911d1cda36f7770c410058aa8b. - - Change-Id: I3f006a1157db9d0b151a4fe8edf50e7edc7a0b9f - -commit c7d973809488b801e8c708d740009f1233bb762e -Author: Nicholas Chum -Date: Sun Nov 8 05:27:28 2015 -0500 - - Themes: Allow Resolver List BG to be fully themed - - We are able to trace the activity of the new resolver/chooser through - different - methods, thus leading us to the Java file: - \com\android\internal\app\ChooserActivity.java - Here we see that the exposed "chooser_service_row_background_color" is - available, but not the rest of the activity, so we look into R.layout's, - and we - find chooser_grid to be the only one containing hardcoded - "@color/white" values (as this is framework, we assume this is also - known as - "@android:color/white" to themers). - - Expose all "@color/white" values from this file to resolver_list_bg. - - Change-Id: I286d92b5d1f672c8adb3c0af1951793521536d90 - -Change-Id: Iec7951147bbbc99aee6b06ae50c1acc7b9c01a7f ---- - core/res/res/layout/chooser_grid.xml | 6 +++--- - .../res/layout/resolver_different_item_header.xml | 2 +- - core/res/res/layout/resolver_list.xml | 8 ++++---- - core/res/res/layout/resolver_list_with_default.xml | 6 +++--- - core/res/res/values/projekt_colors.xml | 20 ++++++++++++++++++++ - 5 files changed, 31 insertions(+), 11 deletions(-) - create mode 100644 core/res/res/values/projekt_colors.xml - -diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml -index d8dd447..78c2e05 100644 ---- a/core/res/res/layout/chooser_grid.xml -+++ b/core/res/res/layout/chooser_grid.xml -@@ -31,7 +31,7 @@ - android:layout_alwaysShow="true" - android:elevation="8dp" - android:paddingStart="16dp" -- android:background="@color/white" > -+ android:background="@color/resolver_list_bg" > - -diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml -index c4e8e9c..1b6230a 100644 ---- a/core/res/res/layout/resolver_list.xml -+++ b/core/res/res/layout/resolver_list.xml -@@ -30,7 +30,7 @@ - android:layout_height="wrap_content" - android:layout_alwaysShow="true" - android:elevation="8dp" -- android:background="@color/white"> -+ android:background="@color/resolver_list_bg"> - - - - - -