Pm.java revision 5e03e2ca7d25b899b129baad2dd5eca6bf99d88a
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 17package com.android.commands.pm; 18 19import com.android.internal.content.PackageHelper; 20 21import android.app.ActivityManagerNative; 22import android.content.ComponentName; 23import android.content.pm.ApplicationInfo; 24import android.content.pm.ContainerEncryptionParams; 25import android.content.pm.FeatureInfo; 26import android.content.pm.IPackageDataObserver; 27import android.content.pm.IPackageDeleteObserver; 28import android.content.pm.IPackageInstallObserver; 29import android.content.pm.IPackageManager; 30import android.content.pm.InstrumentationInfo; 31import android.content.pm.PackageInfo; 32import android.content.pm.PackageItemInfo; 33import android.content.pm.PackageManager; 34import android.content.pm.ParceledListSlice; 35import android.content.pm.PermissionGroupInfo; 36import android.content.pm.PermissionInfo; 37import android.content.pm.UserInfo; 38import android.content.pm.VerificationParams; 39import android.content.res.AssetManager; 40import android.content.res.Resources; 41import android.net.Uri; 42import android.os.IUserManager; 43import android.os.RemoteException; 44import android.os.ServiceManager; 45 46import java.io.File; 47import java.lang.reflect.Field; 48import java.lang.reflect.Modifier; 49import java.security.InvalidAlgorithmParameterException; 50import java.util.ArrayList; 51import java.util.Collections; 52import java.util.Comparator; 53import java.util.List; 54import java.util.WeakHashMap; 55 56import javax.crypto.SecretKey; 57import javax.crypto.spec.IvParameterSpec; 58import javax.crypto.spec.SecretKeySpec; 59 60public final class Pm { 61 IPackageManager mPm; 62 IUserManager mUm; 63 64 private WeakHashMap<String, Resources> mResourceCache 65 = new WeakHashMap<String, Resources>(); 66 67 private String[] mArgs; 68 private int mNextArg; 69 private String mCurArgData; 70 71 private static final String PM_NOT_RUNNING_ERR = 72 "Error: Could not access the Package Manager. Is the system running?"; 73 74 public static void main(String[] args) { 75 new Pm().run(args); 76 } 77 78 public void run(String[] args) { 79 boolean validCommand = false; 80 if (args.length < 1) { 81 showUsage(); 82 return; 83 } 84 85 mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user")); 86 mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 87 if (mPm == null) { 88 System.err.println(PM_NOT_RUNNING_ERR); 89 return; 90 } 91 92 mArgs = args; 93 String op = args[0]; 94 mNextArg = 1; 95 96 if ("list".equals(op)) { 97 runList(); 98 return; 99 } 100 101 if ("path".equals(op)) { 102 runPath(); 103 return; 104 } 105 106 if ("install".equals(op)) { 107 runInstall(); 108 return; 109 } 110 111 if ("uninstall".equals(op)) { 112 runUninstall(); 113 return; 114 } 115 116 if ("clear".equals(op)) { 117 runClear(); 118 return; 119 } 120 121 if ("enable".equals(op)) { 122 runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); 123 return; 124 } 125 126 if ("disable".equals(op)) { 127 runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); 128 return; 129 } 130 131 if ("disable-user".equals(op)) { 132 runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER); 133 return; 134 } 135 136 if ("grant".equals(op)) { 137 runGrantRevokePermission(true); 138 return; 139 } 140 141 if ("revoke".equals(op)) { 142 runGrantRevokePermission(false); 143 return; 144 } 145 146 if ("set-permission-enforced".equals(op)) { 147 runSetPermissionEnforced(); 148 return; 149 } 150 151 if ("set-install-location".equals(op)) { 152 runSetInstallLocation(); 153 return; 154 } 155 156 if ("get-install-location".equals(op)) { 157 runGetInstallLocation(); 158 return; 159 } 160 161 if ("trim-caches".equals(op)) { 162 runTrimCaches(); 163 return; 164 } 165 166 if ("create-user".equals(op)) { 167 runCreateUser(); 168 return; 169 } 170 171 if ("remove-user".equals(op)) { 172 runRemoveUser(); 173 return; 174 } 175 176 try { 177 if (args.length == 1) { 178 if (args[0].equalsIgnoreCase("-l")) { 179 validCommand = true; 180 runListPackages(false); 181 } else if (args[0].equalsIgnoreCase("-lf")){ 182 validCommand = true; 183 runListPackages(true); 184 } 185 } else if (args.length == 2) { 186 if (args[0].equalsIgnoreCase("-p")) { 187 validCommand = true; 188 displayPackageFilePath(args[1]); 189 } 190 } 191 } finally { 192 if (validCommand == false) { 193 if (op != null) { 194 System.err.println("Error: unknown command '" + op + "'"); 195 } 196 showUsage(); 197 } 198 } 199 } 200 201 /** 202 * Execute the list sub-command. 203 * 204 * pm list [package | packages] 205 * pm list permission-groups 206 * pm list permissions 207 * pm list features 208 * pm list libraries 209 * pm list instrumentation 210 */ 211 private void runList() { 212 String type = nextArg(); 213 if (type == null) { 214 System.err.println("Error: didn't specify type of data to list"); 215 return; 216 } 217 if ("package".equals(type) || "packages".equals(type)) { 218 runListPackages(false); 219 } else if ("permission-groups".equals(type)) { 220 runListPermissionGroups(); 221 } else if ("permissions".equals(type)) { 222 runListPermissions(); 223 } else if ("features".equals(type)) { 224 runListFeatures(); 225 } else if ("libraries".equals(type)) { 226 runListLibraries(); 227 } else if ("instrumentation".equals(type)) { 228 runListInstrumentation(); 229 } else if ("users".equals(type)) { 230 runListUsers(); 231 } else { 232 System.err.println("Error: unknown list type '" + type + "'"); 233 } 234 } 235 236 /** 237 * Lists all the installed packages. 238 */ 239 private void runListPackages(boolean showApplicationPackage) { 240 int getFlags = 0; 241 boolean listDisabled = false, listEnabled = false; 242 boolean listSystem = false, listThirdParty = false; 243 boolean listInstaller = false; 244 try { 245 String opt; 246 while ((opt=nextOption()) != null) { 247 if (opt.equals("-l")) { 248 // old compat 249 } else if (opt.equals("-lf")) { 250 showApplicationPackage = true; 251 } else if (opt.equals("-f")) { 252 showApplicationPackage = true; 253 } else if (opt.equals("-d")) { 254 listDisabled = true; 255 } else if (opt.equals("-e")) { 256 listEnabled = true; 257 } else if (opt.equals("-s")) { 258 listSystem = true; 259 } else if (opt.equals("-3")) { 260 listThirdParty = true; 261 } else if (opt.equals("-i")) { 262 listInstaller = true; 263 } else if (opt.equals("-u")) { 264 getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES; 265 } else { 266 System.err.println("Error: Unknown option: " + opt); 267 return; 268 } 269 } 270 } catch (RuntimeException ex) { 271 System.err.println("Error: " + ex.toString()); 272 return; 273 } 274 275 String filter = nextArg(); 276 277 try { 278 final List<PackageInfo> packages = getInstalledPackages(mPm, getFlags); 279 280 int count = packages.size(); 281 for (int p = 0 ; p < count ; p++) { 282 PackageInfo info = packages.get(p); 283 if (filter != null && !info.packageName.contains(filter)) { 284 continue; 285 } 286 final boolean isSystem = 287 (info.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0; 288 if ((!listDisabled || !info.applicationInfo.enabled) && 289 (!listEnabled || info.applicationInfo.enabled) && 290 (!listSystem || isSystem) && 291 (!listThirdParty || !isSystem)) { 292 System.out.print("package:"); 293 if (showApplicationPackage) { 294 System.out.print(info.applicationInfo.sourceDir); 295 System.out.print("="); 296 } 297 System.out.print(info.packageName); 298 if (listInstaller) { 299 System.out.print(" installer="); 300 System.out.print(mPm.getInstallerPackageName(info.packageName)); 301 } 302 System.out.println(); 303 } 304 } 305 } catch (RemoteException e) { 306 System.err.println(e.toString()); 307 System.err.println(PM_NOT_RUNNING_ERR); 308 } 309 } 310 311 @SuppressWarnings("unchecked") 312 private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags) 313 throws RemoteException { 314 final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>(); 315 PackageInfo lastItem = null; 316 ParceledListSlice<PackageInfo> slice; 317 318 do { 319 final String lastKey = lastItem != null ? lastItem.packageName : null; 320 slice = pm.getInstalledPackages(flags, lastKey); 321 lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR); 322 } while (!slice.isLastSlice()); 323 324 return packageInfos; 325 } 326 327 /** 328 * Lists all of the features supported by the current device. 329 * 330 * pm list features 331 */ 332 private void runListFeatures() { 333 try { 334 List<FeatureInfo> list = new ArrayList<FeatureInfo>(); 335 FeatureInfo[] rawList = mPm.getSystemAvailableFeatures(); 336 for (int i=0; i<rawList.length; i++) { 337 list.add(rawList[i]); 338 } 339 340 341 // Sort by name 342 Collections.sort(list, new Comparator<FeatureInfo>() { 343 public int compare(FeatureInfo o1, FeatureInfo o2) { 344 if (o1.name == o2.name) return 0; 345 if (o1.name == null) return -1; 346 if (o2.name == null) return 1; 347 return o1.name.compareTo(o2.name); 348 } 349 }); 350 351 int count = (list != null) ? list.size() : 0; 352 for (int p = 0; p < count; p++) { 353 FeatureInfo fi = list.get(p); 354 System.out.print("feature:"); 355 if (fi.name != null) System.out.println(fi.name); 356 else System.out.println("reqGlEsVersion=0x" 357 + Integer.toHexString(fi.reqGlEsVersion)); 358 } 359 } catch (RemoteException e) { 360 System.err.println(e.toString()); 361 System.err.println(PM_NOT_RUNNING_ERR); 362 } 363 } 364 365 /** 366 * Lists all of the libraries supported by the current device. 367 * 368 * pm list libraries 369 */ 370 private void runListLibraries() { 371 try { 372 List<String> list = new ArrayList<String>(); 373 String[] rawList = mPm.getSystemSharedLibraryNames(); 374 for (int i=0; i<rawList.length; i++) { 375 list.add(rawList[i]); 376 } 377 378 379 // Sort by name 380 Collections.sort(list, new Comparator<String>() { 381 public int compare(String o1, String o2) { 382 if (o1 == o2) return 0; 383 if (o1 == null) return -1; 384 if (o2 == null) return 1; 385 return o1.compareTo(o2); 386 } 387 }); 388 389 int count = (list != null) ? list.size() : 0; 390 for (int p = 0; p < count; p++) { 391 String lib = list.get(p); 392 System.out.print("library:"); 393 System.out.println(lib); 394 } 395 } catch (RemoteException e) { 396 System.err.println(e.toString()); 397 System.err.println(PM_NOT_RUNNING_ERR); 398 } 399 } 400 401 /** 402 * Lists all of the installed instrumentation, or all for a given package 403 * 404 * pm list instrumentation [package] [-f] 405 */ 406 private void runListInstrumentation() { 407 int flags = 0; // flags != 0 is only used to request meta-data 408 boolean showPackage = false; 409 String targetPackage = null; 410 411 try { 412 String opt; 413 while ((opt=nextArg()) != null) { 414 if (opt.equals("-f")) { 415 showPackage = true; 416 } else if (opt.charAt(0) != '-') { 417 targetPackage = opt; 418 } else { 419 System.err.println("Error: Unknown option: " + opt); 420 return; 421 } 422 } 423 } catch (RuntimeException ex) { 424 System.err.println("Error: " + ex.toString()); 425 return; 426 } 427 428 try { 429 List<InstrumentationInfo> list = mPm.queryInstrumentation(targetPackage, flags); 430 431 // Sort by target package 432 Collections.sort(list, new Comparator<InstrumentationInfo>() { 433 public int compare(InstrumentationInfo o1, InstrumentationInfo o2) { 434 return o1.targetPackage.compareTo(o2.targetPackage); 435 } 436 }); 437 438 int count = (list != null) ? list.size() : 0; 439 for (int p = 0; p < count; p++) { 440 InstrumentationInfo ii = list.get(p); 441 System.out.print("instrumentation:"); 442 if (showPackage) { 443 System.out.print(ii.sourceDir); 444 System.out.print("="); 445 } 446 ComponentName cn = new ComponentName(ii.packageName, ii.name); 447 System.out.print(cn.flattenToShortString()); 448 System.out.print(" (target="); 449 System.out.print(ii.targetPackage); 450 System.out.println(")"); 451 } 452 } catch (RemoteException e) { 453 System.err.println(e.toString()); 454 System.err.println(PM_NOT_RUNNING_ERR); 455 } 456 } 457 458 /** 459 * Lists all the known permission groups. 460 */ 461 private void runListPermissionGroups() { 462 try { 463 List<PermissionGroupInfo> pgs = mPm.getAllPermissionGroups(0); 464 465 int count = pgs.size(); 466 for (int p = 0 ; p < count ; p++) { 467 PermissionGroupInfo pgi = pgs.get(p); 468 System.out.print("permission group:"); 469 System.out.println(pgi.name); 470 } 471 } catch (RemoteException e) { 472 System.err.println(e.toString()); 473 System.err.println(PM_NOT_RUNNING_ERR); 474 } 475 } 476 477 private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized) { 478 if (nonLocalized != null) { 479 return nonLocalized.toString(); 480 } 481 if (res != 0) { 482 Resources r = getResources(pii); 483 if (r != null) { 484 return r.getString(res); 485 } 486 } 487 return null; 488 } 489 490 /** 491 * Lists all the permissions in a group. 492 */ 493 private void runListPermissions() { 494 try { 495 boolean labels = false; 496 boolean groups = false; 497 boolean userOnly = false; 498 boolean summary = false; 499 boolean dangerousOnly = false; 500 String opt; 501 while ((opt=nextOption()) != null) { 502 if (opt.equals("-f")) { 503 labels = true; 504 } else if (opt.equals("-g")) { 505 groups = true; 506 } else if (opt.equals("-s")) { 507 groups = true; 508 labels = true; 509 summary = true; 510 } else if (opt.equals("-u")) { 511 userOnly = true; 512 } else if (opt.equals("-d")) { 513 dangerousOnly = true; 514 } else { 515 System.err.println("Error: Unknown option: " + opt); 516 return; 517 } 518 } 519 520 String grp = nextOption(); 521 ArrayList<String> groupList = new ArrayList<String>(); 522 if (groups) { 523 List<PermissionGroupInfo> infos = 524 mPm.getAllPermissionGroups(0); 525 for (int i=0; i<infos.size(); i++) { 526 groupList.add(infos.get(i).name); 527 } 528 groupList.add(null); 529 } else { 530 groupList.add(grp); 531 } 532 533 if (dangerousOnly) { 534 System.out.println("Dangerous Permissions:"); 535 System.out.println(""); 536 doListPermissions(groupList, groups, labels, summary, 537 PermissionInfo.PROTECTION_DANGEROUS, 538 PermissionInfo.PROTECTION_DANGEROUS); 539 if (userOnly) { 540 System.out.println("Normal Permissions:"); 541 System.out.println(""); 542 doListPermissions(groupList, groups, labels, summary, 543 PermissionInfo.PROTECTION_NORMAL, 544 PermissionInfo.PROTECTION_NORMAL); 545 } 546 } else if (userOnly) { 547 System.out.println("Dangerous and Normal Permissions:"); 548 System.out.println(""); 549 doListPermissions(groupList, groups, labels, summary, 550 PermissionInfo.PROTECTION_NORMAL, 551 PermissionInfo.PROTECTION_DANGEROUS); 552 } else { 553 System.out.println("All Permissions:"); 554 System.out.println(""); 555 doListPermissions(groupList, groups, labels, summary, 556 -10000, 10000); 557 } 558 } catch (RemoteException e) { 559 System.err.println(e.toString()); 560 System.err.println(PM_NOT_RUNNING_ERR); 561 } 562 } 563 564 private void doListPermissions(ArrayList<String> groupList, 565 boolean groups, boolean labels, boolean summary, 566 int startProtectionLevel, int endProtectionLevel) 567 throws RemoteException { 568 for (int i=0; i<groupList.size(); i++) { 569 String groupName = groupList.get(i); 570 String prefix = ""; 571 if (groups) { 572 if (i > 0) System.out.println(""); 573 if (groupName != null) { 574 PermissionGroupInfo pgi = mPm.getPermissionGroupInfo( 575 groupName, 0); 576 if (summary) { 577 Resources res = getResources(pgi); 578 if (res != null) { 579 System.out.print(loadText(pgi, pgi.labelRes, 580 pgi.nonLocalizedLabel) + ": "); 581 } else { 582 System.out.print(pgi.name + ": "); 583 584 } 585 } else { 586 System.out.println((labels ? "+ " : "") 587 + "group:" + pgi.name); 588 if (labels) { 589 System.out.println(" package:" + pgi.packageName); 590 Resources res = getResources(pgi); 591 if (res != null) { 592 System.out.println(" label:" 593 + loadText(pgi, pgi.labelRes, 594 pgi.nonLocalizedLabel)); 595 System.out.println(" description:" 596 + loadText(pgi, pgi.descriptionRes, 597 pgi.nonLocalizedDescription)); 598 } 599 } 600 } 601 } else { 602 System.out.println(((labels && !summary) 603 ? "+ " : "") + "ungrouped:"); 604 } 605 prefix = " "; 606 } 607 List<PermissionInfo> ps = mPm.queryPermissionsByGroup( 608 groupList.get(i), 0); 609 int count = ps.size(); 610 boolean first = true; 611 for (int p = 0 ; p < count ; p++) { 612 PermissionInfo pi = ps.get(p); 613 if (groups && groupName == null && pi.group != null) { 614 continue; 615 } 616 final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; 617 if (base < startProtectionLevel 618 || base > endProtectionLevel) { 619 continue; 620 } 621 if (summary) { 622 if (first) { 623 first = false; 624 } else { 625 System.out.print(", "); 626 } 627 Resources res = getResources(pi); 628 if (res != null) { 629 System.out.print(loadText(pi, pi.labelRes, 630 pi.nonLocalizedLabel)); 631 } else { 632 System.out.print(pi.name); 633 } 634 } else { 635 System.out.println(prefix + (labels ? "+ " : "") 636 + "permission:" + pi.name); 637 if (labels) { 638 System.out.println(prefix + " package:" + pi.packageName); 639 Resources res = getResources(pi); 640 if (res != null) { 641 System.out.println(prefix + " label:" 642 + loadText(pi, pi.labelRes, 643 pi.nonLocalizedLabel)); 644 System.out.println(prefix + " description:" 645 + loadText(pi, pi.descriptionRes, 646 pi.nonLocalizedDescription)); 647 } 648 System.out.println(prefix + " protectionLevel:" 649 + PermissionInfo.protectionToString(pi.protectionLevel)); 650 } 651 } 652 } 653 654 if (summary) { 655 System.out.println(""); 656 } 657 } 658 } 659 660 private void runPath() { 661 String pkg = nextArg(); 662 if (pkg == null) { 663 System.err.println("Error: no package specified"); 664 return; 665 } 666 displayPackageFilePath(pkg); 667 } 668 669 class PackageInstallObserver extends IPackageInstallObserver.Stub { 670 boolean finished; 671 int result; 672 673 public void packageInstalled(String name, int status) { 674 synchronized( this) { 675 finished = true; 676 result = status; 677 notifyAll(); 678 } 679 } 680 } 681 682 /** 683 * Converts a failure code into a string by using reflection to find a matching constant 684 * in PackageManager. 685 */ 686 private String installFailureToString(int result) { 687 Field[] fields = PackageManager.class.getFields(); 688 for (Field f: fields) { 689 if (f.getType() == int.class) { 690 int modifiers = f.getModifiers(); 691 // only look at public final static fields. 692 if (((modifiers & Modifier.FINAL) != 0) && 693 ((modifiers & Modifier.PUBLIC) != 0) && 694 ((modifiers & Modifier.STATIC) != 0)) { 695 String fieldName = f.getName(); 696 if (fieldName.startsWith("INSTALL_FAILED_") || 697 fieldName.startsWith("INSTALL_PARSE_FAILED_")) { 698 // get the int value and compare it to result. 699 try { 700 if (result == f.getInt(null)) { 701 return fieldName; 702 } 703 } catch (IllegalAccessException e) { 704 // this shouldn't happen since we only look for public static fields. 705 } 706 } 707 } 708 } 709 } 710 711 // couldn't find a matching constant? return the value 712 return Integer.toString(result); 713 } 714 715 private void runSetInstallLocation() { 716 int loc; 717 718 String arg = nextArg(); 719 if (arg == null) { 720 System.err.println("Error: no install location specified."); 721 return; 722 } 723 try { 724 loc = Integer.parseInt(arg); 725 } catch (NumberFormatException e) { 726 System.err.println("Error: install location has to be a number."); 727 return; 728 } 729 try { 730 if (!mPm.setInstallLocation(loc)) { 731 System.err.println("Error: install location has to be a number."); 732 } 733 } catch (RemoteException e) { 734 System.err.println(e.toString()); 735 System.err.println(PM_NOT_RUNNING_ERR); 736 } 737 } 738 739 private void runGetInstallLocation() { 740 try { 741 int loc = mPm.getInstallLocation(); 742 String locStr = "invalid"; 743 if (loc == PackageHelper.APP_INSTALL_AUTO) { 744 locStr = "auto"; 745 } else if (loc == PackageHelper.APP_INSTALL_INTERNAL) { 746 locStr = "internal"; 747 } else if (loc == PackageHelper.APP_INSTALL_EXTERNAL) { 748 locStr = "external"; 749 } 750 System.out.println(loc + "[" + locStr + "]"); 751 } catch (RemoteException e) { 752 System.err.println(e.toString()); 753 System.err.println(PM_NOT_RUNNING_ERR); 754 } 755 } 756 757 private void runInstall() { 758 int installFlags = PackageManager.INSTALL_ALL_USERS; 759 String installerPackageName = null; 760 761 String opt; 762 763 String algo = null; 764 byte[] iv = null; 765 byte[] key = null; 766 767 String macAlgo = null; 768 byte[] macKey = null; 769 byte[] tag = null; 770 String originatingUriString = null; 771 String referrer = null; 772 773 while ((opt=nextOption()) != null) { 774 if (opt.equals("-l")) { 775 installFlags |= PackageManager.INSTALL_FORWARD_LOCK; 776 } else if (opt.equals("-r")) { 777 installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; 778 } else if (opt.equals("-i")) { 779 installerPackageName = nextOptionData(); 780 if (installerPackageName == null) { 781 System.err.println("Error: no value specified for -i"); 782 return; 783 } 784 } else if (opt.equals("-t")) { 785 installFlags |= PackageManager.INSTALL_ALLOW_TEST; 786 } else if (opt.equals("-s")) { 787 // Override if -s option is specified. 788 installFlags |= PackageManager.INSTALL_EXTERNAL; 789 } else if (opt.equals("-f")) { 790 // Override if -s option is specified. 791 installFlags |= PackageManager.INSTALL_INTERNAL; 792 } else if (opt.equals("-d")) { 793 installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE; 794 } else if (opt.equals("--algo")) { 795 algo = nextOptionData(); 796 if (algo == null) { 797 System.err.println("Error: must supply argument for --algo"); 798 return; 799 } 800 } else if (opt.equals("--iv")) { 801 iv = hexToBytes(nextOptionData()); 802 if (iv == null) { 803 System.err.println("Error: must supply argument for --iv"); 804 return; 805 } 806 } else if (opt.equals("--key")) { 807 key = hexToBytes(nextOptionData()); 808 if (key == null) { 809 System.err.println("Error: must supply argument for --key"); 810 return; 811 } 812 } else if (opt.equals("--macalgo")) { 813 macAlgo = nextOptionData(); 814 if (macAlgo == null) { 815 System.err.println("Error: must supply argument for --macalgo"); 816 return; 817 } 818 } else if (opt.equals("--mackey")) { 819 macKey = hexToBytes(nextOptionData()); 820 if (macKey == null) { 821 System.err.println("Error: must supply argument for --mackey"); 822 return; 823 } 824 } else if (opt.equals("--tag")) { 825 tag = hexToBytes(nextOptionData()); 826 if (tag == null) { 827 System.err.println("Error: must supply argument for --tag"); 828 return; 829 } 830 } else if (opt.equals("--originating-uri")) { 831 originatingUriString = nextOptionData(); 832 if (originatingUriString == null) { 833 System.err.println("Error: must supply argument for --originating-uri"); 834 return; 835 } 836 } else if (opt.equals("--referrer")) { 837 referrer = nextOptionData(); 838 if (referrer == null) { 839 System.err.println("Error: must supply argument for --referrer"); 840 return; 841 } 842 } else { 843 System.err.println("Error: Unknown option: " + opt); 844 return; 845 } 846 } 847 848 final ContainerEncryptionParams encryptionParams; 849 if (algo != null || iv != null || key != null || macAlgo != null || macKey != null 850 || tag != null) { 851 if (algo == null || iv == null || key == null) { 852 System.err.println("Error: all of --algo, --iv, and --key must be specified"); 853 return; 854 } 855 856 if (macAlgo != null || macKey != null || tag != null) { 857 if (macAlgo == null || macKey == null || tag == null) { 858 System.err.println("Error: all of --macalgo, --mackey, and --tag must " 859 + "be specified"); 860 return; 861 } 862 } 863 864 try { 865 final SecretKey encKey = new SecretKeySpec(key, "RAW"); 866 867 final SecretKey macSecretKey; 868 if (macKey == null || macKey.length == 0) { 869 macSecretKey = null; 870 } else { 871 macSecretKey = new SecretKeySpec(macKey, "RAW"); 872 } 873 874 encryptionParams = new ContainerEncryptionParams(algo, new IvParameterSpec(iv), 875 encKey, macAlgo, null, macSecretKey, tag, -1, -1, -1); 876 } catch (InvalidAlgorithmParameterException e) { 877 e.printStackTrace(); 878 return; 879 } 880 } else { 881 encryptionParams = null; 882 } 883 884 final Uri apkURI; 885 final Uri verificationURI; 886 final Uri originatingURI; 887 final Uri referrerURI; 888 889 if (originatingUriString != null) { 890 originatingURI = Uri.parse(originatingUriString); 891 } else { 892 originatingURI = null; 893 } 894 895 if (referrer != null) { 896 referrerURI = Uri.parse(referrer); 897 } else { 898 referrerURI = null; 899 } 900 901 // Populate apkURI, must be present 902 final String apkFilePath = nextArg(); 903 System.err.println("\tpkg: " + apkFilePath); 904 if (apkFilePath != null) { 905 apkURI = Uri.fromFile(new File(apkFilePath)); 906 } else { 907 System.err.println("Error: no package specified"); 908 return; 909 } 910 911 // Populate verificationURI, optionally present 912 final String verificationFilePath = nextArg(); 913 if (verificationFilePath != null) { 914 System.err.println("\tver: " + verificationFilePath); 915 verificationURI = Uri.fromFile(new File(verificationFilePath)); 916 } else { 917 verificationURI = null; 918 } 919 920 PackageInstallObserver obs = new PackageInstallObserver(); 921 try { 922 VerificationParams verificationParams = new VerificationParams(verificationURI, 923 originatingURI, referrerURI, null); 924 925 mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags, 926 installerPackageName, verificationParams, encryptionParams); 927 928 synchronized (obs) { 929 while (!obs.finished) { 930 try { 931 obs.wait(); 932 } catch (InterruptedException e) { 933 } 934 } 935 if (obs.result == PackageManager.INSTALL_SUCCEEDED) { 936 System.out.println("Success"); 937 } else { 938 System.err.println("Failure [" 939 + installFailureToString(obs.result) 940 + "]"); 941 } 942 } 943 } catch (RemoteException e) { 944 System.err.println(e.toString()); 945 System.err.println(PM_NOT_RUNNING_ERR); 946 } 947 } 948 949 /** 950 * Convert a string containing hex-encoded bytes to a byte array. 951 * 952 * @param input String containing hex-encoded bytes 953 * @return input as an array of bytes 954 */ 955 private byte[] hexToBytes(String input) { 956 if (input == null) { 957 return null; 958 } 959 960 final int inputLength = input.length(); 961 if ((inputLength % 2) != 0) { 962 System.err.print("Invalid length; must be multiple of 2"); 963 return null; 964 } 965 966 final int byteLength = inputLength / 2; 967 final byte[] output = new byte[byteLength]; 968 969 int inputIndex = 0; 970 int byteIndex = 0; 971 while (inputIndex < inputLength) { 972 output[byteIndex++] = (byte) Integer.parseInt( 973 input.substring(inputIndex, inputIndex + 2), 16); 974 inputIndex += 2; 975 } 976 977 return output; 978 } 979 980 public void runCreateUser() { 981 String name; 982 String arg = nextArg(); 983 if (arg == null) { 984 System.err.println("Error: no user name specified."); 985 return; 986 } 987 name = arg; 988 try { 989 if (mUm.createUser(name, 0) == null) { 990 System.err.println("Error: couldn't create User."); 991 } 992 } catch (RemoteException e) { 993 System.err.println(e.toString()); 994 System.err.println(PM_NOT_RUNNING_ERR); 995 } 996 997 } 998 999 public void runRemoveUser() { 1000 int userId; 1001 String arg = nextArg(); 1002 if (arg == null) { 1003 System.err.println("Error: no user id specified."); 1004 return; 1005 } 1006 try { 1007 userId = Integer.parseInt(arg); 1008 } catch (NumberFormatException e) { 1009 System.err.println("Error: user id '" + arg + "' is not a number."); 1010 return; 1011 } 1012 try { 1013 if (!mUm.removeUser(userId)) { 1014 System.err.println("Error: couldn't remove user #" + userId + "."); 1015 } 1016 } catch (RemoteException e) { 1017 System.err.println(e.toString()); 1018 System.err.println(PM_NOT_RUNNING_ERR); 1019 } 1020 } 1021 1022 public void runListUsers() { 1023 try { 1024 List<UserInfo> users = mUm.getUsers(); 1025 if (users == null) { 1026 System.err.println("Error: couldn't get users"); 1027 } else { 1028 System.out.println("Users:"); 1029 for (int i = 0; i < users.size(); i++) { 1030 System.out.println("\t" + users.get(i).toString()); 1031 } 1032 } 1033 } catch (RemoteException e) { 1034 System.err.println(e.toString()); 1035 System.err.println(PM_NOT_RUNNING_ERR); 1036 } 1037 } 1038 class PackageDeleteObserver extends IPackageDeleteObserver.Stub { 1039 boolean finished; 1040 boolean result; 1041 1042 public void packageDeleted(String packageName, int returnCode) { 1043 synchronized (this) { 1044 finished = true; 1045 result = returnCode == PackageManager.DELETE_SUCCEEDED; 1046 notifyAll(); 1047 } 1048 } 1049 } 1050 1051 private void runUninstall() { 1052 int unInstallFlags = PackageManager.DELETE_ALL_USERS; 1053 1054 String opt; 1055 while ((opt=nextOption()) != null) { 1056 if (opt.equals("-k")) { 1057 unInstallFlags |= PackageManager.DELETE_KEEP_DATA; 1058 } else { 1059 System.err.println("Error: Unknown option: " + opt); 1060 return; 1061 } 1062 } 1063 1064 String pkg = nextArg(); 1065 if (pkg == null) { 1066 System.err.println("Error: no package specified"); 1067 showUsage(); 1068 return; 1069 } 1070 boolean result = deletePackage(pkg, unInstallFlags); 1071 if (result) { 1072 System.out.println("Success"); 1073 } else { 1074 System.out.println("Failure"); 1075 } 1076 } 1077 1078 private boolean deletePackage(String pkg, int unInstallFlags) { 1079 PackageDeleteObserver obs = new PackageDeleteObserver(); 1080 try { 1081 mPm.deletePackage(pkg, obs, unInstallFlags); 1082 1083 synchronized (obs) { 1084 while (!obs.finished) { 1085 try { 1086 obs.wait(); 1087 } catch (InterruptedException e) { 1088 } 1089 } 1090 } 1091 } catch (RemoteException e) { 1092 System.err.println(e.toString()); 1093 System.err.println(PM_NOT_RUNNING_ERR); 1094 } 1095 return obs.result; 1096 } 1097 1098 static class ClearDataObserver extends IPackageDataObserver.Stub { 1099 boolean finished; 1100 boolean result; 1101 1102 @Override 1103 public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { 1104 synchronized (this) { 1105 finished = true; 1106 result = succeeded; 1107 notifyAll(); 1108 } 1109 } 1110 1111 } 1112 1113 private void runClear() { 1114 String pkg = nextArg(); 1115 if (pkg == null) { 1116 System.err.println("Error: no package specified"); 1117 showUsage(); 1118 return; 1119 } 1120 1121 ClearDataObserver obs = new ClearDataObserver(); 1122 try { 1123 // XXX TO DO: add user arg 1124 if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, 0)) { 1125 System.err.println("Failed"); 1126 } 1127 1128 synchronized (obs) { 1129 while (!obs.finished) { 1130 try { 1131 obs.wait(); 1132 } catch (InterruptedException e) { 1133 } 1134 } 1135 } 1136 1137 if (obs.result) { 1138 System.err.println("Success"); 1139 } else { 1140 System.err.println("Failed"); 1141 } 1142 } catch (RemoteException e) { 1143 System.err.println(e.toString()); 1144 System.err.println(PM_NOT_RUNNING_ERR); 1145 } 1146 } 1147 1148 private static String enabledSettingToString(int state) { 1149 switch (state) { 1150 case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: 1151 return "default"; 1152 case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: 1153 return "enabled"; 1154 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: 1155 return "disabled"; 1156 case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: 1157 return "disabled-user"; 1158 } 1159 return "unknown"; 1160 } 1161 1162 private boolean isNumber(String s) { 1163 try { 1164 Integer.parseInt(s); 1165 } catch (NumberFormatException nfe) { 1166 return false; 1167 } 1168 return true; 1169 } 1170 1171 private void runSetEnabledSetting(int state) { 1172 int userId = 0; 1173 String option = nextOption(); 1174 if (option != null && option.equals("--user")) { 1175 String optionData = nextOptionData(); 1176 if (optionData == null || !isNumber(optionData)) { 1177 System.err.println("Error: no USER_ID specified"); 1178 showUsage(); 1179 return; 1180 } else { 1181 userId = Integer.parseInt(optionData); 1182 } 1183 } 1184 1185 String pkg = nextArg(); 1186 if (pkg == null) { 1187 System.err.println("Error: no package or component specified"); 1188 showUsage(); 1189 return; 1190 } 1191 ComponentName cn = ComponentName.unflattenFromString(pkg); 1192 if (cn == null) { 1193 try { 1194 mPm.setApplicationEnabledSetting(pkg, state, 0, userId); 1195 System.err.println("Package " + pkg + " new state: " 1196 + enabledSettingToString( 1197 mPm.getApplicationEnabledSetting(pkg, userId))); 1198 } catch (RemoteException e) { 1199 System.err.println(e.toString()); 1200 System.err.println(PM_NOT_RUNNING_ERR); 1201 } 1202 } else { 1203 try { 1204 mPm.setComponentEnabledSetting(cn, state, 0, userId); 1205 System.err.println("Component " + cn.toShortString() + " new state: " 1206 + enabledSettingToString( 1207 mPm.getComponentEnabledSetting(cn, userId))); 1208 } catch (RemoteException e) { 1209 System.err.println(e.toString()); 1210 System.err.println(PM_NOT_RUNNING_ERR); 1211 } 1212 } 1213 } 1214 1215 private void runGrantRevokePermission(boolean grant) { 1216 String pkg = nextArg(); 1217 if (pkg == null) { 1218 System.err.println("Error: no package specified"); 1219 showUsage(); 1220 return; 1221 } 1222 String perm = nextArg(); 1223 if (perm == null) { 1224 System.err.println("Error: no permission specified"); 1225 showUsage(); 1226 return; 1227 } 1228 try { 1229 if (grant) { 1230 mPm.grantPermission(pkg, perm); 1231 } else { 1232 mPm.revokePermission(pkg, perm); 1233 } 1234 } catch (RemoteException e) { 1235 System.err.println(e.toString()); 1236 System.err.println(PM_NOT_RUNNING_ERR); 1237 } catch (IllegalArgumentException e) { 1238 System.err.println("Bad argument: " + e.toString()); 1239 showUsage(); 1240 } catch (SecurityException e) { 1241 System.err.println("Operation not allowed: " + e.toString()); 1242 } 1243 } 1244 1245 private void runSetPermissionEnforced() { 1246 final String permission = nextArg(); 1247 if (permission == null) { 1248 System.err.println("Error: no permission specified"); 1249 showUsage(); 1250 return; 1251 } 1252 final String enforcedRaw = nextArg(); 1253 if (enforcedRaw == null) { 1254 System.err.println("Error: no enforcement specified"); 1255 showUsage(); 1256 return; 1257 } 1258 final boolean enforced = Boolean.parseBoolean(enforcedRaw); 1259 try { 1260 mPm.setPermissionEnforced(permission, enforced); 1261 } catch (RemoteException e) { 1262 System.err.println(e.toString()); 1263 System.err.println(PM_NOT_RUNNING_ERR); 1264 } catch (IllegalArgumentException e) { 1265 System.err.println("Bad argument: " + e.toString()); 1266 showUsage(); 1267 } catch (SecurityException e) { 1268 System.err.println("Operation not allowed: " + e.toString()); 1269 } 1270 } 1271 1272 static class ClearCacheObserver extends IPackageDataObserver.Stub { 1273 boolean finished; 1274 boolean result; 1275 1276 @Override 1277 public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { 1278 synchronized (this) { 1279 finished = true; 1280 result = succeeded; 1281 notifyAll(); 1282 } 1283 } 1284 1285 } 1286 1287 private void runTrimCaches() { 1288 String size = nextArg(); 1289 if (size == null) { 1290 System.err.println("Error: no size specified"); 1291 showUsage(); 1292 return; 1293 } 1294 int len = size.length(); 1295 long multiplier = 1; 1296 if (len > 1) { 1297 char c = size.charAt(len-1); 1298 if (c == 'K' || c == 'k') { 1299 multiplier = 1024L; 1300 } else if (c == 'M' || c == 'm') { 1301 multiplier = 1024L*1024L; 1302 } else if (c == 'G' || c == 'g') { 1303 multiplier = 1024L*1024L*1024L; 1304 } else { 1305 System.err.println("Invalid suffix: " + c); 1306 showUsage(); 1307 return; 1308 } 1309 size = size.substring(0, len-1); 1310 } 1311 long sizeVal; 1312 try { 1313 sizeVal = Long.parseLong(size) * multiplier; 1314 } catch (NumberFormatException e) { 1315 System.err.println("Error: expected number at: " + size); 1316 showUsage(); 1317 return; 1318 } 1319 ClearDataObserver obs = new ClearDataObserver(); 1320 try { 1321 mPm.freeStorageAndNotify(sizeVal, obs); 1322 synchronized (obs) { 1323 while (!obs.finished) { 1324 try { 1325 obs.wait(); 1326 } catch (InterruptedException e) { 1327 } 1328 } 1329 } 1330 } catch (RemoteException e) { 1331 System.err.println(e.toString()); 1332 System.err.println(PM_NOT_RUNNING_ERR); 1333 } catch (IllegalArgumentException e) { 1334 System.err.println("Bad argument: " + e.toString()); 1335 showUsage(); 1336 } catch (SecurityException e) { 1337 System.err.println("Operation not allowed: " + e.toString()); 1338 } 1339 } 1340 1341 /** 1342 * Displays the package file for a package. 1343 * @param pckg 1344 */ 1345 private void displayPackageFilePath(String pckg) { 1346 try { 1347 PackageInfo info = mPm.getPackageInfo(pckg, 0, 0); 1348 if (info != null && info.applicationInfo != null) { 1349 System.out.print("package:"); 1350 System.out.println(info.applicationInfo.sourceDir); 1351 } 1352 } catch (RemoteException e) { 1353 System.err.println(e.toString()); 1354 System.err.println(PM_NOT_RUNNING_ERR); 1355 } 1356 } 1357 1358 private Resources getResources(PackageItemInfo pii) { 1359 Resources res = mResourceCache.get(pii.packageName); 1360 if (res != null) return res; 1361 1362 try { 1363 ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0, 0); 1364 AssetManager am = new AssetManager(); 1365 am.addAssetPath(ai.publicSourceDir); 1366 res = new Resources(am, null, null); 1367 mResourceCache.put(pii.packageName, res); 1368 return res; 1369 } catch (RemoteException e) { 1370 System.err.println(e.toString()); 1371 System.err.println(PM_NOT_RUNNING_ERR); 1372 return null; 1373 } 1374 } 1375 1376 private String nextOption() { 1377 if (mNextArg >= mArgs.length) { 1378 return null; 1379 } 1380 String arg = mArgs[mNextArg]; 1381 if (!arg.startsWith("-")) { 1382 return null; 1383 } 1384 mNextArg++; 1385 if (arg.equals("--")) { 1386 return null; 1387 } 1388 if (arg.length() > 1 && arg.charAt(1) != '-') { 1389 if (arg.length() > 2) { 1390 mCurArgData = arg.substring(2); 1391 return arg.substring(0, 2); 1392 } else { 1393 mCurArgData = null; 1394 return arg; 1395 } 1396 } 1397 mCurArgData = null; 1398 return arg; 1399 } 1400 1401 private String nextOptionData() { 1402 if (mCurArgData != null) { 1403 return mCurArgData; 1404 } 1405 if (mNextArg >= mArgs.length) { 1406 return null; 1407 } 1408 String data = mArgs[mNextArg]; 1409 mNextArg++; 1410 return data; 1411 } 1412 1413 private String nextArg() { 1414 if (mNextArg >= mArgs.length) { 1415 return null; 1416 } 1417 String arg = mArgs[mNextArg]; 1418 mNextArg++; 1419 return arg; 1420 } 1421 1422 private static void showUsage() { 1423 System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [FILTER]"); 1424 System.err.println(" pm list permission-groups"); 1425 System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); 1426 System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); 1427 System.err.println(" pm list features"); 1428 System.err.println(" pm list libraries"); 1429 System.err.println(" pm list users"); 1430 System.err.println(" pm path PACKAGE"); 1431 System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]"); 1432 System.err.println(" [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]"); 1433 System.err.println(" [--originating-uri <URI>] [--referrer <URI>] PATH"); 1434 System.err.println(" pm uninstall [-k] PACKAGE"); 1435 System.err.println(" pm clear PACKAGE"); 1436 System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT"); 1437 System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT"); 1438 System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT"); 1439 System.err.println(" pm grant PACKAGE PERMISSION"); 1440 System.err.println(" pm revoke PACKAGE PERMISSION"); 1441 System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]"); 1442 System.err.println(" pm get-install-location"); 1443 System.err.println(" pm set-permission-enforced PERMISSION [true|false]"); 1444 System.err.println(" pm trim-caches DESIRED_FREE_SPACE"); 1445 System.err.println(" pm create-user USER_NAME"); 1446 System.err.println(" pm remove-user USER_ID"); 1447 System.err.println(""); 1448 System.err.println("pm list packages: prints all packages, optionally only"); 1449 System.err.println(" those whose package name contains the text in FILTER. Options:"); 1450 System.err.println(" -f: see their associated file."); 1451 System.err.println(" -d: filter to only show disbled packages."); 1452 System.err.println(" -e: filter to only show enabled packages."); 1453 System.err.println(" -s: filter to only show system packages."); 1454 System.err.println(" -3: filter to only show third party packages."); 1455 System.err.println(" -i: see the installer for the packages."); 1456 System.err.println(" -u: also include uninstalled packages."); 1457 System.err.println(""); 1458 System.err.println("pm list permission-groups: prints all known permission groups."); 1459 System.err.println(""); 1460 System.err.println("pm list permissions: prints all known permissions, optionally only"); 1461 System.err.println(" those in GROUP. Options:"); 1462 System.err.println(" -g: organize by group."); 1463 System.err.println(" -f: print all information."); 1464 System.err.println(" -s: short summary."); 1465 System.err.println(" -d: only list dangerous permissions."); 1466 System.err.println(" -u: list only the permissions users will see."); 1467 System.err.println(""); 1468 System.err.println("pm list instrumentation: use to list all test packages; optionally"); 1469 System.err.println(" supply <TARGET-PACKAGE> to list the test packages for a particular"); 1470 System.err.println(" application. Options:"); 1471 System.err.println(" -f: list the .apk file for the test package."); 1472 System.err.println(""); 1473 System.err.println("pm list features: prints all features of the system."); 1474 System.err.println(""); 1475 System.err.println("pm list users: prints all users on the system."); 1476 System.err.println(""); 1477 System.err.println("pm path: print the path to the .apk of the given PACKAGE."); 1478 System.err.println(""); 1479 System.err.println("pm install: installs a package to the system. Options:"); 1480 System.err.println(" -l: install the package with FORWARD_LOCK."); 1481 System.err.println(" -r: reinstall an exisiting app, keeping its data."); 1482 System.err.println(" -t: allow test .apks to be installed."); 1483 System.err.println(" -i: specify the installer package name."); 1484 System.err.println(" -s: install package on sdcard."); 1485 System.err.println(" -f: install package on internal flash."); 1486 System.err.println(" -d: allow version code downgrade."); 1487 System.err.println(""); 1488 System.err.println("pm uninstall: removes a package from the system. Options:"); 1489 System.err.println(" -k: keep the data and cache directories around after package removal."); 1490 System.err.println(""); 1491 System.err.println("pm clear: deletes all data associated with a package."); 1492 System.err.println(""); 1493 System.err.println("pm enable, disable, disable-user: these commands change the enabled state"); 1494 System.err.println(" of a given package or component (written as \"package/class\")."); 1495 System.err.println(""); 1496 System.err.println("pm grant, revoke: these commands either grant or revoke permissions"); 1497 System.err.println(" to applications. Only optional permissions the application has"); 1498 System.err.println(" declared can be granted or revoked."); 1499 System.err.println(""); 1500 System.err.println("pm get-install-location: returns the current install location."); 1501 System.err.println(" 0 [auto]: Let system decide the best location"); 1502 System.err.println(" 1 [internal]: Install on internal device storage"); 1503 System.err.println(" 2 [external]: Install on external media"); 1504 System.err.println(""); 1505 System.err.println("pm set-install-location: changes the default install location."); 1506 System.err.println(" NOTE: this is only intended for debugging; using this can cause"); 1507 System.err.println(" applications to break and other undersireable behavior."); 1508 System.err.println(" 0 [auto]: Let system decide the best location"); 1509 System.err.println(" 1 [internal]: Install on internal device storage"); 1510 System.err.println(" 2 [external]: Install on external media"); 1511 System.err.println(""); 1512 System.err.println("pm trim-caches: trim cache files to reach the given free space."); 1513 System.err.println(""); 1514 System.err.println("pm create-user: create a new user with the given USER_NAME,"); 1515 System.err.println(" printing the new user identifier of the user."); 1516 System.err.println(""); 1517 System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,"); 1518 System.err.println(" deleting all data associated with that user"); 1519 } 1520} 1521