Merge "Update light mode when battery saver changes" into nyc-mr1-dev
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ff3f159..21ff50c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17777,6 +17777,7 @@
|| Intent.ACTION_MEDIA_BUTTON.equals(action)
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
|| Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
+ || Intent.ACTION_MASTER_CLEAR.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
|| LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 6a56fa6..d25abbf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -870,13 +870,8 @@
IntentSender statusReceiver, int userId) {
final int callingUid = Binder.getCallingUid();
mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
- boolean allowSilentUninstall = true;
if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
mAppOps.checkPackage(callingUid, callerPackageName);
- final String installerPackageName = mPm.getInstallerPackageName(packageName);
- allowSilentUninstall = mPm.isOrphaned(packageName) ||
- (installerPackageName != null
- && installerPackageName.equals(callerPackageName));
}
// Check whether the caller is device owner, in which case we do it silently.
@@ -887,8 +882,8 @@
final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
statusReceiver, packageName, isDeviceOwner, userId);
- if (allowSilentUninstall && mContext.checkCallingOrSelfPermission(
- android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
+ == PackageManager.PERMISSION_GRANTED) {
// Sweet, call straight through!
mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
} else if (isDeviceOwner) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 005c6b3..fa37177 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -8366,6 +8366,10 @@
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FACTORY_TEST;
}
+ if (isSystemApp(pkg)) {
+ pkgSetting.isOrphaned = true;
+ }
+
ArrayList<PackageParser.Package> clientLibPkgs = null;
if ((scanFlags & SCAN_CHECK_ONLY) != 0) {
@@ -15315,6 +15319,19 @@
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(observer);
final int uid = Binder.getCallingUid();
+ if (uid != Process.SHELL_UID && uid != Process.ROOT_UID && uid != Process.SYSTEM_UID
+ && uid != getPackageUid(mRequiredInstallerPackage, 0, UserHandle.getUserId(uid))
+ && !isOrphaned(packageName)
+ && !isCallerSameAsInstaller(uid, packageName)) {
+ try {
+ final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
+ intent.setData(Uri.fromParts("package", packageName, null));
+ intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
+ observer.onUserActionRequired(intent);
+ } catch (RemoteException re) {
+ }
+ return;
+ }
final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId };
if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
@@ -15383,6 +15400,12 @@
});
}
+ private boolean isCallerSameAsInstaller(int callingUid, String pkgName) {
+ final int installerPkgUid = getPackageUid(getInstallerPackageName(pkgName),
+ 0 /* flags */, UserHandle.getUserId(callingUid));
+ return installerPkgUid == callingUid;
+ }
+
private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
int[] result = EMPTY_INT_ARRAY;
for (int userId : userIds) {
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 827b88a..6f6fd7c 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -667,6 +667,12 @@
// - version code hasn't change
// - lastUpdateTime hasn't change
// - all target activities are still enabled.
+
+ // Note, system apps timestamps do *not* change after OTAs. (But they do
+ // after an adb sync or a local flash.)
+ // This means if a system app's version code doesn't change on an OTA,
+ // we don't notice it's updated. But that's fine since their version code *should*
+ // really change on OTAs.
if ((getPackageInfo().getVersionCode() == pi.versionCode)
&& (getPackageInfo().getLastUpdateTime() == pi.lastUpdateTime)
&& areAllActivitiesStillEnabled()) {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index b80775b..adf19dc 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -54,6 +54,7 @@
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
@@ -2659,10 +2660,14 @@
boolean forceRescan) {
final ShortcutUser user = getUserShortcutsLocked(userId);
+ // Note after each OTA, we'll need to rescan all system apps, as their lastUpdateTime
+ // is not reliable.
final long now = injectCurrentTimeMillis();
+ final boolean afterOta =
+ !injectBuildFingerprint().equals(user.getLastAppScanOsFingerprint());
// Then for each installed app, publish manifest shortcuts when needed.
- forUpdatedPackages(userId, lastScanTime, ai -> {
+ forUpdatedPackages(userId, lastScanTime, afterOta, ai -> {
user.attemptToRestoreIfNeededAndSave(this, ai.packageName, userId);
user.rescanPackageIfNeeded(ai.packageName, forceRescan);
});
@@ -2670,6 +2675,7 @@
// Write the time just before the scan, because there may be apps that have just
// been updated, and we want to catch them in the next time.
user.setLastAppScanTime(now);
+ user.setLastAppScanOsFingerprint(injectBuildFingerprint());
scheduleSaveUser(userId);
}
@@ -2908,7 +2914,7 @@
return parceledList.getList();
}
- private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime,
+ private void forUpdatedPackages(@UserIdInt int userId, long lastScanTime, boolean afterOta,
Consumer<ApplicationInfo> callback) {
if (DEBUG) {
Slog.d(TAG, "forUpdatedPackages for user " + userId + ", lastScanTime=" + lastScanTime);
@@ -2920,7 +2926,8 @@
// If the package has been updated since the last scan time, then scan it.
// Also if it's a system app with no update, lastUpdateTime is not reliable, so
// just scan it.
- if (pi.lastUpdateTime >= lastScanTime || isPureSystemApp(pi.applicationInfo)) {
+ if (pi.lastUpdateTime >= lastScanTime
+ || (afterOta && isPureSystemApp(pi.applicationInfo))) {
if (DEBUG) {
Slog.d(TAG, "Found updated package " + pi.packageName);
}
@@ -3598,6 +3605,12 @@
Binder.restoreCallingIdentity(token);
}
+ // Injection point.
+ @VisibleForTesting
+ String injectBuildFingerprint() {
+ return Build.FINGERPRINT;
+ }
+
final void wtf(String message) {
wtf(message, /* exception= */ null);
}
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index ce3ed9c..c05c66f 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -60,6 +60,7 @@
// Suffix "2" was added to force rescan all packages after the next OTA.
private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
+ private static final String ATTR_LAST_APP_SCAN_OS_FINGERPRINT = "last-app-scan-fp";
private static final String KEY_USER_ID = "userId";
private static final String KEY_LAUNCHERS = "launchers";
private static final String KEY_PACKAGES = "packages";
@@ -125,6 +126,8 @@
private long mLastAppScanTime;
+ private String mLastAppScanOsFingerprint;
+
public ShortcutUser(ShortcutService service, int userId) {
mService = service;
mUserId = userId;
@@ -142,6 +145,14 @@
mLastAppScanTime = lastAppScanTime;
}
+ public String getLastAppScanOsFingerprint() {
+ return mLastAppScanOsFingerprint;
+ }
+
+ public void setLastAppScanOsFingerprint(String lastAppScanOsFingerprint) {
+ mLastAppScanOsFingerprint = lastAppScanOsFingerprint;
+ }
+
// We don't expose this directly to non-test code because only ShortcutUser should add to/
// remove from it.
@VisibleForTesting
@@ -318,6 +329,8 @@
ShortcutService.writeAttr(out, ATTR_KNOWN_LOCALES, mKnownLocales);
ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_TIME,
mLastAppScanTime);
+ ShortcutService.writeAttr(out, ATTR_LAST_APP_SCAN_OS_FINGERPRINT,
+ mLastAppScanOsFingerprint);
ShortcutService.writeTagValue(out, TAG_LAUNCHER, mLastKnownLauncher);
@@ -364,7 +377,8 @@
ATTR_LAST_APP_SCAN_TIME);
final long currentTime = s.injectCurrentTimeMillis();
ret.mLastAppScanTime = lastAppScanTime < currentTime ? lastAppScanTime : 0;
-
+ ret.mLastAppScanOsFingerprint = ShortcutService.parseStringAttribute(parser,
+ ATTR_LAST_APP_SCAN_OS_FINGERPRINT);
final int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -457,6 +471,8 @@
pw.print(mLastAppScanTime);
pw.print("] ");
pw.print(ShortcutService.formatTime(mLastAppScanTime));
+ pw.print(" Last app scan FP: ");
+ pw.print(mLastAppScanOsFingerprint);
pw.println();
prefix += prefix + " ";
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index e96e97b..792f300 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -407,6 +407,11 @@
}
@Override
+ String injectBuildFingerprint() {
+ return mInjectedBuildFingerprint;
+ }
+
+ @Override
void wtf(String message, Throwable th) {
// During tests, WTF is fatal.
fail(message + " exception: " + th + "\n" + Log.getStackTraceString(th));
@@ -528,6 +533,7 @@
protected Map<String, PackageInfo> mInjectedPackages;
protected Set<PackageWithUser> mUninstalledPackages;
+ protected Set<String> mSystemPackages;
protected PackageManager mMockPackageManager;
protected PackageManagerInternal mMockPackageManagerInternal;
@@ -628,6 +634,8 @@
protected static final String PACKAGE_FALLBACK_LAUNCHER_NAME = "fallback";
protected static final int PACKAGE_FALLBACK_LAUNCHER_PRIORITY = -999;
+ protected String mInjectedBuildFingerprint = "build1";
+
static {
QUERY_ALL.setQueryFlags(
ShortcutQuery.FLAG_GET_ALL_KINDS);
@@ -677,6 +685,7 @@
pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
mUninstalledPackages = new HashSet<>();
+ mSystemPackages = new HashSet<>();
mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
@@ -963,6 +972,9 @@
if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
+ if (mSystemPackages.contains(packageName)) {
+ ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+ }
if (getSignatures) {
ret.signatures = pi.signatures;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index ed4e391..46ac7ce 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -4347,6 +4347,128 @@
});
}
+ public void testHandlePackageUpdate_systemAppUpdate() {
+
+ // Package1 is a system app. Package 2 is not a system app, so it's not scanned
+ // in this test at all.
+ mSystemPackages.add(CALLING_PACKAGE_1);
+
+ // Initial state: no shortcuts.
+ mService.checkPackageChanges(USER_0);
+
+ assertEquals(mInjectedCurrentTimeMillis,
+ mService.getUserShortcutsLocked(USER_0).getLastAppScanTime());
+ assertEquals(mInjectedBuildFingerprint,
+ mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint());
+
+ // They have no shortcuts.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .isEmpty();
+ });
+
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .isEmpty();
+ });
+
+ // Next.
+ // Update the packages -- now they have 1 manifest shortcut.
+ // But checkPackageChanges() don't notice it, since their version code / timestamp haven't
+ // changed.
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_1);
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+ R.xml.shortcut_1);
+ mInjectedCurrentTimeMillis += 1000;
+ mService.checkPackageChanges(USER_0);
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .isEmpty();
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .isEmpty();
+ });
+
+ // Next.
+ // Update the build finger print. All system apps will be scanned now.
+ mInjectedBuildFingerprint = "update1";
+ mInjectedCurrentTimeMillis += 1000;
+ mService.checkPackageChanges(USER_0);
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .isEmpty();
+ });
+
+ // Next.
+ // Update manifest shortcuts.
+ mInjectedBuildFingerprint = "update2";
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ addManifestShortcutResource(
+ new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+ R.xml.shortcut_2);
+ mInjectedCurrentTimeMillis += 1000;
+ mService.checkPackageChanges(USER_0);
+
+ // Fingerprint hasn't changed, so CALLING_PACKAGE_1 wasn't scanned.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .isEmpty();
+ });
+
+ // Update the fingerprint, but CALLING_PACKAGE_1's version code hasn't changed, so
+ // still not scanned.
+ mInjectedBuildFingerprint = "update2";
+ mInjectedCurrentTimeMillis += 1000;
+ mService.checkPackageChanges(USER_0);
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .isEmpty();
+ });
+
+ // Now update the version code, so CALLING_PACKAGE_1 is scanned again.
+ mInjectedBuildFingerprint = "update3";
+ mInjectedCurrentTimeMillis += 1000;
+ updatePackageVersion(CALLING_PACKAGE_1, 1);
+ mService.checkPackageChanges(USER_0);
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .haveIds("ms1", "ms2");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertWith(getCallerShortcuts())
+ .isEmpty();
+ });
+
+ // Make sure getLastAppScanTime / getLastAppScanOsFingerprint are persisted.
+ initService();
+ assertEquals(mInjectedCurrentTimeMillis,
+ mService.getUserShortcutsLocked(USER_0).getLastAppScanTime());
+ assertEquals(mInjectedBuildFingerprint,
+ mService.getUserShortcutsLocked(USER_0).getLastAppScanOsFingerprint());
+ }
+
public void testHandlePackageChanged() {
final ComponentName ACTIVITY1 = new ComponentName(CALLING_PACKAGE_1, "act1");
final ComponentName ACTIVITY2 = new ComponentName(CALLING_PACKAGE_1, "act2");