Merge "Allow auto-fill services to disable themselves"
This commit is contained in:
committed by
Android (Google) Code Review
commit
5a66e72a95
@@ -265,6 +265,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/security/IKeystoreService.aidl \
|
||||
core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl \
|
||||
core/java/android/service/autofill/IAutoFillService.aidl \
|
||||
core/java/android/service/autofill/IAutoFillServiceConnection.aidl \
|
||||
core/java/android/service/autofill/IFillCallback.aidl \
|
||||
core/java/android/service/autofill/ISaveCallback.aidl \
|
||||
core/java/android/service/carrier/ICarrierService.aidl \
|
||||
|
||||
@@ -36472,6 +36472,7 @@ package android.service.autofill {
|
||||
|
||||
public abstract class AutoFillService extends android.app.Service {
|
||||
ctor public AutoFillService();
|
||||
method public final void disableSelf();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public void onConnected();
|
||||
method public void onDisconnected();
|
||||
|
||||
@@ -39395,6 +39395,7 @@ package android.service.autofill {
|
||||
|
||||
public abstract class AutoFillService extends android.app.Service {
|
||||
ctor public AutoFillService();
|
||||
method public final void disableSelf();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public void onConnected();
|
||||
method public void onDisconnected();
|
||||
|
||||
@@ -36611,6 +36611,7 @@ package android.service.autofill {
|
||||
|
||||
public abstract class AutoFillService extends android.app.Service {
|
||||
ctor public AutoFillService();
|
||||
method public final void disableSelf();
|
||||
method public final android.os.IBinder onBind(android.content.Intent);
|
||||
method public void onConnected();
|
||||
method public void onDisconnected();
|
||||
|
||||
@@ -15,9 +15,12 @@
|
||||
*/
|
||||
package android.service.autofill;
|
||||
|
||||
import android.accessibilityservice.IAccessibilityServiceConnection;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.view.accessibility.AccessibilityInteractionClient;
|
||||
import com.android.internal.os.HandlerCaller;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.app.Activity;
|
||||
@@ -78,6 +81,15 @@ public abstract class AutoFillService extends Service {
|
||||
private static final int MSG_ON_SAVE_REQUEST = 4;
|
||||
|
||||
private final IAutoFillService mInterface = new IAutoFillService.Stub() {
|
||||
@Override
|
||||
public void onInit(IAutoFillServiceConnection connection) {
|
||||
if (connection != null) {
|
||||
mHandlerCaller.obtainMessageO(MSG_CONNECT, connection).sendToTarget();
|
||||
} else {
|
||||
mHandlerCaller.obtainMessage(MSG_DISCONNECT).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFillRequest(AssistStructure structure, Bundle extras,
|
||||
IFillCallback callback) {
|
||||
@@ -98,21 +110,12 @@ public abstract class AutoFillService extends Service {
|
||||
mHandlerCaller.obtainMessageOOO(MSG_ON_SAVE_REQUEST, structure,
|
||||
extras, callback).sendToTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected() {
|
||||
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_CONNECT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
mHandlerCaller.sendMessage(mHandlerCaller.obtainMessage(MSG_DISCONNECT));
|
||||
}
|
||||
};
|
||||
|
||||
private final HandlerCaller.Callback mHandlerCallback = (msg) -> {
|
||||
switch (msg.what) {
|
||||
case MSG_CONNECT: {
|
||||
mConnection = (IAutoFillServiceConnection) msg.obj;
|
||||
onConnected();
|
||||
break;
|
||||
} case MSG_ON_FILL_REQUEST: {
|
||||
@@ -136,6 +139,7 @@ public abstract class AutoFillService extends Service {
|
||||
break;
|
||||
} case MSG_DISCONNECT: {
|
||||
onDisconnected();
|
||||
mConnection = null;
|
||||
break;
|
||||
} default: {
|
||||
Log.w(TAG, "MyCallbacks received invalid message type: " + msg);
|
||||
@@ -145,6 +149,8 @@ public abstract class AutoFillService extends Service {
|
||||
|
||||
private HandlerCaller mHandlerCaller;
|
||||
|
||||
private IAutoFillServiceConnection mConnection;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
@@ -223,4 +229,22 @@ public abstract class AutoFillService extends Service {
|
||||
public void onDisconnected() {
|
||||
//TODO(b/33197203): is not called anymore, fix it!
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables the service. After calling this method, the service will
|
||||
* be disabled and settings will show that it is turned off.
|
||||
*
|
||||
* <p>You should call this method only after a call to {@link #onConnected()}
|
||||
* and before the corresponding call to {@link #onDisconnected()}. In other words
|
||||
* you can disable your service only while the system is connected to it.</p>
|
||||
*/
|
||||
public final void disableSelf() {
|
||||
if (mConnection != null) {
|
||||
try {
|
||||
mConnection.disableSelf();
|
||||
} catch (RemoteException re) {
|
||||
throw re.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package android.service.autofill;
|
||||
|
||||
import android.app.assist.AssistStructure;
|
||||
import android.os.Bundle;
|
||||
import android.service.autofill.IAutoFillServiceConnection;
|
||||
import android.service.autofill.IFillCallback;
|
||||
import android.service.autofill.ISaveCallback;
|
||||
import com.android.internal.os.IResultReceiver;
|
||||
@@ -28,10 +29,9 @@ import com.android.internal.os.IResultReceiver;
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IAutoFillService {
|
||||
void onInit(in IAutoFillServiceConnection connection);
|
||||
void onFillRequest(in AssistStructure structure, in Bundle extras,
|
||||
in IFillCallback callback);
|
||||
void onSaveRequest(in AssistStructure structure, in Bundle extras,
|
||||
in ISaveCallback callback);
|
||||
void onConnected();
|
||||
void onDisconnected();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.service.autofill;
|
||||
|
||||
/**
|
||||
* Interface from an auto fill service to the system.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
interface IAutoFillServiceConnection {
|
||||
void disableSelf();
|
||||
}
|
||||
@@ -185,6 +185,29 @@ public final class AutoFillManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
// Called by Shell command.
|
||||
void destroySessions(int userId, IResultReceiver receiver) {
|
||||
Slog.i(TAG, "destroySessions() for userId " + userId);
|
||||
mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
|
||||
synchronized (mLock) {
|
||||
if (userId != UserHandle.USER_ALL) {
|
||||
mServicesCache.get(userId).destroySessionsLocked();
|
||||
} else {
|
||||
final int size = mServicesCache.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
mServicesCache.valueAt(i).destroySessionsLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
receiver.send(0, new Bundle());
|
||||
} catch (RemoteException e) {
|
||||
// Just ignore it...
|
||||
}
|
||||
}
|
||||
|
||||
// Called by Shell command.
|
||||
void listSessions(int userId, IResultReceiver receiver) {
|
||||
Slog.i(TAG, "listSessions() for userId " + userId);
|
||||
|
||||
@@ -405,6 +405,12 @@ final class AutoFillManagerServiceImpl {
|
||||
}
|
||||
}
|
||||
|
||||
void destroySessionsLocked() {
|
||||
for (Session session : mSessions.values()) {
|
||||
session.removeSelf();
|
||||
}
|
||||
}
|
||||
|
||||
void listSessionsLocked(ArrayList<String> output) {
|
||||
for (IBinder activityToken : mSessions.keySet()) {
|
||||
output.add((mInfo != null ? mInfo.getServiceInfo().getComponentName()
|
||||
@@ -664,6 +670,28 @@ final class AutoFillManagerServiceImpl {
|
||||
});
|
||||
}
|
||||
|
||||
// FillServiceCallbacks
|
||||
@Override
|
||||
public void onDisableSelf() {
|
||||
final long identity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
final String autoFillService = Settings.Secure.getStringForUser(
|
||||
mContext.getContentResolver(),
|
||||
Settings.Secure.AUTO_FILL_SERVICE, mUserId);
|
||||
if (mInfo.getServiceInfo().getComponentName().equals(
|
||||
ComponentName.unflattenFromString(autoFillService))) {
|
||||
Settings.Secure.putStringForUser(mContext.getContentResolver(),
|
||||
Settings.Secure.AUTO_FILL_SERVICE, null, mUserId);
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
}
|
||||
synchronized (mLock) {
|
||||
destroyLocked();
|
||||
mSessions.remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
// FillServiceCallbacks
|
||||
@Override
|
||||
public void onServiceDied(RemoteFillService service) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import static com.android.server.autofill.AutoFillManagerService.RECEIVER_BUNDLE
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.UserHandle;
|
||||
|
||||
@@ -50,6 +49,8 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand {
|
||||
return requestSave();
|
||||
case "list":
|
||||
return requestList(pw);
|
||||
case "destroy":
|
||||
return requestDestroy(pw);
|
||||
case "reset":
|
||||
return requestReset();
|
||||
default:
|
||||
@@ -67,6 +68,9 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand {
|
||||
pw.println(" list sessions [--user USER_ID]");
|
||||
pw.println(" List all pending sessions.");
|
||||
pw.println("");
|
||||
pw.println(" destroy sessions [--user USER_ID]");
|
||||
pw.println(" Destroy all pending sessions.");
|
||||
pw.println("");
|
||||
pw.println(" save [--user USER_ID]");
|
||||
pw.println(" Request provider to save contents of the top activity. ");
|
||||
pw.println("");
|
||||
@@ -82,30 +86,55 @@ public final class AutoFillManagerServiceShellCommand extends ShellCommand {
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int requestList(PrintWriter pw) {
|
||||
final String type = getNextArgRequired();
|
||||
if (!type.equals("sessions")) {
|
||||
pw.println("Error: invalid list type");
|
||||
private int requestDestroy(PrintWriter pw) {
|
||||
if (!isNextArgSessions(pw)) {
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
final int userId = getUserIdFromArgsOrAllUsers();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final IResultReceiver receiver = new IResultReceiver.Stub() {
|
||||
|
||||
@Override
|
||||
public void send(int resultCode, Bundle resultData) throws RemoteException {
|
||||
public void send(int resultCode, Bundle resultData) {
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
return requestSessionCommon(pw, latch, () -> mService.destroySessions(userId, receiver));
|
||||
}
|
||||
|
||||
private int requestList(PrintWriter pw) {
|
||||
if (!isNextArgSessions(pw)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
final int userId = getUserIdFromArgsOrAllUsers();
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
final IResultReceiver receiver = new IResultReceiver.Stub() {
|
||||
@Override
|
||||
public void send(int resultCode, Bundle resultData) {
|
||||
final ArrayList<String> sessions = resultData
|
||||
.getStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS);
|
||||
|
||||
for (String session : sessions) {
|
||||
pw.println(session);
|
||||
}
|
||||
latch.countDown();
|
||||
}
|
||||
};
|
||||
return requestSessionCommon(pw, latch, () -> mService.listSessions(userId, receiver));
|
||||
}
|
||||
|
||||
mService.listSessions(userId, receiver);
|
||||
private boolean isNextArgSessions(PrintWriter pw) {
|
||||
final String type = getNextArgRequired();
|
||||
if (!type.equals("sessions")) {
|
||||
pw.println("Error: invalid list type");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int requestSessionCommon(PrintWriter pw, CountDownLatch latch,
|
||||
Runnable command) {
|
||||
command.run();
|
||||
|
||||
try {
|
||||
final boolean received = latch.await(5, TimeUnit.SECONDS);
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.os.UserHandle;
|
||||
import android.service.autofill.AutoFillService;
|
||||
import android.service.autofill.FillResponse;
|
||||
import android.service.autofill.IAutoFillService;
|
||||
import android.service.autofill.IAutoFillServiceConnection;
|
||||
import android.service.autofill.IFillCallback;
|
||||
import android.service.autofill.ISaveCallback;
|
||||
import android.text.format.DateUtils;
|
||||
@@ -57,7 +58,7 @@ final class RemoteFillService implements DeathRecipient {
|
||||
private static final boolean DEBUG = Helper.DEBUG;
|
||||
|
||||
// How long after the last interaction with the service we would unbind
|
||||
private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.MINUTE_IN_MILLIS;
|
||||
private static final long TIMEOUT_IDLE_BIND_MILLIS = 5 * DateUtils.SECOND_IN_MILLIS;
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
@@ -91,6 +92,7 @@ final class RemoteFillService implements DeathRecipient {
|
||||
void onSaveRequestSuccess();
|
||||
void onSaveRequestFailure(CharSequence message);
|
||||
void onServiceDied(RemoteFillService service);
|
||||
void onDisableSelf();
|
||||
}
|
||||
|
||||
public RemoteFillService(Context context, ComponentName componentName,
|
||||
@@ -197,6 +199,10 @@ final class RemoteFillService implements DeathRecipient {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDisableSelf() {
|
||||
mCallbacks.onDisableSelf();
|
||||
}
|
||||
|
||||
private boolean isBound() {
|
||||
return mAutoFillService != null;
|
||||
}
|
||||
@@ -239,7 +245,7 @@ final class RemoteFillService implements DeathRecipient {
|
||||
// Need to double check if it's null, since it could be set on onServiceDisconnected()
|
||||
if (mAutoFillService != null) {
|
||||
try {
|
||||
mAutoFillService.onDisconnected();
|
||||
mAutoFillService.onInit(null);
|
||||
} catch (Exception e) {
|
||||
Slog.w(LOG_TAG, "Exception calling onDisconnected(): " + e);
|
||||
}
|
||||
@@ -321,7 +327,12 @@ final class RemoteFillService implements DeathRecipient {
|
||||
// Need to double check if it's null, since it could be set on
|
||||
// onServiceDisconnected()
|
||||
if (mAutoFillService != null) {
|
||||
mAutoFillService.onConnected();
|
||||
mAutoFillService.onInit(new IAutoFillServiceConnection.Stub() {
|
||||
@Override
|
||||
public void disableSelf() {
|
||||
mHandler.obtainMessage(MyHandler.MSG_ON_DISABLE_SELF).sendToTarget();
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(LOG_TAG, "Exception calling onConnected(): " + e);
|
||||
@@ -347,6 +358,7 @@ final class RemoteFillService implements DeathRecipient {
|
||||
public static final int MSG_BINDER_DIED = 2;
|
||||
public static final int MSG_UNBIND = 3;
|
||||
public static final int MSG_ON_PENDING_REQUEST = 4;
|
||||
public static final int MSG_ON_DISABLE_SELF = 5;
|
||||
|
||||
public MyHandler(Context context) {
|
||||
// Cannot use lambda - doesn't compile
|
||||
@@ -374,6 +386,10 @@ final class RemoteFillService implements DeathRecipient {
|
||||
case MSG_ON_PENDING_REQUEST: {
|
||||
handlePendingRequest((PendingRequest) message.obj);
|
||||
} break;
|
||||
|
||||
case MSG_ON_DISABLE_SELF: {
|
||||
handleDisableSelf();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
|
||||
Reference in New Issue
Block a user