diff options
| author | 2021-05-21 21:42:02 +0800 | |
|---|---|---|
| committer | 2021-06-02 15:55:15 +0800 | |
| commit | ce9903f1ed54d167d66751ea0bb60a30ff3be71d (patch) | |
| tree | cc0882909ff3cd058e08aade7e3b1d067901efd5 | |
| parent | 35a187904cb93d45f95e2bc54ccda6db7c658980 (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.java | 139 |
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); |