android静默卸载与在6.0上的异常

 

1. 静默应用卸载方式

我们在进行应用卸载的时候,有种使用shell命令的方式进行静默卸载,不起界面,此种方式也可以适用于其他的命令

//代码本质是一种在android代码中使用ProcessBuilder,非常规调用shell命令的方式
String[] args = {
   "pm", "uninstall", packageName
};//这个是shell命令中卸载的命令,也可以是其他的命令

String result = null;
ProcessBuilder processBuilder = new ProcessBuilder(args);
Process process = null;
InputStream errIs = null;
InputStream inIs = null;

try {
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   int read = -1;
   process = processBuilder.start();
   errIs = process.getErrorStream();
   while ((read = errIs.read()) != -1) {
      baos.write(read);
   }
   baos.write('\n');
   inIs = process.getInputStream();
   while ((read = inIs.read()) != -1) {
      baos.write(read);
   }
   byte[] data = baos.toByteArray();
   result = new String(data);

} catch (Exception e) {
   e.printStackTrace();
} finally {
   try {
      if (errIs != null) {
         errIs.close();
      }
      if (inIs != null) {
         inIs.close();
      }
   } catch (Exception e) {
      e.printStackTrace();
   }
   if (process != null) {
      process.destroy(); //用完后要销毁
   }
}

2. 平台异常不支持

但是此段代码在6.0的平台中会爆出异常

03-02 16:16:31.138  4360  4360 D AndroidRuntime: Calling main entry com.android.commands.pm.Pm
03-02 16:16:31.142  1848  2706 W AppOps  : Bad call: specified package null under uid 1000 but it is really -1
03-02 16:16:31.143  4360  4360 E Pm      : Error
03-02 16:16:31.143  4360  4360 E Pm      : java.lang.SecurityException: Package null does not belong to 1000
03-02 16:16:31.143  4360  4360 E Pm      :     at android.os.Parcel.readException(Parcel.java:1599)
03-02 16:16:31.143  4360  4360 E Pm      :     at android.os.Parcel.readException(Parcel.java:1552)
03-02 16:16:31.143  4360  4360 E Pm      :     at android.content.pm.IPackageInstaller$Stub$Proxy.uninstall(IPackageInstaller.java:448)
03-02 16:16:31.143  4360  4360 E Pm      :     at com.android.commands.pm.Pm.runUninstall(Pm.java:1614)
03-02 16:16:31.143  4360  4360 E Pm      :     at com.android.commands.pm.Pm.run(Pm.java:174)
03-02 16:16:31.143  4360  4360 E Pm      :     at com.android.commands.pm.Pm.main(Pm.java:108)
03-02 16:16:31.143  4360  4360 E Pm      :     at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
03-02 16:16:31.143  4360  4360 E Pm      :     at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:251)
03-02 16:16:31.144  4360  4360 I art     : System.exit called, status: 1

我们追踪代码,可以看到在6.0的系统中在使用uninstall方法时候会做出shell命令的检测,下面记录一下追踪过程

at com.android.commands.pm.Pm.runUninstall,这段代码可以看做是问题的开始,卸载的shell命令经过一系列转发发到Pm.java中,

   public int run(String[] args) throws IOException, RemoteException {
        boolean validCommand = false;
        ...


        if ("install-abandon".equals(op) || "install-destroy".equals(op)) {
            return runInstallAbandon();
        }

        if ("set-installer".equals(op)) {
            return runSetInstaller();
        }

        if ("uninstall".equals(op)) {
            return runUninstall();
        }

        if ("clear".equals(op)) {
            return runClear();
        }
        ....
        ....    
        ....
    }

   private int runUninstall() throws RemoteException {  //这个方法扔出异常
        ....

        final LocalIntentReceiver receiver = new LocalIntentReceiver();
        //这个重点,会调用到mInstaller的卸载方法, 看到mInstaller为IPackageInstaller类型,设计到aidl调用,我们直接代码搜索 IPackageInstaller.Stub 关键字,可以搜到这个uninstall的方法实现,定位到PackageInstallerService.java类
        mInstaller.uninstall(pkg, null /* callerPackageName */, flags,
                receiver.getIntentSender(), userId); 
        ....
    }


 

 


    public void uninstall(String packageName, String callerPackageName, int flags,
                IntentSender statusReceiver, int userId) {
        final int callingUid = Binder.getCallingUid(); 
        
        mPm.enforceCrossUserPermission(callingUid, userId, true, true, "uninstall");
        //这个是异常导致点,会做uid检测,Process.SHELL_UID=2000,这是shell用户,Process.ROOT_UID是表示root用户,我们用adb或者串口是这个进程,但是我们正常用户uid不等于0或者2000,所以需要checkPackage
        if ((callingUid != Process.SHELL_UID) && (callingUid != Process.ROOT_UID)) {
            mAppOps.checkPackage(callingUid, callerPackageName);
        }
    
        ....
    }

    public void checkPackage(int uid, String packageName) {
        try {
            if (mService.checkPackage(uid, packageName) != MODE_ALLOWED) {
                throw new SecurityException(
                        "Package " + packageName + " does not belong to " + uid);
            }  

        } catch (RemoteException e) {
            throw new SecurityException("Unable to verify package ownership", e);
        }
    }

是这个地方扔出的安全异常,log可以对上Package null does not belong to 1000,(这里1000对应系统进程,uid为1000),扔出异常是因为runUninstall中的
        mInstaller.uninstall(pkg, null /* callerPackageName */, flags,
                receiver.getIntentSender(), userId); 

callerPackageName 这个参数设为了null,所以检查包名是否属于这个uidGroup中为否,扔出了SecurityException

这是6.0平台不准使用这种方式进行uninstall的操作,所以我们可以注掉这个检测,规避这种异常,查看了一下,应该只有6.0会存在这个异常

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值