Merge "OMS: handle overlay package upgrades, uninstalls"
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index 1a207ba..8464e26 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -16,10 +16,14 @@
package android.content.om;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Immutable overlay information about a package. All PackageInfos that
* represent an overlay package will have a corresponding OverlayInfo.
@@ -27,6 +31,19 @@
* @hide
*/
public final class OverlayInfo implements Parcelable {
+
+ @IntDef(prefix = "STATE_", value = {
+ STATE_UNKNOWN,
+ STATE_MISSING_TARGET,
+ STATE_NO_IDMAP,
+ STATE_DISABLED,
+ STATE_ENABLED,
+ STATE_TARGET_UPGRADING,
+ STATE_OVERLAY_UPGRADING,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface State {}
+
/**
* An internal state used as the initial state of an overlay. OverlayInfo
* objects exposed outside the {@link
@@ -61,6 +78,18 @@
public static final int STATE_ENABLED = 3;
/**
+ * The target package is currently being upgraded; the state will change
+ * once the package installation has finished.
+ */
+ public static final int STATE_TARGET_UPGRADING = 4;
+
+ /**
+ * The overlay package is currently being upgraded; the state will change
+ * once the package installation has finished.
+ */
+ public static final int STATE_OVERLAY_UPGRADING = 5;
+
+ /**
* Package name of the overlay package
*/
public final String packageName;
@@ -77,13 +106,8 @@
/**
* The state of this OverlayInfo as defined by the STATE_* constants in this class.
- *
- * @see #STATE_MISSING_TARGET
- * @see #STATE_NO_IDMAP
- * @see #STATE_DISABLED
- * @see #STATE_ENABLED
*/
- public final int state;
+ public final @State int state;
/**
* User handle for which this overlay applies
@@ -96,13 +120,13 @@
* @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) {
+ public OverlayInfo(@NonNull OverlayInfo source, @State 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) {
+ @NonNull String baseCodePath, @State int state, int userId) {
this.packageName = packageName;
this.targetPackageName = targetPackageName;
this.baseCodePath = baseCodePath;
@@ -136,6 +160,8 @@
case STATE_NO_IDMAP:
case STATE_DISABLED:
case STATE_ENABLED:
+ case STATE_TARGET_UPGRADING:
+ case STATE_OVERLAY_UPGRADING:
break;
default:
throw new IllegalArgumentException("State " + state + " is not a valid state");
@@ -156,7 +182,8 @@
dest.writeInt(userId);
}
- public static final Parcelable.Creator<OverlayInfo> CREATOR = new Parcelable.Creator<OverlayInfo>() {
+ public static final Parcelable.Creator<OverlayInfo> CREATOR =
+ new Parcelable.Creator<OverlayInfo>() {
@Override
public OverlayInfo createFromParcel(Parcel source) {
return new OverlayInfo(source);
@@ -189,14 +216,9 @@
* Translate a state to a human readable string. Only intended for
* debugging purposes.
*
- * @see #STATE_MISSING_TARGET
- * @see #STATE_NO_IDMAP
- * @see #STATE_DISABLED
- * @see #STATE_ENABLED
- *
* @return a human readable String representing the state.
*/
- public static String stateToString(int state) {
+ public static String stateToString(@State int state) {
switch (state) {
case STATE_UNKNOWN:
return "STATE_UNKNOWN";
@@ -208,6 +230,10 @@
return "STATE_DISABLED";
case STATE_ENABLED:
return "STATE_ENABLED";
+ case STATE_TARGET_UPGRADING:
+ return "STATE_TARGET_UPGRADING";
+ case STATE_OVERLAY_UPGRADING:
+ return "STATE_OVERLAY_UPGRADING";
default:
return "<unknown state>";
}
diff --git a/core/tests/overlaytests/host/Android.mk b/core/tests/overlaytests/host/Android.mk
index d8e1fc1..b48a46b 100644
--- a/core/tests/overlaytests/host/Android.mk
+++ b/core/tests/overlaytests/host/Android.mk
@@ -24,7 +24,11 @@
OverlayHostTests_BadSignatureOverlay \
OverlayHostTests_PlatformSignatureStaticOverlay \
OverlayHostTests_PlatformSignatureOverlay \
- OverlayHostTests_PlatformSignatureOverlayV2
+ OverlayHostTests_UpdateOverlay \
+ OverlayHostTests_FrameworkOverlayV1 \
+ OverlayHostTests_FrameworkOverlayV2 \
+ OverlayHostTests_AppOverlayV1 \
+ OverlayHostTests_AppOverlayV2
include $(BUILD_HOST_JAVA_LIBRARY)
# Include to build test-apps.
diff --git a/core/tests/overlaytests/host/AndroidTest.xml b/core/tests/overlaytests/host/AndroidTest.xml
index 6884623..1f750a8 100644
--- a/core/tests/overlaytests/host/AndroidTest.xml
+++ b/core/tests/overlaytests/host/AndroidTest.xml
@@ -18,6 +18,11 @@
<option name="test-tag" value="OverlayHostTests" />
<option name="test-suite-tag" value="apct" />
+ <!-- Install the device tests that will be used to verify things on device. -->
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="OverlayHostTests_UpdateOverlay.apk" />
+ </target_preparer>
+
<test class="com.android.tradefed.testtype.HostTest">
<option name="class" value="com.android.server.om.hosttest.InstallOverlayTests" />
</test>
diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
index 5093710..bf91a16 100644
--- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
+++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
@@ -23,14 +23,48 @@
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(DeviceJUnit4ClassRunner.class)
public class InstallOverlayTests extends BaseHostJUnit4Test {
-
- private static final String OVERLAY_PACKAGE_NAME =
+ private static final String SIG_OVERLAY_PACKAGE_NAME =
"com.android.server.om.hosttest.signature_overlay";
+ private static final String APP_OVERLAY_PACKAGE_NAME =
+ "com.android.server.om.hosttest.app_overlay";
+ private static final String FRAMEWORK_OVERLAY_PACKAGE_NAME =
+ "com.android.server.om.hosttest.framework_overlay";
+ private static final String[] ALL_PACKAGES = new String[] {
+ SIG_OVERLAY_PACKAGE_NAME, APP_OVERLAY_PACKAGE_NAME, FRAMEWORK_OVERLAY_PACKAGE_NAME
+ };
+
+ private static final String DEVICE_TEST_PKG =
+ "com.android.server.om.hosttest.update_overlay_test";
+ private static final String DEVICE_TEST_CLS = DEVICE_TEST_PKG + ".UpdateOverlayTest";
+
+ @Before
+ public void ensureNoOverlays() throws Exception {
+ // Make sure we're starting with a clean slate.
+ for (String pkg : ALL_PACKAGES) {
+ assertFalse(pkg + " should not be installed", isPackageInstalled(pkg));
+ assertFalse(pkg + " should not be registered with overlay manager service",
+ overlayManagerContainsPackage(pkg));
+ }
+ }
+
+ /*
+ For some reason, SuiteApkInstaller is *not* uninstalling overlays, even though #installPackage()
+ claims it will auto-clean.
+ TODO(b/72877546): Remove when auto-clean is fixed.
+ */
+ @After
+ public void uninstallOverlays() throws Exception {
+ for (String pkg : ALL_PACKAGES) {
+ uninstallPackage(pkg);
+ }
+ }
@Test
public void failToInstallNonPlatformSignedOverlay() throws Exception {
@@ -40,7 +74,7 @@
} catch (Exception e) {
// Expected.
}
- assertFalse(overlayManagerContainsPackage());
+ assertFalse(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME));
}
@Test
@@ -51,28 +85,64 @@
} catch (Exception e) {
// Expected.
}
- assertFalse(overlayManagerContainsPackage());
+ assertFalse(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME));
}
@Test
- public void succeedToInstallPlatformSignedOverlay() throws Exception {
+ public void installPlatformSignedOverlay() throws Exception {
installPackage("OverlayHostTests_PlatformSignatureOverlay.apk");
- assertTrue(overlayManagerContainsPackage());
+ assertTrue(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME));
}
@Test
- public void succeedToInstallPlatformSignedOverlayAndUpdate() throws Exception {
- installPackage("OverlayHostTests_PlatformSignatureOverlay.apk");
- assertTrue(overlayManagerContainsPackage());
- assertEquals("v1", getDevice().getAppPackageInfo(OVERLAY_PACKAGE_NAME).getVersionName());
+ public void installPlatformSignedAppOverlayAndUpdate() throws Exception {
+ assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, "expectAppResource"));
- installPackage("OverlayHostTests_PlatformSignatureOverlayV2.apk");
- assertTrue(overlayManagerContainsPackage());
- assertEquals("v2", getDevice().getAppPackageInfo(OVERLAY_PACKAGE_NAME).getVersionName());
+ installPackage("OverlayHostTests_AppOverlayV1.apk");
+ setOverlayEnabled(APP_OVERLAY_PACKAGE_NAME, true);
+ assertTrue(overlayManagerContainsPackage(APP_OVERLAY_PACKAGE_NAME));
+ assertEquals("v1", getDevice()
+ .getAppPackageInfo(APP_OVERLAY_PACKAGE_NAME)
+ .getVersionName());
+ assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+ "expectAppOverlayV1Resource"));
+
+ installPackage("OverlayHostTests_AppOverlayV2.apk");
+ assertTrue(overlayManagerContainsPackage(APP_OVERLAY_PACKAGE_NAME));
+ assertEquals("v2", getDevice()
+ .getAppPackageInfo(APP_OVERLAY_PACKAGE_NAME)
+ .getVersionName());
+ assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+ "expectAppOverlayV2Resource"));
}
- private boolean overlayManagerContainsPackage() throws Exception {
- return getDevice().executeShellCommand("cmd overlay list")
- .contains(OVERLAY_PACKAGE_NAME);
+ @Test
+ public void installPlatformSignedFrameworkOverlayAndUpdate() throws Exception {
+ assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS, "expectAppResource"));
+
+ installPackage("OverlayHostTests_FrameworkOverlayV1.apk");
+ setOverlayEnabled(FRAMEWORK_OVERLAY_PACKAGE_NAME, true);
+ assertTrue(overlayManagerContainsPackage(FRAMEWORK_OVERLAY_PACKAGE_NAME));
+ assertEquals("v1", getDevice()
+ .getAppPackageInfo(FRAMEWORK_OVERLAY_PACKAGE_NAME)
+ .getVersionName());
+ assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+ "expectFrameworkOverlayV1Resource"));
+
+ installPackage("OverlayHostTests_FrameworkOverlayV2.apk");
+ assertTrue(overlayManagerContainsPackage(FRAMEWORK_OVERLAY_PACKAGE_NAME));
+ assertEquals("v2", getDevice()
+ .getAppPackageInfo(FRAMEWORK_OVERLAY_PACKAGE_NAME)
+ .getVersionName());
+ assertTrue(runDeviceTests(DEVICE_TEST_PKG, DEVICE_TEST_CLS,
+ "expectFrameworkOverlayV2Resource"));
+ }
+
+ private void setOverlayEnabled(String pkg, boolean enabled) throws Exception {
+ getDevice().executeShellCommand("cmd overlay " + (enabled ? "enable " : "disable ") + pkg);
+ }
+
+ private boolean overlayManagerContainsPackage(String pkg) throws Exception {
+ return getDevice().executeShellCommand("cmd overlay list").contains(pkg);
}
}
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
index b051a82..4249549 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
@@ -40,13 +40,4 @@
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
include $(BUILD_PACKAGE)
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlayV2
-LOCAL_COMPATIBILITY_SUITE := general-tests
-LOCAL_CERTIFICATE := platform
-LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
-LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
-include $(BUILD_PACKAGE)
-
my_package_prefix :=
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
new file mode 100644
index 0000000..bd6d73d
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -0,0 +1,73 @@
+# Copyright (C) 2018 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+include $(BUILD_PACKAGE)
+
+my_package_prefix := com.android.server.om.hosttest.framework_overlay
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
+LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/framework/v1/res
+LOCAL_MANIFEST_FILE := framework/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
+LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/framework/v2/res
+LOCAL_MANIFEST_FILE := framework/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
+my_package_prefix := com.android.server.om.hosttest.app_overlay
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
+LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res
+LOCAL_MANIFEST_FILE := app/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS := tests
+LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2
+LOCAL_COMPATIBILITY_SUITE := general-tests
+LOCAL_CERTIFICATE := platform
+LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
+LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res
+LOCAL_MANIFEST_FILE := app/AndroidManifest.xml
+include $(BUILD_PACKAGE)
+
+my_package_prefix :=
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..06077a7
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.om.hosttest.update_overlay_test">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.server.om.hosttest.update_overlay_test"
+ android:label="Update Overlay Test"/>
+</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/AndroidManifest.xml
new file mode 100644
index 0000000..73804eb
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.om.hosttest.app_overlay">
+ <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test" />
+</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/res/values/values.xml
new file mode 100644
index 0000000..63f85c2
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v1/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<resources>
+ <string name="app_resource">App Resource Overlay V1</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/res/values/values.xml
new file mode 100644
index 0000000..fa4a697
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<resources>
+ <string name="app_resource">App Resource Overlay V2</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
new file mode 100644
index 0000000..8c8fe94
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.server.om.hosttest.framework_overlay">
+ <overlay android:targetPackage="android" />
+</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v1/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v1/res/values/values.xml
new file mode 100644
index 0000000..fedb2c6
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v1/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<resources>
+ <string name="ok">Framework Overlay V1</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v2/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v2/res/values/values.xml
new file mode 100644
index 0000000..8aebf483
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/framework/v2/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<resources>
+ <string name="ok">Framework Overlay V2</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/res/values/values.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/res/values/values.xml
new file mode 100644
index 0000000..7393166
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/res/values/values.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<resources>
+ <string name="app_resource">App Resource</string>
+</resources>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java b/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java
new file mode 100644
index 0000000..d46bb37
--- /dev/null
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/src/com/android/server/om/hosttest/update_overlay_test/UpdateOverlayTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 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.hosttest.update_overlay_test;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class UpdateOverlayTest {
+ private Resources mResources;
+
+ @Before
+ public void setUp() throws Exception {
+ final Configuration defaultLocaleConfiguration = new Configuration();
+ defaultLocaleConfiguration.setLocale(Locale.US);
+ mResources = InstrumentationRegistry
+ .getInstrumentation()
+ .getContext()
+ .createConfigurationContext(defaultLocaleConfiguration)
+ .getResources();
+ }
+
+ @Test
+ public void expectAppResource() throws Exception {
+ assertEquals("App Resource", mResources.getString(R.string.app_resource));
+ }
+
+ @Test
+ public void expectAppOverlayV1Resource() throws Exception {
+ assertEquals("App Resource Overlay V1", mResources.getString(R.string.app_resource));
+ }
+
+ @Test
+ public void expectAppOverlayV2Resource() throws Exception {
+ assertEquals("App Resource Overlay V2", mResources.getString(R.string.app_resource));
+ }
+
+ @Test
+ public void expectFrameworkOverlayResource() throws Exception {
+ assertEquals("OK", mResources.getString(android.R.string.ok));
+ }
+
+ @Test
+ public void expectFrameworkOverlayV1Resource() throws Exception {
+ assertEquals("Framework Overlay V1", mResources.getString(android.R.string.ok));
+ }
+
+ @Test
+ public void expectFrameworkOverlayV2Resource() throws Exception {
+ assertEquals("Framework Overlay V2", mResources.getString(android.R.string.ok));
+ }
+}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 7600e81..6e02db7 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -20,6 +20,8 @@
import static android.content.om.OverlayInfo.STATE_ENABLED;
import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
+import static android.content.om.OverlayInfo.STATE_OVERLAY_UPGRADING;
+import static android.content.om.OverlayInfo.STATE_TARGET_UPGRADING;
import static com.android.server.om.OverlayManagerService.DEBUG;
import static com.android.server.om.OverlayManagerService.TAG;
@@ -50,6 +52,10 @@
* @see OverlayManagerService
*/
final class OverlayManagerServiceImpl {
+ // Flags to use in conjunction with updateState.
+ private static final int FLAG_TARGET_IS_UPGRADING = 1<<0;
+ private static final int FLAG_OVERLAY_IS_UPGRADING = 1<<1;
+
private final PackageManagerHelper mPackageManager;
private final IdmapManager mIdmapManager;
private final OverlayManagerSettings mSettings;
@@ -123,9 +129,7 @@
}
try {
- final PackageInfo targetPackage =
- mPackageManager.getPackageInfo(overlayPackage.overlayTarget, newUserId);
- updateState(targetPackage, overlayPackage, newUserId);
+ updateState(overlayPackage.overlayTarget, overlayPackage.packageName, newUserId, 0);
} catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e);
mSettings.remove(overlayPackage.packageName, newUserId);
@@ -168,8 +172,7 @@
Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId);
}
- final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
- if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+ if (updateAllOverlaysForTarget(packageName, userId, 0)) {
mListener.onOverlaysChanged(packageName, userId);
}
}
@@ -179,18 +182,18 @@
Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId);
}
- final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
- if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+ if (updateAllOverlaysForTarget(packageName, userId, 0)) {
mListener.onOverlaysChanged(packageName, userId);
}
}
void onTargetPackageUpgrading(@NonNull final String packageName, final int userId) {
if (DEBUG) {
- Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId=" + userId);
+ Slog.d(TAG, "onTargetPackageUpgrading packageName=" + packageName + " userId="
+ + userId);
}
- if (updateAllOverlaysForTarget(packageName, userId, null)) {
+ if (updateAllOverlaysForTarget(packageName, userId, FLAG_TARGET_IS_UPGRADING)) {
mListener.onOverlaysChanged(packageName, userId);
}
}
@@ -200,8 +203,7 @@
Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
}
- final PackageInfo targetPackage = mPackageManager.getPackageInfo(packageName, userId);
- if (updateAllOverlaysForTarget(packageName, userId, targetPackage)) {
+ if (updateAllOverlaysForTarget(packageName, userId, 0)) {
mListener.onOverlaysChanged(packageName, userId);
}
}
@@ -211,7 +213,7 @@
Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId);
}
- if (updateAllOverlaysForTarget(packageName, userId, null)) {
+ if (updateAllOverlaysForTarget(packageName, userId, 0)) {
mListener.onOverlaysChanged(packageName, userId);
}
}
@@ -219,20 +221,21 @@
/**
* Returns true if the settings were modified for this target.
*/
- private boolean updateAllOverlaysForTarget(@NonNull final String packageName, final int userId,
- @Nullable final PackageInfo targetPackage) {
+ private boolean updateAllOverlaysForTarget(@NonNull final String targetPackageName,
+ final int userId, final int flags) {
boolean modified = false;
- final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(packageName, userId);
+ final List<OverlayInfo> ois = mSettings.getOverlaysForTarget(targetPackageName, userId);
final int N = ois.size();
for (int i = 0; i < N; i++) {
final OverlayInfo oi = ois.get(i);
- final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName, userId);
+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(oi.packageName,
+ userId);
if (overlayPackage == null) {
modified |= mSettings.remove(oi.packageName, oi.userId);
removeIdmapIfPossible(oi);
} else {
try {
- modified |= updateState(targetPackage, overlayPackage, userId);
+ modified |= updateState(targetPackageName, oi.packageName, userId, flags);
} catch (OverlayManagerSettings.BadKeyException e) {
Slog.e(TAG, "failed to update settings", e);
modified |= mSettings.remove(oi.packageName, userId);
@@ -254,14 +257,11 @@
return;
}
- final PackageInfo targetPackage =
- mPackageManager.getPackageInfo(overlayPackage.overlayTarget, userId);
-
mSettings.init(packageName, userId, overlayPackage.overlayTarget,
overlayPackage.applicationInfo.getBaseCodePath(),
overlayPackage.isStaticOverlayPackage(), overlayPackage.overlayPriority);
try {
- if (updateState(targetPackage, overlayPackage, userId)) {
+ if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) {
mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId);
}
} catch (OverlayManagerSettings.BadKeyException e) {
@@ -271,15 +271,64 @@
}
void onOverlayPackageChanged(@NonNull final String packageName, final int userId) {
- Slog.wtf(TAG, "onOverlayPackageChanged called, but only pre-installed overlays supported");
+ if (DEBUG) {
+ Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId);
+ }
+
+ try {
+ final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
+ if (updateState(oi.targetPackageName, packageName, userId, 0)) {
+ mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ }
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ Slog.e(TAG, "failed to update settings", e);
+ }
}
void onOverlayPackageUpgrading(@NonNull final String packageName, final int userId) {
- Slog.wtf(TAG, "onOverlayPackageUpgrading called, but only pre-installed overlays supported");
+ if (DEBUG) {
+ Slog.d(TAG, "onOverlayPackageUpgrading packageName=" + packageName + " userId="
+ + userId);
+ }
+
+ try {
+ final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
+ if (updateState(oi.targetPackageName, packageName, userId, FLAG_OVERLAY_IS_UPGRADING)) {
+ removeIdmapIfPossible(oi);
+ mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ }
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ Slog.e(TAG, "failed to update settings", e);
+ }
}
void onOverlayPackageUpgraded(@NonNull final String packageName, final int userId) {
- Slog.wtf(TAG, "onOverlayPackageUpgraded called, but only pre-installed overlays supported");
+ if (DEBUG) {
+ Slog.d(TAG, "onOverlayPackageUpgraded packageName=" + packageName + " userId="
+ + userId);
+ }
+
+ final PackageInfo pkg = mPackageManager.getPackageInfo(packageName, userId);
+ if (pkg == null) {
+ Slog.w(TAG, "overlay package " + packageName + " was upgraded, but couldn't be found");
+ onOverlayPackageRemoved(packageName, userId);
+ return;
+ }
+
+ try {
+ final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId);
+ if (!oldOi.targetPackageName.equals(pkg.overlayTarget)) {
+ mSettings.init(packageName, userId, pkg.overlayTarget,
+ pkg.applicationInfo.getBaseCodePath(), pkg.isStaticOverlayPackage(),
+ pkg.overlayPriority);
+ }
+
+ if (updateState(pkg.overlayTarget, packageName, userId, 0)) {
+ mListener.onOverlaysChanged(pkg.overlayTarget, userId);
+ }
+ } catch (OverlayManagerSettings.BadKeyException e) {
+ Slog.e(TAG, "failed to update settings", e);
+ }
}
void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) {
@@ -333,10 +382,8 @@
try {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
- final PackageInfo targetPackage =
- mPackageManager.getPackageInfo(oi.targetPackageName, userId);
boolean modified = mSettings.setEnabled(packageName, userId, enable);
- modified |= updateState(targetPackage, overlayPackage, userId);
+ modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0);
if (modified) {
mListener.onOverlaysChanged(oi.targetPackageName, userId);
@@ -349,7 +396,8 @@
boolean setEnabledExclusive(@NonNull final String packageName, final int userId) {
if (DEBUG) {
- Slog.d(TAG, String.format("setEnabledExclusive packageName=%s userId=%d", packageName, userId));
+ Slog.d(TAG, String.format("setEnabledExclusive packageName=%s userId=%d", packageName,
+ userId));
}
final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId);
@@ -359,10 +407,9 @@
try {
final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId);
- final PackageInfo targetPackage =
- mPackageManager.getPackageInfo(oi.targetPackageName, userId);
+ final String targetPackageName = oi.targetPackageName;
- List<OverlayInfo> allOverlays = getOverlayInfosForTarget(oi.targetPackageName, userId);
+ List<OverlayInfo> allOverlays = getOverlayInfosForTarget(targetPackageName, userId);
boolean modified = false;
@@ -384,15 +431,15 @@
// Disable the overlay.
modified |= mSettings.setEnabled(disabledOverlayPackageName, userId, false);
- modified |= updateState(targetPackage, disabledOverlayPackageInfo, userId);
+ modified |= updateState(targetPackageName, disabledOverlayPackageName, userId, 0);
}
// Enable the selected overlay.
modified |= mSettings.setEnabled(packageName, userId, true);
- modified |= updateState(targetPackage, overlayPackage, userId);
+ modified |= updateState(targetPackageName, packageName, userId, 0);
if (modified) {
- mListener.onOverlaysChanged(oi.targetPackageName, userId);
+ mListener.onOverlaysChanged(targetPackageName, userId);
}
return true;
} catch (OverlayManagerSettings.BadKeyException e) {
@@ -477,7 +524,8 @@
List<String> getEnabledOverlayPackageNames(@NonNull final String targetPackageName,
final int userId) {
- final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName, userId);
+ final List<OverlayInfo> overlays = mSettings.getOverlaysForTarget(targetPackageName,
+ userId);
final List<String> paths = new ArrayList<>(overlays.size());
final int N = overlays.size();
for (int i = 0; i < N; i++) {
@@ -492,36 +540,59 @@
/**
* Returns true if the settings/state was modified, false otherwise.
*/
- private boolean updateState(@Nullable final PackageInfo targetPackage,
- @NonNull final PackageInfo overlayPackage, final int userId)
+ private boolean updateState(@NonNull final String targetPackageName,
+ @NonNull final String overlayPackageName, final int userId, final int flags)
throws OverlayManagerSettings.BadKeyException {
+
+ final PackageInfo targetPackage = mPackageManager.getPackageInfo(targetPackageName, userId);
+ final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName,
+ userId);
+
// Static RROs targeting to "android", ie framework-res.apk, are handled by native layers.
- if (targetPackage != null &&
- !("android".equals(targetPackage.packageName)
+ if (targetPackage != null && overlayPackage != null &&
+ !("android".equals(targetPackageName)
&& overlayPackage.isStaticOverlayPackage())) {
mIdmapManager.createIdmap(targetPackage, overlayPackage, userId);
}
- boolean modified = mSettings.setBaseCodePath(overlayPackage.packageName, userId,
- overlayPackage.applicationInfo.getBaseCodePath());
+ boolean modified = false;
+ if (overlayPackage != null) {
+ modified |= mSettings.setBaseCodePath(overlayPackageName, userId,
+ overlayPackage.applicationInfo.getBaseCodePath());
+ }
- final int currentState = mSettings.getState(overlayPackage.packageName, userId);
- final int newState = calculateNewState(targetPackage, overlayPackage, userId);
+ final @OverlayInfo.State int currentState = mSettings.getState(overlayPackageName, userId);
+ final @OverlayInfo.State int newState = calculateNewState(targetPackage, overlayPackage,
+ userId, flags);
if (currentState != newState) {
if (DEBUG) {
Slog.d(TAG, String.format("%s:%d: %s -> %s",
- overlayPackage.packageName, userId,
+ overlayPackageName, userId,
OverlayInfo.stateToString(currentState),
OverlayInfo.stateToString(newState)));
}
- modified |= mSettings.setState(overlayPackage.packageName, userId, newState);
+ modified |= mSettings.setState(overlayPackageName, userId, newState);
}
return modified;
}
- private int calculateNewState(@Nullable final PackageInfo targetPackage,
- @NonNull final PackageInfo overlayPackage, final int userId)
+ private @OverlayInfo.State int calculateNewState(@Nullable final PackageInfo targetPackage,
+ @Nullable final PackageInfo overlayPackage, final int userId, final int flags)
throws OverlayManagerSettings.BadKeyException {
+
+ if ((flags & FLAG_TARGET_IS_UPGRADING) != 0) {
+ return STATE_TARGET_UPGRADING;
+ }
+
+ if ((flags & FLAG_OVERLAY_IS_UPGRADING) != 0) {
+ return STATE_OVERLAY_UPGRADING;
+ }
+
+ // assert expectation on overlay package: can only be null if the flags are used
+ if (DEBUG && overlayPackage == null) {
+ throw new IllegalArgumentException("null overlay package not compatible with no flags");
+ }
+
if (targetPackage == null) {
return STATE_MISSING_TARGET;
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 17b38de..a80cae4 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -145,7 +145,8 @@
return mItems.get(idx).setEnabled(enable);
}
- int getState(@NonNull final String packageName, final int userId) throws BadKeyException {
+ @OverlayInfo.State int getState(@NonNull final String packageName, final int userId)
+ throws BadKeyException {
final int idx = select(packageName, userId);
if (idx < 0) {
throw new BadKeyException(packageName, userId);
@@ -156,8 +157,8 @@
/**
* Returns true if the settings were modified, false if they remain the same.
*/
- boolean setState(@NonNull final String packageName, final int userId, final int state)
- throws BadKeyException {
+ boolean setState(@NonNull final String packageName, final int userId,
+ final @OverlayInfo.State int state) throws BadKeyException {
final int idx = select(packageName, userId);
if (idx < 0) {
throw new BadKeyException(packageName, userId);
@@ -413,7 +414,7 @@
private final String mPackageName;
private final String mTargetPackageName;
private String mBaseCodePath;
- private int mState;
+ private @OverlayInfo.State int mState;
private boolean mIsEnabled;
private OverlayInfo mCache;
private boolean mIsStatic;
@@ -421,7 +422,7 @@
SettingsItem(@NonNull final String packageName, final int userId,
@NonNull final String targetPackageName, @NonNull final String baseCodePath,
- final int state, final boolean isEnabled, final boolean isStatic,
+ final @OverlayInfo.State int state, final boolean isEnabled, final boolean isStatic,
final int priority) {
mPackageName = packageName;
mUserId = userId;
@@ -462,11 +463,11 @@
return false;
}
- private int getState() {
+ private @OverlayInfo.State int getState() {
return mState;
}
- private boolean setState(final int state) {
+ private boolean setState(final @OverlayInfo.State int state) {
if (mState != state) {
mState = state;
invalidateCache();