diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index e11ac64eee47e..cc9a8b092203e 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -40,7 +40,6 @@ import android.content.pm.ActivityInfo; import android.content.pm.ActivityPresentationInfo; import android.content.pm.ApplicationInfo; -import android.content.pm.GosPackageState; import android.content.pm.IPackageDataObserver; import android.content.pm.UserInfo; import android.net.Uri; @@ -1478,7 +1477,7 @@ public abstract void getExecutableMethodFileOffsets(@NonNull String processName, */ public abstract boolean hasServiceBindingOrProviderUse(int uid, int clientUid); - public abstract void onGosPackageStateChanged(int uid, GosPackageState state); + public abstract void dispatchGosPackageStateCallbacks(int uid); public static class ProcessRecordSnapshot { public final int pid; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 8e225a181e46f..2c9b544a8d39e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -96,7 +96,6 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ComponentInfo; -import android.content.pm.GosPackageState; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; @@ -2517,9 +2516,8 @@ public void getExecutableMethodFileOffsets( } @Override - public void onGosPackageStateChanged(GosPackageState state) { - // this is a oneway method, caller (ActivityManager) will not be blocked - ActivityThreadHooks.onGosPackageStateChanged(mInitialApplication, state, false); + public void onGosPackageStateChanged() { + ActivityThreadHooks.onGosPackageStateChanged(null); } } diff --git a/core/java/android/app/ActivityThreadHooks.java b/core/java/android/app/ActivityThreadHooks.java index 6542e25e887de..14c6861ce2f98 100644 --- a/core/java/android/app/ActivityThreadHooks.java +++ b/core/java/android/app/ActivityThreadHooks.java @@ -1,5 +1,6 @@ package android.app; +import android.annotation.Nullable; import android.content.Context; import android.content.pm.GosPackageState; import android.content.pm.SrtPermissions; @@ -8,16 +9,19 @@ import android.location.HookedLocationManager; import android.os.Bundle; import android.os.Process; +import android.util.Log; import com.android.internal.app.ContactScopes; import com.android.internal.app.StorageScopesAppHooks; import com.android.internal.gmscompat.GmsHooks; +import com.android.internal.util.Preconditions; import java.util.Objects; class ActivityThreadHooks { - - private static volatile boolean called; + @Nullable // null during the early part of app process init + private static volatile Context appContext; + private static volatile boolean onBindCalled; // called after the initial app context is constructed // ActivityThread.handleBindApplication @@ -25,10 +29,8 @@ static Bundle onBind(ActivityThread.AppBindData appBindData) { Bundle args = appBindData.extraArgs; Objects.requireNonNull(args, "args bundle is null"); - if (called) { - throw new IllegalStateException("onBind called for the second time"); - } - called = true; + Preconditions.checkState(!onBindCalled); + onBindCalled = true; AssetManager.systemIdmapPaths_ = args.getStringArray(AppBindArgs.KEY_SYSTEM_IDMAP_PATHS); @@ -49,17 +51,50 @@ static Bundle onBind(ActivityThread.AppBindData appBindData) { // of app's code // ActivityThread.handleBindApplication static void onBind2(Context appContext, Bundle appBindArgs) { - GosPackageState gosPs = appBindArgs.getParcelable(AppBindArgs.KEY_GOS_PACKAGE_STATE, - GosPackageState.class); - onGosPackageStateChanged(appContext, gosPs, true); + ActivityThreadHooks.appContext = appContext; + if (!Process.isIsolated()) { // isolated processes don't have access to GosPackageState + onGosPackageStateChanged(appBindArgs); + } } - // called from both main and worker threads - static void onGosPackageStateChanged(Context ctx, GosPackageState state, boolean fromBind) { - if (!Process.isIsolated()) { - StorageScopesAppHooks.maybeEnable(state); - ContactScopes.maybeEnable(ctx, state); + private static final Object gosPackageStateChangeLock = new Object(); + private static boolean hadInitialGosPsChangeCallback; + private static boolean hasPendingGosPsChangeCallback; + + // called from both main and binder threads + static void onGosPackageStateChanged(@Nullable Bundle appBindArgs) { + Context ctx = appContext; + GosPackageState state; + synchronized (gosPackageStateChangeLock) { + if (appBindArgs != null) { + Preconditions.checkState(!hadInitialGosPsChangeCallback); + hadInitialGosPsChangeCallback = true; + // app context is always initialized by this point + Objects.requireNonNull(ctx); + if (hasPendingGosPsChangeCallback) { + Log.i("GosPackageState", "ignoring AppBindArgs since hasPendingGosPsChangeCallback is set"); + } + state = hasPendingGosPsChangeCallback ? + // GosPackageState from AppBindArgs is outdated, obtain a fresh one + GosPackageState.getForSelf(ctx) : + // this is the initial onGosPackageStateChanged() call during app binding, + // use GosPackageState from AppBindArgs to avoid IPC + appBindArgs.getParcelable(AppBindArgs.KEY_GOS_PACKAGE_STATE, GosPackageState.class); + + Objects.requireNonNull(state); + hasPendingGosPsChangeCallback = false; + } else { + if (ctx == null) { + Preconditions.checkState(!hadInitialGosPsChangeCallback); + hasPendingGosPsChangeCallback = true; + Log.i("GosPackageState", "set hasPendingGosPsChangeCallback"); + return; + } + state = GosPackageState.getForSelf(ctx); + } } + StorageScopesAppHooks.maybeEnable(state); + ContactScopes.maybeEnable(ctx, state); } static Service instantiateService(String className) { diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl index 9967cb52547af..d35b6c05d46a8 100644 --- a/core/java/android/app/IApplicationThread.aidl +++ b/core/java/android/app/IApplicationThread.aidl @@ -191,7 +191,7 @@ oneway interface IApplicationThread { void getExecutableMethodFileOffsets(in MethodDescriptor methodDescriptor, in IOffsetCallback resultCallback); - void onGosPackageStateChanged(in android.content.pm.GosPackageState state); + void onGosPackageStateChanged(); void requestHandoffActivityData(in IBinder requestToken, in List activityTokens); } diff --git a/core/java/android/content/pm/GosPackageState.java b/core/java/android/content/pm/GosPackageState.java index 91daf0b273226..58b0a00af6961 100644 --- a/core/java/android/content/pm/GosPackageState.java +++ b/core/java/android/content/pm/GosPackageState.java @@ -14,7 +14,10 @@ import android.os.RemoteException; import android.os.UserHandle; import android.permission.PermissionManager; +import android.util.Log; +import android.util.SparseArray; +import java.lang.reflect.Field; import java.util.Arrays; import java.util.Objects; @@ -171,6 +174,71 @@ public boolean isNone() { return this == NONE; } + private static volatile SparseArray flagNames; + + @Override + public String toString() { + if (this == DEFAULT) { + return "GosPackageState.DEFAULT"; + } + if (this == NONE) { + return "GosPackageState.NONE"; + } + var b = new StringBuilder("GosPackageState{"); + int origLength = b.length(); + if (flagStorage1 != 0) { + SparseArray flagNames = GosPackageState.flagNames; + if (flagNames == null) { + Field[] fields = GosPackageStateFlag.class.getDeclaredFields(); + int numFields = fields.length; + flagNames = new SparseArray(numFields); + for (int i = 0; i < numFields; ++i) { + Field f = fields[i]; + int fieldValue; + try { + fieldValue = (int) f.get(null); + } catch (ReflectiveOperationException e) { + Log.e("GosPackageState", "", e); + continue; + } + flagNames.set(fieldValue, f.getName()); + } + GosPackageState.flagNames = flagNames; + } + b.append("flags:"); + boolean first = true; + for (int i = 0; i < Long.SIZE; ++i) { + if (hasFlag(i)) { + String name = flagNames.get(i); + if (name == null) { + name = "UNKNOWN_FLAG_" + i; + } + b.append(first ? " " : " | "); + first = false; + b.append(name); + } + } + b.append(", "); + } + if (packageFlagStorage != 0) { + b.append("packageFlags: 0x"); + b.append(Long.toHexString(packageFlagStorage)); + b.append(", "); + } + if (storageScopes != null) { + b.append("has storageScopes, "); + } + if (contactScopes != null) { + b.append("has contactScopes, "); + } + if (b.length() != origLength) { + // trim trailing comma + space + b.setLength(b.length() - 2); + } + b.append('}'); + return b.toString(); + } + @NonNull public static GosPackageState getForSelf(@NonNull Context context) { return get(context.getPackageName(), context.getUserId()); diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/WifiTileTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/WifiTileTest.kt index f9fffa9cc3b8b..3260c30f53599 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/WifiTileTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/WifiTileTest.kt @@ -40,6 +40,7 @@ import com.android.systemui.qs.tiles.impl.wifi.domain.interactor.WifiTileUserAct import com.android.systemui.qs.tiles.impl.wifi.domain.model.WifiTileModel import com.android.systemui.qs.tiles.impl.wifi.ui.mapper.WifiTileMapper import com.android.systemui.res.R +import com.android.systemui.statusbar.policy.KeyguardStateController import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.test.runTest @@ -61,6 +62,7 @@ import org.mockito.kotlin.whenever class WifiTileTest : SysuiTestCase() { @Mock private lateinit var host: QSHost + @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var uiEventLogger: QsEventLogger @Mock private lateinit var metricsLogger: MetricsLogger @Mock private lateinit var statusBarStateController: StatusBarStateController @@ -101,6 +103,9 @@ class WifiTileTest : SysuiTestCase() { } ) + whenever(keyguardStateController.isMethodSecure).thenReturn(false) + whenever(host.keyguardStateController).thenReturn(keyguardStateController) + underTest = WifiTile( host, diff --git a/services/api/current.txt b/services/api/current.txt index b9f5ba7aa400a..00cff22d3f179 100644 --- a/services/api/current.txt +++ b/services/api/current.txt @@ -84,10 +84,12 @@ package com.android.server.permission { package com.android.server.pm { public interface PackageManagerLocal { + method public void addGosPackageStateChangeCallback(@NonNull com.android.server.pm.PackageManagerLocal.GosPackageStateChangeCallback); method @Nullable public String maybeOverrideCompilerFilter(@NonNull String, @NonNull com.android.server.pm.pkg.AndroidPackage, @NonNull Object); method public void onBgDexoptCompleted(@Nullable Object, long); method public void onBgDexoptProgressUpdate(long, int, int, int); method public void reconcileSdkData(@Nullable String, @NonNull String, @NonNull java.util.List, int, int, int, @NonNull String, int) throws java.io.IOException; + method public boolean removeGosPackageStateChangeCallback(@NonNull com.android.server.pm.PackageManagerLocal.GosPackageStateChangeCallback); method @NonNull public com.android.server.pm.PackageManagerLocal.FilteredSnapshot withFilteredSnapshot(); method @NonNull public com.android.server.pm.PackageManagerLocal.FilteredSnapshot withFilteredSnapshot(int, @NonNull android.os.UserHandle); method @NonNull public com.android.server.pm.PackageManagerLocal.UnfilteredSnapshot withUnfilteredSnapshot(); @@ -101,6 +103,11 @@ package com.android.server.pm { method @NonNull public java.util.Map getPackageStates(); } + public abstract static class PackageManagerLocal.GosPackageStateChangeCallback { + ctor public PackageManagerLocal.GosPackageStateChangeCallback(@NonNull android.os.Handler); + method public abstract void onGosPackageStateChanged(int, @NonNull android.content.pm.GosPackageState, int); + } + public static interface PackageManagerLocal.UnfilteredSnapshot extends AutoCloseable { method public void close(); method @NonNull public com.android.server.pm.PackageManagerLocal.FilteredSnapshot filtered(int, @NonNull android.os.UserHandle); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ca09ed62fcaf9..b2da89210e1e9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -343,7 +343,6 @@ import android.content.pm.AllowComponentAccessPolicyInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy; -import android.content.pm.GosPackageState; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; import android.content.pm.IncrementalStatesInfo; @@ -19401,9 +19400,9 @@ public boolean hasServiceBindingOrProviderUse(int uid, int clientUid) { } @Override - public void onGosPackageStateChanged(int uid, GosPackageState state) { - synchronized (mProcLock) { - mProcessList.onGosPackageStateChangedLOSP(uid, state); + public void dispatchGosPackageStateCallbacks(int uid) { + synchronized (mGlobalLock) { + mProcessList.dispatchGosPackageStateChangedLOSP(uid); } } diff --git a/services/core/java/com/android/server/am/NativeApplicationThreadWrapper.java b/services/core/java/com/android/server/am/NativeApplicationThreadWrapper.java index ed9cdddf96749..2e750fd2bf88d 100644 --- a/services/core/java/com/android/server/am/NativeApplicationThreadWrapper.java +++ b/services/core/java/com/android/server/am/NativeApplicationThreadWrapper.java @@ -525,9 +525,9 @@ public void getExecutableMethodFileOffsets( @NonNull MethodDescriptor methodDescriptor, @NonNull IOffsetCallback resultCallback) {} @Override - public void onGosPackageStateChanged(GosPackageState state) { - Slog.e(TAG, "onGosPackageStateChanged"); - System.exit(1); + public void onGosPackageStateChanged() { + // native processes run in isolated UIDs, onGosPackageStateChanged() is never called for them + Slog.wtf(TAG, "onGosPackageStateChanged called"); } @NeverCompile diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 58f92d7f2e19c..bee753865afbe 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -3922,22 +3922,21 @@ void handleAllTrustStorageUpdateLOSP() { } } - @GuardedBy(anyOf = {"mService", "mProcLock"}) - void onGosPackageStateChangedLOSP(int uid, GosPackageState state) { + @GuardedBy("mService") + void dispatchGosPackageStateChangedLOSP(int uid) { for (int i = mLruProcesses.size() - 1; i >= 0; i--) { ProcessRecord r = mLruProcesses.get(i); if (r.uid != uid) { - // isolated and "sdk sandbox" processes are skipped intentionally (they run in - // separate UIDs) + // isolated processes are skipped intentionally (they run in separate UIDs) continue; } final IApplicationThread thread = r.getThread(); if (thread != null) { try { - thread.onGosPackageStateChanged(state); + thread.onGosPackageStateChanged(); } catch (RemoteException ex) { - Slog.d(TAG, "onGosPackageStateChanged failed; uid " + uid - + ", processName " + r.info.processName); + Slog.i(TAG, "onGosPackageStateChanged failed; uid " + uid + + ", processName " + r.info.processName, ex); } } } diff --git a/services/core/java/com/android/server/pm/GosPackageStatePmHooks.java b/services/core/java/com/android/server/pm/GosPackageStatePmHooks.java index 8ef17565fe069..4a8c2b52a80c2 100644 --- a/services/core/java/com/android/server/pm/GosPackageStatePmHooks.java +++ b/services/core/java/com/android/server/pm/GosPackageStatePmHooks.java @@ -19,6 +19,7 @@ import com.android.internal.pm.parsing.pkg.AndroidPackageInternal; import com.android.internal.pm.pkg.component.ParsedUsesPermission; import com.android.server.LocalServices; +import com.android.server.pm.PackageManagerLocal.GosPackageStateChangeCallback; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageStateInternal; import com.android.server.pm.pkg.PackageUserStateInternal; @@ -26,6 +27,7 @@ import com.android.server.utils.Slogf; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import static android.content.pm.GosPackageState.*; import static com.android.server.pm.GosPackageStateUtils.parseFlag; @@ -33,17 +35,25 @@ public class GosPackageStatePmHooks { private static final String TAG = "GosPackageStatePmHooks"; - static void init(PackageManagerService pm) { - GosPackageStatePermissions.init(pm); + private final PackageManagerService pkgManager; + + private final CopyOnWriteArrayList changeCallbacks = new CopyOnWriteArrayList<>(); + + GosPackageStatePmHooks(PackageManagerService pkgManager) { + this.pkgManager = pkgManager; + } + + void init() { + GosPackageStatePermissions.init(pkgManager); } @NonNull - public static GosPackageState getUnfiltered(PackageManagerService pm, String packageName, int userId) { - return getUnfiltered(pm.snapshotComputer(), packageName, userId); + GosPackageState getUnfiltered(String packageName, int userId) { + return getUnfiltered(pkgManager.snapshotComputer(), packageName, userId); } @NonNull - public static GosPackageState getUnfiltered(Computer snapshot, String packageName, int userId) { + private static GosPackageState getUnfiltered(Computer snapshot, String packageName, int userId) { PackageStateInternal psi = snapshot.getPackageStates().get(packageName); if (psi == null) { return NONE; @@ -52,9 +62,8 @@ public static GosPackageState getUnfiltered(Computer snapshot, String packageNam } @NonNull - public static GosPackageState getFiltered(PackageManagerService pm, int callingUid, int callingPid, - String packageName, int userId) { - Computer pmComputer = pm.snapshotComputer(); + GosPackageState getFiltered(int callingUid, int callingPid, String packageName, int userId) { + Computer pmComputer = pkgManager.snapshotComputer(); PackageStateInternal packageState = pmComputer.getPackageStates().get(packageName); if (packageState == null) { // the package was likely racily uninstalled @@ -80,12 +89,14 @@ public static GosPackageState getFiltered(Computer pmComputer, return permission.filterRead(gosPs); } - static boolean set(PackageManagerService pm, - final int callingUid, final int callingPid, + boolean set(final int callingUid, final int callingPid, String packageName, int userId, GosPackageState update, int editorFlags) { final int appId; + final int uid; + final GosPackageState updatedGosPs; + final PackageManagerService pm = pkgManager; synchronized (pm.mLock) { PackageSetting packageSetting = pm.mSettings.getPackageLPr(packageName); if (packageSetting == null) { @@ -118,7 +129,7 @@ static boolean set(PackageManagerService pm, } GosPackageState currentGosPs = userState.getGosPackageState(); - GosPackageState updatedGosPs = permission.filterWrite(currentGosPs, update); + updatedGosPs = permission.filterWrite(currentGosPs, update); SharedUserSetting sharedUser = pm.mSettings.getSharedUserSettingLPr(packageSetting); @@ -138,13 +149,22 @@ static boolean set(PackageManagerService pm, // will invalidate app-side caches (GosPackageState.sCache) pm.scheduleWritePackageRestrictions(userId); + + uid = UserHandle.getUid(userId, appId); + + // changeCallbacks is a CopyOnWriteArrayList, no need for external synchronization + for (GosPackageStateChangeCallback callback : changeCallbacks) { + callback.getHandler().post(() -> + callback.onGosPackageStateChanged(uid, updatedGosPs, userId)); + } } + Slogf.i(TAG, "set: callingUid: %s, uid: %s, pkgName: %s, value: %s", callingUid, uid, packageName, updatedGosPs); if ((editorFlags & EDITOR_FLAG_KILL_UID_AFTER_APPLY) != 0) { final long token = Binder.clearCallingIdentity(); try { // important to call outside the 'synchronized (pm.mLock)' section, may deadlock otherwise - ActivityManager.getService().killUid(appId, userId, "GosPackageState"); + ActivityManager.getService().killUid(appId, userId, "GosPackageStateChange"); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } finally { @@ -152,15 +172,15 @@ static boolean set(PackageManagerService pm, } } if ((editorFlags & EDITOR_FLAG_NOTIFY_UID_AFTER_APPLY) != 0) { - int uid = UserHandle.getUid(userId, appId); - - // get GosPackageState as the target app - GosPackageState ps = getFiltered(pm, uid, GosPackageStatePermissions.UNKNOWN_CALLING_PID, packageName, userId); - final long token = Binder.clearCallingIdentity(); try { var am = LocalServices.getService(ActivityManagerInternal.class); - am.onGosPackageStateChanged(uid, ps); + // New GosPackageState is intentionally not passed since the GosPackageState change + // callback is delivered to the app process via a oneway binder call. Oneway binder + // calls to frozen processes are queued until the process is unfrozen. Not passing + // the GosPackageState also removes the need to maintain ordering between + // concurrent GosPackageState changes. + am.dispatchGosPackageStateCallbacks(uid); } finally { Binder.restoreCallingIdentity(token); } @@ -168,6 +188,23 @@ static boolean set(PackageManagerService pm, return true; } + public void addChangeCallback(GosPackageStateChangeCallback callback) { + synchronized (changeCallbacks) { + changeCallbacks.add(callback); + } + } + + public boolean removeChangeCallback(GosPackageStateChangeCallback callback) { + boolean res; + synchronized (changeCallbacks) { + res = changeCallbacks.remove(callback); + } + if (!res) { + Slog.e(TAG, "removeChangeCallback: callback is not in changeCallbacks list"); + } + return res; + } + private static void maybeDeriveFlags(Computer snapshot, GosPackageState gosPs, PackageStateInternal pkgState) { if ((gosPs.derivedFlags & DerivedPackageFlag.DFLAGS_SET) != 0) { return; diff --git a/services/core/java/com/android/server/pm/PackageManagerLocal.java b/services/core/java/com/android/server/pm/PackageManagerLocal.java index 8ecaee02f9eeb..0c25449040a1b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerLocal.java +++ b/services/core/java/com/android/server/pm/PackageManagerLocal.java @@ -22,8 +22,11 @@ import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.annotation.UserIdInt; +import android.content.pm.GosPackageState; import android.content.pm.SigningDetails; import android.os.Binder; +import android.os.Handler; import android.os.UserHandle; import com.android.server.pm.pkg.AndroidPackage; @@ -36,6 +39,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.List; import java.util.Map; +import java.util.Objects; /** * In-process API for server side PackageManager related infrastructure. @@ -48,6 +52,40 @@ @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) public interface PackageManagerLocal { + /** @hide */ + @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) + abstract class GosPackageStateChangeCallback { + private final Handler handler; + + /** @param handler Handler for dispatching {@link #onGosPackageStateChanged} callbacks. */ + public GosPackageStateChangeCallback(@NonNull Handler handler) { + this.handler = Objects.requireNonNull(handler); + } + + /** @hide */ + @NonNull + public final Handler getHandler() { + return this.handler; + } + + /** + * Called after each successful GosPackageState update. + * + * @param uid UID of the package(s). GosPackageState is shared for sharedUid packages. + * @param state Updated GosPackageState. + * @param userId The user id. + */ + public abstract void onGosPackageStateChanged(int uid, @NonNull GosPackageState state, @UserIdInt int userId); + } + + void addGosPackageStateChangeCallback(@NonNull GosPackageStateChangeCallback callback); + + /** + * @param callback A callback that was previously registered with {@link #addGosPackageStateChangeCallback}. + * @return {@code false} if the callback was missing from the list of callbacks, {@code true} otherwise. + */ + boolean removeGosPackageStateChangeCallback(@NonNull GosPackageStateChangeCallback callback); + /** * Indicates if operation should include device encrypted storage. */ diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3c390db2cb2ca..201d99aa9e9af 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -348,6 +348,7 @@ * */ public class PackageManagerService implements PackageSender, TestUtilityService { + public final GosPackageStatePmHooks gosPackageStatePmHooks; static final String TAG = "PackageManager"; public static final boolean DEBUG_SETTINGS = false; @@ -1907,6 +1908,7 @@ private void registerObservers(boolean verify) { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) public PackageManagerService(@NonNull PackageManagerServiceInjector injector, @NonNull PackageManagerServiceTestParams testParams) { + gosPackageStatePmHooks = new GosPackageStatePmHooks(this); mInjector = injector; mInjector.bootstrap(this); mAppsFilter = injector.getAppsFilter(); @@ -2022,6 +2024,7 @@ public PackageManagerService(PackageManagerServiceInjector injector, boolean fac final String partitionsFingerprint, final boolean isEngBuild, final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion, final int sdkVersionFull) { + gosPackageStatePmHooks = new GosPackageStatePmHooks(this); mIsEngBuild = isEngBuild; mIsUserDebugBuild = isUserDebugBuild; mSdkVersion = sdkVersion; @@ -4690,7 +4693,7 @@ public void onReceive(Context context, Intent intent) { dexUseManager.systemReady(); } - GosPackageStatePmHooks.init(this); + gosPackageStatePmHooks.init(); PackageMetrics.logInvalidationMetrics(); } @@ -7130,7 +7133,7 @@ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { public GosPackageState getGosPackageState(@NonNull String packageName, int userId) { int callingUid = Binder.getCallingUid(); int callingPid = Binder.getCallingPid(); - return GosPackageStatePmHooks.getFiltered(PackageManagerService.this, callingUid, callingPid, packageName, userId); + return gosPackageStatePmHooks.getFiltered(callingUid, callingPid, packageName, userId); } @Override @@ -7138,7 +7141,7 @@ public boolean setGosPackageState(@NonNull String packageName, int userId, @NonNull GosPackageState updatedPs, int editorFlags) { int callingUid = Binder.getCallingUid(); int callingPid = Binder.getCallingPid(); - return GosPackageStatePmHooks.set(PackageManagerService.this, callingUid, callingPid, packageName, userId, + return gosPackageStatePmHooks.set(callingUid, callingPid, packageName, userId, updatedPs, editorFlags); } @@ -7836,7 +7839,7 @@ public boolean isUpgradingFromLowerThanBySdkVersionFull( @NonNull @Override public GosPackageState getGosPackageState(String packageName, int userId) { - return GosPackageStatePmHooks.getUnfiltered(PackageManagerService.this, packageName, userId); + return gosPackageStatePmHooks.getUnfiltered(packageName, userId); } @Override diff --git a/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java b/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java index 2296eba86c560..7277fb04c49c3 100644 --- a/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java +++ b/services/core/java/com/android/server/pm/local/PackageManagerLocalImpl.java @@ -60,6 +60,16 @@ public PackageManagerLocalImpl(PackageManagerService service) { mService = service; } + @Override + public void addGosPackageStateChangeCallback(GosPackageStateChangeCallback callback) { + mService.gosPackageStatePmHooks.addChangeCallback(callback); + } + + @Override + public boolean removeGosPackageStateChangeCallback(GosPackageStateChangeCallback callback) { + return mService.gosPackageStatePmHooks.removeChangeCallback(callback); + } + @Override public void reconcileSdkData(@Nullable String volumeUuid, @NonNull String packageName, @NonNull List subDirNames, int userId, int appId, int previousAppId,