Merge "Allow auto-fill services to disable themselves"

This commit is contained in:
TreeHugger Robot
2017-03-03 04:45:35 +00:00
committed by Android (Google) Code Review
11 changed files with 175 additions and 25 deletions

View File

@@ -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 \

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();

View File

@@ -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();
}
}
}
}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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);