diff options
9 files changed, 113 insertions, 0 deletions
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 027ddf51a069..2ce02df3b00d 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -2630,4 +2630,13 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowAsRuntimeException(); } } + + @Override + public String getInstantAppAndroidId(String packageName, UserHandle user) { + try { + return mPM.getInstantAppAndroidId(packageName, user.getIdentifier()); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index bbc942aff372..bc7a61200e8b 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -634,4 +634,6 @@ interface IPackageManager { ComponentName getInstantAppResolverSettingsComponent(); ComponentName getInstantAppInstallerComponent(); + + String getInstantAppAndroidId(String packageName, int userId); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 65bc307ab234..7cc2334f16d5 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -6305,4 +6305,12 @@ public abstract class PackageManager { */ @SystemApi public abstract ComponentName getInstantAppInstallerComponent(); + + /** + * Return the Android Id for a given Instant App. + * + * @see {@link android.provider.Settings.Secure#ANDROID_ID} + * @hide + */ + public abstract String getInstantAppAndroidId(String packageName, @NonNull UserHandle user); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index f32f163a86b0..22de27f81034 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5082,6 +5082,10 @@ public final class Settings { * (available on certain devices running Android 4.2 or higher), each user appears as a * completely separate device, so the {@code ANDROID_ID} value is unique to each * user.</p> + * + * <p class="note"><strong>Note:</strong> If the caller is an Instant App the id is scoped + * to the Instant App, it is generated when the Instant App is first installed and reset if + * the user clears the Instant App. */ public static final String ANDROID_ID = "android_id"; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 169a034f447c..48429e8b2b05 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -1109,6 +1109,33 @@ public class SettingsProvider extends ContentProvider { // Retrieve the ssaid from the table if present. final Setting ssaid = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId, name); + // If the app is an Instant App use its stored SSAID instead of our own. + final String instantSsaid; + final long token = Binder.clearCallingIdentity(); + try { + instantSsaid = mPackageManager.getInstantAppAndroidId(callingPkg.packageName, + owningUserId); + } catch (RemoteException e) { + Slog.e(LOG_TAG, "Failed to get Instant App Android ID", e); + return null; + } finally { + Binder.restoreCallingIdentity(token); + } + if (instantSsaid != null) { + // Use the stored value if it is still valid. + if (ssaid != null && instantSsaid.equals(ssaid.getValue())) { + return ssaid; + } + // The value has changed, update the stored value. + final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked( + SETTINGS_TYPE_SSAID, owningUserId); + final boolean success = ssaidSettings.insertSettingLocked(name, instantSsaid, null, + true, callingPkg.packageName); + if (!success) { + throw new IllegalStateException("Failed to update instant app android id"); + } + return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId, name); + } // Lazy initialize ssaid if not yet present in ssaid table. if (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) { diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java index 89a303d21413..46bc69b8d712 100644 --- a/services/core/java/com/android/server/pm/InstantAppRegistry.java +++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java @@ -35,6 +35,7 @@ import android.os.Message; import android.provider.Settings; import android.util.ArrayMap; import android.util.AtomicFile; +import android.util.ByteStringUtils; import android.util.PackageUtils; import android.util.Slog; import android.util.SparseArray; @@ -56,8 +57,10 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.function.Predicate; @@ -81,6 +84,7 @@ class InstantAppRegistry { private static final String INSTANT_APP_COOKIE_FILE_PREFIX = "cookie_"; private static final String INSTANT_APP_COOKIE_FILE_SIFFIX = ".dat"; private static final String INSTANT_APP_METADATA_FILE = "metadata.xml"; + private static final String INSTANT_APP_ANDROID_ID_FILE = "android_id"; private static final String TAG_PACKAGE = "package"; private static final String TAG_PERMISSIONS = "permissions"; @@ -195,6 +199,36 @@ class InstantAppRegistry { return null; } + public String getInstantAppAndroidIdLPw(@NonNull String packageName, + @UserIdInt int userId) { + File idFile = new File(getInstantApplicationDir(packageName, userId), + INSTANT_APP_ANDROID_ID_FILE); + if (idFile.exists()) { + try { + return IoUtils.readFileAsString(idFile.getAbsolutePath()); + } catch (IOException e) { + Slog.e(LOG_TAG, "Failed to read instant app android id file: " + idFile, e); + } + } + return generateInstantAppAndroidIdLPw(packageName, userId); + } + + private String generateInstantAppAndroidIdLPw(@NonNull String packageName, + @UserIdInt int userId) { + byte[] randomBytes = new byte[8]; + new SecureRandom().nextBytes(randomBytes); + String id = ByteStringUtils.toHexString(randomBytes).toLowerCase(Locale.US); + File idFile = new File(getInstantApplicationDir(packageName, userId), + INSTANT_APP_ANDROID_ID_FILE); + try (FileOutputStream fos = new FileOutputStream(idFile)) { + fos.write(id.getBytes()); + } catch (IOException e) { + Slog.e(LOG_TAG, "Error writing instant app android id file: " + idFile, e); + } + return id; + + } + public @Nullable List<InstantAppInfo> getInstantAppsLPr(@UserIdInt int userId) { List<InstantAppInfo> installedApps = getInstalledInstantApplicationsLPr(userId); List<InstantAppInfo> uninstalledApps = getUninstalledInstantApplicationsLPr(userId); @@ -462,6 +496,7 @@ class InstantAppRegistry { File instantAppDir = getInstantApplicationDir(packageName, userId); new File(instantAppDir, INSTANT_APP_METADATA_FILE).delete(); new File(instantAppDir, INSTANT_APP_ICON_FILE).delete(); + new File(instantAppDir, INSTANT_APP_ANDROID_ID_FILE).delete(); File cookie = peekInstantCookieFile(packageName, userId); if (cookie != null) { cookie.delete(); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5535d1790e5d..74acacc339be 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -23654,6 +23654,22 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return mInstantAppInstallerActivity == null ? null : mInstantAppInstallerActivity.getComponentName(); } + + @Override + public String getInstantAppAndroidId(String packageName, int userId) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_INSTANT_APPS, + "getInstantAppAndroidId"); + enforceCrossUserPermission(Binder.getCallingUid(), userId, + true /* requireFullPermission */, false /* checkShell */, + "getInstantAppAndroidId"); + // Make sure the target is an Instant App. + if (!isInstantApp(packageName, userId)) { + return null; + } + synchronized (mPackages) { + return mInstantAppRegistry.getInstantAppAndroidIdLPw(packageName, userId); + } + } } interface PackageSender { diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 20392e733599..589dd0cfee15 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -1134,4 +1134,11 @@ public class MockPackageManager extends PackageManager { public ComponentName getInstantAppInstallerComponent() { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + public String getInstantAppAndroidId(String packageName, UserHandle user) { + 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 ad26bc8b8672..93319a37ad42 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 @@ -928,4 +928,9 @@ public class BridgePackageManager extends PackageManager { public ComponentName getInstantAppInstallerComponent() { return null; } + + @Override + public String getInstantAppAndroidId(String packageName, UserHandle user) { + return null; + } } |