AndroidL 预置APK

来源:互联网 发布:大学生网络借贷 编辑:程序博客网 时间:2024/06/15 10:08

AndroidL预置第三方应用
1. 预置有源码的APK
a) 将apk源码拷贝到在packages/apps/文件夹下,然后写好apk源码下创建Android.mk文件,添加以下内容:

LOCAL_PATH:= $(call my-dir)             #调用my-dir脚本来获取当前路径
include $(CLEAR_VARS)                     #调用CLEAR_VARS来初始化除LOCAL_PATH以外以LOCAL_开头的变量
LOCAL_MODULE_TAGS := optional #表明这个应用是在所有编译模式都编译的,
LOCAL_SRC_FILES := $(call all-subdir-java-files)#指定要编译的java文件
LOCAL_PACKAGE_NAME := Test    #指定这个应用模块的名称
include $(BUILD_PACKAGE)               #编译这个模块

b) 上述模块加到PRODUCT_PACKAGES中,重新进行编译整个工程。

build/target/product/customers_preset_apackage.mk文件中添加 PRODUCT_PACKAGES += Test


2. 预置无源码的apk
a) packages/apps/创建Test文件夹,将apk拷贝到这个文件夹中,在这个文件下创建一个Android.mk的文件

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# Module name should match apk name to be installed
LOCAL_MODULE := Test
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
#指定这是APPS类型,还有DATA,ETC之类的类型,编译后放到不同的地方,如ETC放etc目录,data放data目录。
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)

#如果有lib则可以添加以下内容,@是将apk的lib抽离出来build进apk同级目录下的lib文件夹中

#lib/armebai/libtest.so是apk减压出来的so的相对路径。这个属性有些应用不写也可以正常预置。

LOCAL_PREBUILT_JNI_LIBS:= \
@lib/armeabi/libtest.so  \
@lib/armeabi/libtest2.so 
# 以下内容是说这个apk已经签过名了,不用再签名了,方便以后apk的升级
LOCAL_CERTIFICATE := PRESIGNED
include $(BUILD_PREBUILT)
b) 如果有多个对应的库,则可以用下述方式来进行匹配
若apk支持不同cpu类型的so,针对so的部分的处理:

Ifeq ($(TARGET_ARCH),arm)
LOCAL_PREBUILT_JNI_LIBS := \
@lib/armeabi-v7a/xxx.so\
@ lib/armeabi-v7a/xxxx.so
else ifeq ($(TARGET_ARCH),x86)
LOCAL_PREBUILT_JNI_LIBS := \
@lib/x86/xxx.so
else ifeq ($(TARGET_ARCH),arm64)
LOCAL_PREBUILT_JNI_LIBS := \
@lib/armeabi-v8a/xxx.so

即将和TARGET_ARCH对应的so抽离出来
c) 将以上模块build进系统,操作如1.b)
d) 指定编译后apk所在位置

LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)  #预置到data/app下
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/app   #预置到system/app下
LOCAL_MODULE_PATH := $(TARGET_OUT)/vendor/app        #预置到system/vendor/app下


3. 预置apk可卸载并可恢复
想要恢复出厂设置时恢复apk,则手机中一定会有个备份,以便恢复出厂设置时恢复。

apk可卸载并可恢复的两种方式 : 

一种是在PackageManagerService中做修改,指定system下的某个目录可以卸载,然后将apk预置到指定的目录中

一种是将apk预置一个不可用目录当备份,然后第一次开机时将此备份后拷贝到data/app目录下即可做一般安装的应用使用

a) 在PackageManagerService中做修改,指定system分区中某个目录为可卸载目录。将apk安装到目录下。
1.  定义两个变,THIRDAPP_DIR为应用安装目录,必须在不可察除分区内
private static final String THIRDAPP_DIR= "/system/vendor/thirdapp";
private static final String THIRDAPP_FILTER_DIR= "/data/data/app";
2.  定义一个可恢复且可卸载的目录
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
……
scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

// add start 
File customersAppDir = new File(THIRDAPP_DIR);
try {
  customersAppDir = customersAppDir.getCanonicalFile();
} catch (IOException e) {
}
scanDirLI(customersAppDir, 0, scanFlags, 0);
// add end
……
}
3.  定义以下两个方法
private boolean filterthirdparyPackage(String scanPath, String pkgName) {
   if (scanPath.startsWith(THIRDAPP_DIR)) {
       final File filter = new File(THIRDAPP_FILTER_DIR, pkgName);
       return filter.isDirectory();
   }
   return false;
}

private void updateVendorthirdpartyFilter(PackageSetting ps) {
   String packageName = ps.name;
       Slog.e(TAG, "packageName---- " + packageName);
       if (ps.pkg != null) {
       String packagePath = ps.pkg.codePath;
       Slog.e(TAG, "packagePath---- " + packagePath);
       if (packagePath != null && packagePath.startsWith(THIRDAPP_DIR)) {
           SystemProperties.set("persist.sys.thirdapp.deleted", "1");
           final File filter = new File(THIRDAPP_FILTER_DIR, packageName);
           filter.mkdirs();
       }
   }
 }
4.  实现重启后删除的apk不再显示
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
   boolean success = false;
   // add start
   final File scanFile = new File(pkg.codePath);
   if (filterthirdparyPackage(scanFile.getPath(), pkg.packageName)) {
       if(SystemProperties.getInt("persist.sys.thirdapp.deleted", -1) == 1){            
           return null;
       }
   }
    // add end
……
}

private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
   ……
   final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, pkgSetting);
   // modified start
   /*if ((isSystemApp(pkg) && !isUpdatedSystemApp(pkg))){*/
   if ((isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) ||
        (codePath.startsWith(THIRDAPP_DIR))) {
   // modified end
   ……
}
……
private boolean deleteInstalledPackageLI(PackageSetting ps,
       boolean deleteCodeAndResources, int flags,
       int[] allUserHandles, boolean[] perUserInstalled,
       PackageRemovedInfo outInfo, boolean writeSettings) {
   ……
   // add start
   updateVendorthirdpartyFilter(ps);
   // add end

   return true;

}


b) 将apk预置到system的某个目录下,如system/endor/thirdpart,将apk备份放到该目录,然后拷贝到data/app下。
1.  在ActivityManagerService中设置一个系统变量(可以是在流程中任意地方)
boolean startHomeActivityLocked(int userId) {
installThirdPartApp();
……
}
private void installThirdPartApp() {
if ("".equals(SystemProperties.get("persist.sys.installapp", "0"))
       || SystemProperties.get("persist.sys.installapp", "0").equals(null)
       || SystemProperties.get("persist.sys.installapp", "0").equals("0")) {
   try{ 
           SystemProperties.set("persist.sys.installapp", "1");
           Slog.d(TAG, "<==> test " + result);
   }catch(Exception e){
           Slog.d(TAG, "<==> test failed" );
           e.printStackTrace();
   }
}
2.  在Init.rc中定义一个拷贝动作
on property:persist.sys.installapp=1
copy /system/installapp /data/app

3.  这个将apk预置到/system/installapp目录中


0 0