diff options
-rw-r--r-- | cmds/pm/src/com/android/commands/pm/Pm.java | 517 | ||||
-rw-r--r-- | core/java/android/os/ShellCommand.java | 11 | ||||
-rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerShellCommand.java | 414 |
3 files changed, 504 insertions, 438 deletions
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index eb7c71295617..031bdbd1f222 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -28,13 +28,24 @@ import android.app.ActivityManagerNative; import android.app.PackageInstallObserver; import android.content.ComponentName; import android.content.Context; +import android.content.IIntentReceiver; +import android.content.IIntentSender; +import android.content.Intent; +import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageInstaller; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; import android.content.pm.UserInfo; +import android.content.pm.VerificationParams; +import android.net.Uri; +import android.os.Binder; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -45,13 +56,26 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; +import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; +import libcore.io.IoUtils; + import com.android.internal.content.PackageHelper; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.SizedInputStream; +import java.io.File; import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; public final class Pm { private static final String TAG = "Pm"; @@ -82,7 +106,7 @@ public final class Pm { System.exit(exitCode); } - public int run(String[] args) throws RemoteException { + public int run(String[] args) throws IOException, RemoteException { boolean validCommand = false; if (args.length < 1) { return showUsage(); @@ -118,19 +142,19 @@ public final class Pm { } if ("install-create".equals(op)) { - return runInstall(); + return runInstallCreate(); } if ("install-write".equals(op)) { - return runInstall(); + return runInstallWrite(); } if ("install-commit".equals(op)) { - return runInstall(); + return runInstallCommit(); } if ("install-abandon".equals(op) || "install-destroy".equals(op)) { - return runInstall(); + return runInstallAbandon(); } if ("set-installer".equals(op)) { @@ -275,10 +299,6 @@ public final class Pm { return -1; } - private int runInstall() { - return runShellCommand("package", mArgs); - } - /** * Execute the list sub-command. * @@ -297,10 +317,6 @@ public final class Pm { return runShellCommand("package", mArgs); } - private int runUninstall() { - return runShellCommand("package", mArgs); - } - private int runPath() { int userId = UserHandle.USER_SYSTEM; String option = nextOption(); @@ -354,6 +370,49 @@ public final class Pm { } } + /** + * Converts a failure code into a string by using reflection to find a matching constant + * in PackageManager. + */ + private String installFailureToString(LocalPackageInstallObserver obs) { + final int result = obs.result; + Field[] fields = PackageManager.class.getFields(); + for (Field f: fields) { + if (f.getType() == int.class) { + int modifiers = f.getModifiers(); + // only look at public final static fields. + if (((modifiers & Modifier.FINAL) != 0) && + ((modifiers & Modifier.PUBLIC) != 0) && + ((modifiers & Modifier.STATIC) != 0)) { + String fieldName = f.getName(); + if (fieldName.startsWith("INSTALL_FAILED_") || + fieldName.startsWith("INSTALL_PARSE_FAILED_")) { + // get the int value and compare it to result. + try { + if (result == f.getInt(null)) { + StringBuilder sb = new StringBuilder(64); + sb.append(fieldName); + if (obs.extraPermission != null) { + sb.append(" perm="); + sb.append(obs.extraPermission); + } + if (obs.extraPackage != null) { + sb.append(" pkg=" + obs.extraPackage); + } + return sb.toString(); + } + } catch (IllegalAccessException e) { + // this shouldn't happen since we only look for public static fields. + } + } + } + } + } + + // couldn't find a matching constant? return the value + return Integer.toString(result); + } + // pm set-app-link [--user USER_ID] PACKAGE {always|ask|always-ask|never|undefined} private int runSetAppLink() { int userId = UserHandle.USER_SYSTEM; @@ -543,6 +602,316 @@ public final class Pm { } } + private int runInstall() { + int installFlags = 0; + int userId = UserHandle.USER_ALL; + String installerPackageName = null; + + String opt; + + String originatingUriString = null; + String referrer = null; + String abi = null; + + while ((opt=nextOption()) != null) { + if (opt.equals("-l")) { + installFlags |= PackageManager.INSTALL_FORWARD_LOCK; + } else if (opt.equals("-r")) { + installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; + } else if (opt.equals("-i")) { + installerPackageName = nextOptionData(); + if (installerPackageName == null) { + System.err.println("Error: no value specified for -i"); + return 1; + } + } else if (opt.equals("-t")) { + installFlags |= PackageManager.INSTALL_ALLOW_TEST; + } else if (opt.equals("-s")) { + // Override if -s option is specified. + installFlags |= PackageManager.INSTALL_EXTERNAL; + } else if (opt.equals("-f")) { + // Override if -s option is specified. + installFlags |= PackageManager.INSTALL_INTERNAL; + } else if (opt.equals("-d")) { + installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; + } else if (opt.equals("-g")) { + installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS; + } else if (opt.equals("--originating-uri")) { + originatingUriString = nextOptionData(); + if (originatingUriString == null) { + System.err.println("Error: must supply argument for --originating-uri"); + return 1; + } + } else if (opt.equals("--referrer")) { + referrer = nextOptionData(); + if (referrer == null) { + System.err.println("Error: must supply argument for --referrer"); + return 1; + } + } else if (opt.equals("--abi")) { + abi = checkAbiArgument(nextOptionData()); + } else if (opt.equals("--user")) { + userId = Integer.parseInt(nextOptionData()); + } else { + System.err.println("Error: Unknown option: " + opt); + return 1; + } + } + + userId = translateUserId(userId, "runInstall"); + if (userId == UserHandle.USER_ALL) { + userId = UserHandle.USER_SYSTEM; + installFlags |= PackageManager.INSTALL_ALL_USERS; + } + + final Uri verificationURI; + final Uri originatingURI; + final Uri referrerURI; + + if (originatingUriString != null) { + originatingURI = Uri.parse(originatingUriString); + } else { + originatingURI = null; + } + + if (referrer != null) { + referrerURI = Uri.parse(referrer); + } else { + referrerURI = null; + } + + // Populate apkURI, must be present + final String apkFilePath = nextArg(); + System.err.println("\tpkg: " + apkFilePath); + if (apkFilePath == null) { + System.err.println("Error: no package specified"); + return 1; + } + + // Populate verificationURI, optionally present + final String verificationFilePath = nextArg(); + if (verificationFilePath != null) { + System.err.println("\tver: " + verificationFilePath); + verificationURI = Uri.fromFile(new File(verificationFilePath)); + } else { + verificationURI = null; + } + + LocalPackageInstallObserver obs = new LocalPackageInstallObserver(); + try { + VerificationParams verificationParams = new VerificationParams(verificationURI, + originatingURI, referrerURI, VerificationParams.NO_UID, null); + + mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags, + installerPackageName, verificationParams, abi, userId); + + synchronized (obs) { + while (!obs.finished) { + try { + obs.wait(); + } catch (InterruptedException e) { + } + } + if (obs.result == PackageManager.INSTALL_SUCCEEDED) { + System.out.println("Success"); + return 0; + } else { + System.err.println("Failure [" + + installFailureToString(obs) + + "]"); + return 1; + } + } + } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); + return 1; + } + } + + /** + * @param userId The user id to be translated. + * @param logContext Optional human readable text to provide some context in error log. + * @return Translated concrete user id. This will include USER_ALL. + */ + private int translateUserId(int userId, String logContext) { + return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), + userId, true, true, logContext, "pm command"); + } + + private int runInstallCreate() throws RemoteException { + int userId = UserHandle.USER_ALL; + String installerPackageName = null; + + final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); + + String opt; + while ((opt = nextOption()) != null) { + if (opt.equals("-l")) { + params.installFlags |= PackageManager.INSTALL_FORWARD_LOCK; + } else if (opt.equals("-r")) { + params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; + } else if (opt.equals("-i")) { + installerPackageName = nextArg(); + if (installerPackageName == null) { + throw new IllegalArgumentException("Missing installer package"); + } + } else if (opt.equals("-t")) { + params.installFlags |= PackageManager.INSTALL_ALLOW_TEST; + } else if (opt.equals("-s")) { + params.installFlags |= PackageManager.INSTALL_EXTERNAL; + } else if (opt.equals("-f")) { + params.installFlags |= PackageManager.INSTALL_INTERNAL; + } else if (opt.equals("-d")) { + params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; + } else if (opt.equals("-g")) { + params.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS; + } else if (opt.equals("--originating-uri")) { + params.originatingUri = Uri.parse(nextOptionData()); + } else if (opt.equals("--referrer")) { + params.referrerUri = Uri.parse(nextOptionData()); + } else if (opt.equals("-p")) { + params.mode = SessionParams.MODE_INHERIT_EXISTING; + params.appPackageName = nextOptionData(); + if (params.appPackageName == null) { + throw new IllegalArgumentException("Missing inherit package name"); + } + } else if (opt.equals("-S")) { + params.setSize(Long.parseLong(nextOptionData())); + } else if (opt.equals("--abi")) { + params.abiOverride = checkAbiArgument(nextOptionData()); + } else if (opt.equals("--user")) { + userId = Integer.parseInt(nextOptionData()); + } else if (opt.equals("--install-location")) { + params.installLocation = Integer.parseInt(nextOptionData()); + } else if (opt.equals("--force-uuid")) { + params.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID; + params.volumeUuid = nextOptionData(); + if ("internal".equals(params.volumeUuid)) { + params.volumeUuid = null; + } + } else { + throw new IllegalArgumentException("Unknown option " + opt); + } + } + + userId = translateUserId(userId, "runInstallCreate"); + if (userId == UserHandle.USER_ALL) { + userId = UserHandle.USER_SYSTEM; + params.installFlags |= PackageManager.INSTALL_ALL_USERS; + } + + final int sessionId = mInstaller.createSession(params, installerPackageName, userId); + + // NOTE: adb depends on parsing this string + System.out.println("Success: created install session [" + sessionId + "]"); + return 0; + } + + private int runInstallWrite() throws IOException, RemoteException { + long sizeBytes = -1; + + String opt; + while ((opt = nextOption()) != null) { + if (opt.equals("-S")) { + sizeBytes = Long.parseLong(nextOptionData()); + } else { + throw new IllegalArgumentException("Unknown option: " + opt); + } + } + + final int sessionId = Integer.parseInt(nextArg()); + final String splitName = nextArg(); + + String path = nextArg(); + if ("-".equals(path)) { + path = null; + } else if (path != null) { + final File file = new File(path); + if (file.isFile()) { + sizeBytes = file.length(); + } + } + + final SessionInfo info = mInstaller.getSessionInfo(sessionId); + + PackageInstaller.Session session = null; + InputStream in = null; + OutputStream out = null; + try { + session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); + + if (path != null) { + in = new FileInputStream(path); + } else { + in = new SizedInputStream(System.in, sizeBytes); + } + out = session.openWrite(splitName, 0, sizeBytes); + + int total = 0; + byte[] buffer = new byte[65536]; + int c; + while ((c = in.read(buffer)) != -1) { + total += c; + out.write(buffer, 0, c); + + if (info.sizeBytes > 0) { + final float fraction = ((float) c / (float) info.sizeBytes); + session.addProgress(fraction); + } + } + session.fsync(out); + + System.out.println("Success: streamed " + total + " bytes"); + return 0; + } finally { + IoUtils.closeQuietly(out); + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(session); + } + } + + private int runInstallCommit() throws RemoteException { + final int sessionId = Integer.parseInt(nextArg()); + + PackageInstaller.Session session = null; + try { + session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); + + final LocalIntentReceiver receiver = new LocalIntentReceiver(); + session.commit(receiver.getIntentSender()); + + final Intent result = receiver.getResult(); + final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + if (status == PackageInstaller.STATUS_SUCCESS) { + System.out.println("Success"); + return 0; + } else { + Log.e(TAG, "Failure details: " + result.getExtras()); + System.err.println("Failure [" + + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); + return 1; + } + } finally { + IoUtils.closeQuietly(session); + } + } + + private int runInstallAbandon() throws RemoteException { + final int sessionId = Integer.parseInt(nextArg()); + + PackageInstaller.Session session = null; + try { + session = new PackageInstaller.Session(mInstaller.openSession(sessionId)); + session.abandon(); + System.out.println("Success"); + return 0; + } finally { + IoUtils.closeQuietly(session); + } + } + private int runSetInstaller() throws RemoteException { final String targetPackage = nextArg(); final String installerPackageName = nextArg(); @@ -711,6 +1080,80 @@ public final class Pm { } } + private int runUninstall() throws RemoteException { + int flags = 0; + int userId = UserHandle.USER_ALL; + + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-k")) { + flags |= PackageManager.DELETE_KEEP_DATA; + } else if (opt.equals("--user")) { + String param = nextArg(); + if (isNumber(param)) { + userId = Integer.parseInt(param); + } else { + showUsage(); + System.err.println("Error: Invalid user: " + param); + return 1; + } + } else { + System.err.println("Error: Unknown option: " + opt); + return 1; + } + } + + String pkg = nextArg(); + if (pkg == null) { + System.err.println("Error: no package specified"); + return showUsage(); + } + + userId = translateUserId(userId, "runUninstall"); + if (userId == UserHandle.USER_ALL) { + userId = UserHandle.USER_SYSTEM; + flags |= PackageManager.DELETE_ALL_USERS; + } else { + PackageInfo info; + try { + info = mPm.getPackageInfo(pkg, 0, userId); + } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); + return 1; + } + if (info == null) { + System.err.println("Failure - not installed for " + userId); + return 1; + } + final boolean isSystem = + (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + // If we are being asked to delete a system app for just one + // user set flag so it disables rather than reverting to system + // version of the app. + if (isSystem) { + flags |= PackageManager.DELETE_SYSTEM_APP; + } + } + + final LocalIntentReceiver receiver = new LocalIntentReceiver(); + mInstaller.uninstall(pkg, null /* callerPackageName */, flags, + receiver.getIntentSender(), userId); + + final Intent result = receiver.getResult(); + final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + if (status == PackageInstaller.STATUS_SUCCESS) { + System.out.println("Success"); + return 0; + } else { + Log.e(TAG, "Failure details: " + result.getExtras()); + System.err.println("Failure [" + + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); + return 1; + } + } + static class ClearDataObserver extends IPackageDataObserver.Stub { boolean finished; boolean result; @@ -1056,6 +1499,54 @@ public final class Pm { return 1; } + private static String checkAbiArgument(String abi) { + if (TextUtils.isEmpty(abi)) { + throw new IllegalArgumentException("Missing ABI argument"); + } + + if ("-".equals(abi)) { + return abi; + } + + final String[] supportedAbis = Build.SUPPORTED_ABIS; + for (String supportedAbi : supportedAbis) { + if (supportedAbi.equals(abi)) { + return abi; + } + } + + throw new IllegalArgumentException("ABI " + abi + " not supported on this device"); + } + + private static class LocalIntentReceiver { + private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>(); + + private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { + @Override + public int send(int code, Intent intent, String resolvedType, + IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { + try { + mResult.offer(intent, 5, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + return 0; + } + }; + + public IntentSender getIntentSender() { + return new IntentSender((IIntentSender) mLocalSender); + } + + public Intent getResult() { + try { + return mResult.take(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + private String nextOption() { if (mNextArg >= mArgs.length) { return null; diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java index cad482b6bab9..73c2c804bdf1 100644 --- a/core/java/android/os/ShellCommand.java +++ b/core/java/android/os/ShellCommand.java @@ -19,11 +19,8 @@ package android.os; import android.util.Slog; import com.android.internal.util.FastPrintWriter; -import java.io.BufferedInputStream; import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.InputStream; import java.io.PrintWriter; /** @@ -46,7 +43,6 @@ public abstract class ShellCommand { private FastPrintWriter mOutPrintWriter; private FastPrintWriter mErrPrintWriter; - private InputStream mInputStream; public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ResultReceiver resultReceiver) { @@ -115,13 +111,6 @@ public abstract class ShellCommand { return mErrPrintWriter; } - public InputStream getInputStream() { - if (mInputStream == null) { - mInputStream = new BufferedInputStream(new FileInputStream(mIn)); - } - return mInputStream; - } - /** * Return the next option on the command line -- that is an argument that * starts with '-'. If the next argument is not an option, null is returned. diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index d7176fd0776b..c259ac2b2fec 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -1,68 +1,28 @@ -/* - * Copyright (C) 2015 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.pm; -import android.app.ActivityManager; import android.content.ComponentName; -import android.content.IIntentReceiver; -import android.content.IIntentSender; -import android.content.Intent; -import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.FeatureInfo; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; -import android.content.pm.PackageInstaller; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; -import android.content.pm.PackageInstaller.SessionInfo; -import android.content.pm.PackageInstaller.SessionParams; import android.content.res.AssetManager; import android.content.res.Resources; -import android.net.Uri; -import android.os.Binder; -import android.os.Build; -import android.os.Bundle; import android.os.RemoteException; import android.os.ShellCommand; import android.os.UserHandle; -import android.text.TextUtils; - -import com.android.internal.util.SizedInputStream; - -import libcore.io.IoUtils; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.WeakHashMap; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.TimeUnit; class PackageManagerShellCommand extends ShellCommand { final IPackageManager mInterface; @@ -82,21 +42,8 @@ class PackageManagerShellCommand extends ShellCommand { final PrintWriter pw = getOutPrintWriter(); try { switch(cmd) { - case "install": - return runInstall(); - case "install-abandon": - case "install-destroy": - return runInstallAbandon(); - case "install-commit": - return runInstallCommit(); - case "install-create": - return runInstallCreate(); - case "install-write": - return runInstallWrite(); case "list": return runList(); - case "uninstall": - return runUninstall(); default: return handleDefaultCommands(cmd); } @@ -106,65 +53,6 @@ class PackageManagerShellCommand extends ShellCommand { return -1; } - private int runInstall() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - final InstallParams params = makeInstallParams(); - final int sessionId = doCreateSession(params.sessionParams, - params.installerPackageName, params.userId); - - final String inPath = getNextArg(); - if (inPath == null && params.sessionParams.sizeBytes == 0) { - pw.println("Error: must either specify a package size or an APK file"); - return 1; - } - if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk") != 0) { - return 1; - } - if (doCommitSession(sessionId) != 0) { - return 1; - } - return 0; - } - - private int runInstallAbandon() throws RemoteException { - final int sessionId = Integer.parseInt(getNextArg()); - return doAbandonSession(sessionId); - } - - private int runInstallCommit() throws RemoteException { - final int sessionId = Integer.parseInt(getNextArg()); - return doCommitSession(sessionId); - } - - private int runInstallCreate() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - final InstallParams installParams = makeInstallParams(); - final int sessionId = doCreateSession(installParams.sessionParams, - installParams.installerPackageName, installParams.userId); - - // NOTE: adb depends on parsing this string - pw.println("Success: created install session [" + sessionId + "]"); - return 0; - } - - private int runInstallWrite() throws RemoteException { - long sizeBytes = -1; - - String opt; - while ((opt = getNextOption()) != null) { - if (opt.equals("-S")) { - sizeBytes = Long.parseLong(getNextArg()); - } else { - throw new IllegalArgumentException("Unknown option: " + opt); - } - } - - final int sessionId = Integer.parseInt(getNextArg()); - final String splitName = getNextArg(); - final String path = getNextArg(); - return doWriteSession(sessionId, path, sizeBytes, splitName); - } - private int runList() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); final String type = getNextArg(); @@ -475,279 +363,6 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } - private int runUninstall() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - int flags = 0; - int userId = UserHandle.USER_ALL; - - String opt; - while ((opt = getNextOption()) != null) { - switch (opt) { - case "-k": - flags |= PackageManager.DELETE_KEEP_DATA; - break; - case "--user": - userId = Integer.parseInt(getNextArg()); - break; - default: - pw.println("Error: Unknown option: " + opt); - return 1; - } - } - - String packageName = getNextArg(); - if (packageName == null) { - pw.println("Error: package name not specified"); - return 1; - } - - userId = translateUserId(userId, "runUninstall"); - if (userId == UserHandle.USER_ALL) { - userId = UserHandle.USER_SYSTEM; - flags |= PackageManager.DELETE_ALL_USERS; - } else { - final PackageInfo info = mInterface.getPackageInfo(packageName, 0, userId); - if (info == null) { - pw.println("Failure - not installed for " + userId); - return 1; - } - final boolean isSystem = - (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; - // If we are being asked to delete a system app for just one - // user set flag so it disables rather than reverting to system - // version of the app. - if (isSystem) { - flags |= PackageManager.DELETE_SYSTEM_APP; - } - } - - final LocalIntentReceiver receiver = new LocalIntentReceiver(); - mInterface.getPackageInstaller().uninstall(packageName, null /*callerPackageName*/, flags, - receiver.getIntentSender(), userId); - - final Intent result = receiver.getResult(); - final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); - if (status == PackageInstaller.STATUS_SUCCESS) { - pw.println("Success"); - return 0; - } else { - pw.println("Failure [" - + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); - return 1; - } - } - - private static class InstallParams { - SessionParams sessionParams; - String installerPackageName; - int userId = UserHandle.USER_ALL; - } - - private InstallParams makeInstallParams() { - final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL); - final InstallParams params = new InstallParams(); - params.sessionParams = sessionParams; - String opt; - while ((opt = getNextOption()) != null) { - switch (opt) { - case "-l": - sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK; - break; - case "-r": - sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; - break; - case "-i": - params.installerPackageName = getNextArg(); - if (params.installerPackageName == null) { - throw new IllegalArgumentException("Missing installer package"); - } - break; - case "-t": - sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST; - break; - case "-s": - sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL; - break; - case "-f": - sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL; - break; - case "-d": - sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; - break; - case "-g": - sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS; - break; - case "--originating-uri": - sessionParams.originatingUri = Uri.parse(getNextArg()); - break; - case "--referrer": - sessionParams.referrerUri = Uri.parse(getNextArg()); - break; - case "-p": - sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING; - sessionParams.appPackageName = getNextArg(); - if (sessionParams.appPackageName == null) { - throw new IllegalArgumentException("Missing inherit package name"); - } - break; - case "-S": - sessionParams.setSize(Long.parseLong(getNextArg())); - break; - case "--abi": - sessionParams.abiOverride = checkAbiArgument(getNextArg()); - break; - case "--user": - params.userId = Integer.parseInt(getNextArg()); - break; - case "--install-location": - sessionParams.installLocation = Integer.parseInt(getNextArg()); - break; - case "--force-uuid": - sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID; - sessionParams.volumeUuid = getNextArg(); - if ("internal".equals(sessionParams.volumeUuid)) { - sessionParams.volumeUuid = null; - } - break; - default: - throw new IllegalArgumentException("Unknown option " + opt); - } - } - return params; - } - - private static String checkAbiArgument(String abi) { - if (TextUtils.isEmpty(abi)) { - throw new IllegalArgumentException("Missing ABI argument"); - } - - if ("-".equals(abi)) { - return abi; - } - - final String[] supportedAbis = Build.SUPPORTED_ABIS; - for (String supportedAbi : supportedAbis) { - if (supportedAbi.equals(abi)) { - return abi; - } - } - - throw new IllegalArgumentException("ABI " + abi + " not supported on this device"); - } - - private int translateUserId(int userId, String logContext) { - return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), - userId, true, true, logContext, "pm command"); - } - - private int doCreateSession(SessionParams params, String installerPackageName, int userId) - throws RemoteException { - userId = translateUserId(userId, "runInstallCreate"); - if (userId == UserHandle.USER_ALL) { - userId = UserHandle.USER_SYSTEM; - params.installFlags |= PackageManager.INSTALL_ALL_USERS; - } - - final int sessionId = mInterface.getPackageInstaller() - .createSession(params, installerPackageName, userId); - return sessionId; - } - - private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName) - throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - if ("-".equals(inPath)) { - inPath = null; - } else if (inPath != null) { - final File file = new File(inPath); - if (file.isFile()) { - sizeBytes = file.length(); - } - } - - final SessionInfo info = mInterface.getPackageInstaller().getSessionInfo(sessionId); - - PackageInstaller.Session session = null; - InputStream in = null; - OutputStream out = null; - try { - session = new PackageInstaller.Session( - mInterface.getPackageInstaller().openSession(sessionId)); - - if (inPath != null) { - in = new FileInputStream(inPath); - } else { - in = new SizedInputStream(getInputStream(), sizeBytes); - } - out = session.openWrite(splitName, 0, sizeBytes); - - int total = 0; - byte[] buffer = new byte[65536]; - int c; - while ((c = in.read(buffer)) != -1) { - total += c; - out.write(buffer, 0, c); - - if (info.sizeBytes > 0) { - final float fraction = ((float) c / (float) info.sizeBytes); - session.addProgress(fraction); - } - } - session.fsync(out); - - pw.println("Success: streamed " + total + " bytes"); - return 0; - } catch (IOException e) { - pw.println("Error: failed to write; " + e.getMessage()); - return 1; - } finally { - IoUtils.closeQuietly(out); - IoUtils.closeQuietly(in); - IoUtils.closeQuietly(session); - } - } - - private int doCommitSession(int sessionId) throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - PackageInstaller.Session session = null; - try { - session = new PackageInstaller.Session( - mInterface.getPackageInstaller().openSession(sessionId)); - - final LocalIntentReceiver receiver = new LocalIntentReceiver(); - session.commit(receiver.getIntentSender()); - - final Intent result = receiver.getResult(); - final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); - if (status == PackageInstaller.STATUS_SUCCESS) { - pw.println("Success"); - } else { - pw.println("Failure [" - + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); - pw.println("Failure details: " + result.getExtras()); - } - return status; - } finally { - IoUtils.closeQuietly(session); - } - } - - private int doAbandonSession(int sessionId) throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - PackageInstaller.Session session = null; - try { - session = new PackageInstaller.Session( - mInterface.getPackageInstaller().openSession(sessionId)); - session.abandon(); - pw.println("Success"); - return 0; - } finally { - IoUtils.closeQuietly(session); - } - } - private void doListPermissions(ArrayList<String> groupList, boolean groups, boolean labels, boolean summary, int startProtectionLevel, int endProtectionLevel) throws RemoteException { @@ -910,34 +525,5 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" -u: list only the permissions users will see"); pw.println(""); } - - private static class LocalIntentReceiver { - private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>(); - - private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { - @Override - public int send(int code, Intent intent, String resolvedType, - IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { - try { - mResult.offer(intent, 5, TimeUnit.SECONDS); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - return 0; - } - }; - - public IntentSender getIntentSender() { - return new IntentSender((IIntentSender) mLocalSender); - } - - public Intent getResult() { - try { - return mResult.take(); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } } |