Merge "Initial implementation of Intelligence Service Shell commands."
This commit is contained in:
committed by
Android (Google) Code Review
commit
b5857c748f
@@ -108,6 +108,7 @@ package android {
|
||||
field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
|
||||
field public static final java.lang.String MANAGE_IPSEC_TUNNELS = "android.permission.MANAGE_IPSEC_TUNNELS";
|
||||
field public static final java.lang.String MANAGE_ROLE_HOLDERS = "android.permission.MANAGE_ROLE_HOLDERS";
|
||||
field public static final java.lang.String MANAGE_SMART_SUGGESTIONS = "android.permission.MANAGE_SMART_SUGGESTIONS";
|
||||
field public static final java.lang.String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER";
|
||||
field public static final java.lang.String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS";
|
||||
field public static final java.lang.String MANAGE_USB = "android.permission.MANAGE_USB";
|
||||
|
||||
@@ -4170,6 +4170,11 @@
|
||||
<permission android:name="android.permission.MANAGE_AUTO_FILL"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- @SystemApi Allows an application to manage the smart suggestions service.
|
||||
@hide <p>Not for use by third-party applications.</p> -->
|
||||
<permission android:name="android.permission.MANAGE_SMART_SUGGESTIONS"
|
||||
android:protectionLevel="signature" />
|
||||
|
||||
<!-- Allows an app to set the theme overlay in /vendor/overlay
|
||||
being used.
|
||||
@hide <p>Not for use by third-party applications.</p> -->
|
||||
|
||||
@@ -130,6 +130,7 @@
|
||||
<uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
|
||||
<uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
|
||||
<uses-permission android:name="android.permission.MANAGE_AUTO_FILL" />
|
||||
<uses-permission android:name="android.permission.MANAGE_SMART_SUGGESTIONS" />
|
||||
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.SET_TIME" />
|
||||
|
||||
@@ -175,10 +175,6 @@ public final class AutofillManagerService
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(b/117779333): move to superclass / create super-class for ShellCommand
|
||||
@GuardedBy("mLock")
|
||||
private boolean mAllowInstantService;
|
||||
|
||||
/**
|
||||
* Supported modes for Augmented Autofill Smart Suggestions.
|
||||
*/
|
||||
@@ -271,6 +267,11 @@ public final class AutofillManagerService
|
||||
addCompatibilityModeRequestsLocked(service, userId);
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void enforceCallingPermissionForManagement() {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
}
|
||||
|
||||
@Override // from SystemService
|
||||
public void onStart() {
|
||||
publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
|
||||
@@ -290,7 +291,7 @@ public final class AutofillManagerService
|
||||
// Called by Shell command.
|
||||
void destroySessions(@UserIdInt int userId, IResultReceiver receiver) {
|
||||
Slog.i(TAG, "destroySessions() for userId " + userId);
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
synchronized (mLock) {
|
||||
if (userId != UserHandle.USER_ALL) {
|
||||
@@ -313,7 +314,7 @@ public final class AutofillManagerService
|
||||
// Called by Shell command.
|
||||
void listSessions(int userId, IResultReceiver receiver) {
|
||||
Slog.i(TAG, "listSessions() for userId " + userId);
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
final Bundle resultData = new Bundle();
|
||||
final ArrayList<String> sessions = new ArrayList<>();
|
||||
@@ -340,7 +341,7 @@ public final class AutofillManagerService
|
||||
// Called by Shell command.
|
||||
void reset() {
|
||||
Slog.i(TAG, "reset()");
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
synchronized (mLock) {
|
||||
visitServicesLocked((s) -> s.destroyLocked());
|
||||
@@ -351,7 +352,7 @@ public final class AutofillManagerService
|
||||
// Called by Shell command.
|
||||
void setLogLevel(int level) {
|
||||
Slog.i(TAG, "setLogLevel(): " + level);
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -388,7 +389,7 @@ public final class AutofillManagerService
|
||||
|
||||
// Called by Shell command.
|
||||
int getLogLevel() {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
synchronized (mLock) {
|
||||
if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
|
||||
@@ -399,7 +400,7 @@ public final class AutofillManagerService
|
||||
|
||||
// Called by Shell command.
|
||||
int getMaxPartitions() {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
synchronized (mLock) {
|
||||
return sPartitionMaxCount;
|
||||
@@ -408,8 +409,8 @@ public final class AutofillManagerService
|
||||
|
||||
// Called by Shell command.
|
||||
void setMaxPartitions(int max) {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
Slog.i(TAG, "setMaxPartitions(): " + max);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -433,7 +434,7 @@ public final class AutofillManagerService
|
||||
|
||||
// Called by Shell command.
|
||||
int getMaxVisibleDatasets() {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
synchronized (sLock) {
|
||||
return sVisibleDatasetsMaxCount;
|
||||
@@ -442,8 +443,8 @@ public final class AutofillManagerService
|
||||
|
||||
// Called by Shell command.
|
||||
void setMaxVisibleDatasets(int max) {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
Slog.i(TAG, "setMaxVisibleDatasets(): " + max);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
@@ -480,7 +481,7 @@ public final class AutofillManagerService
|
||||
// Called by Shell command.
|
||||
void getScore(@Nullable String algorithmName, @NonNull String value1,
|
||||
@NonNull String value2, @NonNull RemoteCallback callback) {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
final FieldClassificationStrategy strategy =
|
||||
new FieldClassificationStrategy(getContext(), UserHandle.USER_CURRENT);
|
||||
@@ -491,33 +492,16 @@ public final class AutofillManagerService
|
||||
|
||||
// Called by Shell command.
|
||||
Boolean getFullScreenMode() {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
return sFullScreenMode;
|
||||
}
|
||||
|
||||
// Called by Shell command.
|
||||
void setFullScreenMode(@Nullable Boolean mode) {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
enforceCallingPermissionForManagement();
|
||||
sFullScreenMode = mode;
|
||||
}
|
||||
|
||||
// Called by Shell command.
|
||||
boolean getAllowInstantService() {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
synchronized (mLock) {
|
||||
return mAllowInstantService;
|
||||
}
|
||||
}
|
||||
|
||||
// Called by Shell command.
|
||||
void setAllowInstantService(boolean mode) {
|
||||
getContext().enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
|
||||
Slog.i(TAG, "setAllowInstantService(): " + mode);
|
||||
synchronized (mLock) {
|
||||
mAllowInstantService = mode;
|
||||
}
|
||||
}
|
||||
|
||||
private void setLoggingLevelsLocked(boolean debug, boolean verbose) {
|
||||
com.android.server.autofill.Helper.sDebug = debug;
|
||||
android.view.autofill.Helper.sDebug = debug;
|
||||
@@ -1218,7 +1202,6 @@ public final class AutofillManagerService
|
||||
mAutofillCompatState.dump(prefix, pw);
|
||||
pw.print("from settings: ");
|
||||
pw.println(getWhitelistedCompatModePackagesFromSettings());
|
||||
pw.print("Allow instant service: "); pw.println(mAllowInstantService);
|
||||
if (mSupportedSmartSuggestionModes != 0) {
|
||||
pw.print("Smart Suggestion modes: ");
|
||||
pw.println(smartSuggestionFlagsToString(mSupportedSmartSuggestionModes));
|
||||
|
||||
@@ -92,6 +92,12 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
*/
|
||||
public boolean debug = false;
|
||||
|
||||
/**
|
||||
* Whether the service is allowed to bind to an instant-app.
|
||||
*/
|
||||
@GuardedBy("mLock")
|
||||
protected boolean mAllowInstantService;
|
||||
|
||||
/**
|
||||
* Users disabled due to {@link UserManager} restrictions, or {@code null} if the service cannot
|
||||
* be disabled through {@link UserManager}.
|
||||
@@ -175,6 +181,47 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether the service is allowed to bind to an instant-app.
|
||||
*
|
||||
* <p>Typically called by {@code ShellCommand} during CTS tests.
|
||||
*
|
||||
* @throws SecurityException if caller is not allowed to manage this service's settings.
|
||||
*/
|
||||
public final boolean getAllowInstantService() {
|
||||
enforceCallingPermissionForManagement();
|
||||
synchronized (mLock) {
|
||||
return mAllowInstantService;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the service is allowed to bind to an instant-app.
|
||||
*
|
||||
* <p>Typically called by {@code ShellCommand} during CTS tests.
|
||||
*
|
||||
* @throws SecurityException if caller is not allowed to manage this service's settings.
|
||||
*/
|
||||
public final void setAllowInstantService(boolean mode) {
|
||||
Slog.i(mTag, "setAllowInstantService(): " + mode);
|
||||
enforceCallingPermissionForManagement();
|
||||
synchronized (mLock) {
|
||||
mAllowInstantService = mode;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the caller has permissions to manage this service.
|
||||
*
|
||||
* <p>Typically called by {@code ShellCommand} implementations.
|
||||
*
|
||||
* @throws UnsupportedOperationException if subclass doesn't override it.
|
||||
* @throws SecurityException if caller is not allowed to manage this service's settings.
|
||||
*/
|
||||
protected void enforceCallingPermissionForManagement() {
|
||||
throw new UnsupportedOperationException("Not implemented by " + getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new service that will be added to the cache.
|
||||
*
|
||||
@@ -362,6 +409,7 @@ public abstract class AbstractMasterSystemService<M extends AbstractMasterSystem
|
||||
pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
|
||||
pw.print(" Verbose: "); pw.println(realVerbose);
|
||||
pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
|
||||
pw.print(prefix); pw.print("Allow instant service: "); pw.println(mAllowInstantService);
|
||||
pw.print(prefix); pw.print("Settings property: "); pw.println(
|
||||
getServiceSettingsProperty());
|
||||
pw.print(prefix); pw.print("Cached services: ");
|
||||
|
||||
@@ -146,7 +146,7 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks
|
||||
}
|
||||
|
||||
@Override // from RemoteScreenObservationServiceCallbacks
|
||||
public void onServiceDied(AbstractRemoteService service) {
|
||||
public void onServiceDied(AbstractRemoteService<?> service) {
|
||||
// TODO(b/111276913): implement (remove session from PerUserSession?)
|
||||
if (mService.isDebug()) {
|
||||
Slog.d(TAG, "onServiceDied() for " + mId);
|
||||
@@ -176,6 +176,10 @@ final class ContentCaptureSession implements RemoteIntelligenceServiceCallbacks
|
||||
pw.println(mAutofillCallback != null);
|
||||
}
|
||||
|
||||
String toShortString() {
|
||||
return mId.getValue() + ":" + mActivityToken;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ContentCaptureSession[id=" + mId.getValue() + ", act=" + mActivityToken + "]";
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.intelligence;
|
||||
|
||||
import static android.Manifest.permission.MANAGE_SMART_SUGGESTIONS;
|
||||
import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
@@ -26,8 +27,13 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.ShellCallback;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.intelligence.InteractionSessionId;
|
||||
import android.util.Slog;
|
||||
import android.view.autofill.AutofillId;
|
||||
import android.view.autofill.IAutoFillManagerClient;
|
||||
import android.view.intelligence.ContentCaptureEvent;
|
||||
@@ -42,6 +48,7 @@ import com.android.server.LocalServices;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -56,6 +63,8 @@ public final class IntelligenceManagerService extends
|
||||
|
||||
private static final String TAG = "IntelligenceManagerService";
|
||||
|
||||
static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private ActivityManagerInternal mAm;
|
||||
|
||||
@@ -90,6 +99,61 @@ public final class IntelligenceManagerService extends
|
||||
service.destroyLocked();
|
||||
}
|
||||
|
||||
@Override // from AbstractMasterSystemService
|
||||
protected void enforceCallingPermissionForManagement() {
|
||||
getContext().enforceCallingPermission(MANAGE_SMART_SUGGESTIONS, TAG);
|
||||
}
|
||||
|
||||
// Called by Shell command.
|
||||
void destroySessions(@UserIdInt int userId, @NonNull IResultReceiver receiver) {
|
||||
Slog.i(TAG, "destroySessions() for userId " + userId);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
synchronized (mLock) {
|
||||
if (userId != UserHandle.USER_ALL) {
|
||||
final IntelligencePerUserService service = peekServiceForUserLocked(userId);
|
||||
if (service != null) {
|
||||
service.destroySessionsLocked();
|
||||
}
|
||||
} else {
|
||||
visitServicesLocked((s) -> s.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);
|
||||
enforceCallingPermissionForManagement();
|
||||
|
||||
final Bundle resultData = new Bundle();
|
||||
final ArrayList<String> sessions = new ArrayList<>();
|
||||
|
||||
synchronized (mLock) {
|
||||
if (userId != UserHandle.USER_ALL) {
|
||||
final IntelligencePerUserService service = peekServiceForUserLocked(userId);
|
||||
if (service != null) {
|
||||
service.listSessionsLocked(sessions);
|
||||
}
|
||||
} else {
|
||||
visitServicesLocked((s) -> s.listSessionsLocked(sessions));
|
||||
}
|
||||
}
|
||||
|
||||
resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions);
|
||||
try {
|
||||
receiver.send(0, resultData);
|
||||
} catch (RemoteException e) {
|
||||
// Just ignore it...
|
||||
}
|
||||
}
|
||||
|
||||
private ActivityManagerInternal getAmInternal() {
|
||||
synchronized (mLock) {
|
||||
if (mAm == null) {
|
||||
@@ -119,7 +183,7 @@ public final class IntelligenceManagerService extends
|
||||
synchronized (mLock) {
|
||||
final IntelligencePerUserService service = getServiceForUserLocked(userId);
|
||||
service.startSessionLocked(activityToken, componentName, taskId, displayId,
|
||||
sessionId, flags, result);
|
||||
sessionId, flags, mAllowInstantService, result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,6 +218,14 @@ public final class IntelligenceManagerService extends
|
||||
dumpLocked("", pw);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
|
||||
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
|
||||
throws RemoteException {
|
||||
new IntelligenceServiceShellCommand(IntelligenceManagerService.this).exec(
|
||||
this, in, out, err, args, callback, resultReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
private final class LocalService extends IntelligenceManagerInternal {
|
||||
|
||||
@@ -49,6 +49,7 @@ import com.android.server.AbstractPerUserSystemService;
|
||||
import com.android.server.intelligence.IntelligenceManagerInternal.AugmentedAutofillCallback;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -108,7 +109,7 @@ final class IntelligencePerUserService
|
||||
@GuardedBy("mLock")
|
||||
public void startSessionLocked(@NonNull IBinder activityToken,
|
||||
@NonNull ComponentName componentName, int taskId, int displayId,
|
||||
@NonNull InteractionSessionId sessionId, int flags,
|
||||
@NonNull InteractionSessionId sessionId, int flags, boolean bindInstantServiceAllowed,
|
||||
@NonNull IResultReceiver resultReceiver) {
|
||||
if (!isEnabledLocked()) {
|
||||
sendToClient(resultReceiver, ContentCaptureManager.STATE_DISABLED);
|
||||
@@ -138,9 +139,6 @@ final class IntelligencePerUserService
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(b/117779333): get from mMaster once it's moved to superclass
|
||||
final boolean bindInstantServiceAllowed = false;
|
||||
|
||||
session = new ContentCaptureSession(getContext(), mUserId, mLock, activityToken,
|
||||
this, serviceComponentName, componentName, taskId, displayId, sessionId, flags,
|
||||
bindInstantServiceAllowed, mMaster.verbose);
|
||||
@@ -253,6 +251,11 @@ final class IntelligencePerUserService
|
||||
@GuardedBy("mLock")
|
||||
public void destroyLocked() {
|
||||
if (mMaster.debug) Slog.d(TAG, "destroyLocked()");
|
||||
destroySessionsLocked();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
void destroySessionsLocked() {
|
||||
final int numSessions = mSessions.size();
|
||||
for (int i = 0; i < numSessions; i++) {
|
||||
final ContentCaptureSession session = mSessions.valueAt(i);
|
||||
@@ -261,6 +264,15 @@ final class IntelligencePerUserService
|
||||
mSessions.clear();
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
void listSessionsLocked(ArrayList<String> output) {
|
||||
final int numSessions = mSessions.size();
|
||||
for (int i = 0; i < numSessions; i++) {
|
||||
final ContentCaptureSession session = mSessions.valueAt(i);
|
||||
output.add(session.toShortString());
|
||||
}
|
||||
}
|
||||
|
||||
public AugmentedAutofillCallback requestAutofill(@NonNull IAutoFillManagerClient client,
|
||||
@NonNull IBinder activityToken, int autofillSessionId, @NonNull AutofillId focusedId) {
|
||||
synchronized (mLock) {
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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 com.android.server.intelligence;
|
||||
|
||||
import static com.android.server.intelligence.IntelligenceManagerService.RECEIVER_BUNDLE_EXTRA_SESSIONS;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.os.Bundle;
|
||||
import android.os.ShellCommand;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.internal.os.IResultReceiver;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Shell Command implementation for {@link IntelligenceManagerService}.
|
||||
*/
|
||||
//TODO(b/111276913): rename once the final name is defined
|
||||
public final class IntelligenceServiceShellCommand extends ShellCommand {
|
||||
|
||||
private final IntelligenceManagerService mService;
|
||||
|
||||
public IntelligenceServiceShellCommand(@NonNull IntelligenceManagerService service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onCommand(String cmd) {
|
||||
if (cmd == null) {
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
final PrintWriter pw = getOutPrintWriter();
|
||||
switch (cmd) {
|
||||
case "list":
|
||||
return requestList(pw);
|
||||
case "destroy":
|
||||
return requestDestroy(pw);
|
||||
case "get":
|
||||
return requestGet(pw);
|
||||
case "set":
|
||||
return requestSet(pw);
|
||||
default:
|
||||
return handleDefaultCommands(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHelp() {
|
||||
try (PrintWriter pw = getOutPrintWriter();) {
|
||||
// TODO(b/111276913): rename "intelligence" once SELinux rule changed
|
||||
pw.println("Intelligence Service (intelligence) commands:");
|
||||
pw.println(" help");
|
||||
pw.println(" Prints this help text.");
|
||||
pw.println("");
|
||||
pw.println(" get bind-instant-service-allowed");
|
||||
pw.println(" Gets whether binding to services provided by instant apps is allowed");
|
||||
pw.println("");
|
||||
pw.println(" set bind-instant-service-allowed [true | false]");
|
||||
pw.println(" Sets whether binding to services provided by instant apps is allowed");
|
||||
pw.println("");
|
||||
pw.println(" list sessions [--user USER_ID]");
|
||||
pw.println(" Lists all pending sessions.");
|
||||
pw.println("");
|
||||
pw.println(" destroy sessions [--user USER_ID]");
|
||||
pw.println(" Destroys all pending sessions.");
|
||||
pw.println("");
|
||||
}
|
||||
}
|
||||
|
||||
private int requestGet(PrintWriter pw) {
|
||||
final String what = getNextArgRequired();
|
||||
switch(what) {
|
||||
case "bind-instant-service-allowed":
|
||||
return getBindInstantService(pw);
|
||||
default:
|
||||
pw.println("Invalid set: " + what);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private int requestSet(PrintWriter pw) {
|
||||
final String what = getNextArgRequired();
|
||||
|
||||
switch(what) {
|
||||
case "bind-instant-service-allowed":
|
||||
return setBindInstantService(pw);
|
||||
default:
|
||||
pw.println("Invalid set: " + what);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private int getBindInstantService(PrintWriter pw) {
|
||||
if (mService.getAllowInstantService()) {
|
||||
pw.println("true");
|
||||
} else {
|
||||
pw.println("false");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int setBindInstantService(PrintWriter pw) {
|
||||
final String mode = getNextArgRequired();
|
||||
switch (mode.toLowerCase()) {
|
||||
case "true":
|
||||
mService.setAllowInstantService(true);
|
||||
return 0;
|
||||
case "false":
|
||||
mService.setAllowInstantService(false);
|
||||
return 0;
|
||||
default:
|
||||
pw.println("Invalid mode: " + mode);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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));
|
||||
}
|
||||
|
||||
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();
|
||||
return waitForLatch(pw, latch);
|
||||
}
|
||||
|
||||
private int waitForLatch(PrintWriter pw, CountDownLatch latch) {
|
||||
try {
|
||||
final boolean received = latch.await(5, TimeUnit.SECONDS);
|
||||
if (!received) {
|
||||
pw.println("Timed out after 5 seconds");
|
||||
return -1;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
pw.println("System call interrupted");
|
||||
Thread.currentThread().interrupt();
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int getUserIdFromArgsOrAllUsers() {
|
||||
if ("--user".equals(getNextArg())) {
|
||||
return UserHandle.parseUserArg(getNextArgRequired());
|
||||
}
|
||||
return UserHandle.USER_ALL;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user