summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Joanne Chung <joannechung@google.com> 2021-05-21 21:42:02 +0800
committer Joanne Chung <joannechung@google.com> 2021-06-02 15:55:15 +0800
commitce9903f1ed54d167d66751ea0bb60a30ff3be71d (patch)
treecc0882909ff3cd058e08aade7e3b1d067901efd5
parent35a187904cb93d45f95e2bc54ccda6db7c658980 (diff)
Do not bind TextClassifierService if the packge doesn't install.
Currently, TCMS will try to bind TCS even the package doesn't install for certain user. If there are a lot of API calls come, we may call bindService() many times, this may cause system stability problem. We received the system reboot problem before. We already have preload TextClassifierService in ExtServices on primary user but it's possible the TextClassifierService doesn't install on the profile user or users unintall package. It's possible the package may not be installed on non-primary user. Users also can disable TextClassifierService from ui interface easily, it's possible occur on both primary and non-primary users, system should also not bind TextClassifierService in this case. In this change, system will avoid trying to call bindService() if the TCS deosn't install or disabled to minimize binder calls. Bug: 188825683 Bug: 170014504 Test: atest CtsTextClassifierTestCases Test: manual. Create work profile, turn on/off it and reboot to check the status. Disable app from Settings and check the status. Change-Id: Ifa2bccc0d2435712461067d650b52cb02a903c59
-rw-r--r--services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java139
1 files changed, 139 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index 753b42b24556..0f37450c24c9 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -25,6 +25,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Binder;
@@ -59,6 +61,7 @@ import android.view.textclassifier.TextLinks;
import android.view.textclassifier.TextSelection;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.FunctionalUtils.ThrowingConsumer;
@@ -110,6 +113,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi
try {
publishBinderService(Context.TEXT_CLASSIFICATION_SERVICE, mManagerService);
mManagerService.startListenSettings();
+ mManagerService.startTrackingPackageChanges();
} catch (Throwable t) {
// Starting this service is not critical to the running of this device and should
// therefore not crash the device. If it fails, log the error and continue.
@@ -119,11 +123,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi
@Override
public void onUserStarting(@NonNull TargetUser user) {
+ updatePackageStateForUser(user.getUserIdentifier());
processAnyPendingWork(user.getUserIdentifier());
}
@Override
public void onUserUnlocking(@NonNull TargetUser user) {
+ // refresh if we failed earlier due to locked encrypted user
+ updatePackageStateForUser(user.getUserIdentifier());
// Rebind if we failed earlier due to locked encrypted user
processAnyPendingWork(user.getUserIdentifier());
}
@@ -134,6 +141,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi
}
}
+ private void updatePackageStateForUser(int userId) {
+ synchronized (mManagerService.mLock) {
+ // Update the cached disable status, the TextClassfier may not be direct boot aware,
+ // we should update the disable status after user unlock
+ mManagerService.getUserStateLocked(userId).updatePackageStateLocked();
+ }
+ }
+
@Override
public void onUserStopping(@NonNull TargetUser user) {
int userId = user.getUserIdentifier();
@@ -160,6 +175,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
private final String mDefaultTextClassifierPackage;
@Nullable
private final String mSystemTextClassifierPackage;
+ // TODO: consider using device config to control it.
+ private boolean DEBUG = false;
private TextClassificationManagerService(Context context) {
mContext = Objects.requireNonNull(context);
@@ -176,6 +193,46 @@ public final class TextClassificationManagerService extends ITextClassifierServi
mSettingsListener.registerObserver();
}
+ void startTrackingPackageChanges() {
+ final PackageMonitor monitor = new PackageMonitor() {
+
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ notifyPackageInstallStatusChange(packageName, /* installed*/ true);
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ notifyPackageInstallStatusChange(packageName, /* installed= */ false);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ final int userId = getChangingUserId();
+ synchronized (mLock) {
+ final UserState userState = getUserStateLocked(userId);
+ final ServiceState serviceState = userState.getServiceStateLocked(packageName);
+ if (serviceState != null) {
+ serviceState.onPackageModifiedLocked();
+ }
+ }
+ }
+
+ private void notifyPackageInstallStatusChange(String packageName, boolean installed) {
+ final int userId = getChangingUserId();
+ synchronized (mLock) {
+ final UserState userState = getUserStateLocked(userId);
+ final ServiceState serviceState = userState.getServiceStateLocked(packageName);
+ if (serviceState != null) {
+ serviceState.onPackageInstallStatusChangeLocked(installed);
+ }
+ }
+ }
+ };
+
+ monitor.register(mContext, null, UserHandle.ALL, true);
+ }
+
@Override
public void onConnectedStateChanged(@ConnectionState int connected) {
}
@@ -452,6 +509,14 @@ public final class TextClassificationManagerService extends ITextClassifierServi
if (serviceState == null) {
Slog.d(LOG_TAG, "No configured system TextClassifierService");
callback.onFailure();
+ } else if (!serviceState.isInstalledLocked() || !serviceState.isEnabledLocked()) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG,
+ serviceState.mPackageName + " is not available in user " + userId
+ + ". Installed: " + serviceState.isInstalledLocked()
+ + ", enabled:" + serviceState.isEnabledLocked());
+ }
+ callback.onFailure();
} else if (attemptToBind && !serviceState.bindLocked()) {
Slog.d(LOG_TAG, "Unable to bind TextClassifierService at " + methodName);
callback.onFailure();
@@ -761,6 +826,24 @@ public final class TextClassificationManagerService extends ITextClassifierServi
return serviceStates;
}
+ @GuardedBy("mLock")
+ @Nullable
+ private ServiceState getServiceStateLocked(String packageName) {
+ for (ServiceState serviceState : getAllServiceStatesLocked()) {
+ if (serviceState.mPackageName.equals(packageName)) {
+ return serviceState;
+ }
+ }
+ return null;
+ }
+
+ @GuardedBy("mLock")
+ private void updatePackageStateLocked() {
+ for (ServiceState serviceState : getAllServiceStatesLocked()) {
+ serviceState.updatePackageStateLocked();
+ }
+ }
+
void dump(IndentingPrintWriter pw) {
synchronized (mLock) {
pw.increaseIndent();
@@ -814,6 +897,10 @@ public final class TextClassificationManagerService extends ITextClassifierServi
ComponentName mBoundComponentName = null;
@GuardedBy("mLock")
int mBoundServiceUid = Process.INVALID_UID;
+ @GuardedBy("mLock")
+ boolean mInstalled;
+ @GuardedBy("mLock")
+ boolean mEnabled;
private ServiceState(
@UserIdInt int userId, @NonNull String packageName, boolean isTrusted) {
@@ -822,6 +909,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
mConnection = new TextClassifierServiceConnection(mUserId);
mIsTrusted = isTrusted;
mBindServiceFlags = createBindServiceFlags(packageName);
+ mInstalled = isPackageInstalledForUser();
+ mEnabled = isServiceEnabledForUser();
}
@Context.BindServiceFlags
@@ -833,6 +922,54 @@ public final class TextClassificationManagerService extends ITextClassifierServi
return flags;
}
+ private boolean isPackageInstalledForUser() {
+ try {
+ PackageManager packageManager = mContext.getPackageManager();
+ return packageManager.getPackageInfoAsUser(mPackageName, 0, mUserId) != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ private boolean isServiceEnabledForUser() {
+ PackageManager packageManager = mContext.getPackageManager();
+ Intent intent = new Intent(TextClassifierService.SERVICE_INTERFACE);
+ intent.setPackage(mPackageName);
+ ResolveInfo resolveInfo = packageManager.resolveServiceAsUser(intent,
+ PackageManager.GET_SERVICES, mUserId);
+ ServiceInfo serviceInfo = resolveInfo == null ? null : resolveInfo.serviceInfo;
+ return serviceInfo != null;
+ }
+
+ @GuardedBy("mLock")
+ @NonNull
+ private void onPackageInstallStatusChangeLocked(boolean installed) {
+ mInstalled = installed;
+ }
+
+ @GuardedBy("mLock")
+ @NonNull
+ private void onPackageModifiedLocked() {
+ mEnabled = isServiceEnabledForUser();
+ }
+
+ @GuardedBy("mLock")
+ @NonNull
+ private void updatePackageStateLocked() {
+ mInstalled = isPackageInstalledForUser();
+ mEnabled = isServiceEnabledForUser();
+ }
+
+ @GuardedBy("mLock")
+ boolean isInstalledLocked() {
+ return mInstalled;
+ }
+
+ @GuardedBy("mLock")
+ boolean isEnabledLocked() {
+ return mEnabled;
+ }
+
@GuardedBy("mLock")
boolean isBoundLocked() {
return mService != null;
@@ -923,6 +1060,8 @@ public final class TextClassificationManagerService extends ITextClassifierServi
pw.printPair("userId", mUserId);
synchronized (mLock) {
pw.printPair("packageName", mPackageName);
+ pw.printPair("installed", mInstalled);
+ pw.printPair("enabled", mEnabled);
pw.printPair("boundComponentName", mBoundComponentName);
pw.printPair("isTrusted", mIsTrusted);
pw.printPair("bindServiceFlags", mBindServiceFlags);