From ab53289c593aad60eddbe1ffc73402ac1f92c112 Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Wed, 8 Mar 2017 14:19:49 -0800 Subject: [PATCH] Add API to mark apps that have an update available Ostensibly for instant apps, we allow play to mark an app as having an update available. This will trigger instant app resolution even if the instant app is already installed on device. Bug: 35143464 Test: Manual; launch URI of installed instant app, see it runs w/o resolution. set bit. launch URI of installed instant app, see it runs resolution Change-Id: I511df2b2a3eab39377167c770255ccbe02d5dad2 --- api/system-current.txt | 2 ++ core/java/android/app/ApplicationPackageManager.java | 9 +++++++++ core/java/android/content/pm/IPackageManager.aidl | 6 ++++++ core/java/android/content/pm/PackageManager.java | 5 +++++ .../com/android/server/pm/PackageManagerService.java | 17 +++++++++++++++++ .../java/com/android/server/pm/PackageSettingBase.java | 11 +++++++++++ services/core/java/com/android/server/pm/Settings.java | 6 ++++++ .../src/android/test/mock/MockPackageManager.java | 6 ++++++ .../layoutlib/bridge/android/BridgePackageManager.java | 4 ++++ 9 files changed, 66 insertions(+) diff --git a/api/system-current.txt b/api/system-current.txt index fbfee83e67cd..34e2a8d85b6b 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -11241,6 +11241,7 @@ package android.content.pm { method public abstract boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int); method public abstract void setInstallerPackageName(java.lang.String, java.lang.String); method public abstract boolean setInstantAppCookie(byte[]); + method public abstract void setUpdateAvailable(java.lang.String, boolean); method public abstract boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int); method public abstract void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle); method public abstract void verifyIntentFilter(int, int, java.util.List); @@ -44138,6 +44139,7 @@ package android.test.mock { method public boolean setDefaultBrowserPackageNameAsUser(java.lang.String, int); method public void setInstallerPackageName(java.lang.String, java.lang.String); method public boolean setInstantAppCookie(byte[]); + method public void setUpdateAvailable(java.lang.String, boolean); method public boolean updateIntentVerificationStatusAsUser(java.lang.String, int, int); method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle); method public void verifyIntentFilter(int, int, java.util.List); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 97992cafee0e..55407e6d7365 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1814,6 +1814,15 @@ public class ApplicationPackageManager extends PackageManager { } @Override + public void setUpdateAvailable(String packageName, boolean updateAvailable) { + try { + mPM.setUpdateAvailable(packageName, updateAvailable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Override public String getInstallerPackageName(String packageName) { try { return mPM.getInstallerPackageName(packageName); diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 147b3e13b998..4de64c41e913 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -608,6 +608,12 @@ interface IPackageManager { boolean setRequiredForSystemUser(String packageName, boolean systemUserApp); + /** + * Sets whether or not an update is available. Ostensibly for instant apps + * to force exteranl resolution. + */ + void setUpdateAvailable(String packageName, boolean updateAvaialble); + String getServicesSystemSharedLibraryPackageName(); String getSharedSystemSharedLibraryPackageName(); diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 3a875bc79aa8..33f57e025473 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -5286,6 +5286,11 @@ public abstract class PackageManager { public abstract void setInstallerPackageName(String targetPackage, String installerPackageName); + /** @hide */ + @SystemApi + @RequiresPermission(Manifest.permission.INSTALL_PACKAGES) + public abstract void setUpdateAvailable(String packageName, boolean updateAvaialble); + /** * Attempts to delete a package. Since this may take a little while, the * result will be posted back to the given observer. A deletion will fail if diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c27806d80ac9..c94fc92c88f0 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -12190,6 +12190,11 @@ public class PackageManagerService extends IPackageManager.Stub { if (!isInstantApp && userState.instantApp) { return null; } + // throw out instant app filters if updates are available; will trigger + // instant app resolution + if (userState.instantApp && ps.isUpdateAvailable()) { + return null; + } final ResolveInfo res = new ResolveInfo(); res.activityInfo = ai; if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { @@ -16885,6 +16890,7 @@ public class PackageManagerService extends IPackageManager.Stub { final PackageSetting ps = mSettings.mPackages.get(pkgName); if (ps != null) { res.newUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); + ps.setUpdateAvailable(false /*updateAvailable*/); } final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; @@ -19674,6 +19680,17 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } @Override + public void setUpdateAvailable(String packageName, boolean updateAvailable) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null); + synchronized (mPackages) { + final PackageSetting pkgSetting = mSettings.mPackages.get(packageName); + if (pkgSetting != null) { + pkgSetting.setUpdateAvailable(updateAvailable); + } + } + } + + @Override public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId) { if (!sUserManager.exists(userId)) return; diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index b9c43da77916..dfed72fa9b61 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -141,6 +141,8 @@ abstract class PackageSettingBase extends SettingBase { String volumeUuid; /** The category of this app, as hinted by the installer */ int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED; + /** Whether or not an update is available. Ostensibly only for instant apps. */ + boolean updateAvailable; IntentFilterVerificationInfo verificationInfo; @@ -219,6 +221,14 @@ abstract class PackageSettingBase extends SettingBase { timeStamp = newStamp; } + public void setUpdateAvailable(boolean updateAvailable) { + this.updateAvailable = updateAvailable; + } + + public boolean isUpdateAvailable() { + return updateAvailable; + } + /** * Makes a shallow copy of the given package settings. * @@ -268,6 +278,7 @@ abstract class PackageSettingBase extends SettingBase { usesStaticLibrariesVersions = orig.usesStaticLibrariesVersions != null ? Arrays.copyOf(orig.usesStaticLibrariesVersions, orig.usesStaticLibrariesVersions.length) : null; + updateAvailable = orig.updateAvailable; } private PackageUserState modifyUserState(int userId) { diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 570b31ffa7b5..7bd34246fe02 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2831,6 +2831,9 @@ final class Settings { if (pkg.parentPackageName != null) { serializer.attribute(null, "parentPackageName", pkg.parentPackageName); } + if (pkg.updateAvailable) { + serializer.attribute(null, "updateAvailable", "true"); + } writeChildPackagesLPw(serializer, pkg.childPackageNames); @@ -3698,6 +3701,7 @@ final class Settings { String isOrphaned = null; String volumeUuid = null; String categoryHintString = null; + String updateAvailable = null; int categoryHint = ApplicationInfo.CATEGORY_UNDEFINED; String uidError = null; int pkgFlags = 0; @@ -3726,6 +3730,7 @@ final class Settings { primaryCpuAbiString = parser.getAttributeValue(null, "primaryCpuAbi"); secondaryCpuAbiString = parser.getAttributeValue(null, "secondaryCpuAbi"); cpuAbiOverrideString = parser.getAttributeValue(null, "cpuAbiOverride"); + updateAvailable = parser.getAttributeValue(null, "updateAvailable"); if (primaryCpuAbiString == null && legacyCpuAbiString != null) { primaryCpuAbiString = legacyCpuAbiString; @@ -3905,6 +3910,7 @@ final class Settings { packageSetting.legacyNativeLibraryPathString = legacyNativeLibraryPathStr; packageSetting.primaryCpuAbiString = primaryCpuAbiString; packageSetting.secondaryCpuAbiString = secondaryCpuAbiString; + packageSetting.updateAvailable = "true".equals(updateAvailable); // Handle legacy string here for single-user mode final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED); if (enabledStr != null) { diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 29ba77663fd0..506f406c333f 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -643,6 +643,12 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } + /** @hide */ + @Override + public void setUpdateAvailable(String packageName, boolean updateAvailable) { + throw new UnsupportedOperationException(); + } + @Override public String getInstallerPackageName(String packageName) { throw new UnsupportedOperationException(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java index 2274b90da49e..906ebb1fe39e 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java @@ -657,6 +657,10 @@ public class BridgePackageManager extends PackageManager { } @Override + public void setUpdateAvailable(String packageName, boolean updateAvailable) { + } + + @Override public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) { } -- 2.11.0