Rebind ContentCaptureService when the binderDied.

If the ContentCaptureService has package dependency with other
package, if the package is updating, ContentCaptureService will also
be killed.

In the normal case, if the service will be reconnected but in this
case the binding is cleared without any notification to the
ContentCaptureManagerService. The bug is in the core platform infra.
In the Content Capture code, we only see the binderDied.

This change is a short term solution in S, we will rebind the service
when the binderDied. To avoid crash loop, we only bind the service
with limit rebind counts.

Bug: 199609306
Test: manual. Add addPackageDependency to package and update the
package. Make sure the state is not zombie.

Change-Id: I09a4cf6281a5a259a9a759ca640d6f075726e562
This commit is contained in:
Joanne Chung
2021-09-23 21:48:31 +08:00
parent 8361670412
commit 4fc5c86bb9
2 changed files with 56 additions and 7 deletions

View File

@@ -223,7 +223,7 @@ public final class ContentCaptureManagerService extends
@Override // from AbstractMasterSystemService
protected ContentCapturePerUserService newServiceLocked(@UserIdInt int resolvedUserId,
boolean disabled) {
return new ContentCapturePerUserService(this, mLock, disabled, resolvedUserId);
return new ContentCapturePerUserService(this, mLock, disabled, resolvedUserId, mHandler);
}
@Override // from SystemService

View File

@@ -46,6 +46,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
import android.provider.Settings;
@@ -75,6 +76,7 @@ import com.android.server.contentcapture.RemoteContentCaptureService.ContentCapt
import com.android.server.infra.AbstractPerUserSystemService;
import java.io.PrintWriter;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@@ -88,6 +90,10 @@ final class ContentCapturePerUserService
private static final String TAG = ContentCapturePerUserService.class.getSimpleName();
private static final int MAX_REBIND_COUNTS = 5;
// 5 minutes
private static final long REBIND_DURATION_MS = 5 * 60 * 1_000;
@GuardedBy("mLock")
private final SparseArray<ContentCaptureServerSession> mSessions = new SparseArray<>();
@@ -121,11 +127,18 @@ final class ContentCapturePerUserService
@GuardedBy("mLock")
private ContentCaptureServiceInfo mInfo;
private Instant mLastRebindTime;
private int mRebindCount;
private final Handler mHandler;
private final Runnable mReBindServiceRunnable = new RebindServiceRunnable();
// TODO(b/111276913): add mechanism to prune stale sessions, similar to Autofill's
ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
@NonNull Object lock, boolean disabled, @UserIdInt int userId) {
@NonNull Object lock, boolean disabled, @UserIdInt int userId, Handler handler) {
super(master, lock, userId);
mHandler = handler;
updateRemoteServiceLocked(disabled);
}
@@ -190,9 +203,43 @@ final class ContentCapturePerUserService
Slog.w(TAG, "remote service died: " + service);
synchronized (mLock) {
mZombie = true;
writeServiceEvent(
FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_REMOTE_SERVICE_DIED,
getServiceComponentName());
// Reset rebindCount if over 12 hours mLastRebindTime
if (mLastRebindTime != null && Instant.now().isAfter(
mLastRebindTime.plusMillis(12 * 60 * 60 * 1000))) {
if (mMaster.debug) {
Slog.i(TAG, "The current rebind count " + mRebindCount + " is reset.");
}
mRebindCount = 0;
}
if (mRebindCount >= MAX_REBIND_COUNTS) {
writeServiceEvent(
FrameworkStatsLog.CONTENT_CAPTURE_SERVICE_EVENTS__EVENT__ON_REMOTE_SERVICE_DIED,
getServiceComponentName());
}
if (mRebindCount < MAX_REBIND_COUNTS) {
mHandler.removeCallbacks(mReBindServiceRunnable);
mHandler.postDelayed(mReBindServiceRunnable, REBIND_DURATION_MS);
}
}
}
private void updateRemoteServiceAndResurrectSessionsLocked() {
boolean disabled = !isEnabledLocked();
updateRemoteServiceLocked(disabled);
resurrectSessionsLocked();
}
private final class RebindServiceRunnable implements Runnable{
@Override
public void run() {
synchronized (mLock) {
if (mZombie) {
mLastRebindTime = Instant.now();
mRebindCount++;
updateRemoteServiceAndResurrectSessionsLocked();
}
}
}
}
@@ -240,8 +287,8 @@ final class ContentCapturePerUserService
}
void onPackageUpdatedLocked() {
updateRemoteServiceLocked(!isEnabledLocked());
resurrectSessionsLocked();
mRebindCount = 0;
updateRemoteServiceAndResurrectSessionsLocked();
}
@GuardedBy("mLock")
@@ -555,6 +602,8 @@ final class ContentCapturePerUserService
mInfo.dump(prefix2, pw);
}
pw.print(prefix); pw.print("Zombie: "); pw.println(mZombie);
pw.print(prefix); pw.print("Rebind count: "); pw.println(mRebindCount);
pw.print(prefix); pw.print("Last rebind: "); pw.println(mLastRebindTime);
if (mRemoteService != null) {
pw.print(prefix); pw.println("remote service:");