diff --git a/api/current.txt b/api/current.txt index 9c19fd7a44b18..fede9cf91d55d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34643,9 +34643,9 @@ package android.service.autofill { public abstract class AutoFillService extends android.app.Service { ctor public AutoFillService(); method public final android.os.IBinder onBind(android.content.Intent); + method public void onConnected(); + method public void onDisconnected(); method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback); - method public void onReady(); - method public void onShutdown(); field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService"; } diff --git a/api/system-current.txt b/api/system-current.txt index e2924b3508f49..b5b744119d1ba 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -37436,9 +37436,9 @@ package android.service.autofill { public abstract class AutoFillService extends android.app.Service { ctor public AutoFillService(); method public final android.os.IBinder onBind(android.content.Intent); + method public void onConnected(); + method public void onDisconnected(); method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback); - method public void onReady(); - method public void onShutdown(); field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService"; } diff --git a/api/test-current.txt b/api/test-current.txt index 7eeb6c1ad3fc6..918400e6a6864 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -34733,9 +34733,9 @@ package android.service.autofill { public abstract class AutoFillService extends android.app.Service { ctor public AutoFillService(); method public final android.os.IBinder onBind(android.content.Intent); + method public void onConnected(); + method public void onDisconnected(); method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.CancellationSignal, android.service.autofill.FillCallback); - method public void onReady(); - method public void onShutdown(); field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService"; } diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java index 83b2065f44fe8..3734831b0db29 100644 --- a/core/java/android/service/autofill/AutoFillService.java +++ b/core/java/android/service/autofill/AutoFillService.java @@ -15,7 +15,6 @@ */ package android.service.autofill; -import android.annotation.IntDef; import android.annotation.SdkConstant; import android.app.Activity; import android.app.Service; @@ -34,9 +33,6 @@ import com.android.internal.os.HandlerCaller; import com.android.internal.os.IResultReceiver; import com.android.internal.os.SomeArgs; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - /** * Top-level service of the current auto-fill service for a given user. * @@ -56,9 +52,9 @@ public abstract class AutoFillService extends Service { @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService"; - private static final int MSG_READY = 1; - private static final int MSG_AUTO_FILL = 2; - private static final int MSG_SHUTDOWN = 3; + private static final int MSG_CONNECT = 1; + private static final int MSG_AUTO_FILL_ACTIVITY = 2; + private static final int MSG_DISCONNECT = 3; private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() { @Override @@ -70,15 +66,15 @@ public abstract class AutoFillService extends Service { .getBinder(VoiceInteractionSession.KEY_AUTO_FILL_CALLBACK); mHandlerCaller - .obtainMessageOO(MSG_AUTO_FILL, structure, binder).sendToTarget(); + .obtainMessageOO(MSG_AUTO_FILL_ACTIVITY, structure, binder).sendToTarget(); } }; private final IAutoFillService mInterface = new IAutoFillService.Stub() { @Override - public void ready() { - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_READY)); + public void onConnected() { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CONNECT)); } @Override @@ -87,8 +83,8 @@ public abstract class AutoFillService extends Service { } @Override - public void shutdown() { - mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_SHUTDOWN)); + public void onDisconnected() { + mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DISCONNECT)); } }; @@ -97,17 +93,17 @@ public abstract class AutoFillService extends Service { @Override public void executeMessage(Message msg) { switch (msg.what) { - case MSG_READY: { - onReady(); + case MSG_CONNECT: { + onConnected(); break; - } case MSG_AUTO_FILL: { + } case MSG_AUTO_FILL_ACTIVITY: { final SomeArgs args = (SomeArgs) msg.obj; final AssistStructure structure = (AssistStructure) args.arg1; final IBinder binder = (IBinder) args.arg2; - autoFillActivity(structure, binder); + requestAutoFill(structure, binder); break; - } case MSG_SHUTDOWN: { - onShutdown(); + } case MSG_DISCONNECT: { + onDisconnected(); break; } default: { Log.w(TAG, "MyCallbacks received invalid message type: " + msg); @@ -135,14 +131,12 @@ public abstract class AutoFillService extends Service { } /** - * Called during service initialization to tell you when the system is ready - * to receive interaction from it. + * Called when the Android System connects to service. * *
You should generally do initialization here rather than in {@link #onCreate}. */ - // TODO: rename to onConnect() / update javadoc - public void onReady() { - if (DEBUG) Log.d(TAG, "onReady()"); + public void onConnected() { + if (DEBUG) Log.d(TAG, "onConnected()"); } /** @@ -155,21 +149,18 @@ public abstract class AutoFillService extends Service { public abstract void onFillRequest(AssistStructure structure, CancellationSignal cancellationSignal, FillCallback callback); - private void autoFillActivity(AssistStructure structure, IBinder binder) { + private void requestAutoFill(AssistStructure structure, IBinder binder) { final FillCallback callback = new FillCallback(binder); // TODO: hook up the cancelationSignal onFillRequest(structure, new CancellationSignal(), callback); } /** - * Called during service de-initialization to tell you when the system is shutting the - * service down. + * Called when the Android System disconnects from the service. * *
At this point this service may no longer be an active {@link AutoFillService}. */ - // TODO: rename to onDisconnected() / update javadoc - public void onShutdown() { - if (DEBUG) Log.d(TAG, "onShutdown()"); + public void onDisconnected() { + if (DEBUG) Log.d(TAG, "onDisconnected()"); } - } diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java index bdcc93b0397c1..23084409569f6 100644 --- a/core/java/android/service/autofill/FillCallback.java +++ b/core/java/android/service/autofill/FillCallback.java @@ -62,9 +62,6 @@ public final class FillCallback { } } - /** - * Notifies the activity that the auto-fill request failed. - */ public void onFailure(CharSequence message) { if (DEBUG) Log.d(TAG, "onFailure(): message=" + message); diff --git a/core/java/android/service/autofill/IAutoFillManagerService.aidl b/core/java/android/service/autofill/IAutoFillManagerService.aidl index a91841b984534..cab073f7045f6 100644 --- a/core/java/android/service/autofill/IAutoFillManagerService.aidl +++ b/core/java/android/service/autofill/IAutoFillManagerService.aidl @@ -30,9 +30,6 @@ interface IAutoFillManagerService { * * @param userId user handle. * @param activityToken optional token of activity that needs to be on top. - * - * @return whether the request succeeded (for example, if the activity's - * user does not have an auto-fill service associated with, it will return false). */ - boolean requestAutoFill(int userId, IBinder activityToken); + void requestAutoFill(int userId, IBinder activityToken); } diff --git a/core/java/android/service/autofill/IAutoFillService.aidl b/core/java/android/service/autofill/IAutoFillService.aidl index dca3c700c0a99..e3e911c392158 100644 --- a/core/java/android/service/autofill/IAutoFillService.aidl +++ b/core/java/android/service/autofill/IAutoFillService.aidl @@ -25,8 +25,7 @@ import com.android.internal.os.IResultReceiver; * @hide */ interface IAutoFillService { - // TODO: rename to onConnected() / onDisconnected() - void ready(); - void shutdown(); + void onConnected(); + void onDisconnected(); IResultReceiver getAssistReceiver(); } diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java index 8b3775657da0a..9157e83a3dd18 100644 --- a/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerService.java @@ -33,16 +33,21 @@ import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; +import android.os.Message; import android.os.Parcel; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ShellCallback; +import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.service.autofill.IAutoFillManagerService; import android.text.TextUtils; +import android.text.format.DateUtils; +import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; @@ -62,7 +67,13 @@ import java.io.PrintWriter; public final class AutoFillManagerService extends SystemService { private static final String TAG = "AutoFillManagerService"; - private static final boolean DEBUG = true; // TODO: change to false once stable + static final boolean DEBUG = true; // TODO: change to false once stable + + private static final long SERVICE_BINDING_LIFETIME_MS = 5 * DateUtils.MINUTE_IN_MILLIS; + + private static final int ARG_NOT_USED = 0; + + protected static final int MSG_UNBIND = 1; private final AutoFillManagerServiceStub mServiceStub; private final Context mContext; @@ -70,30 +81,36 @@ public final class AutoFillManagerService extends SystemService { private final Object mLock = new Object(); - @GuardedBy("mLock") - private boolean mSafeMode; + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UNBIND: + removeStaleServiceForUser(msg.arg1); + return; + default: + Slog.w(TAG, "Invalid message: " + msg); + } + } + + }; /** - * Map of {@link AutoFillManagerServiceImpl} per user id. + * Cache of {@link AutoFillManagerServiceImpl} per user id. *
* It has to be mapped by user id because the same current user could have simultaneous sessions - * associated to different user profiles (for example, in a multi-window environment). + * associated to different user profiles (for example, in a multi-window environment or when + * device has work profiles). *
- * This map is filled on demand in the following scenarios: + * Entries on this cache are added on demand and removed when: *
First it tries to return the existing instance from the cache; if it's not cached, it
+ * creates a new instance and caches it.
+ */
+ private AutoFillManagerServiceImpl getServiceForUserLocked(int userId) {
+ AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ if (service != null) {
+ if (DEBUG) Log.d(TAG, "reusing cached service for userId " + userId);
+ service.setLifeExpectancy(SERVICE_BINDING_LIFETIME_MS);
+ } else {
+ service = newServiceForUser(userId);
+ if (service == null) {
+ // Already logged
+ return null;
}
+ if (DEBUG) Log.d(TAG, "creating new cached service for userId " + userId);
+ service.startLocked();
+ mServicesCache.put(userId, service);
+ }
+ // Keep service connection alive for a while, in case user needs to interact with it
+ // (for example, to save the data that was inputted in)
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_UNBIND, userId, ARG_NOT_USED),
+ SERVICE_BINDING_LIFETIME_MS);
+ return service;
+ }
+
+ /**
+ * Removes a cached service, but respecting its TTL.
+ */
+ private void removeStaleServiceForUser(int userId) {
+ synchronized (mLock) {
+ removeCachedService(userId, false);
}
}
- // TODO: might need to return null instead of throw exception
- private AutoFillManagerServiceImpl getImplOrThrowLocked(int userId) {
- final AutoFillManagerServiceImpl impl = mImplByUser.get(userId);
- if (impl == null) {
- throw new IllegalStateException("no auto-fill service for user " + userId);
+ /**
+ * Removes a cached service, even if it has TTL.
+ */
+ void removeCachedServiceForUserLocked(int userId) {
+ removeCachedService(userId, true);
+ }
+
+ private void removeCachedService(int userId, boolean force) {
+ if (DEBUG) Log.d(TAG, "removing cached service for userId " + userId);
+ final AutoFillManagerServiceImpl service = mServicesCache.get(userId);
+ if (service == null) {
+ Log.w(TAG, "removeCachedServiceForUser(): no cached service for userId " + userId);
+ return;
}
- return impl;
+ if (!force) {
+ // Check TTL first.
+ final long now = SystemClock.uptimeMillis();
+ if (service.mEstimateTimeOfDeath > now) {
+ if (DEBUG) {
+ final StringBuilder msg = new StringBuilder("service has some TTL left: ");
+ TimeUtils.formatDuration(service.mEstimateTimeOfDeath - now, msg);
+ Log.d(TAG, msg.toString());
+ }
+ return;
+ }
+ }
+ mServicesCache.delete(userId);
+ service.stopLocked();
}
final class AutoFillManagerServiceStub extends IAutoFillManagerService.Stub {
@Override
- public boolean requestAutoFill(int userId, IBinder activityToken) {
+ public void requestAutoFill(int userId, IBinder activityToken) {
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
synchronized (mLock) {
- return getImplOrThrowLocked(userId).requestAutoFill(activityToken);
+ final AutoFillManagerServiceImpl service = getServiceForUserLocked(userId);
+ if (service != null) {
+ service.requestAutoFill(activityToken);
+ }
}
}
@@ -236,17 +250,15 @@ public final class AutoFillManagerService extends SystemService {
return;
}
synchronized (mLock) {
- pw.print("mEnableService: "); pw.println(mEnableService);
- pw.print("mSafeMode: "); pw.println(mSafeMode);
- final int size = mImplByUser.size();
- pw.print("Number of implementations: ");
+ final int size = mServicesCache.size();
+ pw.print("Cached services: ");
if (size == 0) {
pw.println("none");
} else {
pw.println(size);
for (int i = 0; i < size; i++) {
- pw.print("\nImplementation at index "); pw.println(i);
- final AutoFillManagerServiceImpl impl = mImplByUser.valueAt(i);
+ pw.print("\nService at index "); pw.println(i);
+ final AutoFillManagerServiceImpl impl = mServicesCache.valueAt(i);
impl.dumpLocked(" ", pw);
}
}
@@ -267,14 +279,14 @@ public final class AutoFillManagerService extends SystemService {
super(handler);
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(Settings.Secure.getUriFor(
- Settings.Secure.AUTO_FILL_SERVICE), false, this,
- UserHandle.USER_ALL);
+ Settings.Secure.AUTO_FILL_SERVICE), false, this, UserHandle.USER_ALL);
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
+ if (DEBUG) Slog.d(TAG, "settings (" + uri + " changed for " + userId);
synchronized (mLock) {
- updateImplementationIfNeededLocked(userId, false);
+ removeCachedServiceForUserLocked(userId);
}
}
}
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index ae687da43cd0f..e409cb072ef51 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -16,6 +16,8 @@
package com.android.server.autofill;
+import static com.android.server.autofill.AutoFillManagerService.DEBUG;
+
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.IActivityManager;
@@ -27,10 +29,11 @@ import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.icu.text.DateFormat;
-import android.os.Bundle;
+import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.service.autofill.AutoFillService;
import android.service.autofill.AutoFillServiceInfo;
@@ -38,14 +41,15 @@ import android.service.autofill.IAutoFillService;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
+import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.server.LocalServices;
-import com.android.server.autofill.AutoFillManagerService.AutoFillManagerServiceStub;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
+import java.util.LinkedList;
import java.util.List;
/**
@@ -56,21 +60,23 @@ import java.util.List;
final class AutoFillManagerServiceImpl {
private static final String TAG = "AutoFillManagerServiceImpl";
- private static final boolean DEBUG = true; // TODO: change to false once stable
-
- final int mUser;
- final ComponentName mComponent;
+ private final int mUserId;
+ private final int mUid;
+ private final ComponentName mComponent;
private final Context mContext;
private final IActivityManager mAm;
private final Object mLock;
- private final AutoFillManagerServiceStub mServiceStub;
private final AutoFillServiceInfo mInfo;
+ private final AutoFillManagerService mManagerService;
// TODO: improve its usage
// - set maximum number of entries
// - disable on low-memory devices.
- private final List