手机管理应用研究【2】—— 安装卸载篇

欢迎转载,转载请注明:http://blog.csdn.net/zhgxhuaa

说明

Android通过PackageManagerService(后面简称Pms)进行包管理,其主要功能包含:用户ID分配、包解析、包的安装卸载等。

本文不正确Pms进行分析。主要目的是探讨一下包安装。在本文中主要探讨包安装的相关操作,卸载作为安装的逆过程。实现类似,不再赘述。在应用安装/卸载这里主要有这么几个常见的功能点:

A.     静默安装/卸载

B.     秒装/秒卸载

C.     卸载应用保存数据

D.     系统内置应用卸载

E.      卸载后清除残留数据

以下就从这几个方面做一下分析介绍。

Android中APK的安装方式

在Android中APK的安装有三种方式:

1、开机Pms初始化时,扫描包安装文件夹。

@/frameworks/base/services/java/com/android/server/SystemServer.java

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public  void  initAndLoop() {      ......             IPackageManager pm =  null ;             ......             try  {          ......                     pm = PackageManagerService.main(context, installer,                  factoryTest != SystemServer.FACTORY_TEST_OFF,                  onlyCore);          ......      catch  (RuntimeException e) {          Slog.e( "System" "******************************************" );          Slog.e( "System" "************ Failure starting core service" , e);      }      ...... }

@/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java

1 2 3 4 5 6 7 public  static  final  IPackageManager main(Context context, Installer installer,          boolean  factoryTest,  boolean  onlyCore) {      PackageManagerService m =  new  PackageManagerService(context, installer,              factoryTest, onlyCore);      ServiceManager.addService( "package" , m);      return  m; }

以下是Pms构造函数的实现:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public  PackageManagerService(Context context, Installer installer,          boolean factoryTest, boolean onlyCore) {      ......             synchronized (mInstallLock) {      // writer      synchronized (mPackages) {          ......                     File dataDir = Environment.getDataDirectory();          mAppDataDir =  new  File(dataDir,  "data" );          mAppInstallDir =  new  File(dataDir,  "app" );          mAppLibInstallDir =  new  File(dataDir,  "app-lib" );          mAsecInternalPath =  new  File(dataDir,  "app-asec" ).getPath();          mUserAppDataDir =  new  File(dataDir,  "user" );          mDrmAppPrivateInstallDir =  new  File(dataDir,  "app-private" );             ......                     // Find base frameworks (resource packages without code).          mFrameworkInstallObserver =  new  AppDirObserver(              frameworkDir.getPath(), OBSERVER_EVENTS,  true false );          mFrameworkInstallObserver.startWatching();          scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM                  | PackageParser.PARSE_IS_SYSTEM_DIR,                  scanMode | SCAN_NO_DEX, 0);             // Collected privileged system packages.          File privilegedAppDir =  new  File(Environment.getRootDirectory(),  "priv-app" );          mPrivilegedInstallObserver =  new  AppDirObserver(                  privilegedAppDir.getPath(), OBSERVER_EVENTS,  true true );          mPrivilegedInstallObserver.startWatching();              scanDirLI(privilegedAppDir, PackageParser.PARSE_IS_SYSTEM                      | PackageParser.PARSE_IS_SYSTEM_DIR                      | PackageParser.PARSE_IS_PRIVILEGED, scanMode, 0);             // Collect ordinary system packages.          File systemAppDir =  new  File(Environment.getRootDirectory(),  "app" );          mSystemInstallObserver =  new  AppDirObserver(              systemAppDir.getPath(), OBSERVER_EVENTS,  true false );          mSystemInstallObserver.startWatching();          scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM                  | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);             // Collect all vendor packages.          File vendorAppDir =  new  File( "/vendor/app" );          mVendorInstallObserver =  new  AppDirObserver(              vendorAppDir.getPath(), OBSERVER_EVENTS,  true false );          mVendorInstallObserver.startWatching();          scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM                  | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);             ......             if  (!mOnlyCore) {              EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,                      SystemClock.uptimeMillis());              mAppInstallObserver =  new  AppDirObserver(                  mAppInstallDir.getPath(), OBSERVER_EVENTS,  false false );              mAppInstallObserver.startWatching();              scanDirLI(mAppInstallDir, 0, scanMode, 0);                 mDrmAppInstallObserver =  new  AppDirObserver(                  mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS,  false false );              mDrmAppInstallObserver.startWatching();              scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,                      scanMode, 0);              ......      // synchronized (mPackages)      // synchronized (mInstallLock) }

通过Pms的构造函数能够看出,Pms在初始化时会扫描/system/app、vender/app、/data/app、/data/app-private四个应用安装文件夹,然后调用sanDirLI方法进行安装。

Pms通过AppDirObserver对这四个应用安装文件夹进行监控。一旦发现APK格式的文件则会调用scanPackageLI进行安装。

2、通过包安装器PackageInstaller安装

Android提供了一个默认的包安装器。位于/package/app/PackageInstaller文件夹。

通过其Manifest文件能够看出。PackageInstaller会对我们安装应用发出的Intent进行处理,这里PackageInstaller提供了两种处理方式,各自是:file方式和package方式。

@/package/app/PackageInstaller/AndroidManifest.xml

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 < activity  android:name = ".PackageInstallerActivity"          android:configChanges = "orientation|keyboardHidden|screenSize"          android:excludeFromRecents = "true" >      < intent-filter >          < action  android:name = "android.intent.action.VIEW"  />          < action  android:name = "android.intent.action.INSTALL_PACKAGE"  />          < category  android:name = "android.intent.category.DEFAULT"  />          < data  android:scheme = "file"  />          < data  android:mimeType = "application/vnd.android.package-archive"  />      </ intent-filter >      < intent-filter >          < action  android:name = "android.intent.action.INSTALL_PACKAGE"  />          < category  android:name = "android.intent.category.DEFAULT"  />          < data  android:scheme = "file"  />          < data  android:scheme = "package"  />      </ intent-filter > </ activity >

@/package/app/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

1 2 3 4 5 6 7 8 @Override protected  void  onCreate(Bundle icicle) {      super .onCreate(icicle);         ......             initiateInstall(); }
1 2 3 4 5 private  void  initiateInstall() {      ......         startInstallConfirm(); }

startInstallConfirm方法中点击“确认”后。会发出一个Intent,接收者为InstallAppProgress。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public  void  onClick(View v) {      if (v == mOk) {          if  (mOkCanInstall || mScrollView ==  null ) {              // Start subactivity to actually install the application              mInstallFlowAnalytics.setInstallButtonClicked();              Intent newIntent =  new  Intent();              newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,                      mPkgInfo.applicationInfo);              newIntent.setData(mPackageURI);              newIntent.setClass( this , InstallAppProgress. class );              ......                             startActivity(newIntent);              finish();          else  {              mScrollView.pageScroll(View.FOCUS_DOWN);          }      else  if (v == mCancel) {          ......      } }

@/package/app/PackageInstaller/src/com/android/packageinstaller/InstallAppProgress.java

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public  void  initView() {      setContentView(R.layout.op_progress);      int  installFlags =  0 ;      PackageManager pm = getPackageManager();             ......             String installerPackageName = getIntent().getStringExtra(              Intent.EXTRA_INSTALLER_PACKAGE_NAME);      Uri originatingURI = getIntent().getParcelableExtra(Intent.EXTRA_ORIGINATING_URI);      Uri referrer = getIntent().getParcelableExtra(Intent.EXTRA_REFERRER);      int  originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,              VerificationParams.NO_UID);      ManifestDigest manifestDigest = getIntent().getParcelableExtra(EXTRA_MANIFEST_DIGEST);      VerificationParams verificationParams =  new  VerificationParams( null , originatingURI,              referrer, originatingUid, manifestDigest);      PackageInstallObserver observer =  new  PackageInstallObserver();         if  ( "package" .equals(mPackageURI.getScheme())) {          try  {              pm.installExistingPackage(mAppInfo.packageName);              observer.packageInstalled(mAppInfo.packageName,                      PackageManager.INSTALL_SUCCEEDED);          catch  (PackageManager.NameNotFoundException e) {              observer.packageInstalled(mAppInfo.packageName,                      PackageManager.INSTALL_FAILED_INVALID_APK);          }      else  {          pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,                  installerPackageName, verificationParams,  null );      } }

InstallAppProgress即应用安装过程中的进度条界面。

通过上面的代码能够看到在initView方法的最后会调用Pms的installPackageWithVerificationAndEncryption方法进行安装。

3、通过adb命令安装

adb命令pm是Pms的Shellclient,通过pm能够进行包相关的一些操作,包含安装和卸载。pm命令的使用方法例如以下:

《手机管理应用研究【2】—— 安装卸载篇》《手机管理应用研究【2】—— 安装卸载篇》

pm的代码实如今Pm.java中。例如以下:

@/frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public  static  void  main(String[] args) {      new  Pm().run(args); }    public  void  run(String[] args) {      ......             mPm = IPackageManager.Stub.asInterface(ServiceManager.getService( "package" ));             ......         if  ( "install" .equals(op)) {          runInstall();          return ;      }         if  ( "uninstall" .equals(op)) {          runUninstall();          return ;      }      ...... }

在run方法中初始化了一个Pms的client代理对象mPm,兴许的相关操作将有mPm完毕。

以下看一下Pm中负责安装的方法runInstall的代码实现:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 private  void  runInstall() {      int  installFlags = PackageManager.INSTALL_ALL_USERS;             ......             while  ((opt=nextOption()) !=  null ) {          if  (opt.equals( "-l" )) {              installFlags |= PackageManager.INSTALL_FORWARD_LOCK;          else  if  (opt.equals( "-r" )) {              installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;          else  if  (opt.equals( "-i" )) {              installerPackageName = nextOptionData();              if  (installerPackageName ==  null ) {                  System.err.println( "Error: no value specified for -i" );                  return ;              }          else  if  (opt.equals( "-t" )) {              installFlags |= PackageManager.INSTALL_ALLOW_TEST;          else  if  (opt.equals( "-s" )) {              // Override if -s option is specified.              installFlags |= PackageManager.INSTALL_EXTERNAL;          else  if  (opt.equals( "-f" )) {              // Override if -s option is specified.              installFlags |= PackageManager.INSTALL_INTERNAL;          else  if  (opt.equals( "-d" )) {              installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;             ......                       PackageInstallObserver obs =  new  PackageInstallObserver();      try  {          VerificationParams verificationParams =  new  VerificationParams(verificationURI,                  originatingURI, referrerURI, VerificationParams.NO_UID,  null );             mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,                  installerPackageName, verificationParams, encryptionParams);             synchronized  (obs) {              while  (!obs.finished) {                  try  {                      obs.wait();                  catch  (InterruptedException e) {                  }              }              if  (obs.result == PackageManager.INSTALL_SUCCEEDED) {                  System.out.println( "Success" );              else  {                  System.err.println( "Failure ["                          + installFailureToString(obs.result)                          "]" );              }          }      catch  (RemoteException e) {          System.err.println(e.toString());          System.err.println(PM_NOT_RUNNING_ERR);      } }

能够看出runInstall终于会调用Pms的installPackageWithVerificationAndEncryption方法进行安装。

通过pm安装时,成功安装的返回信息为“Success”,安装失败的返回信息为”Failure[失败信息]”。

静默安装实现

在了解了Android中包安装的方式后,接下来探讨一些怎样实现”静默安装“。所谓静默安装即跳过安装界面和进度条。在不被用户察觉的情况下载后台安装。以下针对上面的三种安装方式分别来分析怎样实现静默安装。

1、push安装包到应用安装文件夹的方式

在Pms初始化时安装包的流程中。我们知道Pms会监控/system/app、vender/app、/data/app、/data/app-private这四个应用安装文件夹。

因此假设可以将APK文件push进应用安装文件夹不就行触发AppDirObserver中的包安装逻辑了了吗?所以这样的思路理论上是行得通的,但有两个须要注意的点:

  • 第一点:例如以下图所看到的。/system/app的訪问权限为root。这就要求在push到/system/app文件夹时必须具有root权限。

    而/data/app的訪问权限为system。要获得system权限就要求使用这样的方式的应用程序必须签名为platform而且sharedUserId制定为“android.uid.system”。

  • 第二点:系统应用(/system/app)与普通应用(/data/app)的安装方式是不同的,对于系统应用。全部资源都包括在apk这个zip包中。并且其在/system/app不必以包名命名(理论上能够随便起名)。

    而对于普通应用安装后,它的dex、lib、资源文件(安装包)分别存放在不同的文件夹,而且安装后以packagename-x.apk的形式保存在/data/app文件夹下。

《手机管理应用研究【2】—— 安装卸载篇》

那这样的安装方式是不是就没实用了呢?

非也。

网上有些电子市场或管家类软件实现的”秒装“功能应该就是安装这个思路实现的,当然这里仅仅是推測,须要进一步研究。

2、调用Pm隐藏API

Android实现了一个应用安装器的APK负责包的安装工作,在上面的分析中我们知道。PackageInstaller的工作实际上仅仅是安装界面、权限确认、进度显示等,真正的安装工作依旧是调用Pms实现的。到这里我们就有了另外一种思路,能不能绕过安装界面,直接调用Pms里面的对应方法呢?当然能够,PackageManager类中就提供了这个方案:

@/frameworks/base/core/java/android/content/pm/PackageManager.java

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 /**   * @hide   *   * Install a package. Since this may take a little while, the result will   * be posted back to the given observer.  An installation will fail if the calling context   * lacks the {@link android.Manifest.permission#INSTALL_PACKAGES} permission, if the   * package named in the package file's manifest is already installed, or if there's no space   * available on the device.   *   * @param packageURI The location of the package file to install.  This can be a 'file:' or a   * 'content:' URI.   * @param observer An observer callback to get notified when the package installation is   * complete. {@link IPackageInstallObserver#packageInstalled(String, int)} will be   * called when that happens.  observer may be null to indicate that no callback is desired.   * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},   * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.   * @param installerPackageName Optional package name of the application that is performing the   * installation. This identifies which market the package came from.   */ public  abstract  void  installPackage(          Uri packageURI, IPackageInstallObserver observer,  int  flags,          String installerPackageName);

能够看出,这种方法是hide的,因此在应用开发时假设要使用,必须通过反射。

这里的IPackageInstallObserver是installPackage方法的一个回调接口通知,事实上如今IPackageInstallObserver.aidl中,例如以下:

@/frameworks/base/core/java/com/android/content/pm/IPackageInstallObserver.aidl

1 2 3 4 5 6 7 8 9 package  android.content.pm;    /**   * API for installation callbacks from the Package Manager.   * @hide   */ oneway  interface  IPackageInstallObserver {      void  packageInstalled(in String packageName,  int  returnCode); }

使用Android内置未公开API有两种方法:一种是通过反射的方式实现;还有一种是在project文件夹下建立与所引用系统类同样的类和方法,这里仅仅要求类和方法名同样。不须要实现,仅仅保证编译时不报错就能够了,依据Java的类载入机制,在执行时,会去载入系统类。

以下是採用另外一种方法时的两段演示样例代码:

实现接口回调的代码例如以下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class  MyPakcageInstallObserver  extends  IPackageInstallObserver.Stub {          Context cxt;          String appName;          String filename;          String pkname;             public  MyPakcageInstallObserver(Context c, String appName,                   String filename,String packagename) {              this .cxt = c;              this .appName = appName;              this .filename = filename;              this .pkname = packagename;          }             @Override          public  void  packageInstalled(String packageName,  int  returnCode) {              Log.i(TAG,  "returnCode = "  + returnCode); // 返回1代表成功安装                          if  (returnCode ==  1 ) {                              //TODO                          }              Intent it =  new  Intent();              it.setAction(CustomAction.INSTALL_ACTION);              it.putExtra( "install_returnCode" , returnCode);              it.putExtra( "install_packageName" , packageName);              it.putExtra( "install_appName" , appName); cxt.sendBroadcast(it);          }      }

调用PackageManager.java隐藏方法,代码例如以下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 /**       * 静默安装       * */      public  static  void  autoInstallApk(Context context, String fileName,              String packageName, String APPName) {          Log.d(TAG,  "jing mo an zhuang:"  + packageName +  ",fileName:"  + fileName);          File file =  new  File(fileName);          int  installFlags =  0 ;          if  (!file.exists())              return ;          installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;          if  (hasSdcard()) {              installFlags |= PackageManager.INSTALL_EXTERNAL;          }          PackageManager pm = context.getPackageManager();          try  {              IPackageInstallObserver observer =  new  MyPakcageInstallObserver(                      context, APPName, appId, fileName,packageName,type_name);              Log.i(TAG,  "########installFlags:"  + installFlags+ "packagename:" +packageName);              pm.installPackage(Uri.fromFile(file), observer, installFlags,                      packageName);          catch  (Exception e) {                         }         }

这样的方法也有一定的限制:

首先,要在AndroidManifest.xml中声明”android.permission.INSTALL_PACKAGES”权限;

其次,应用须要system权限。


3、调用pm命令进行安装

在adb窗体通过pm install安装包本来就是没有安装界面的。这不正是我们想要的吗?通过pm的安装方式须要取得root或system权限。

pm的安装方式有两种,一种须要root权限,演示样例代码例如以下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 new  Thread() {      public  void  run() {      Process process =  null ;      OutputStream out =  null ;      InputStream in =  null ;      try  {      // 请求root      process = Runtime.getRuntime().exec( "su" );      out = process.getOutputStream();      // 调用安装      out.write(( "pm install -r "  + currentTempFilePath +  "\n" ).getBytes());      in = process.getInputStream();      int  len =  0 ;      byte [] bs =  new  byte [ 256 ];      while  (- 1  != (len = in.read(bs))) {      String state =  new  String(bs,  0 , len);      if  (state.equals( "Success\n" )) {         //成功安装后的操作           }         }      catch  (IOException e) {          e.printStackTrace();      catch  (Exception e) {          e.printStackTrace();      finally  {          try  {              if  (out !=  null ) {                  out.flush();                  out.close();              }              if  (in !=  null ) {                  in.close();              }          catch  (IOException e) {              e.printStackTrace();          }      }    } }.start();

还有一钟须要system权限,示比例如以下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 new  Thread() {      public  void  run() {      Process process =  null ;      InputStream in =  null ;      try  {      // 请求root      process = Runtime.getRuntime().exec( "pm install -r "  + currentTempFilePath +  "\n" );      in = process.getInputStream();      int  len =  0 ;      byte [] bs =  new  byte [ 256 ];      while  (- 1  != (len = in.read(bs))) {      String state =  new  String(bs,  0 , len);      if  (state.equals( "Success\n" )) {         //成功安装后的操作           }         }      catch  (IOException e) {          e.printStackTrace();      catch  (Exception e) {          e.printStackTrace();      finally  {          try  {              if  (in !=  null ) {                  in.close();              }          catch  (IOException e) {              e.printStackTrace();          }      }    } }.start();

关于system权限的获取在介绍push方式的安装时已做介绍。

上面的代码仅仅给出了比較核心的部分,在实际实现中。对返回结果的处理相同重要。

高速秒装实现

发现市面上有些手机管家和电子市场类管理软件实现了所谓的”秒装“功能。这个功能本身的实现原理很easy,实现思路为:我们能够利用Android中第一种安装方式,不经过Android应用安装器,直接将应用push到/data/app文件夹中,此时会触发Pms中对/data/app的文件夹监控机制。触发安装。

然而在实现次功能时有这么几点须要注意:

  • 第一点:须要获得root权限(或通过系统漏洞(MastKey等)绕过root,总之要提示权限。这里没有深入研究)。

  • 第二点:因为push的方式会绕过Android的一些验证机制,因此在push之前须要人为进行校验等保证,这里仅仅举两个比較普遍的样例:

    1)如今非常多应用都是用so库,可是大部分应用往往仅仅提供arm版本号的so库集成,那边在push之前。就须要校验当前手机平台是否存在相应的so库,假设不存在则不建议是用秒装。

    2)在对已存在的应用进行升级时,假设通过秒装进行升级,那么必需要人为校验保证新的apk与已安装apk的签名一致。

好了,到这里,Android安装就介绍完了,欢迎大家交流讨论。

删除系统内置应用

Google定义的存放系统内置应用的位置有两个:/system/app和/vender/app,当中/system/app用于存放Android内置应用。/vender/app用于存放厂商内置应用。实际上在使用时,/vender/app文件夹往往不使用。以下我们看一下/system/app文件夹(以下是我小米2S手机/system/app文件夹的截图):

《手机管理应用研究【2】—— 安装卸载篇》

能够看出/system/app文件夹下应用文件的权限为644,用户为root。我们通过PackageManager是无法卸载系统内置应用的。要想删除系统内置应用,须要在获得root权限的前提下,通过rm命令删除就可以。

这样的卸载方式有一些须要注意的问题。请结合5中卸载应用保存数据一起来看。

卸载应用保存数据

在有些手机管理软件和电子市场(91手机助手)中有这么一个功能“删除应用保存数据”,那它是怎样做到的呢?这里显然不能走Android默认的卸载流程。

于是,我们想到了是不是能够通过rm直接删除/system/app或者/data/app文件夹下的apk文件就能够了呢?以下对这个想法做一个验证。

以应用宝为例:

1)在/data/app文件夹下找到应用宝安装后的apk文件。例如以下图:

《手机管理应用研究【2】—— 安装卸载篇》

2)通过rm命令将/data/app文件夹下的应用宝apk文件删除,删除后/data/data文件夹下的情况例如以下:

《手机管理应用研究【2】—— 安装卸载篇》

3)        看到这里相信大部分人都会有这种疑问?

A.       重新启动手机后/data/data文件夹下的应用宝数据文件会不会被系统删除?

B.       又一次安装应用宝后。新的应用宝还能訪问上次安装未删除的数据文件吗?

带着这些疑问,首先看一下第一个情况,在重新启动手机后/data/data文件夹例如以下:

《手机管理应用研究【2】—— 安装卸载篇》

能够看到应用宝的数据文件夹依旧是存在的。

4)在又一次安装应用宝后,我们发现也是能够使用之前的数据文件夹的。

《手机管理应用研究【2】—— 安装卸载篇》

从上图能够看出,又一次安装后应用宝的user为app_18与上次安装一样。

对于这里一些原理性的东西临时先不做介绍。

5)这里有几个须要注意的问题。例如以下:

A.   在通过这样的方式删除应用时。要注意第三方Launcher上快捷方式(图标)的处理。例如以下图所看到的,在删除应用宝后,在小米桌面上的图标并未一起删除。

《手机管理应用研究【2】—— 安装卸载篇》

B. 在删除应用之前,最好先调用PackageManager中的foreStopPackage方法停止相关应用,然后再删除。否则可能会有不友好的系统提示,例如以下图:

《手机管理应用研究【2】—— 安装卸载篇》

应用安装卸载相关的还有其它一些内容。比方说:清理应用卸载残留、应用锁、应用隐藏、应用安装位置、远程adb安装等等。

这些内容临时不做介绍,放到其它篇目中研究。

下一篇介绍系统垃圾清理。

 

OK,应用安装卸载篇就到这里,欢迎大家讨论交流。

    原文作者:blfshiye
    原文地址: http://www.cnblogs.com/blfshiye/p/5079649.html
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞