diff options
27 files changed, 617 insertions, 274 deletions
diff --git a/Android.mk b/Android.mk index 121a38efd587..e352bc70d085 100644 --- a/Android.mk +++ b/Android.mk @@ -332,6 +332,7 @@ LOCAL_SRC_FILES += \ core/java/com/android/internal/os/IDropBoxManagerService.aidl \ core/java/com/android/internal/os/IParcelFileDescriptorFactory.aidl \ core/java/com/android/internal/os/IResultReceiver.aidl \ + core/java/com/android/internal/os/IShellCallback.aidl \ core/java/com/android/internal/statusbar/IStatusBar.aidl \ core/java/com/android/internal/statusbar/IStatusBarService.aidl \ core/java/com/android/internal/textservice/ISpellCheckerService.aidl \ diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 91334bd87296..3759de2e7197 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -26,7 +26,6 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import android.app.ActivityManager; import android.app.ActivityManager.StackInfo; import android.app.ActivityManagerNative; -import android.app.ActivityOptions; import android.app.IActivityContainer; import android.app.IActivityController; import android.app.IActivityManager; @@ -46,7 +45,6 @@ import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.ParceledListSlice; -import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.content.res.Configuration; import android.graphics.Rect; @@ -55,10 +53,11 @@ import android.os.Build; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.ResultReceiver; import android.os.SELinux; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.ShellCommand; -import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.text.TextUtils; @@ -72,6 +71,7 @@ import com.android.internal.util.Preconditions; import java.io.BufferedReader; import java.io.File; +import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; @@ -96,6 +96,7 @@ public class Am extends BaseCommand { // Amount we reduce the stack size by when testing a task re-size. private static final int STACK_BOUNDS_INSET = 10; + public static final String NO_CLASS_ERROR_CODE = "Error type 3"; private IActivityManager mAm; private IPackageManager mPm; @@ -198,7 +199,7 @@ public class Am extends BaseCommand { " --track-allocation: enable tracking of object allocations\n" + " --user <USER_ID> | current: Specify which user to run as; if not\n" + " specified then run as the current user.\n" + - " --stack <STACK_ID>: Specify into which stack should the activity be put." + + " --stack <STACK_ID>: Specify into which stack should the activity be put.\n" + "\n" + "am startservice: start a Service. Options are:\n" + " --user <USER_ID> | current: Specify which user to run as; if not\n" + @@ -385,17 +386,13 @@ public class Am extends BaseCommand { String op = nextArgRequired(); if (op.equals("start")) { - runStart(); + runAmCmd(getRawArgs()); } else if (op.equals("startservice")) { runStartService(); } else if (op.equals("stopservice")) { runStopService(); - } else if (op.equals("force-stop")) { - runForceStop(); - } else if (op.equals("kill")) { - runKill(); - } else if (op.equals("kill-all")) { - runKillAll(); + } else if (op.equals("force-stop") || op.equals("kill") || op.equals("kill-all")) { + runAmCmd(getRawArgs()); } else if (op.equals("instrument")) { runInstrument(); } else if (op.equals("trace-ipc")) { @@ -475,6 +472,49 @@ public class Am extends BaseCommand { return userId; } + static final class MyShellCallback extends ShellCallback { + @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) { + File file = new File(path); + //System.err.println("Opening file: " + file.getAbsolutePath()); + //Log.i("Am", "Opening file: " + file.getAbsolutePath()); + final ParcelFileDescriptor fd; + try { + fd = ParcelFileDescriptor.open(file, + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_WRITE_ONLY); + } catch (FileNotFoundException e) { + String msg = "Unable to open file " + path + ": " + e; + System.err.println(msg); + throw new IllegalArgumentException(msg); + } + if (seLinuxContext != null) { + final String tcon = SELinux.getFileContext(file.getAbsolutePath()); + if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) { + try { + fd.close(); + } catch (IOException e) { + } + String msg = "System server has no access to file context " + tcon; + System.err.println(msg + " (from path " + file.getAbsolutePath() + + ", context " + seLinuxContext + ")"); + throw new IllegalArgumentException(msg); + } + } + return fd; + } + } + + void runAmCmd(String[] args) throws AndroidException { + try { + mAm.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, + args, new MyShellCallback(), new ResultReceiver(null) { }); + } catch (RemoteException e) { + System.err.println(NO_SYSTEM_ERROR_CODE); + throw new AndroidException("Can't call activity manager; is the system running?"); + } + } + private Intent makeIntent(int defUser) throws URISyntaxException { mStartFlags = 0; mWaitOption = false; @@ -558,211 +598,6 @@ public class Am extends BaseCommand { } } - private void runStart() throws Exception { - Intent intent = makeIntent(UserHandle.USER_CURRENT); - - if (mUserId == UserHandle.USER_ALL) { - System.err.println("Error: Can't start service with user 'all'"); - return; - } - - String mimeType = intent.getType(); - if (mimeType == null && intent.getData() != null - && "content".equals(intent.getData().getScheme())) { - mimeType = mAm.getProviderMimeType(intent.getData(), mUserId); - } - - - do { - if (mStopOption) { - String packageName; - if (intent.getComponent() != null) { - packageName = intent.getComponent().getPackageName(); - } else { - List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0, - mUserId).getList(); - if (activities == null || activities.size() <= 0) { - System.err.println("Error: Intent does not match any activities: " - + intent); - return; - } else if (activities.size() > 1) { - System.err.println("Error: Intent matches multiple activities; can't stop: " - + intent); - return; - } - packageName = activities.get(0).activityInfo.packageName; - } - System.out.println("Stopping: " + packageName); - mAm.forceStopPackage(packageName, mUserId); - Thread.sleep(250); - } - - System.out.println("Starting: " + intent); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - ParcelFileDescriptor fd = null; - ProfilerInfo profilerInfo = null; - - if (mProfileFile != null) { - try { - fd = openForSystemServer( - new File(mProfileFile), - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE | - ParcelFileDescriptor.MODE_WRITE_ONLY); - } catch (FileNotFoundException e) { - System.err.println("Error: Unable to open file: " + mProfileFile); - System.err.println("Consider using a file under /data/local/tmp/"); - return; - } - profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop); - } - - IActivityManager.WaitResult result = null; - int res; - final long startTime = SystemClock.uptimeMillis(); - ActivityOptions options = null; - if (mStackId != INVALID_STACK_ID) { - options = ActivityOptions.makeBasic(); - options.setLaunchStackId(mStackId); - } - if (mWaitOption) { - result = mAm.startActivityAndWait(null, null, intent, mimeType, - null, null, 0, mStartFlags, profilerInfo, - options != null ? options.toBundle() : null, mUserId); - res = result.result; - } else { - res = mAm.startActivityAsUser(null, null, intent, mimeType, - null, null, 0, mStartFlags, profilerInfo, - options != null ? options.toBundle() : null, mUserId); - } - final long endTime = SystemClock.uptimeMillis(); - PrintStream out = mWaitOption ? System.out : System.err; - boolean launched = false; - switch (res) { - case ActivityManager.START_SUCCESS: - launched = true; - break; - case ActivityManager.START_SWITCHES_CANCELED: - launched = true; - out.println( - "Warning: Activity not started because the " - + " current activity is being kept for the user."); - break; - case ActivityManager.START_DELIVERED_TO_TOP: - launched = true; - out.println( - "Warning: Activity not started, intent has " - + "been delivered to currently running " - + "top-most instance."); - break; - case ActivityManager.START_RETURN_INTENT_TO_CALLER: - launched = true; - out.println( - "Warning: Activity not started because intent " - + "should be handled by the caller"); - break; - case ActivityManager.START_TASK_TO_FRONT: - launched = true; - out.println( - "Warning: Activity not started, its current " - + "task has been brought to the front"); - break; - case ActivityManager.START_INTENT_NOT_RESOLVED: - out.println( - "Error: Activity not started, unable to " - + "resolve " + intent.toString()); - break; - case ActivityManager.START_CLASS_NOT_FOUND: - out.println(NO_CLASS_ERROR_CODE); - out.println("Error: Activity class " + - intent.getComponent().toShortString() - + " does not exist."); - break; - case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: - out.println( - "Error: Activity not started, you requested to " - + "both forward and receive its result"); - break; - case ActivityManager.START_PERMISSION_DENIED: - out.println( - "Error: Activity not started, you do not " - + "have permission to access it."); - break; - case ActivityManager.START_NOT_VOICE_COMPATIBLE: - out.println( - "Error: Activity not started, voice control not allowed for: " - + intent); - break; - case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY: - out.println( - "Error: Not allowed to start background user activity" - + " that shouldn't be displayed for all users."); - break; - default: - out.println( - "Error: Activity not started, unknown error code " + res); - break; - } - if (mWaitOption && launched) { - if (result == null) { - result = new IActivityManager.WaitResult(); - result.who = intent.getComponent(); - } - System.out.println("Status: " + (result.timeout ? "timeout" : "ok")); - if (result.who != null) { - System.out.println("Activity: " + result.who.flattenToShortString()); - } - if (result.thisTime >= 0) { - System.out.println("ThisTime: " + result.thisTime); - } - if (result.totalTime >= 0) { - System.out.println("TotalTime: " + result.totalTime); - } - System.out.println("WaitTime: " + (endTime-startTime)); - System.out.println("Complete"); - } - mRepeat--; - if (mRepeat > 0) { - mAm.unhandledBack(); - } - } while (mRepeat > 0); - } - - private void runForceStop() throws Exception { - int userId = UserHandle.USER_ALL; - - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - mAm.forceStopPackage(nextArgRequired(), userId); - } - - private void runKill() throws Exception { - int userId = UserHandle.USER_ALL; - - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("--user")) { - userId = parseUserArg(nextArgRequired()); - } else { - System.err.println("Error: Unknown option: " + opt); - return; - } - } - mAm.killBackgroundProcesses(nextArgRequired(), userId); - } - - private void runKillAll() throws Exception { - mAm.killAllBackgroundProcesses(); - } - private void sendBroadcast() throws Exception { Intent intent = makeIntent(UserHandle.USER_CURRENT); IntentReceiver receiver = new IntentReceiver(); diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 32a8088e9c4e..ace4e3284930 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -49,9 +49,12 @@ import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.IUserManager; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.SELinux; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; @@ -68,6 +71,7 @@ import libcore.io.IoUtils; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -284,13 +288,45 @@ public final class Pm { } } + static final class MyShellCallback extends ShellCallback { + @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) { + File file = new File(path); + final ParcelFileDescriptor fd; + try { + fd = ParcelFileDescriptor.open(file, + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_WRITE_ONLY); + } catch (FileNotFoundException e) { + String msg = "Unable to open file " + path + ": " + e; + System.err.println(msg); + throw new IllegalArgumentException(msg); + } + if (seLinuxContext != null) { + final String tcon = SELinux.getFileContext(file.getAbsolutePath()); + if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) { + try { + fd.close(); + } catch (IOException e) { + } + String msg = "System server has no access to file context " + tcon; + System.err.println(msg + " (from path " + file.getAbsolutePath() + + ", context " + seLinuxContext + ")"); + throw new IllegalArgumentException(msg); + } + } + return fd; + } + } + private int runShellCommand(String serviceName, String[] args) { final HandlerThread handlerThread = new HandlerThread("results"); handlerThread.start(); try { ServiceManager.getService(serviceName).shellCommand( FileDescriptor.in, FileDescriptor.out, FileDescriptor.err, - args, new ResultReceiver(new Handler(handlerThread.getLooper()))); + args, new MyShellCallback(), + new ResultReceiver(new Handler(handlerThread.getLooper()))); return 0; } catch (RemoteException e) { e.printStackTrace(); diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index ea8ba2f1e6df..cf77567540f0 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -23,7 +23,6 @@ import libcore.io.IoUtils; import java.io.FileDescriptor; import java.io.FileOutputStream; -import java.io.IOException; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.lang.reflect.Modifier; @@ -361,13 +360,14 @@ public class Binder implements IBinder { ParcelFileDescriptor out = data.readFileDescriptor(); ParcelFileDescriptor err = data.readFileDescriptor(); String[] args = data.readStringArray(); + ShellCallback shellCallback = ShellCallback.CREATOR.createFromParcel(data); ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data); try { if (out != null) { shellCommand(in != null ? in.getFileDescriptor() : null, out.getFileDescriptor(), err != null ? err.getFileDescriptor() : out.getFileDescriptor(), - args, resultReceiver); + args, shellCallback, resultReceiver); } } finally { IoUtils.closeQuietly(in); @@ -459,13 +459,15 @@ public class Binder implements IBinder { * @param out The raw file descriptor that normal command messages should be written to. * @param err The raw file descriptor that command error messages should be written to. * @param args Command-line arguments. + * @param callback Callback through which to interact with the invoking shell. * @param resultReceiver Called when the command has finished executing, with the result code. * @throws RemoteException * @hide */ public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException { - onShellCommand(in, out, err, args, resultReceiver); + String[] args, ShellCallback callback, + ResultReceiver resultReceiver) throws RemoteException { + onShellCommand(in, out, err, args, callback, resultReceiver); } /** @@ -477,7 +479,7 @@ public class Binder implements IBinder { * @hide */ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException { + String[] args, ShellCallback callback, ResultReceiver resultReceiver) throws RemoteException { FileOutputStream fout = new FileOutputStream(err != null ? err : out); PrintWriter pw = new FastPrintWriter(fout); pw.println("No shell command implementation."); @@ -650,13 +652,15 @@ final class BinderProxy implements IBinder { } public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException { + String[] args, ShellCallback callback, + ResultReceiver resultReceiver) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeFileDescriptor(in); data.writeFileDescriptor(out); data.writeFileDescriptor(err); data.writeStringArray(args); + ShellCallback.writeToParcel(callback, data); resultReceiver.writeToParcel(data, 0); try { transact(SHELL_COMMAND_TRANSACTION, data, reply, 0); diff --git a/core/java/android/os/IBinder.java b/core/java/android/os/IBinder.java index 0fa87509a77a..f762a052cb41 100644 --- a/core/java/android/os/IBinder.java +++ b/core/java/android/os/IBinder.java @@ -220,11 +220,13 @@ public interface IBinder { * @param out The raw file descriptor that normal command messages should be written to. * @param err The raw file descriptor that command error messages should be written to. * @param args Command-line arguments. + * @param shellCallback Optional callback to the caller's shell to perform operations in it. * @param resultReceiver Called when the command has finished executing, with the result code. * @hide */ public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException; + String[] args, ShellCallback shellCallback, + ResultReceiver resultReceiver) throws RemoteException; /** * Perform a generic operation with the object. diff --git a/core/java/android/os/ShellCallback.java b/core/java/android/os/ShellCallback.java new file mode 100644 index 000000000000..e7fe697f9c54 --- /dev/null +++ b/core/java/android/os/ShellCallback.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2016 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.os; + +import android.util.Log; + +import com.android.internal.os.IShellCallback; + +/** + * Special-purpose API for use with {@link IBinder#shellCommand IBinder.shellCommand} for + * performing operations back on the invoking shell. + * @hide + */ +public class ShellCallback implements Parcelable { + final static String TAG = "ShellCallback"; + + final static boolean DEBUG = false; + + final boolean mLocal; + + IShellCallback mShellCallback; + + class MyShellCallback extends IShellCallback.Stub { + public ParcelFileDescriptor openOutputFile(String path, String seLinuxContext) { + return onOpenOutputFile(path, seLinuxContext); + } + } + + /** + * Create a new ShellCallback to receive requests. + */ + public ShellCallback() { + mLocal = true; + } + + /** + * Ask the shell to open a file for writing. This will truncate the file if it + * already exists. It will create the file if it doesn't exist. + * @param path Path of the file to be opened/created. + * @param seLinuxContext Optional SELinux context that must be allowed to have + * access to the file; if null, nothing is required. + */ + public ParcelFileDescriptor openOutputFile(String path, String seLinuxContext) { + if (DEBUG) Log.d(TAG, "openOutputFile " + this + ": mLocal=" + mLocal + + " mShellCallback=" + mShellCallback); + + if (mLocal) { + return onOpenOutputFile(path, seLinuxContext); + } + + if (mShellCallback != null) { + try { + return mShellCallback.openOutputFile(path, seLinuxContext); + } catch (RemoteException e) { + Log.w(TAG, "Failure opening " + path, e); + } + } + return null; + } + + public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) { + return null; + } + + public static void writeToParcel(ShellCallback callback, Parcel out) { + if (callback == null) { + out.writeStrongBinder(null); + } else { + callback.writeToParcel(out, 0); + } + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel out, int flags) { + synchronized (this) { + if (mShellCallback == null) { + mShellCallback = new MyShellCallback(); + } + out.writeStrongBinder(mShellCallback.asBinder()); + } + } + + ShellCallback(Parcel in) { + mLocal = false; + mShellCallback = IShellCallback.Stub.asInterface(in.readStrongBinder()); + } + + public static final Parcelable.Creator<ShellCallback> CREATOR + = new Parcelable.Creator<ShellCallback>() { + public ShellCallback createFromParcel(Parcel in) { + return new ShellCallback(in); + } + public ShellCallback[] newArray(int size) { + return new ShellCallback[size]; + } + }; +} diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java index fc804e592148..831c9b27ac45 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -40,6 +40,7 @@ public abstract class ShellCommand { private FileDescriptor mOut; private FileDescriptor mErr; private String[] mArgs; + private ShellCallback mShellCallback; private ResultReceiver mResultReceiver; private String mCmd; @@ -55,12 +56,13 @@ public abstract class ShellCommand { private InputStream mInputStream; public void init(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, int firstArgPos) { + String[] args, ShellCallback callback, int firstArgPos) { mTarget = target; mIn = in; mOut = out; mErr = err; mArgs = args; + mShellCallback = callback; mResultReceiver = null; mCmd = null; mArgPos = firstArgPos; @@ -74,7 +76,7 @@ public abstract class ShellCommand { } public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) { + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { String cmd; int start; if (args != null && args.length > 0) { @@ -84,7 +86,7 @@ public abstract class ShellCommand { cmd = null; start = 0; } - init(target, in, out, err, args, start); + init(target, in, out, err, args, callback, start); mCmd = cmd; mResultReceiver = resultReceiver; @@ -105,7 +107,7 @@ public abstract class ShellCommand { // go. PrintWriter eout = getErrPrintWriter(); eout.println(); - eout.println("Exception occurred while dumping:"); + eout.println("Exception occurred while executing:"); e.printStackTrace(eout); } finally { if (DEBUG) Slog.d(TAG, "Flushing output streams on " + mTarget); @@ -257,6 +259,13 @@ public abstract class ShellCommand { return arg; } + /** + * Return the {@link ShellCallback} for communicating back with the calling shell. + */ + public ShellCallback getShellCallback() { + return mShellCallback; + } + public int handleDefaultCommands(String cmd) { if ("dump".equals(cmd)) { String[] newArgs = new String[mArgs.length-1]; diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java index c067da7e1dec..3baccee049b0 100644 --- a/core/java/com/android/internal/os/BaseCommand.java +++ b/core/java/com/android/internal/os/BaseCommand.java @@ -36,6 +36,8 @@ public abstract class BaseCommand { public static final String NO_SYSTEM_ERROR_CODE = "Error type 2"; public static final String NO_CLASS_ERROR_CODE = "Error type 3"; + private String[] mRawArgs; + /** * Call to run the command. */ @@ -45,7 +47,8 @@ public abstract class BaseCommand { return; } - mArgs.init(null, null, null, null, args, 0); + mRawArgs = args; + mArgs.init(null, null, null, null, args, null, 0); try { onRun(); @@ -109,4 +112,11 @@ public abstract class BaseCommand { public String nextArgRequired() { return mArgs.getNextArgRequired(); } + + /** + * Return the original raw argument list supplied to the command. + */ + public String[] getRawArgs() { + return mRawArgs; + } } diff --git a/core/java/com/android/internal/os/IShellCallback.aidl b/core/java/com/android/internal/os/IShellCallback.aidl new file mode 100644 index 000000000000..57d67890d840 --- /dev/null +++ b/core/java/com/android/internal/os/IShellCallback.aidl @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2016, 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.internal.os; + +import android.os.ParcelFileDescriptor; + +/** @hide */ +interface IShellCallback { + ParcelFileDescriptor openOutputFile(String path, String seLinuxContext); +} diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 238bf927c43e..7c2eea3f68aa 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -51,6 +51,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.ShellCommand; import android.os.UserHandle; import android.os.storage.MountServiceInternal; @@ -1787,8 +1788,9 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ResultReceiver resultReceiver) { - (new Shell(this, this)).exec(this, in, out, err, args, resultReceiver); + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { + (new Shell(this, this)).exec(this, in, out, err, args, callback, resultReceiver); } static void dumpCommandHelp(PrintWriter pw) { diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java index 6b517210ef31..d2cfb6d51002 100644 --- a/services/core/java/com/android/server/BatteryService.java +++ b/services/core/java/com/android/server/BatteryService.java @@ -20,6 +20,7 @@ import android.database.ContentObserver; import android.os.BatteryStats; import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.ShellCommand; import com.android.internal.app.IBatteryStats; import com.android.server.am.BatteryStatsService; @@ -789,7 +790,7 @@ public final class BatteryService extends SystemService { pw.println(" technology: " + mBatteryProps.batteryTechnology); } else { Shell shell = new Shell(); - shell.exec(mBinderService, null, fd, null, args, new ResultReceiver(null)); + shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null)); } } } @@ -875,8 +876,9 @@ public final class BatteryService extends SystemService { } @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ResultReceiver resultReceiver) { - (new Shell()).exec(this, in, out, err, args, resultReceiver); + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { + (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); } } diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 6b73fec8c920..dbc1f31a9348 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -60,6 +60,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.UserHandle; @@ -1232,8 +1233,8 @@ public class DeviceIdleController extends SystemService } @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ResultReceiver resultReceiver) { - (new Shell()).exec(this, in, out, err, args, resultReceiver); + FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver) { + (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); } } @@ -2838,7 +2839,8 @@ public class DeviceIdleController extends SystemService shell.userId = userId; String[] newArgs = new String[args.length-i]; System.arraycopy(args, i, newArgs, 0, args.length-i); - shell.exec(mBinderService, null, fd, null, newArgs, new ResultReceiver(null)); + shell.exec(mBinderService, null, fd, null, newArgs, null, + new ResultReceiver(null)); return; } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e5b611ca3231..03610868d04b 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -182,6 +182,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; @@ -14024,9 +14025,10 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ResultReceiver resultReceiver) { + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { (new ActivityManagerShellCommand(this, false)).exec( - this, in, out, err, args, resultReceiver); + this, in, out, err, args, callback, resultReceiver); } @Override @@ -14249,7 +14251,8 @@ public final class ActivityManagerService extends ActivityManagerNative // Dumping a single activity? if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll, dumpVisibleStacks)) { ActivityManagerShellCommand shell = new ActivityManagerShellCommand(this, true); - int res = shell.exec(this, null, fd, null, args, new ResultReceiver(null)); + int res = shell.exec(this, null, fd, null, args, null, + new ResultReceiver(null)); if (res < 0) { pw.println("Bad activity command, or no activities match: " + cmd); pw.println("Use -h for help."); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index adf6d3670af3..aed9fa4435fd 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -17,26 +17,57 @@ package com.android.server.am; import android.app.ActivityManager; +import android.app.ActivityOptions; +import android.app.AppGlobals; import android.app.IActivityManager; +import android.app.ProfilerInfo; +import android.content.Intent; +import android.content.pm.IPackageManager; +import android.content.pm.ResolveInfo; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ShellCommand; +import android.os.SystemClock; import android.os.UserHandle; import android.util.DebugUtils; import java.io.PrintWriter; +import java.net.URISyntaxException; +import java.util.List; + +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; class ActivityManagerShellCommand extends ShellCommand { + public static final String NO_CLASS_ERROR_CODE = "Error type 3"; + // IPC interface to activity manager -- don't need to do additional security checks. final IActivityManager mInterface; // Internal service impl -- must perform security checks before touching. final ActivityManagerService mInternal; + // Convenience for interacting with package manager. + final IPackageManager mPm; + + private int mStartFlags = 0; + private boolean mWaitOption = false; + private boolean mStopOption = false; + + private int mRepeat = 0; + private int mUserId; + private String mReceiverPermission; + + private String mProfileFile; + private int mSamplingInterval; + private boolean mAutoStop; + private int mStackId; + final boolean mDumping; ActivityManagerShellCommand(ActivityManagerService service, boolean dumping) { mInterface = service; mInternal = service; + mPm = AppGlobals.getPackageManager(); mDumping = dumping; } @@ -48,6 +79,15 @@ class ActivityManagerShellCommand extends ShellCommand { PrintWriter pw = getOutPrintWriter(); try { switch (cmd) { + case "start": + case "start-activity": + return runStartActivity(pw); + case "startservice": + case "start-service": + return 1; //runStartService(pw); + case "stopservice": + case "stop-service": + return 1; //runStopService(pw); case "force-stop": return runForceStop(pw); case "kill": @@ -75,6 +115,241 @@ class ActivityManagerShellCommand extends ShellCommand { return -1; } + private Intent makeIntent(int defUser) throws URISyntaxException { + mStartFlags = 0; + mWaitOption = false; + mStopOption = false; + mRepeat = 0; + mProfileFile = null; + mSamplingInterval = 0; + mAutoStop = false; + mUserId = defUser; + mStackId = INVALID_STACK_ID; + + return Intent.parseCommandArgs(this, new Intent.CommandOptionHandler() { + @Override + public boolean handleOption(String opt, ShellCommand cmd) { + if (opt.equals("-D")) { + mStartFlags |= ActivityManager.START_FLAG_DEBUG; + } else if (opt.equals("-N")) { + mStartFlags |= ActivityManager.START_FLAG_NATIVE_DEBUGGING; + } else if (opt.equals("-W")) { + mWaitOption = true; + } else if (opt.equals("-P")) { + mProfileFile = getNextArgRequired(); + mAutoStop = true; + } else if (opt.equals("--start-profiler")) { + mProfileFile = getNextArgRequired(); + mAutoStop = false; + } else if (opt.equals("--sampling")) { + mSamplingInterval = Integer.parseInt(getNextArgRequired()); + } else if (opt.equals("-R")) { + mRepeat = Integer.parseInt(getNextArgRequired()); + } else if (opt.equals("-S")) { + mStopOption = true; + } else if (opt.equals("--track-allocation")) { + mStartFlags |= ActivityManager.START_FLAG_TRACK_ALLOCATION; + } else if (opt.equals("--user")) { + mUserId = UserHandle.parseUserArg(getNextArgRequired()); + } else if (opt.equals("--receiver-permission")) { + mReceiverPermission = getNextArgRequired(); + } else if (opt.equals("--stack")) { + mStackId = Integer.parseInt(getNextArgRequired()); + } else { + return false; + } + return true; + } + }); + } + + ParcelFileDescriptor openOutputFile(String path) { + try { + ParcelFileDescriptor pfd = getShellCallback().openOutputFile(path, + "u:r:system_server:s0"); + if (pfd != null) { + return pfd; + } + } catch (RuntimeException e) { + getErrPrintWriter().println("Failure opening file: " + e.getMessage()); + } + getErrPrintWriter().println("Error: Unable to open file: " + path); + getErrPrintWriter().println("Consider using a file under /data/local/tmp/"); + return null; + } + + int runStartActivity(PrintWriter pw) throws RemoteException { + Intent intent; + try { + intent = makeIntent(UserHandle.USER_CURRENT); + } catch (URISyntaxException e) { + throw new RuntimeException(e.getMessage(), e); + } + + if (mUserId == UserHandle.USER_ALL) { + getErrPrintWriter().println("Error: Can't start service with user 'all'"); + return 1; + } + + String mimeType = intent.getType(); + if (mimeType == null && intent.getData() != null + && "content".equals(intent.getData().getScheme())) { + mimeType = mInterface.getProviderMimeType(intent.getData(), mUserId); + } + + do { + if (mStopOption) { + String packageName; + if (intent.getComponent() != null) { + packageName = intent.getComponent().getPackageName(); + } else { + List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0, + mUserId).getList(); + if (activities == null || activities.size() <= 0) { + getErrPrintWriter().println("Error: Intent does not match any activities: " + + intent); + return 1; + } else if (activities.size() > 1) { + getErrPrintWriter().println( + "Error: Intent matches multiple activities; can't stop: " + + intent); + return 1; + } + packageName = activities.get(0).activityInfo.packageName; + } + pw.println("Stopping: " + packageName); + mInterface.forceStopPackage(packageName, mUserId); + try { + Thread.sleep(250); + } catch (InterruptedException e) { + } + } + + ProfilerInfo profilerInfo = null; + + if (mProfileFile != null) { + ParcelFileDescriptor fd = openOutputFile(mProfileFile); + if (fd == null) { + return 1; + } + profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop); + } + + pw.println("Starting: " + intent); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + IActivityManager.WaitResult result = null; + int res; + final long startTime = SystemClock.uptimeMillis(); + ActivityOptions options = null; + if (mStackId != INVALID_STACK_ID) { + options = ActivityOptions.makeBasic(); + options.setLaunchStackId(mStackId); + } + if (mWaitOption) { + result = mInterface.startActivityAndWait(null, null, intent, mimeType, + null, null, 0, mStartFlags, profilerInfo, + options != null ? options.toBundle() : null, mUserId); + res = result.result; + } else { + res = mInterface.startActivityAsUser(null, null, intent, mimeType, + null, null, 0, mStartFlags, profilerInfo, + options != null ? options.toBundle() : null, mUserId); + } + final long endTime = SystemClock.uptimeMillis(); + PrintWriter out = mWaitOption ? pw : getErrPrintWriter(); + boolean launched = false; + switch (res) { + case ActivityManager.START_SUCCESS: + launched = true; + break; + case ActivityManager.START_SWITCHES_CANCELED: + launched = true; + out.println( + "Warning: Activity not started because the " + + " current activity is being kept for the user."); + break; + case ActivityManager.START_DELIVERED_TO_TOP: + launched = true; + out.println( + "Warning: Activity not started, intent has " + + "been delivered to currently running " + + "top-most instance."); + break; + case ActivityManager.START_RETURN_INTENT_TO_CALLER: + launched = true; + out.println( + "Warning: Activity not started because intent " + + "should be handled by the caller"); + break; + case ActivityManager.START_TASK_TO_FRONT: + launched = true; + out.println( + "Warning: Activity not started, its current " + + "task has been brought to the front"); + break; + case ActivityManager.START_INTENT_NOT_RESOLVED: + out.println( + "Error: Activity not started, unable to " + + "resolve " + intent.toString()); + break; + case ActivityManager.START_CLASS_NOT_FOUND: + out.println(NO_CLASS_ERROR_CODE); + out.println("Error: Activity class " + + intent.getComponent().toShortString() + + " does not exist."); + break; + case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: + out.println( + "Error: Activity not started, you requested to " + + "both forward and receive its result"); + break; + case ActivityManager.START_PERMISSION_DENIED: + out.println( + "Error: Activity not started, you do not " + + "have permission to access it."); + break; + case ActivityManager.START_NOT_VOICE_COMPATIBLE: + out.println( + "Error: Activity not started, voice control not allowed for: " + + intent); + break; + case ActivityManager.START_NOT_CURRENT_USER_ACTIVITY: + out.println( + "Error: Not allowed to start background user activity" + + " that shouldn't be displayed for all users."); + break; + default: + out.println( + "Error: Activity not started, unknown error code " + res); + break; + } + if (mWaitOption && launched) { + if (result == null) { + result = new IActivityManager.WaitResult(); + result.who = intent.getComponent(); + } + pw.println("Status: " + (result.timeout ? "timeout" : "ok")); + if (result.who != null) { + pw.println("Activity: " + result.who.flattenToShortString()); + } + if (result.thisTime >= 0) { + pw.println("ThisTime: " + result.thisTime); + } + if (result.totalTime >= 0) { + pw.println("TotalTime: " + result.totalTime); + } + pw.println("WaitTime: " + (endTime-startTime)); + pw.println("Complete"); + } + mRepeat--; + if (mRepeat > 0) { + mInterface.unhandledBack(); + } + } while (mRepeat > 0); + return 0; + } + int runIsUserStopped(PrintWriter pw) { int userId = UserHandle.parseUserArg(getNextArgRequired()); boolean stopped = mInternal.isUserStopped(userId); @@ -223,6 +498,24 @@ class ActivityManagerShellCommand extends ShellCommand { pw.println("Activity manager (activity) commands:"); pw.println(" help"); pw.println(" Print this help text."); + pw.println(" start-activity [-D] [-N] [-W] [-P <FILE>] [--start-profiler <FILE>]"); + pw.println(" [--sampling INTERVAL] [-R COUNT] [-S]"); + pw.println(" [--track-allocation] [--user <USER_ID> | current] <INTENT>"); + pw.println(" Start an Activity. Options are:"); + pw.println(" -D: enable debugging"); + pw.println(" -N: enable native debugging"); + pw.println(" -W: wait for launch to complete"); + pw.println(" --start-profiler <FILE>: start profiler and send results to <FILE>"); + pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds"); + pw.println(" between samples (use with --start-profiler)"); + pw.println(" -P <FILE>: like above, but profiling stops when app goes idle"); + pw.println(" -R: repeat the activity launch <COUNT> times. Prior to each repeat,"); + pw.println(" the top activity will be finished."); + pw.println(" -S: force stop the target app before starting the activity"); + pw.println(" --track-allocation: enable tracking of object allocations"); + pw.println(" --user <USER_ID> | current: Specify which user to run as; if not"); + pw.println(" specified then run as the current user."); + pw.println(" --stack <STACK_ID>: Specify into which stack should the activity be put."); pw.println(" force-stop [--user <USER_ID> | all | current] <PACKAGE>"); pw.println(" Completely stop the given application package."); pw.println(" kill [--user <USER_ID> | all | current] <PACKAGE>"); @@ -241,6 +534,8 @@ class ActivityManagerShellCommand extends ShellCommand { pw.println(" Optionally controls lenient background check mode, returns current mode."); pw.println(" get-uid-state <UID>"); pw.println(" Gets the process state of an app given its <UID>."); + pw.println(); + Intent.printIntentArgsHelp(pw, ""); } } } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 7708b0205074..6b00c86bf699 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -5029,7 +5029,7 @@ final class ActivityStack { if (top >= 0) { final ArrayList<ActivityRecord> activities = mTaskHistory.get(top).mActivities; int activityTop = activities.size() - 1; - if (activityTop > 0) { + if (activityTop >= 0) { finishActivityLocked(activities.get(activityTop), Activity.RESULT_CANCELED, null, "unhandled-back", true); } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 74095acca16a..87f4030a9049 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -18,8 +18,8 @@ package com.android.server.input; import android.annotation.NonNull; import android.annotation.Nullable; -import android.os.Build; import android.os.LocaleList; +import android.os.ShellCallback; import android.util.Log; import android.view.Display; import com.android.internal.inputmethod.InputMethodSubtypeHandle; @@ -91,10 +91,8 @@ import android.view.PointerIcon; import android.view.Surface; import android.view.ViewConfiguration; import android.view.WindowManagerPolicy; -import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; -import android.widget.Toast; import java.io.File; import java.io.FileDescriptor; @@ -103,11 +101,8 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -1739,8 +1734,9 @@ public class InputManagerService extends IInputManager.Stub @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ResultReceiver resultReceiver) { - (new Shell()).exec(this, in, out, err, args, resultReceiver); + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { + (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); } public int onShellCommand(Shell shell, String cmd) { diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 9d931467d914..fe3a02d193f6 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -44,9 +44,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ServiceInfo; import android.content.pm.PackageManager.NameNotFoundException; @@ -62,6 +60,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; @@ -1718,9 +1717,9 @@ public final class JobSchedulerService extends com.android.server.SystemService @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException { + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { (new JobSchedulerShellCommand(JobSchedulerService.this)).exec( - this, in, out, err, args, resultReceiver); + this, in, out, err, args, callback, resultReceiver); } }; diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 6381aa747022..547cc51e9a05 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -123,7 +123,6 @@ import android.net.LinkProperties; import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkPolicy; -import android.net.NetworkPolicyManager; import android.net.NetworkQuotaInfo; import android.net.NetworkState; import android.net.NetworkTemplate; @@ -144,6 +143,7 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; @@ -2386,9 +2386,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException { + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { (new NetworkPolicyManagerShellCommand(mContext, this)).exec( - this, in, out, err, args, resultReceiver); + this, in, out, err, args, callback, resultReceiver); } @Override diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 689917cd670a..f777aaebdd14 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -28,6 +28,7 @@ import android.os.Environment; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.storage.StorageManager; import android.util.Log; import android.util.Slog; @@ -107,9 +108,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub { @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException { + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { (new OtaDexoptShellCommand(this)).exec( - this, in, out, err, args, resultReceiver); + this, in, out, err, args, callback, resultReceiver); } @Override diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index c76302c1053c..13428b2e2c8a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -185,6 +185,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SELinux; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; @@ -18397,9 +18398,10 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ResultReceiver resultReceiver) { + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { (new PackageManagerShellCommand(this)).exec( - this, in, out, err, args, resultReceiver); + this, in, out, err, args, callback, resultReceiver); } @Override diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 13f558e3dd13..19bf751417ce 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -67,6 +67,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SELinux; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.ShellCommand; import android.os.SystemClock; import android.os.UserHandle; @@ -3366,13 +3367,14 @@ public class ShortcutService extends IShortcutService.Stub { @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException { + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { enforceShell(); final long token = injectClearCallingIdentity(); try { - final int status = (new MyShellCommand()).exec(this, in, out, err, args, resultReceiver); + final int status = (new MyShellCommand()).exec(this, in, out, err, args, callback, + resultReceiver); resultReceiver.send(status, null); } finally { injectRestoreCallingIdentity(token); diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index c1cb032ce97f..c6b09d190bff 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -62,6 +62,7 @@ import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SELinux; import android.os.ServiceManager; +import android.os.ShellCallback; import android.os.ShellCommand; import android.os.UserHandle; import android.os.UserManager; @@ -3209,8 +3210,9 @@ public class UserManagerService extends IUserManager.Stub { @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ResultReceiver resultReceiver) { - (new Shell()).exec(this, in, out, err, args, resultReceiver); + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { + (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); } int onShellCommand(Shell shell, String cmd) { diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index 552803f47652..7b7db0e1440b 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -28,23 +28,21 @@ import android.os.IBinder; import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.Slog; -import android.view.KeyEvent; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.StatusBarIcon; -import com.android.internal.util.FastPrintWriter; import com.android.server.LocalServices; import com.android.server.notification.NotificationDelegate; import com.android.server.wm.WindowManagerService; import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; @@ -849,9 +847,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub { @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) throws RemoteException { + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { (new StatusBarShellCommand(this)).exec( - this, in, out, err, args, resultReceiver); + this, in, out, err, args, callback, resultReceiver); } // ================================================================================ diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java index 846169cbf9c3..43cdf5978068 100644 --- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java +++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java @@ -25,10 +25,10 @@ import android.os.Binder; import android.os.PatternMatcher; import android.os.Process; import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.UserHandle; import android.util.Slog; import android.webkit.IWebViewUpdateService; -import android.webkit.WebViewFactory; import android.webkit.WebViewProviderInfo; import android.webkit.WebViewProviderResponse; @@ -140,9 +140,10 @@ public class WebViewUpdateService extends SystemService { @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, - FileDescriptor err, String[] args, ResultReceiver resultReceiver) { + FileDescriptor err, String[] args, ShellCallback callback, + ResultReceiver resultReceiver) { (new WebViewUpdateServiceShellCommand(this)).exec( - this, in, out, err, args, resultReceiver); + this, in, out, err, args, callback, resultReceiver); } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java index 3c99174142cb..25f9100d9252 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest7.java @@ -68,7 +68,7 @@ public class ShortcutManagerTest7 extends BaseShortcutManagerTest { /* fdin*/ null, /* fdout*/ fd.getFileDescriptor(), /* fderr*/ fd.getFileDescriptor(), - args, rr); + args, null, rr); } return readAll(out); } finally { diff --git a/tests/VoiceInteraction/AndroidManifest.xml b/tests/VoiceInteraction/AndroidManifest.xml index cbc6c76aa934..5fdf0dd3992c 100644 --- a/tests/VoiceInteraction/AndroidManifest.xml +++ b/tests/VoiceInteraction/AndroidManifest.xml @@ -1,6 +1,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.test.voiceinteraction"> + <uses-sdk android:minSdkVersion="23" android:targetSdkVersion="25" /> + <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" /> <uses-permission android:name="android.permission.READ_LOGS" /> diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 8d93b7f32100..a0b297701869 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -76,6 +76,7 @@ import android.os.Parcel; import android.os.PowerManager; import android.os.RemoteException; import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.UserHandle; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -1180,7 +1181,7 @@ public final class BridgeContext extends Context { @Override public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, - String[] args, ResultReceiver resultReceiver) { + String[] args, ShellCallback shellCallback, ResultReceiver resultReceiver) { } }; } |