Register PackageChangedReceiver to AppSearchManagerService.
The Receiver could receive ACTION_PACKAGE_FULLY_REMOVED and
ACTION_PACKAGE_DATA_CLEARED broadcast and clean the package data.
The CL has been reverted back since the receiver tries to write
to /data/system_ce/appSearch before user storage has been unlocked.
And this prevents encryption policy from being setup correctly.
Added check and only handle those actions if used is unlocked.
PatchSet 1 is the old version that has been reverted.
Bug: 145759910
Test: atest --rebuild-module-info CtsAppSearchHostTestCases
Test: atest StagedRollbackTest:com.android.tests.rollback.host.StagedRollbackTest#testRollbackDataPolicy -- --abi x86_64
Change-Id: I41dc0501ac227551ae9bf2c59f57accc66adc85f
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 7ca77d4..3f6e8a5 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.appsearch;
import static android.app.appsearch.AppSearchResult.throwableToFailedResult;
+import static android.os.Process.INVALID_UID;
import static android.os.UserHandle.USER_NULL;
import android.annotation.ElapsedRealtimeLong;
@@ -53,7 +54,6 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
@@ -128,6 +128,17 @@
mContext.registerReceiverAsUser(new UserActionReceiver(), UserHandle.ALL,
new IntentFilter(Intent.ACTION_USER_REMOVED), /*broadcastPermission=*/ null,
/*scheduler=*/ null);
+
+ //TODO(b/145759910) Add a direct callback when user clears the data instead of relying on
+ // broadcasts
+ IntentFilter packageChangedFilter = new IntentFilter();
+ packageChangedFilter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
+ packageChangedFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
+ packageChangedFilter.addDataScheme("package");
+ packageChangedFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiverAsUser(new PackageChangedReceiver(), UserHandle.ALL,
+ packageChangedFilter, /*broadcastPermission=*/ null,
+ /*scheduler=*/ null);
}
private class UserActionReceiver extends BroadcastReceiver {
@@ -135,15 +146,15 @@
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
switch (intent.getAction()) {
case Intent.ACTION_USER_REMOVED:
- final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
+ int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_NULL);
if (userId == USER_NULL) {
- Slog.e(TAG, "userId is missing in the intent: " + intent);
+ Log.e(TAG, "userId is missing in the intent: " + intent);
return;
}
handleUserRemoved(userId);
break;
default:
- Slog.e(TAG, "Received unknown intent: " + intent);
+ Log.e(TAG, "Received unknown intent: " + intent);
}
}
}
@@ -163,9 +174,52 @@
try {
mImplInstanceManager.removeAppSearchImplForUser(userId);
mLoggerInstanceManager.removePlatformLoggerForUser(userId);
- Slog.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
+ Log.i(TAG, "Removed AppSearchImpl instance for user: " + userId);
} catch (Throwable t) {
- Slog.e(TAG, "Unable to remove data for user: " + userId, t);
+ Log.e(TAG, "Unable to remove data for user: " + userId, t);
+ }
+ }
+
+ private class PackageChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(@NonNull Context context, @NonNull Intent intent) {
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_FULLY_REMOVED:
+ case Intent.ACTION_PACKAGE_DATA_CLEARED:
+ String packageName = intent.getData().getSchemeSpecificPart();
+ if (packageName == null) {
+ Log.e(TAG, "Package name is missing in the intent: " + intent);
+ return;
+ }
+ int uid = intent.getIntExtra(Intent.EXTRA_UID, INVALID_UID);
+ if (uid == INVALID_UID) {
+ Log.e(TAG, "uid is missing in the intent: " + intent);
+ return;
+ }
+ handlePackageRemoved(packageName, uid);
+ break;
+ default:
+ Log.e(TAG, "Received unknown intent: " + intent);
+ }
+ }
+ }
+
+ private void handlePackageRemoved(String packageName, int uid) {
+ int userId = UserHandle.getUserId(uid);
+ try {
+ if (isUserLocked(userId)) {
+ //TODO(b/186151459) clear the uninstalled package data when user is unlocked.
+ return;
+ }
+ if (ImplInstanceManager.getAppSearchDir(userId).exists()) {
+ // Only clear the package's data if AppSearch exists for this user.
+ AppSearchImpl impl = mImplInstanceManager.getOrCreateAppSearchImpl(mContext,
+ userId);
+ //TODO(b/145759910) clear visibility setting for package.
+ impl.clearPackageData(packageName);
+ }
+ } catch (Throwable t) {
+ Log.e(TAG, "Unable to remove data for package: " + packageName, t);
}
}
@@ -177,17 +231,20 @@
}
private void verifyUserUnlocked(int callingUserId) {
+ if (isUserLocked(callingUserId)) {
+ throw new IllegalStateException("User " + callingUserId + " is locked or not running.");
+ }
+ }
+
+ private boolean isUserLocked(int callingUserId) {
synchronized (mUnlockedUserIdsLocked) {
// First, check the local copy.
if (mUnlockedUserIdsLocked.contains(callingUserId)) {
- return;
+ return false;
}
// If the local copy says the user is locked, check with UM for the actual state,
// since the user might just have been unlocked.
- if (!mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId))) {
- throw new IllegalStateException(
- "User " + callingUserId + " is locked or not running.");
- }
+ return !mUserManager.isUserUnlockingOrUnlocked(UserHandle.of(callingUserId));
}
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
index af39b79..45023f9 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/ImplInstanceManager.java
@@ -73,6 +73,15 @@
}
/**
+ * Returns AppSearch directory in the credential encrypted system directory for the given user.
+ *
+ * <p>This folder should only be accessed after unlock.
+ */
+ public static File getAppSearchDir(@UserIdInt int userId) {
+ return new File(Environment.getDataSystemCeDirectory(userId), APP_SEARCH_DIR);
+ }
+
+ /**
* Gets an instance of AppSearchImpl for the given user, or creates one if none exists.
*
* <p>If no AppSearchImpl instance exists for the unlocked user, Icing will be initialized and
@@ -139,15 +148,10 @@
private AppSearchImpl createImpl(@NonNull Context context, @UserIdInt int userId)
throws AppSearchException {
- File appSearchDir = getAppSearchDir(context, userId);
+ File appSearchDir = getAppSearchDir(userId);
return AppSearchImpl.create(appSearchDir, context, userId, mGlobalQuerierPackage);
}
- private static File getAppSearchDir(@NonNull Context context, @UserIdInt int userId) {
- // See com.android.internal.app.ChooserActivity::getPinnedSharedPrefs
- return new File(Environment.getDataSystemCeDirectory(userId), APP_SEARCH_DIR);
- }
-
/**
* Returns the global querier package if it's a system package. Otherwise, empty string.
*