Remove AutofillManagerClient after AutofillManager is finalized
Symptom: Global reference table overflow happens on system_server. Root cause: If a process repeatedly create a context and get AutofillManager from the context, each BinderProxy of AutofillManagerClient are registered to AutofillManagerServiceImpl. They aren't removed until the process is died. BinderProxy consumes global reference and finally causes crash on system_server. Solution: Remove AutofillManagerClient from AutofillManagerServiceImpl after AutofillManager is finalized. Test: cts-tradefed run commandAndExit cts-dev -m CtsAutoFillServiceTestCases Bug: 68747744 Change-Id: I8b76c5368b54317b8696cac470cc390b36e910e7
This commit is contained in:
@@ -19,6 +19,7 @@ package android.os;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -399,6 +400,13 @@ public class RemoteCallbackList<E extends IInterface> {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
pw.print(prefix); pw.print("callbacks: "); pw.println(mCallbacks.size());
|
||||
pw.print(prefix); pw.print("killed: "); pw.println(mKilled);
|
||||
pw.print(prefix); pw.print("broadcasts count: "); pw.println(mBroadcastCount);
|
||||
}
|
||||
|
||||
private void logExcessiveCallbacks() {
|
||||
final long size = mCallbacks.size();
|
||||
final long TOO_MANY = 3000;
|
||||
|
||||
@@ -51,6 +51,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
// TODO: use java.lang.ref.Cleaner once Android supports Java 9
|
||||
import sun.misc.Cleaner;
|
||||
|
||||
/**
|
||||
* The {@link AutofillManager} provides ways for apps and custom views to integrate with the
|
||||
* Autofill Framework lifecycle.
|
||||
@@ -224,6 +227,9 @@ public final class AutofillManager {
|
||||
@GuardedBy("mLock")
|
||||
private IAutoFillManagerClient mServiceClient;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private Cleaner mServiceClientCleaner;
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private AutofillCallback mCallback;
|
||||
|
||||
@@ -958,10 +964,19 @@ public final class AutofillManager {
|
||||
if (mServiceClient == null) {
|
||||
mServiceClient = new AutofillManagerClient(this);
|
||||
try {
|
||||
final int flags = mService.addClient(mServiceClient, mContext.getUserId());
|
||||
final int userId = mContext.getUserId();
|
||||
final int flags = mService.addClient(mServiceClient, userId);
|
||||
mEnabled = (flags & FLAG_ADD_CLIENT_ENABLED) != 0;
|
||||
sDebug = (flags & FLAG_ADD_CLIENT_DEBUG) != 0;
|
||||
sVerbose = (flags & FLAG_ADD_CLIENT_VERBOSE) != 0;
|
||||
final IAutoFillManager service = mService;
|
||||
final IAutoFillManagerClient serviceClient = mServiceClient;
|
||||
mServiceClientCleaner = Cleaner.create(this, () -> {
|
||||
try {
|
||||
service.removeClient(serviceClient, userId);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
@@ -1068,6 +1083,10 @@ public final class AutofillManager {
|
||||
if (resetClient) {
|
||||
// Reset connection to system
|
||||
mServiceClient = null;
|
||||
if (mServiceClientCleaner != null) {
|
||||
mServiceClientCleaner.clean();
|
||||
mServiceClientCleaner = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.view.autofill.IAutoFillManagerClient;
|
||||
interface IAutoFillManager {
|
||||
// Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
|
||||
int addClient(in IAutoFillManagerClient client, int userId);
|
||||
void removeClient(in IAutoFillManagerClient client, int userId);
|
||||
int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
|
||||
in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
|
||||
String packageName);
|
||||
|
||||
@@ -498,6 +498,16 @@ public final class AutofillManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeClient(IAutoFillManagerClient client, int userId) {
|
||||
synchronized (mLock) {
|
||||
final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
|
||||
if (service != null) {
|
||||
service.removeClientLocked(client);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId,
|
||||
int userId) {
|
||||
|
||||
@@ -261,6 +261,12 @@ final class AutofillManagerServiceImpl {
|
||||
return isEnabled();
|
||||
}
|
||||
|
||||
void removeClientLocked(IAutoFillManagerClient client) {
|
||||
if (mClients != null) {
|
||||
mClients.unregister(client);
|
||||
}
|
||||
}
|
||||
|
||||
void setAuthenticationResultLocked(Bundle data, int sessionId, int authenticationId, int uid) {
|
||||
if (!isEnabled()) {
|
||||
return;
|
||||
@@ -478,6 +484,10 @@ final class AutofillManagerServiceImpl {
|
||||
}
|
||||
|
||||
sendStateToClients(true);
|
||||
if (mClients != null) {
|
||||
mClients.kill();
|
||||
mClients = null;
|
||||
}
|
||||
}
|
||||
|
||||
CharSequence getServiceLabel() {
|
||||
@@ -605,6 +615,9 @@ final class AutofillManagerServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
pw.print(prefix); pw.println("Clients");
|
||||
mClients.dump(pw, prefix2);
|
||||
|
||||
if (mEventHistory == null || mEventHistory.getEvents() == null
|
||||
|| mEventHistory.getEvents().size() == 0) {
|
||||
pw.print(prefix); pw.println("No event on last fill response");
|
||||
|
||||
Reference in New Issue
Block a user