OSDN Git Service

Return exit code 0 when the command run successfully
[android-x86/frameworks-base.git] / cmds / pm / src / com / android / commands / pm / Pm.java
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.commands.pm;
18
19 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
20 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
21 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
22 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
23 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
24
25 import android.accounts.IAccountManager;
26 import android.app.ActivityManager;
27 import android.app.PackageInstallObserver;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.IIntentReceiver;
31 import android.content.IIntentSender;
32 import android.content.Intent;
33 import android.content.IntentSender;
34 import android.content.pm.ApplicationInfo;
35 import android.content.pm.IPackageDataObserver;
36 import android.content.pm.IPackageInstaller;
37 import android.content.pm.IPackageManager;
38 import android.content.pm.PackageInfo;
39 import android.content.pm.PackageInstaller;
40 import android.content.pm.PackageInstaller.SessionInfo;
41 import android.content.pm.PackageInstaller.SessionParams;
42 import android.content.pm.PackageManager;
43 import android.content.pm.PackageParser;
44 import android.content.pm.PackageParser.ApkLite;
45 import android.content.pm.PackageParser.PackageLite;
46 import android.content.pm.PackageParser.PackageParserException;
47 import android.content.pm.UserInfo;
48 import android.net.Uri;
49 import android.os.Binder;
50 import android.os.Build;
51 import android.os.Bundle;
52 import android.os.Handler;
53 import android.os.HandlerThread;
54 import android.os.IBinder;
55 import android.os.IUserManager;
56 import android.os.ParcelFileDescriptor;
57 import android.os.Process;
58 import android.os.RemoteException;
59 import android.os.ResultReceiver;
60 import android.os.SELinux;
61 import android.os.ServiceManager;
62 import android.os.ShellCallback;
63 import android.os.SystemClock;
64 import android.os.UserHandle;
65 import android.os.UserManager;
66 import android.os.storage.StorageManager;
67 import android.text.TextUtils;
68 import android.text.format.DateUtils;
69 import android.util.Log;
70 import android.util.Pair;
71
72 import com.android.internal.content.PackageHelper;
73 import com.android.internal.util.ArrayUtils;
74 import com.android.internal.util.SizedInputStream;
75
76 import libcore.io.IoUtils;
77
78 import java.io.File;
79 import java.io.FileDescriptor;
80 import java.io.FileInputStream;
81 import java.io.FileNotFoundException;
82 import java.io.IOException;
83 import java.io.InputStream;
84 import java.io.OutputStream;
85 import java.util.concurrent.SynchronousQueue;
86 import java.util.concurrent.TimeUnit;
87
88 public final class Pm {
89     private static final String TAG = "Pm";
90     private static final String STDIN_PATH = "-";
91
92     IPackageManager mPm;
93     IPackageInstaller mInstaller;
94     IUserManager mUm;
95     IAccountManager mAm;
96
97     private String[] mArgs;
98     private int mNextArg;
99     private String mCurArgData;
100
101     private static final String PM_NOT_RUNNING_ERR =
102         "Error: Could not access the Package Manager.  Is the system running?";
103
104     public static void main(String[] args) {
105         int exitCode = 1;
106         try {
107             exitCode = new Pm().run(args);
108         } catch (Exception e) {
109             Log.e(TAG, "Error", e);
110             System.err.println("Error: " + e);
111             if (e instanceof RemoteException) {
112                 System.err.println(PM_NOT_RUNNING_ERR);
113             }
114         }
115         System.exit(exitCode);
116     }
117
118     public int run(String[] args) throws RemoteException {
119         boolean validCommand = false;
120         if (args.length < 1) {
121             return showUsage();
122         }
123         mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
124         mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
125         mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
126
127         if (mPm == null) {
128             System.err.println(PM_NOT_RUNNING_ERR);
129             return 1;
130         }
131         mInstaller = mPm.getPackageInstaller();
132
133         mArgs = args;
134         String op = args[0];
135         mNextArg = 1;
136
137         if ("list".equals(op)) {
138             return runList();
139         }
140
141         if ("path".equals(op)) {
142             return runPath();
143         }
144
145         if ("dump".equals(op)) {
146             return runDump();
147         }
148
149         if ("install".equals(op)) {
150             return runInstall();
151         }
152
153         if ("install-create".equals(op)) {
154             return runInstallCreate();
155         }
156
157         if ("install-write".equals(op)) {
158             return runInstallWrite();
159         }
160
161         if ("install-commit".equals(op)) {
162             return runInstallCommit();
163         }
164
165         if ("install-abandon".equals(op) || "install-destroy".equals(op)) {
166             return runInstallAbandon();
167         }
168
169         if ("set-installer".equals(op)) {
170             return runSetInstaller();
171         }
172
173         if ("uninstall".equals(op)) {
174             return runUninstall();
175         }
176
177         if ("clear".equals(op)) {
178             return runClear();
179         }
180
181         if ("enable".equals(op)) {
182             return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
183         }
184
185         if ("disable".equals(op)) {
186             return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
187         }
188
189         if ("disable-user".equals(op)) {
190             return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
191         }
192
193         if ("disable-until-used".equals(op)) {
194             return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
195         }
196
197         if ("default-state".equals(op)) {
198             return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
199         }
200
201         if ("hide".equals(op)) {
202             return runSetHiddenSetting(true);
203         }
204
205         if ("unhide".equals(op)) {
206             return runSetHiddenSetting(false);
207         }
208
209         if ("grant".equals(op)) {
210             return runGrantRevokePermission(true);
211         }
212
213         if ("revoke".equals(op)) {
214             return runGrantRevokePermission(false);
215         }
216
217         if ("reset-permissions".equals(op)) {
218             return runResetPermissions();
219         }
220
221         if ("set-permission-enforced".equals(op)) {
222             return runSetPermissionEnforced();
223         }
224
225         if ("set-app-link".equals(op)) {
226             return runSetAppLink();
227         }
228
229         if ("get-app-link".equals(op)) {
230             return runGetAppLink();
231         }
232
233         if ("set-install-location".equals(op)) {
234             return runSetInstallLocation();
235         }
236
237         if ("get-install-location".equals(op)) {
238             return runGetInstallLocation();
239         }
240
241         if ("trim-caches".equals(op)) {
242             return runTrimCaches();
243         }
244
245         if ("create-user".equals(op)) {
246             return runCreateUser();
247         }
248
249         if ("remove-user".equals(op)) {
250             return runRemoveUser();
251         }
252
253         if ("get-max-users".equals(op)) {
254             return runGetMaxUsers();
255         }
256
257         if ("force-dex-opt".equals(op)) {
258             return runForceDexOpt();
259         }
260
261         if ("move-package".equals(op)) {
262             return runMovePackage();
263         }
264
265         if ("move-primary-storage".equals(op)) {
266             return runMovePrimaryStorage();
267         }
268
269         if ("set-user-restriction".equals(op)) {
270             return runSetUserRestriction();
271         }
272
273         try {
274             if (args.length == 1) {
275                 if (args[0].equalsIgnoreCase("-l")) {
276                     validCommand = true;
277                     return runShellCommand("package", new String[] { "list", "package" });
278                 } else if (args[0].equalsIgnoreCase("-lf")) {
279                     validCommand = true;
280                     return runShellCommand("package", new String[] { "list", "package", "-f" });
281                 }
282             } else if (args.length == 2) {
283                 if (args[0].equalsIgnoreCase("-p")) {
284                     validCommand = true;
285                     return displayPackageFilePath(args[1], UserHandle.USER_SYSTEM);
286                 }
287             }
288             return 1;
289         } finally {
290             if (validCommand == false) {
291                 if (op != null) {
292                     System.err.println("Error: unknown command '" + op + "'");
293                 }
294                 showUsage();
295             }
296         }
297     }
298
299     static final class MyShellCallback extends ShellCallback {
300         @Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
301             File file = new File(path);
302             final ParcelFileDescriptor fd;
303             try {
304                 fd = ParcelFileDescriptor.open(file,
305                             ParcelFileDescriptor.MODE_CREATE |
306                             ParcelFileDescriptor.MODE_TRUNCATE |
307                             ParcelFileDescriptor.MODE_WRITE_ONLY);
308             } catch (FileNotFoundException e) {
309                 String msg = "Unable to open file " + path + ": " + e;
310                 System.err.println(msg);
311                 throw new IllegalArgumentException(msg);
312             }
313             if (seLinuxContext != null) {
314                 final String tcon = SELinux.getFileContext(file.getAbsolutePath());
315                 if (!SELinux.checkSELinuxAccess(seLinuxContext, tcon, "file", "write")) {
316                     try {
317                         fd.close();
318                     } catch (IOException e) {
319                     }
320                     String msg = "System server has no access to file context " + tcon;
321                     System.err.println(msg + " (from path " + file.getAbsolutePath()
322                             + ", context " + seLinuxContext + ")");
323                     throw new IllegalArgumentException(msg);
324                 }
325             }
326             return fd;
327         }
328     }
329
330     private int runShellCommand(String serviceName, String[] args) {
331         final HandlerThread handlerThread = new HandlerThread("results");
332         handlerThread.start();
333         try {
334             ServiceManager.getService(serviceName).shellCommand(
335                     FileDescriptor.in, FileDescriptor.out, FileDescriptor.err,
336                     args, new MyShellCallback(),
337                     new ResultReceiver(new Handler(handlerThread.getLooper())));
338             return 0;
339         } catch (RemoteException e) {
340             e.printStackTrace();
341         } finally {
342             handlerThread.quitSafely();
343         }
344         return -1;
345     }
346
347     private static class LocalIntentReceiver {
348         private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
349
350         private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
351             @Override
352             public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
353                     IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
354                 try {
355                     mResult.offer(intent, 5, TimeUnit.SECONDS);
356                 } catch (InterruptedException e) {
357                     throw new RuntimeException(e);
358                 }
359             }
360         };
361
362         public IntentSender getIntentSender() {
363             return new IntentSender((IIntentSender) mLocalSender);
364         }
365
366         public Intent getResult() {
367             try {
368                 return mResult.take();
369             } catch (InterruptedException e) {
370                 throw new RuntimeException(e);
371             }
372         }
373     }
374
375     private int translateUserId(int userId, String logContext) {
376         return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
377                 userId, true, true, logContext, "pm command");
378     }
379
380     private static String checkAbiArgument(String abi) {
381         if (TextUtils.isEmpty(abi)) {
382             throw new IllegalArgumentException("Missing ABI argument");
383         }
384         if ("-".equals(abi)) {
385             return abi;
386         }
387         final String[] supportedAbis = Build.SUPPORTED_ABIS;
388         for (String supportedAbi : supportedAbis) {
389             if (supportedAbi.equals(abi)) {
390                 return abi;
391             }
392         }
393         throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
394     }
395
396     /*
397      * Keep this around to support existing users of the "pm install" command that may not be
398      * able to be updated [or, at least informed the API has changed] such as ddmlib.
399      *
400      * Moving the implementation of "pm install" to "cmd package install" changes the executing
401      * context. Instead of being a stand alone process, "cmd package install" runs in the
402      * system_server process. Due to SELinux rules, system_server cannot access many directories;
403      * one of which being the package install staging directory [/data/local/tmp].
404      *
405      * The use of "adb install" or "cmd package install" over "pm install" is highly encouraged.
406      */
407     private int runInstall() throws RemoteException {
408         long startedTime = SystemClock.elapsedRealtime();
409         final InstallParams params = makeInstallParams();
410         final String inPath = nextArg();
411         if (params.sessionParams.sizeBytes == -1 && !STDIN_PATH.equals(inPath)) {
412             File file = new File(inPath);
413             if (file.isFile()) {
414                 try {
415                     ApkLite baseApk = PackageParser.parseApkLite(file, 0);
416                     PackageLite pkgLite = new PackageLite(null, baseApk, null, null, null, null,
417                             null, null);
418                     params.sessionParams.setSize(
419                             PackageHelper.calculateInstalledSize(pkgLite, false,
420                             params.sessionParams.abiOverride));
421                 } catch (PackageParserException | IOException e) {
422                     System.err.println("Error: Failed to parse APK file: " + e);
423                     return 1;
424                 }
425             } else {
426                 System.err.println("Error: Can't open non-file: " + inPath);
427                 return 1;
428             }
429         }
430
431         final int sessionId = doCreateSession(params.sessionParams,
432                 params.installerPackageName, params.userId);
433
434         try {
435             if (inPath == null && params.sessionParams.sizeBytes == -1) {
436                 System.err.println("Error: must either specify a package size or an APK file");
437                 return 1;
438             }
439             if (doWriteSession(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk",
440                     false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
441                 return 1;
442             }
443             Pair<String, Integer> status = doCommitSession(sessionId, false /*logSuccess*/);
444             if (status.second != PackageInstaller.STATUS_SUCCESS) {
445                 return 1;
446             }
447             Log.i(TAG, "Package " + status.first + " installed in " + (SystemClock.elapsedRealtime()
448                     - startedTime) + " ms");
449             System.out.println("Success");
450             return 0;
451         } finally {
452             try {
453                 mInstaller.abandonSession(sessionId);
454             } catch (Exception ignore) {
455             }
456         }
457     }
458
459     private int runInstallAbandon() throws RemoteException {
460         final int sessionId = Integer.parseInt(nextArg());
461         return doAbandonSession(sessionId, true /*logSuccess*/);
462     }
463
464     private int runInstallCommit() throws RemoteException {
465         final int sessionId = Integer.parseInt(nextArg());
466         return doCommitSession(sessionId, true /*logSuccess*/).second;
467     }
468
469     private int runInstallCreate() throws RemoteException {
470         final InstallParams installParams = makeInstallParams();
471         final int sessionId = doCreateSession(installParams.sessionParams,
472                 installParams.installerPackageName, installParams.userId);
473
474         // NOTE: adb depends on parsing this string
475         System.out.println("Success: created install session [" + sessionId + "]");
476         return PackageInstaller.STATUS_SUCCESS;
477     }
478
479     private int runInstallWrite() throws RemoteException {
480         long sizeBytes = -1;
481
482         String opt;
483         while ((opt = nextOption()) != null) {
484             if (opt.equals("-S")) {
485                 sizeBytes = Long.parseLong(nextArg());
486             } else {
487                 throw new IllegalArgumentException("Unknown option: " + opt);
488             }
489         }
490
491         final int sessionId = Integer.parseInt(nextArg());
492         final String splitName = nextArg();
493         final String path = nextArg();
494         return doWriteSession(sessionId, path, sizeBytes, splitName, true /*logSuccess*/);
495     }
496
497     private static class InstallParams {
498         SessionParams sessionParams;
499         String installerPackageName;
500         int userId = UserHandle.USER_ALL;
501     }
502
503     private InstallParams makeInstallParams() {
504         final SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);
505         final InstallParams params = new InstallParams();
506         params.sessionParams = sessionParams;
507         String opt;
508         while ((opt = nextOption()) != null) {
509             switch (opt) {
510                 case "-l":
511                     sessionParams.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
512                     break;
513                 case "-r":
514                     sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
515                     break;
516                 case "-i":
517                     params.installerPackageName = nextArg();
518                     if (params.installerPackageName == null) {
519                         throw new IllegalArgumentException("Missing installer package");
520                     }
521                     break;
522                 case "-t":
523                     sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
524                     break;
525                 case "-s":
526                     sessionParams.installFlags |= PackageManager.INSTALL_EXTERNAL;
527                     break;
528                 case "-f":
529                     sessionParams.installFlags |= PackageManager.INSTALL_INTERNAL;
530                     break;
531                 case "-d":
532                     sessionParams.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
533                     break;
534                 case "-g":
535                     sessionParams.installFlags |= PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS;
536                     break;
537                 case "--dont-kill":
538                     sessionParams.installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
539                     break;
540                 case "--originating-uri":
541                     sessionParams.originatingUri = Uri.parse(nextOptionData());
542                     break;
543                 case "--referrer":
544                     sessionParams.referrerUri = Uri.parse(nextOptionData());
545                     break;
546                 case "-p":
547                     sessionParams.mode = SessionParams.MODE_INHERIT_EXISTING;
548                     sessionParams.appPackageName = nextOptionData();
549                     if (sessionParams.appPackageName == null) {
550                         throw new IllegalArgumentException("Missing inherit package name");
551                     }
552                     break;
553                 case "--pkg":
554                     sessionParams.appPackageName = nextOptionData();
555                     if (sessionParams.appPackageName == null) {
556                         throw new IllegalArgumentException("Missing package name");
557                     }
558                     break;
559                 case "-S":
560                     final long sizeBytes = Long.parseLong(nextOptionData());
561                     if (sizeBytes <= 0) {
562                         throw new IllegalArgumentException("Size must be positive");
563                     }
564                     sessionParams.setSize(sizeBytes);
565                     break;
566                 case "--abi":
567                     sessionParams.abiOverride = checkAbiArgument(nextOptionData());
568                     break;
569                 case "--ephemeral":
570                 case "--instant":
571                     sessionParams.setInstallAsInstantApp(true /*isInstantApp*/);
572                     break;
573                 case "--full":
574                     sessionParams.setInstallAsInstantApp(false /*isInstantApp*/);
575                     break;
576                 case "--user":
577                     params.userId = UserHandle.parseUserArg(nextOptionData());
578                     break;
579                 case "--install-location":
580                     sessionParams.installLocation = Integer.parseInt(nextOptionData());
581                     break;
582                 case "--force-uuid":
583                     sessionParams.installFlags |= PackageManager.INSTALL_FORCE_VOLUME_UUID;
584                     sessionParams.volumeUuid = nextOptionData();
585                     if ("internal".equals(sessionParams.volumeUuid)) {
586                         sessionParams.volumeUuid = null;
587                     }
588                     break;
589                 case "--force-sdk":
590                     sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
591                     break;
592                 default:
593                     throw new IllegalArgumentException("Unknown option " + opt);
594             }
595         }
596         return params;
597     }
598
599     private int doCreateSession(SessionParams params, String installerPackageName, int userId)
600             throws RemoteException {
601         userId = translateUserId(userId, "runInstallCreate");
602         if (userId == UserHandle.USER_ALL) {
603             userId = UserHandle.USER_SYSTEM;
604             params.installFlags |= PackageManager.INSTALL_ALL_USERS;
605         }
606
607         final int sessionId = mInstaller.createSession(params, installerPackageName, userId);
608         return sessionId;
609     }
610
611     private int doWriteSession(int sessionId, String inPath, long sizeBytes, String splitName,
612             boolean logSuccess) throws RemoteException {
613         if (STDIN_PATH.equals(inPath)) {
614             inPath = null;
615         } else if (inPath != null) {
616             final File file = new File(inPath);
617             if (file.isFile()) {
618                 sizeBytes = file.length();
619             }
620         }
621
622         final SessionInfo info = mInstaller.getSessionInfo(sessionId);
623
624         PackageInstaller.Session session = null;
625         InputStream in = null;
626         OutputStream out = null;
627         try {
628             session = new PackageInstaller.Session(
629                     mInstaller.openSession(sessionId));
630
631             if (inPath != null) {
632                 in = new FileInputStream(inPath);
633             } else {
634                 in = new SizedInputStream(System.in, sizeBytes);
635             }
636             out = session.openWrite(splitName, 0, sizeBytes);
637
638             int total = 0;
639             byte[] buffer = new byte[65536];
640             int c;
641             while ((c = in.read(buffer)) != -1) {
642                 total += c;
643                 out.write(buffer, 0, c);
644
645                 if (info.sizeBytes > 0) {
646                     final float fraction = ((float) c / (float) info.sizeBytes);
647                     session.addProgress(fraction);
648                 }
649             }
650             session.fsync(out);
651
652             if (logSuccess) {
653                 System.out.println("Success: streamed " + total + " bytes");
654             }
655             return PackageInstaller.STATUS_SUCCESS;
656         } catch (IOException e) {
657             System.err.println("Error: failed to write; " + e.getMessage());
658             return PackageInstaller.STATUS_FAILURE;
659         } finally {
660             IoUtils.closeQuietly(out);
661             IoUtils.closeQuietly(in);
662             IoUtils.closeQuietly(session);
663         }
664     }
665
666     private Pair<String, Integer> doCommitSession(int sessionId, boolean logSuccess)
667             throws RemoteException {
668         PackageInstaller.Session session = null;
669         try {
670             session = new PackageInstaller.Session(
671                     mInstaller.openSession(sessionId));
672
673             final LocalIntentReceiver receiver = new LocalIntentReceiver();
674             session.commit(receiver.getIntentSender());
675
676             final Intent result = receiver.getResult();
677             final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
678                     PackageInstaller.STATUS_FAILURE);
679             if (status == PackageInstaller.STATUS_SUCCESS) {
680                 if (logSuccess) {
681                     System.out.println("Success");
682                 }
683             } else {
684                 System.err.println("Failure ["
685                         + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
686             }
687             return new Pair<>(result.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME), status);
688         } finally {
689             IoUtils.closeQuietly(session);
690         }
691     }
692
693     private int doAbandonSession(int sessionId, boolean logSuccess) throws RemoteException {
694         PackageInstaller.Session session = null;
695         try {
696             session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
697             session.abandon();
698             if (logSuccess) {
699                 System.out.println("Success");
700             }
701             return PackageInstaller.STATUS_SUCCESS;
702         } finally {
703             IoUtils.closeQuietly(session);
704         }
705     }
706
707     /**
708      * Execute the list sub-command.
709      *
710      * pm list [package | packages]
711      * pm list permission-groups
712      * pm list permissions
713      * pm list features
714      * pm list libraries
715      * pm list instrumentation
716      */
717     private int runList() {
718         final String type = nextArg();
719         if ("users".equals(type)) {
720             return runShellCommand("user", new String[] { "list" });
721         }
722         return runShellCommand("package", mArgs);
723     }
724
725     private int runUninstall() {
726         return runShellCommand("package", mArgs);
727     }
728
729     private int runPath() {
730         int userId = UserHandle.USER_SYSTEM;
731         String option = nextOption();
732         if (option != null && option.equals("--user")) {
733             String optionData = nextOptionData();
734             if (optionData == null || !isNumber(optionData)) {
735                 System.err.println("Error: no USER_ID specified");
736                 return showUsage();
737             } else {
738                 userId = Integer.parseInt(optionData);
739             }
740         }
741
742         String pkg = nextArg();
743         if (pkg == null) {
744             System.err.println("Error: no package specified");
745             return 1;
746         }
747         return displayPackageFilePath(pkg, userId);
748     }
749
750     private int runDump() {
751         String pkg = nextArg();
752         if (pkg == null) {
753             System.err.println("Error: no package specified");
754             return 1;
755         }
756         ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
757         return 0;
758     }
759
760     class LocalPackageInstallObserver extends PackageInstallObserver {
761         boolean finished;
762         int result;
763         String extraPermission;
764         String extraPackage;
765
766         @Override
767         public void onPackageInstalled(String name, int status, String msg, Bundle extras) {
768             synchronized (this) {
769                 finished = true;
770                 result = status;
771                 if (status == PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION) {
772                     extraPermission = extras.getString(
773                             PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION);
774                     extraPackage = extras.getString(
775                             PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
776                 }
777                 notifyAll();
778             }
779         }
780     }
781
782     // pm set-app-link [--user USER_ID] PACKAGE {always|ask|always-ask|never|undefined}
783     private int runSetAppLink() {
784         int userId = UserHandle.USER_SYSTEM;
785
786         String opt;
787         while ((opt = nextOption()) != null) {
788             if (opt.equals("--user")) {
789                 userId = Integer.parseInt(nextOptionData());
790                 if (userId < 0) {
791                     System.err.println("Error: user must be >= 0");
792                     return 1;
793                 }
794             } else {
795                 System.err.println("Error: unknown option: " + opt);
796                 return showUsage();
797             }
798         }
799
800         // Package name to act on; required
801         final String pkg = nextArg();
802         if (pkg == null) {
803             System.err.println("Error: no package specified.");
804             return showUsage();
805         }
806
807         // State to apply; {always|ask|never|undefined}, required
808         final String modeString = nextArg();
809         if (modeString == null) {
810             System.err.println("Error: no app link state specified.");
811             return showUsage();
812         }
813
814         final int newMode;
815         switch (modeString.toLowerCase()) {
816             case "undefined":
817                 newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
818                 break;
819
820             case "always":
821                 newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
822                 break;
823
824             case "ask":
825                 newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK;
826                 break;
827
828             case "always-ask":
829                 newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
830                 break;
831
832             case "never":
833                 newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
834                 break;
835
836             default:
837                 System.err.println("Error: unknown app link state '" + modeString + "'");
838                 return 1;
839         }
840
841         try {
842             final PackageInfo info = mPm.getPackageInfo(pkg, 0, userId);
843             if (info == null) {
844                 System.err.println("Error: package " + pkg + " not found.");
845                 return 1;
846             }
847
848             if ((info.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) == 0) {
849                 System.err.println("Error: package " + pkg + " does not handle web links.");
850                 return 1;
851             }
852
853             if (!mPm.updateIntentVerificationStatus(pkg, newMode, userId)) {
854                 System.err.println("Error: unable to update app link status for " + pkg);
855                 return 1;
856             }
857         } catch (Exception e) {
858             System.err.println(e.toString());
859             System.err.println(PM_NOT_RUNNING_ERR);
860             return 1;
861         }
862
863         return 0;
864     }
865
866     // pm get-app-link [--user USER_ID] PACKAGE
867     private int runGetAppLink() {
868         int userId = UserHandle.USER_SYSTEM;
869
870         String opt;
871         while ((opt = nextOption()) != null) {
872             if (opt.equals("--user")) {
873                 userId = Integer.parseInt(nextOptionData());
874                 if (userId < 0) {
875                     System.err.println("Error: user must be >= 0");
876                     return 1;
877                 }
878             } else {
879                 System.err.println("Error: unknown option: " + opt);
880                 return showUsage();
881             }
882         }
883
884         // Package name to act on; required
885         final String pkg = nextArg();
886         if (pkg == null) {
887             System.err.println("Error: no package specified.");
888             return showUsage();
889         }
890
891         try {
892             final PackageInfo info = mPm.getPackageInfo(pkg, 0, userId);
893             if (info == null) {
894                 System.err.println("Error: package " + pkg + " not found.");
895                 return 1;
896             }
897
898             if ((info.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) == 0) {
899                 System.err.println("Error: package " + pkg + " does not handle web links.");
900                 return 1;
901             }
902
903             System.out.println(linkStateToString(mPm.getIntentVerificationStatus(pkg, userId)));
904         } catch (Exception e) {
905             System.err.println(e.toString());
906             System.err.println(PM_NOT_RUNNING_ERR);
907             return 1;
908         }
909
910         return 0;
911     }
912
913     private String linkStateToString(int state) {
914         switch (state) {
915             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: return "undefined";
916             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: return "ask";
917             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: return "always";
918             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: return "never";
919             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK : return "always ask";
920         }
921         return "Unknown link state: " + state;
922     }
923
924     private int runSetInstallLocation() {
925         int loc;
926
927         String arg = nextArg();
928         if (arg == null) {
929             System.err.println("Error: no install location specified.");
930             return 1;
931         }
932         try {
933             loc = Integer.parseInt(arg);
934         } catch (NumberFormatException e) {
935             System.err.println("Error: install location has to be a number.");
936             return 1;
937         }
938         try {
939             if (!mPm.setInstallLocation(loc)) {
940                 System.err.println("Error: install location has to be a number.");
941                 return 1;
942             }
943             return 0;
944         } catch (RemoteException e) {
945             System.err.println(e.toString());
946             System.err.println(PM_NOT_RUNNING_ERR);
947             return 1;
948         }
949     }
950
951     private int runGetInstallLocation() {
952         try {
953             int loc = mPm.getInstallLocation();
954             String locStr = "invalid";
955             if (loc == PackageHelper.APP_INSTALL_AUTO) {
956                 locStr = "auto";
957             } else if (loc == PackageHelper.APP_INSTALL_INTERNAL) {
958                 locStr = "internal";
959             } else if (loc == PackageHelper.APP_INSTALL_EXTERNAL) {
960                 locStr = "external";
961             }
962             System.out.println(loc + "[" + locStr + "]");
963             return 0;
964         } catch (RemoteException e) {
965             System.err.println(e.toString());
966             System.err.println(PM_NOT_RUNNING_ERR);
967             return 1;
968         }
969     }
970
971     private int runSetInstaller() throws RemoteException {
972         final String targetPackage = nextArg();
973         final String installerPackageName = nextArg();
974
975         if (targetPackage == null || installerPackageName == null) {
976             throw new IllegalArgumentException(
977                     "must provide both target and installer package names");
978         }
979
980         mPm.setInstallerPackageName(targetPackage, installerPackageName);
981         System.out.println("Success");
982         return 0;
983     }
984
985     public int runCreateUser() {
986         String name;
987         int userId = -1;
988         int flags = 0;
989         String opt;
990         while ((opt = nextOption()) != null) {
991             if ("--profileOf".equals(opt)) {
992                 String optionData = nextOptionData();
993                 if (optionData == null || !isNumber(optionData)) {
994                     System.err.println("Error: no USER_ID specified");
995                     return showUsage();
996                 } else {
997                     userId = Integer.parseInt(optionData);
998                 }
999             } else if ("--managed".equals(opt)) {
1000                 flags |= UserInfo.FLAG_MANAGED_PROFILE;
1001             } else if ("--restricted".equals(opt)) {
1002                 flags |= UserInfo.FLAG_RESTRICTED;
1003             } else if ("--ephemeral".equals(opt)) {
1004                 flags |= UserInfo.FLAG_EPHEMERAL;
1005             } else if ("--guest".equals(opt)) {
1006                 flags |= UserInfo.FLAG_GUEST;
1007             } else if ("--demo".equals(opt)) {
1008                 flags |= UserInfo.FLAG_DEMO;
1009             } else {
1010                 System.err.println("Error: unknown option " + opt);
1011                 return showUsage();
1012             }
1013         }
1014         String arg = nextArg();
1015         if (arg == null) {
1016             System.err.println("Error: no user name specified.");
1017             return 1;
1018         }
1019         name = arg;
1020         try {
1021             UserInfo info;
1022             if ((flags & UserInfo.FLAG_RESTRICTED) != 0) {
1023                 // In non-split user mode, userId can only be SYSTEM
1024                 int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
1025                 info = mUm.createRestrictedProfile(name, parentUserId);
1026                 mAm.addSharedAccountsFromParentUser(parentUserId, userId,
1027                         (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell");
1028             } else if (userId < 0) {
1029                 info = mUm.createUser(name, flags);
1030             } else {
1031                 info = mUm.createProfileForUser(name, flags, userId, null);
1032             }
1033
1034             if (info != null) {
1035                 System.out.println("Success: created user id " + info.id);
1036                 return 0;
1037             } else {
1038                 System.err.println("Error: couldn't create User.");
1039                 return 1;
1040             }
1041         } catch (RemoteException e) {
1042             System.err.println(e.toString());
1043             System.err.println(PM_NOT_RUNNING_ERR);
1044             return 1;
1045         }
1046     }
1047
1048     public int runRemoveUser() {
1049         int userId;
1050         String arg = nextArg();
1051         if (arg == null) {
1052             System.err.println("Error: no user id specified.");
1053             return 1;
1054         }
1055         try {
1056             userId = Integer.parseInt(arg);
1057         } catch (NumberFormatException e) {
1058             System.err.println("Error: user id '" + arg + "' is not a number.");
1059             return 1;
1060         }
1061         try {
1062             if (mUm.removeUser(userId)) {
1063                 System.out.println("Success: removed user");
1064                 return 0;
1065             } else {
1066                 System.err.println("Error: couldn't remove user id " + userId);
1067                 return 1;
1068             }
1069         } catch (RemoteException e) {
1070             System.err.println(e.toString());
1071             System.err.println(PM_NOT_RUNNING_ERR);
1072             return 1;
1073         }
1074     }
1075
1076     public int runGetMaxUsers() {
1077         System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers());
1078         return 0;
1079     }
1080
1081     public int runForceDexOpt() {
1082         final String packageName = nextArg();
1083         try {
1084             mPm.forceDexOpt(packageName);
1085             return 0;
1086         } catch (RemoteException e) {
1087             throw e.rethrowAsRuntimeException();
1088         }
1089     }
1090
1091     public int runMovePackage() {
1092         final String packageName = nextArg();
1093         String volumeUuid = nextArg();
1094         if ("internal".equals(volumeUuid)) {
1095             volumeUuid = null;
1096         }
1097
1098         try {
1099             final int moveId = mPm.movePackage(packageName, volumeUuid);
1100
1101             int status = mPm.getMoveStatus(moveId);
1102             while (!PackageManager.isMoveStatusFinished(status)) {
1103                 SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
1104                 status = mPm.getMoveStatus(moveId);
1105             }
1106
1107             if (status == PackageManager.MOVE_SUCCEEDED) {
1108                 System.out.println("Success");
1109                 return 0;
1110             } else {
1111                 System.err.println("Failure [" + status + "]");
1112                 return 1;
1113             }
1114         } catch (RemoteException e) {
1115             throw e.rethrowAsRuntimeException();
1116         }
1117     }
1118
1119     public int runMovePrimaryStorage() {
1120         String volumeUuid = nextArg();
1121         if ("internal".equals(volumeUuid)) {
1122             volumeUuid = null;
1123         }
1124
1125         try {
1126             final int moveId = mPm.movePrimaryStorage(volumeUuid);
1127
1128             int status = mPm.getMoveStatus(moveId);
1129             while (!PackageManager.isMoveStatusFinished(status)) {
1130                 SystemClock.sleep(DateUtils.SECOND_IN_MILLIS);
1131                 status = mPm.getMoveStatus(moveId);
1132             }
1133
1134             if (status == PackageManager.MOVE_SUCCEEDED) {
1135                 System.out.println("Success");
1136                 return 0;
1137             } else {
1138                 System.err.println("Failure [" + status + "]");
1139                 return 1;
1140             }
1141         } catch (RemoteException e) {
1142             throw e.rethrowAsRuntimeException();
1143         }
1144     }
1145
1146     public int runSetUserRestriction() {
1147         int userId = UserHandle.USER_SYSTEM;
1148         String opt = nextOption();
1149         if (opt != null && "--user".equals(opt)) {
1150             String arg = nextArg();
1151             if (arg == null || !isNumber(arg)) {
1152                 System.err.println("Error: valid userId not specified");
1153                 return 1;
1154             }
1155             userId = Integer.parseInt(arg);
1156         }
1157
1158         String restriction = nextArg();
1159         String arg = nextArg();
1160         boolean value;
1161         if ("1".equals(arg)) {
1162             value = true;
1163         } else if ("0".equals(arg)) {
1164             value = false;
1165         } else {
1166             System.err.println("Error: valid value not specified");
1167             return 1;
1168         }
1169         try {
1170             mUm.setUserRestriction(restriction, value, userId);
1171             return 0;
1172         } catch (RemoteException e) {
1173             System.err.println(e.toString());
1174             return 1;
1175         }
1176     }
1177
1178     static class ClearDataObserver extends IPackageDataObserver.Stub {
1179         boolean finished;
1180         boolean result;
1181
1182         @Override
1183         public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
1184             synchronized (this) {
1185                 finished = true;
1186                 result = succeeded;
1187                 notifyAll();
1188             }
1189         }
1190     }
1191
1192     private int runClear() {
1193         int userId = UserHandle.USER_SYSTEM;
1194         String option = nextOption();
1195         if (option != null && option.equals("--user")) {
1196             String optionData = nextOptionData();
1197             if (optionData == null || !isNumber(optionData)) {
1198                 System.err.println("Error: no USER_ID specified");
1199                 return showUsage();
1200             } else {
1201                 userId = Integer.parseInt(optionData);
1202             }
1203         }
1204
1205         String pkg = nextArg();
1206         if (pkg == null) {
1207             System.err.println("Error: no package specified");
1208             return showUsage();
1209         }
1210
1211         ClearDataObserver obs = new ClearDataObserver();
1212         try {
1213             ActivityManager.getService().clearApplicationUserData(pkg, obs, userId);
1214             synchronized (obs) {
1215                 while (!obs.finished) {
1216                     try {
1217                         obs.wait();
1218                     } catch (InterruptedException e) {
1219                     }
1220                 }
1221             }
1222
1223             if (obs.result) {
1224                 System.out.println("Success");
1225                 return 0;
1226             } else {
1227                 System.err.println("Failed");
1228                 return 1;
1229             }
1230         } catch (RemoteException e) {
1231             System.err.println(e.toString());
1232             System.err.println(PM_NOT_RUNNING_ERR);
1233             return 1;
1234         }
1235     }
1236
1237     private static String enabledSettingToString(int state) {
1238         switch (state) {
1239             case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:
1240                 return "default";
1241             case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:
1242                 return "enabled";
1243             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
1244                 return "disabled";
1245             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:
1246                 return "disabled-user";
1247             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:
1248                 return "disabled-until-used";
1249         }
1250         return "unknown";
1251     }
1252
1253     private static boolean isNumber(String s) {
1254         try {
1255             Integer.parseInt(s);
1256         } catch (NumberFormatException nfe) {
1257             return false;
1258         }
1259         return true;
1260     }
1261
1262     private int runSetEnabledSetting(int state) {
1263         int userId = UserHandle.USER_SYSTEM;
1264         String option = nextOption();
1265         if (option != null && option.equals("--user")) {
1266             String optionData = nextOptionData();
1267             if (optionData == null || !isNumber(optionData)) {
1268                 System.err.println("Error: no USER_ID specified");
1269                 return showUsage();
1270             } else {
1271                 userId = Integer.parseInt(optionData);
1272             }
1273         }
1274
1275         String pkg = nextArg();
1276         if (pkg == null) {
1277             System.err.println("Error: no package or component specified");
1278             return showUsage();
1279         }
1280         ComponentName cn = ComponentName.unflattenFromString(pkg);
1281         if (cn == null) {
1282             try {
1283                 mPm.setApplicationEnabledSetting(pkg, state, 0, userId,
1284                         "shell:" + android.os.Process.myUid());
1285                 System.out.println("Package " + pkg + " new state: "
1286                         + enabledSettingToString(
1287                         mPm.getApplicationEnabledSetting(pkg, userId)));
1288                 return 0;
1289             } catch (RemoteException e) {
1290                 System.err.println(e.toString());
1291                 System.err.println(PM_NOT_RUNNING_ERR);
1292                 return 1;
1293             }
1294         } else {
1295             try {
1296                 mPm.setComponentEnabledSetting(cn, state, 0, userId);
1297                 System.out.println("Component " + cn.toShortString() + " new state: "
1298                         + enabledSettingToString(
1299                         mPm.getComponentEnabledSetting(cn, userId)));
1300                 return 0;
1301             } catch (RemoteException e) {
1302                 System.err.println(e.toString());
1303                 System.err.println(PM_NOT_RUNNING_ERR);
1304                 return 1;
1305             }
1306         }
1307     }
1308
1309     private int runSetHiddenSetting(boolean state) {
1310         int userId = UserHandle.USER_SYSTEM;
1311         String option = nextOption();
1312         if (option != null && option.equals("--user")) {
1313             String optionData = nextOptionData();
1314             if (optionData == null || !isNumber(optionData)) {
1315                 System.err.println("Error: no USER_ID specified");
1316                 return showUsage();
1317             } else {
1318                 userId = Integer.parseInt(optionData);
1319             }
1320         }
1321
1322         String pkg = nextArg();
1323         if (pkg == null) {
1324             System.err.println("Error: no package or component specified");
1325             return showUsage();
1326         }
1327         try {
1328             mPm.setApplicationHiddenSettingAsUser(pkg, state, userId);
1329             System.out.println("Package " + pkg + " new hidden state: "
1330                     + mPm.getApplicationHiddenSettingAsUser(pkg, userId));
1331             return 0;
1332         } catch (RemoteException e) {
1333             System.err.println(e.toString());
1334             System.err.println(PM_NOT_RUNNING_ERR);
1335             return 1;
1336         }
1337     }
1338
1339     private int runGrantRevokePermission(boolean grant) {
1340         int userId = UserHandle.USER_SYSTEM;
1341
1342         String opt = null;
1343         while ((opt = nextOption()) != null) {
1344             if (opt.equals("--user")) {
1345                 userId = Integer.parseInt(nextArg());
1346             }
1347         }
1348
1349         String pkg = nextArg();
1350         if (pkg == null) {
1351             System.err.println("Error: no package specified");
1352             return showUsage();
1353         }
1354         String perm = nextArg();
1355         if (perm == null) {
1356             System.err.println("Error: no permission specified");
1357             return showUsage();
1358         }
1359
1360         try {
1361             if (grant) {
1362                 mPm.grantRuntimePermission(pkg, perm, userId);
1363             } else {
1364                 mPm.revokeRuntimePermission(pkg, perm, userId);
1365             }
1366             return 0;
1367         } catch (RemoteException e) {
1368             System.err.println(e.toString());
1369             System.err.println(PM_NOT_RUNNING_ERR);
1370             return 1;
1371         } catch (IllegalArgumentException e) {
1372             System.err.println("Bad argument: " + e.toString());
1373             return showUsage();
1374         } catch (SecurityException e) {
1375             System.err.println("Operation not allowed: " + e.toString());
1376             return 1;
1377         }
1378     }
1379
1380     private int runResetPermissions() {
1381         try {
1382             mPm.resetRuntimePermissions();
1383             return 0;
1384         } catch (RemoteException e) {
1385             System.err.println(e.toString());
1386             System.err.println(PM_NOT_RUNNING_ERR);
1387             return 1;
1388         } catch (IllegalArgumentException e) {
1389             System.err.println("Bad argument: " + e.toString());
1390             return showUsage();
1391         } catch (SecurityException e) {
1392             System.err.println("Operation not allowed: " + e.toString());
1393             return 1;
1394         }
1395     }
1396
1397     private int runSetPermissionEnforced() {
1398         final String permission = nextArg();
1399         if (permission == null) {
1400             System.err.println("Error: no permission specified");
1401             return showUsage();
1402         }
1403         final String enforcedRaw = nextArg();
1404         if (enforcedRaw == null) {
1405             System.err.println("Error: no enforcement specified");
1406             return showUsage();
1407         }
1408         final boolean enforced = Boolean.parseBoolean(enforcedRaw);
1409         try {
1410             mPm.setPermissionEnforced(permission, enforced);
1411             return 0;
1412         } catch (RemoteException e) {
1413             System.err.println(e.toString());
1414             System.err.println(PM_NOT_RUNNING_ERR);
1415             return 1;
1416         } catch (IllegalArgumentException e) {
1417             System.err.println("Bad argument: " + e.toString());
1418             return showUsage();
1419         } catch (SecurityException e) {
1420             System.err.println("Operation not allowed: " + e.toString());
1421             return 1;
1422         }
1423     }
1424
1425     static class ClearCacheObserver extends IPackageDataObserver.Stub {
1426         boolean finished;
1427         boolean result;
1428
1429         @Override
1430         public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
1431             synchronized (this) {
1432                 finished = true;
1433                 result = succeeded;
1434                 notifyAll();
1435             }
1436         }
1437
1438     }
1439
1440     private int runTrimCaches() {
1441         String size = nextArg();
1442         if (size == null) {
1443             System.err.println("Error: no size specified");
1444             return showUsage();
1445         }
1446         long multiplier = 1;
1447         int len = size.length();
1448         char c = size.charAt(len - 1);
1449         if (c < '0' || c > '9') {
1450             if (c == 'K' || c == 'k') {
1451                 multiplier = 1024L;
1452             } else if (c == 'M' || c == 'm') {
1453                 multiplier = 1024L*1024L;
1454             } else if (c == 'G' || c == 'g') {
1455                 multiplier = 1024L*1024L*1024L;
1456             } else {
1457                 System.err.println("Invalid suffix: " + c);
1458                 return showUsage();
1459             }
1460             size = size.substring(0, len-1);
1461         }
1462         long sizeVal;
1463         try {
1464             sizeVal = Long.parseLong(size) * multiplier;
1465         } catch (NumberFormatException e) {
1466             System.err.println("Error: expected number at: " + size);
1467             return showUsage();
1468         }
1469         String volumeUuid = nextArg();
1470         if ("internal".equals(volumeUuid)) {
1471             volumeUuid = null;
1472         }
1473         ClearDataObserver obs = new ClearDataObserver();
1474         try {
1475             mPm.freeStorageAndNotify(volumeUuid, sizeVal,
1476                     StorageManager.FLAG_ALLOCATE_DEFY_RESERVED, obs);
1477             synchronized (obs) {
1478                 while (!obs.finished) {
1479                     try {
1480                         obs.wait();
1481                     } catch (InterruptedException e) {
1482                     }
1483                 }
1484             }
1485             return 0;
1486         } catch (RemoteException e) {
1487             System.err.println(e.toString());
1488             System.err.println(PM_NOT_RUNNING_ERR);
1489             return 1;
1490         } catch (IllegalArgumentException e) {
1491             System.err.println("Bad argument: " + e.toString());
1492             return showUsage();
1493         } catch (SecurityException e) {
1494             System.err.println("Operation not allowed: " + e.toString());
1495             return 1;
1496         }
1497     }
1498
1499     /**
1500      * Displays the package file for a package.
1501      * @param pckg
1502      */
1503     private int displayPackageFilePath(String pckg, int userId) {
1504         try {
1505             PackageInfo info = mPm.getPackageInfo(pckg, 0, userId);
1506             if (info != null && info.applicationInfo != null) {
1507                 System.out.print("package:");
1508                 System.out.println(info.applicationInfo.sourceDir);
1509                 if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
1510                     for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
1511                         System.out.print("package:");
1512                         System.out.println(splitSourceDir);
1513                     }
1514                 }
1515                 return 0;
1516             }
1517         } catch (RemoteException e) {
1518             System.err.println(e.toString());
1519             System.err.println(PM_NOT_RUNNING_ERR);
1520         }
1521         return 1;
1522     }
1523
1524     private String nextOption() {
1525         if (mNextArg >= mArgs.length) {
1526             return null;
1527         }
1528         String arg = mArgs[mNextArg];
1529         if (!arg.startsWith("-")) {
1530             return null;
1531         }
1532         mNextArg++;
1533         if (arg.equals("--")) {
1534             return null;
1535         }
1536         if (arg.length() > 1 && arg.charAt(1) != '-') {
1537             if (arg.length() > 2) {
1538                 mCurArgData = arg.substring(2);
1539                 return arg.substring(0, 2);
1540             } else {
1541                 mCurArgData = null;
1542                 return arg;
1543             }
1544         }
1545         mCurArgData = null;
1546         return arg;
1547     }
1548
1549     private String nextOptionData() {
1550         if (mCurArgData != null) {
1551             return mCurArgData;
1552         }
1553         if (mNextArg >= mArgs.length) {
1554             return null;
1555         }
1556         String data = mArgs[mNextArg];
1557         mNextArg++;
1558         return data;
1559     }
1560
1561     private String nextArg() {
1562         if (mNextArg >= mArgs.length) {
1563             return null;
1564         }
1565         String arg = mArgs[mNextArg];
1566         mNextArg++;
1567         return arg;
1568     }
1569
1570     private static int showUsage() {
1571         System.err.println("usage: pm path [--user USER_ID] PACKAGE");
1572         System.err.println("       pm dump PACKAGE");
1573         System.err.println("       pm install [-lrtsfd] [-i PACKAGE] [--user USER_ID] [PATH]");
1574         System.err.println("       pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]");
1575         System.err.println("               [--install-location 0/1/2]");
1576         System.err.println("               [--force-uuid internal|UUID]");
1577         System.err.println("       pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]");
1578         System.err.println("       pm install-commit SESSION_ID");
1579         System.err.println("       pm install-abandon SESSION_ID");
1580         System.err.println("       pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE");
1581         System.err.println("       pm set-installer PACKAGE INSTALLER");
1582         System.err.println("       pm move-package PACKAGE [internal|UUID]");
1583         System.err.println("       pm move-primary-storage [internal|UUID]");
1584         System.err.println("       pm clear [--user USER_ID] PACKAGE");
1585         System.err.println("       pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
1586         System.err.println("       pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
1587         System.err.println("       pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
1588         System.err.println("       pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
1589         System.err.println("       pm default-state [--user USER_ID] PACKAGE_OR_COMPONENT");
1590         System.err.println("       pm set-user-restriction [--user USER_ID] RESTRICTION VALUE");
1591         System.err.println("       pm hide [--user USER_ID] PACKAGE_OR_COMPONENT");
1592         System.err.println("       pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
1593         System.err.println("       pm grant [--user USER_ID] PACKAGE PERMISSION");
1594         System.err.println("       pm revoke [--user USER_ID] PACKAGE PERMISSION");
1595         System.err.println("       pm reset-permissions");
1596         System.err.println("       pm set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}");
1597         System.err.println("       pm get-app-link [--user USER_ID] PACKAGE");
1598         System.err.println("       pm set-install-location [0/auto] [1/internal] [2/external]");
1599         System.err.println("       pm get-install-location");
1600         System.err.println("       pm set-permission-enforced PERMISSION [true|false]");
1601         System.err.println("       pm trim-caches DESIRED_FREE_SPACE [internal|UUID]");
1602         System.err.println("       pm create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral] [--guest] USER_NAME");
1603         System.err.println("       pm remove-user USER_ID");
1604         System.err.println("       pm get-max-users");
1605         System.err.println("");
1606         System.err.println("NOTE: 'pm list' commands have moved! Run 'adb shell cmd package'");
1607         System.err.println("  to display the new commands.");
1608         System.err.println("");
1609         System.err.println("pm path: print the path to the .apk of the given PACKAGE.");
1610         System.err.println("");
1611         System.err.println("pm dump: print system state associated with the given PACKAGE.");
1612         System.err.println("");
1613         System.err.println("pm install: install a single legacy package");
1614         System.err.println("pm install-create: create an install session");
1615         System.err.println("    -l: forward lock application");
1616         System.err.println("    -r: replace existing application");
1617         System.err.println("    -t: allow test packages");
1618         System.err.println("    -i: specify the installer package name");
1619         System.err.println("    -s: install application on sdcard");
1620         System.err.println("    -f: install application on internal flash");
1621         System.err.println("    -d: allow version code downgrade (debuggable packages only)");
1622         System.err.println("    -p: partial application install");
1623         System.err.println("    -g: grant all runtime permissions");
1624         System.err.println("    -S: size in bytes of entire session");
1625         System.err.println("");
1626         System.err.println("pm install-write: write a package into existing session; path may");
1627         System.err.println("  be '-' to read from stdin");
1628         System.err.println("    -S: size in bytes of package, required for stdin");
1629         System.err.println("");
1630         System.err.println("pm install-commit: perform install of fully staged session");
1631         System.err.println("pm install-abandon: abandon session");
1632         System.err.println("");
1633         System.err.println("pm set-installer: set installer package name");
1634         System.err.println("");
1635         System.err.println("pm uninstall: removes a package from the system. Options:");
1636         System.err.println("    -k: keep the data and cache directories around after package removal.");
1637         System.err.println("");
1638         System.err.println("pm clear: deletes all data associated with a package.");
1639         System.err.println("");
1640         System.err.println("pm enable, disable, disable-user, disable-until-used, default-state:");
1641         System.err.println("  these commands change the enabled state of a given package or");
1642         System.err.println("  component (written as \"package/class\").");
1643         System.err.println("");
1644         System.err.println("pm grant, revoke: these commands either grant or revoke permissions");
1645         System.err.println("    to apps. The permissions must be declared as used in the app's");
1646         System.err.println("    manifest, be runtime permissions (protection level dangerous),");
1647         System.err.println("    and the app targeting SDK greater than Lollipop MR1.");
1648         System.err.println("");
1649         System.err.println("pm reset-permissions: revert all runtime permissions to their default state.");
1650         System.err.println("");
1651         System.err.println("pm get-install-location: returns the current install location.");
1652         System.err.println("    0 [auto]: Let system decide the best location");
1653         System.err.println("    1 [internal]: Install on internal device storage");
1654         System.err.println("    2 [external]: Install on external media");
1655         System.err.println("");
1656         System.err.println("pm set-install-location: changes the default install location.");
1657         System.err.println("  NOTE: this is only intended for debugging; using this can cause");
1658         System.err.println("  applications to break and other undersireable behavior.");
1659         System.err.println("    0 [auto]: Let system decide the best location");
1660         System.err.println("    1 [internal]: Install on internal device storage");
1661         System.err.println("    2 [external]: Install on external media");
1662         System.err.println("");
1663         System.err.println("pm trim-caches: trim cache files to reach the given free space.");
1664         System.err.println("");
1665         System.err.println("pm create-user: create a new user with the given USER_NAME,");
1666         System.err.println("  printing the new user identifier of the user.");
1667         System.err.println("");
1668         System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,");
1669         System.err.println("  deleting all data associated with that user");
1670         System.err.println("");
1671         return 1;
1672     }
1673 }