Android6.0关于预置三方app卸载(一) copy到data/app下
2018-03-12 15:25
507 查看
我们知道每个手机会预装一些三方的应用,但我们需要用户把这些应用删除的权限。这可怎么操作呢,我们在编译的时候可以把应用放在data/app下,但是这样的话,手机一恢复出厂设置预留应用就没有了。这篇博客我们就来解决这个问题。
一、安装预置应用方法
这里提供一个思路,把预留应用放在system/third-app下,然后在第一次开机的时候把这些应用copy到data/app下,当然要在PKMS扫描data/app之前,这样第一次开机的时候就能安装上这些应用了。因为应用在data/app下也能删除。因为应用在system/third-app中也有,而恢复出厂设置的时候system的目录不会清空。在恢复出厂设置后,还会把这些应用copy到data/app下(恢复出厂设置开机等于第一次开机),下面我们看下如何实现。
先看下apk的编译时放在了third_app下,
功能如下,就是把system/third-app下面的apk复制到data/app, 但是在哪里调用这个函数呢?
在PKMS的构造函数,开始处理非系统应用的时候,但是一定要在扫描data/app之前,这样才能后面扫描到data/app这些复制进去的app,才会第一次开机安装成功。
二、adb install处理
下面几个问题,我们知道PKMS会在开机的时候扫描data/app,所以一般我们把一个apk push到data/app下的时候,再把手机重启也会安装应用。但是一定要重启。
那adb install又是如何做到安装应用的,我们来看下代码,下面这段代码是pc侧的
我们来看下install_app这个函数,也是把apk文件push到/data/local/tmp下,然后调用了pm命令安装应用。
看下pm_command函数,是调用了pm install命令来安装应用。
我们来看下pm install的处理,调用了runInstall函数
在runInstall函数会调用PKMS的installPackageAsUser函数安装应用
三、注意
上面PKMS中把system/third_app下面的apk放在data/app有点问题,原因是android6.0 编译apk文件,会自动生成一个目录,所以代码需要修改一下。
主要是下面这个函数,system/third_app目录下多了一层目录。
一、安装预置应用方法
这里提供一个思路,把预留应用放在system/third-app下,然后在第一次开机的时候把这些应用copy到data/app下,当然要在PKMS扫描data/app之前,这样第一次开机的时候就能安装上这些应用了。因为应用在data/app下也能删除。因为应用在system/third-app中也有,而恢复出厂设置的时候system的目录不会清空。在恢复出厂设置后,还会把这些应用copy到data/app下(恢复出厂设置开机等于第一次开机),下面我们看下如何实现。
先看下apk的编译时放在了third_app下,
include $(CLEAR_VARS) LOCAL_MODULE_PATH := $(TARGET_OUT)/third_app LOCAL_MODULE := MobileMusic LOCAL_MODULE_TAGS := optional LOCAL_MODULE_CLASS := APPS LOCAL_SRC_FILES := $(LOCAL_MODULE).apk LOCAL_CERTIFICATE := PRESIGNED include $(BUILD_PREBUILT)
功能如下,就是把system/third-app下面的apk复制到data/app, 但是在哪里调用这个函数呢?
//install the third apps when system is first boot private void installThirdApps(){ //the source directory not exists File storeDir = new File("/system/third_app"); if(!storeDir.exists()){ Log.e(TAG,"/system/third_app is not exist"); return; } //get the apk files in /system/third_app String apkFilesNames[] = storeDir.list(); if(apkFilesNames == null){ Log.e(TAG,"apk file name is null"); return; } //copy the apk files to /data/app boolean installSucc = false; for(int i = 0; i < apkFilesNames.length; i++){ //Uri srcFileUri = Uri.parse(storeDir+"/"+apkFilesNames[i]); File srcFile = new File("/system/third_app",apkFilesNames[i]); Log.e(TAG,"srcFile="+srcFile); File destFile = new File("/data/app",apkFilesNames[i]); Log.e(TAG,"destFile="+destFile.toString()); boolean installResult = copyThirdApps(srcFile,destFile); if(!installResult){ Log.d(TAG,"install failed"); return; } } } /** * File copy function. * It will be used when installThirdApps * @param srcFile just like '/system/third_app/***.apk' * @param destDir just like '/data/app/***.apk' * @return */ private boolean copyThirdApps(File srcFile, File destDir) { //do some check actions if (srcFile == null || destDir == null || !srcFile.exists()) { Log.e(TAG, "invalid arguments for movePreinstallApkFile()"); Log.e(TAG, "move " + srcFile + " to " + destDir + " failed"); return false; } //create new file try{ destDir.createNewFile(); }catch(Exception e){ Log.e(TAG, "create file faild! due to:" + e); return false; } //set permission try{ Runtime.getRuntime().exec("chmod 644 "+destDir.getAbsolutePath()); }catch(Exception e){ Log.e(TAG, "chmod file faild! due to:"+e); } //do copy try{ boolean ret = FileUtils.copyFile(srcFile,destDir); if(!ret){ Log.e(TAG,"copy file faild!"); return false; } }catch(Exception e){ Log.e(TAG, "copy file faild! due to:"+e); } return true && destDir.exists(); }
在PKMS的构造函数,开始处理非系统应用的时候,但是一定要在扫描data/app之前,这样才能后面扫描到data/app这些复制进去的app,才会第一次开机安装成功。
if (!mOnlyCore) { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis()); if(isFirstBoot()){//判断第一次开机 Log.i(TAG, "It's first boot, install the third apps"); installThirdApps();//安装三方应用(copy到data/app下) } scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0); scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanFlags | SCAN_REQUIRE_KNOWN, 0);a
二、adb install处理
下面几个问题,我们知道PKMS会在开机的时候扫描data/app,所以一般我们把一个apk push到data/app下的时候,再把手机重启也会安装应用。但是一定要重启。
那adb install又是如何做到安装应用的,我们来看下代码,下面这段代码是pc侧的
else if (!strcmp(argv[0], "install")) { if (argc < 2) return usage(); return install_app(ttype, serial, argc, argv); }
我们来看下install_app这个函数,也是把apk文件push到/data/local/tmp下,然后调用了pm命令安装应用。
static int install_app(transport_type transport, const char* serial, int argc, const char** argv) { static const char *const DATA_DEST = "/data/local/tmp/%s"; static const char *const SD_DEST = "/sdcard/tmp/%s"; const char* where = DATA_DEST; int i; struct stat sb; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-s")) { where = SD_DEST; } } // Find last APK argument. // All other arguments passed through verbatim. int last_apk = -1; for (i = argc - 1; i >= 0; i--) { const char* file = argv[i]; char* dot = strrchr(file, '.'); if (dot && !strcasecmp(dot, ".apk")) { if (stat(file, &sb) == -1 || !S_ISREG(sb.st_mode)) { fprintf(stderr, "Invalid APK file: %s\n", file); return -1; } last_apk = i; break; } } if (last_apk == -1) { fprintf(stderr, "Missing APK file\n"); return -1; } const char* apk_file = argv[last_apk]; char apk_dest[PATH_MAX]; snprintf(apk_dest, sizeof apk_dest, where, get_basename(apk_file)); int err = do_sync_push(apk_file, apk_dest, 0 /* no show progress */);//把apk文件push到/data/local/tmp/目录下 if (err) { goto cleanup_apk; } else { argv[last_apk] = apk_dest; /* destination name, not source location */ } err = pm_command(transport, serial, argc, argv);//调用了pm命令 cleanup_apk: delete_file(transport, serial, apk_dest); return err; }
看下pm_command函数,是调用了pm install命令来安装应用。
static int pm_command(transport_type transport, const char* serial, int argc, const char** argv) { std::string cmd = "shell:pm"; while (argc-- > 0) { cmd += " " + escape_arg(*argv++); } return send_shell_command(transport, serial, cmd); }
我们来看下pm install的处理,调用了runInstall函数
if ("install".equals(op)) { return runInstall(); }
在runInstall函数会调用PKMS的installPackageAsUser函数安装应用
VerificationParams verificationParams = new VerificationParams(verificationURI, originatingURI, referrerURI, VerificationParams.NO_UID, null); mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags, installerPackageName, verificationParams, abi, userId);
三、注意
上面PKMS中把system/third_app下面的apk放在data/app有点问题,原因是android6.0 编译apk文件,会自动生成一个目录,所以代码需要修改一下。
主要是下面这个函数,system/third_app目录下多了一层目录。
private void installThirdApps(){ //the source directory not exists File storeDir = new File("/system/third_app"); if(!storeDir.exists()){ Log.e(TAG,"/system/third_app is not exist"); return; } //get the apk files in /system/third_app String apkDirFilesNames[] = storeDir.list(); if(apkDirFilesNames == null){ Log.e(TAG,"apk file name is null"); return; } //copy the apk files to /data/app boolean installSucc = false; for(int i = 0; i < apkDirFilesNames.length; i++){ File srcFileDir = new File("/system/third_app", apkDirFilesNames[i]); Log.e(TAG,"srcFile=" + srcFileDir); String srcFileNames[] = srcFileDir.list(); for(int j = 0; j < srcFileNames.length; j++) { File srcFile = new File(srcFileDir, srcFileNames[j]); File destFile = new File("/data/app", srcFileNames[j]); boolean installResult = copyThirdApps(srcFile, destFile); if(!installResult){ Log.d(TAG,"install failed"); return; } } } }
相关文章推荐
- Android6.0关于预置三方app卸载(一) copy到data/app下
- Android6.0关于预置三方app卸载(二) 调用接口安装
- Android6.0关于预置三方app卸载(三) 扫描system/third_app目录
- Android6.0关于预置三方app卸载 扫描system/third_app目录
- [RK3288][Android6.0] 调试笔记 --- /data/app/预置apk安装失败
- 关于使用Intent协议在webview中跳转三方app
- 关于app内含支付,使用支付宝等三方被拒绝n次的血与泪!
- [Android6.0][RK3399] 出厂预置可卸载 APK
- 关于ubuntu下Android工作空间出现android-support-v7-appcompat
- 关于Android app首次安装完成后在安装界面直接“打开”应用再按home键返回桌面,重新进入app重复实例化launcher activity的问题的解决
- 关于 android app 返回键模拟 home键 功能的介绍_仿QQ返回键 又重新回到当前界面_锁屏状态 又要重新唤醒
- 关于Certificate、Provisioning Profile、App ID的介绍及其之间的关系
- 关于在VS2008和VS2010中禁用及卸载Visual Assist X的方法研究
- Android6.0 Framework分析——应用程序APP的安装过程
- 关于chrome外部协议请求,启动外部程序,itms,macappstore下载相关
- 关于那些最好玩的户外APP合集下(适合资深驴友、牛逼设计狮、装逼攻城狮)
- ios开发关于用户跳转app store评价app
- 预置APK使用户可以卸载,并且恢复出厂设置时能够恢复
- tizen开发(1)- app卸载,启动与源码
- 关于iOS App 国际化和本地化 的一些总结:国际化 vs 本地化(Internationalization vs Localization)