android 内置第三方apk

本文详细介绍了如何在Android系统中预置APK,包括不可卸载和可卸载的APK预置方法,涉及data/app、vendor/operator/app、system/app和vendor/app等不同目录的预置流程,以及预置过程中遇到的签名、so库路径和权限问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.预置可卸载APK,恢复出厂设置以后不可以恢复,将apk预置到data/app目录下

android o 版本以后google 加入了patch,不允许预置apk到data/app目录下,只允许使用adb install 的方式来安装apk到data/app目录下,需要将
其roll back 回以前的版本,然后用下列方法可以完成预置:
 
https://android.googlesource.com/platform/frameworks/base/+/02cecae02901c86334e09b162c09a6e99187f171%5E%21/services/core/java/com/
android/server/pm/PackageManagerService.java

不能翻墙的可以直接删除下面的代码

                                     + " but expected at " + known.codePathString
                                     + "; ignoring.");
                         }
-                    } else {
+                    } /*else {
                         throw new PackageManagerException(INSTALL_FAILED_INVALID_INSTALL_LOCATION,
                                 "Application package " + pkg.packageName
                                 + " not found; ignoring.");
-                    }
+                    }*/
                 }

 
(1)在 packages/apps 下面以需要预置的 APK 名字创建文件夹,以预置一个名为Test的APK为例 
(2)将 Test.apk 放到 packages/apps/Test 下面 
(3)在 packages/apps/Test 下面创建文件 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 
LOCAL_MODULE_CLASS := APPS 
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) 
# LOCAL_PRIVILEGED_MODULE := true 
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) 
LOCAL_CERTIFICATE := PRESIGNED 
include $(BUILD_PREBUILT) 

(4)打开文件 device\mediatek\common\device.mk 
将 Test 添加到 PRODUCT_PACKAGES 里面。 
PRODUCT_PACKAGES += Test 
(5)重新 build 整个工程 
注意:这个比不能卸载的多了一句 
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
将 Test 添加到 PRODUCT_PACKAGES 里面。 
PRODUCT_PACKAGES += Test 

注意:这里发现了几个问题

这样编译出来的app正常情况会在data/app目录下,并打包到userdata.img,可以通过查看userdata.img的大小来判断,然后烧录,发现app并没有安装成功,发现有下面的错误log

2010-01-01 08:00:30.708 801-801/system_process I/PackageManager: /data/app/Test changed; collecting certs
2010-01-01 08:00:30.762 801-801/system_process W/PackageManager: Failed to scan /data/app/Test: Failed to collect certificates from /data/app/Test/Test.apk
2010-01-01 08:00:30.762 801-801/system_process W/PackageManager: Deleting invalid package at /data/app/Test

签名不对,这个apk采用的是v1签名,于是我去对比了原始的apk和编译到out目录下的,发现确实不一样,查看out目录apk签名,发现多了下面这句:

JAR signature META-INF/CERT.SF indicates the APK is signed using APK Signature Scheme v2 but no such signature was found. Signature stripped?

难道是必须要用v2签名?于是我把apk改成v2的签名,但还是不行,错误如下:

JAR signature META-INF/OSGSERVI.SF indicates the APK is signed using APK Signature Scheme v2 but no such signature was found. Signature stripped?

没办法,我试着把原始的apk直接拷到data/app,然后用make userdataimage-nodeps -j64进行打包,重新烧录,发现这时没有问题

于是我把mk文件改成直接拷贝的方式:

LOCAL_PATH := $(call my-dir)

LOCAL_MODULE := Test.apk
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)/Test
LOCAL_SRC_FILES := Test.apk
 
include $(BUILD_PREBUILT)

这时好了,没有任何问题。当然也可以在其它mk文件添加下面的代码

$(shell mkdir -p $(TARGET_OUT_DATA_APPS)/app/Test)
$(shell cp $(LOCAL_PATH)/Test.apk $(TARGET_OUT_DATA_APPS)/app/Test)

2.预置APK使得用户可以卸载,并且恢复出厂设置时能够恢复,将apk预置到vendor/operator/app目录下

如果apk是v1签名方式,按照如下方式预置:
(1)在 vendor\mediatek\proprietary\packages\3rd-party下面以需要预置的 APK 名字创建文件夹,以预置一个名为Wechat.apk为例 
(2) 将Wechat.apk 放入vendor\mediatek\proprietary\packages\3rd-party\Wechat下面 
(3)在vendor\mediatek\proprietary\packages\3rd-party\Wechat 下面创建文件 Android.mk,文件内容如下 

LOCAL_PATH := $(call my-dir) 
include $(CLEAR_VARS) 
# Module name should match apk name to be installed 
LOCAL_MODULE := Wechat 
LOCAL_MODULE_TAGS := optional 
LOCAL_SRC_FILES := Wechat.apk 
LOCAL_MODULE_CLASS := APPS 
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) 
LOCAL_CERTIFICATE := PRESIGNED 
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/operator/app 
LOCAL_PROPRIETARY_MODULE := true 
LOCAL_MODULE_OWNER := mtk 
include $(BUILD_PREBUILT) 

(4)打开文件device\mediatek\common\device.mk 
将 Wechat 添加到 PRODUCT_PACKAGES 里面。 
PRODUCT_PACKAGES += Wechat 
(5)然后重新build整个工程
 
注意:需要确保MTK_CTA_SET宏是打开的,会定义属性值persist.vendor.pms_removable=1,MTK_CTA_SET和这个属性值不是强相关的,可以分离,然
后在/vendor/mediatek/proprietary/frameworks/base/data/etc/pms_sysapp_removable_vendor_list.txt这个白名单文件中加入需要卸载的apk的
包名

如果是apk是V2签名方式:
(1)在任意一个apk的目录下(Xunfei)的Android.mk的文件中添加如下内容: 
$(shell mkdir $(TARGET_OUT)/vendor/operator/app/Facebook) 
$(shell cp $(LOCAL_PATH)/Facebook.apk $(TARGET_OUT)/vendor/operator/app/Facebook) 
(2)将该Facebook.apk放入任意一个apk目录中,比如放入Xunfei这个目录中 
(3)打开文件device\mediatek\common\device.mk 
将 Facebook 添加到 PRODUCT_PACKAGES 里面。 
PRODUCT_PACKAGES += Facebook 
(4)然后重新build整个工程
 
注意:
(1)需要确保MTK_CTA_SET宏是打开的,会定义属性值persist.vendor.pms_removable=1,MTK_CTA_SET和这个属性值不是强相关的,可以分离,然后
在/vendor/mediatek/proprietary/frameworks/base/data/etc/pms_sysapp_removable_vendor_list.txt这个白名单文件中加入需要卸载的apk的包

 (2)这种方式预置facebook,facebook可以成功预置进手机,但是点击手机的时候会报出avc:denied,selinux权限异常的情况,可以通过在相应的te文
件中加入allow语句

3.预置APK使得用户可以卸载,并且恢复出厂设置时能够恢复,将apk预置到system/app目录下
 
(1) 在 packages/apps 下面以需要预置的 APK 名字创建文件夹,以预置一个名为Test的APK为例 
(2) 将 Test.apk 放到 packages/apps/Test 下面 
(3) 在 packages/apps/Test 下面创建文件 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 
LOCAL_MODULE_CLASS := APPS 
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX) 
 
LOCAL_CERTIFICATE := PRESIGNED 
include $(BUILD_PREBUILT)
 

(4) 打开文件 device\mediatek\common\device.mk 
将 Test 添加到 PRODUCT_PACKAGES 里面。 
PRODUCT_PACKAGES += Test 
(5) 重新 build 整个工程

注意:
(1)需要确保MTK_CTA_SET宏是打开的,会定义属性值persist.vendor.pms_removable=1,MTK_CTA_SET和这个属性值不是强相关的,可以分离,然后
在/vendor/mediatek/proprietary/frameworks/base/data/etc/pms_sysapp_removable_system_list.txt这个白名单文件中加入需要卸载的apk的包

(2)同时需要把so文件放到对应的system/lib下面,这里为什么要放到system/lib目录下面?我试过放在app的lib/arm目录下面,但是会报找不到so库的错误,程序直接崩溃,只有放在vendor/operator/app才会这样,放到vendor/app目录的app就没问题。通过测试发现这种拷贝的方式有一个很大的问题,就是当app版本升级后,机器重启会恢复到原来的版本,所以不要使用这种方式。可以把每一个so库当做module来处理,当然也可以通过拷贝的方式来

include $(CLEAR_VARS)
LOCAL_MODULE := libleds_jni
LOCAL_SRC_FILES := $(LIB_DIR)/libleds_jni.so
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_OWNER := mtk
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_SUFFIX = .so
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/lib/
include $(BUILD_PREBUILT)
$(shell mkdir -p $(PRODUCT_OUT)/system/lib)
$(shell cp $(LOCAL_PATH)/lib/armeabi-v7a/libgpio_jni.so $(PRODUCT_OUT)/system/lib)

4.预置APK使得用户可以卸载,并且恢复出厂设置时能够恢复,将apk预置到vendor/app目录下

写法和vendor/operator/app一样,但是会出现找不到so的错误,可以看到会从3个地方找so库。

libnativeloader: classloader namespace configured for unbundled vendor apk. library_path=/vendor/app/Test/lib/arm64:/vendor/app/Test/Test.apk!/lib/arm64-v8a:/vendor/lib64

所以做法有三种:

a)可以把so提取取出来,然后编译到Test/lib/arm64,这种写法的好处就是不用管系统是32位还是64位的,如果是32位的会编译成lib/arm64,64位的则会编译成lib/arm64

LOCAL_PREBUILT_JNI_LIBS := \
  libgdinamapv4sdk752.so \
  libgdinamapv4sdk752ex.so \
  libJNI_GaussisanBlur.so \
  libStDualCam.so

b)我的apk里面明明是有lib/arm64-v8a文件夹的,但是就是找不到库,也没看到报avc的错误

c)放到系统的vendor/lib64文件夹

include $(CLEAR_VARS)
LOCAL_MODULE := libleds_jni
LOCAL_SRC_FILES := $(LIB_DIR)/libleds_jni.so
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_OWNER := mtk
LOCAL_PROPRIETARY_MODULE := true
LOCAL_MODULE_SUFFIX = .so
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/lib64
include $(BUILD_PREBUILT)

 

内置好了并成功安装之后:

这里发现了一个问题,当app升级之后,重启机器,发现app不见了,写到pms_sysapp_removable_system_list.txt,privapp-permissions-mediatek.xml的app都会这样,反复打log,发现在PackageManagerService.java里面做了处理,可以做如下修改

                     if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                         // M:operator app also is removable and not system flag
-                        if ((!sPmsExt.isRemovableSysApp(ps.name))) {
+						//modify by jueme for vendor app can install at 20201109
+                        //if ((!sPmsExt.isRemovableSysApp(ps.name))) {
                             continue;
-                        }
+                        //}
+						//modify end
                     }


-        final boolean scanSystemPartition = ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0)
+		//modify by jueme for vendor app can install at 20201109
+        //final boolean scanSystemPartition = ((parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0)
                 // M:operator app also is removable and not system flag
-                || sPmsExt.isRemovableSysApp(pkg.packageName);
+                //|| sPmsExt.isRemovableSysApp(pkg.packageName);
+		final boolean scanSystemPartition = (parseFlags & PackageParser.PARSE_IS_SYSTEM_DIR) != 0;
+		//modify end

之后还有个奇怪的问题,当把预制的app卸载后然后重新安装时,发现PackageManager奔溃,错误信息如下

2020-11-09 17:16:19.650 659-963/system_process E/AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: PackageManager
    java.lang.NullPointerException: Attempt to get length of null array
        at com.mediatek.server.pm.PmsExtImpl.updatePackageSettings(PmsExtImpl.java:539)
        at com.android.server.pm.PackageManagerService.updateSettingsInternalLI(PackageManagerService.java:17123)
        at com.android.server.pm.PackageManagerService.updateSettingsLI(PackageManagerService.java:17057)
        at com.android.server.pm.PackageManagerService.installNewPackageLIF(PackageManagerService.java:16468)
        at com.android.server.pm.PackageManagerService.installPackageLI(PackageManagerService.java:17680)
        at com.android.server.pm.PackageManagerService.installPackageTracedLI(PackageManagerService.java:17168)
        at com.android.server.pm.PackageManagerService.access$3500(PackageManagerService.java:416)
        at com.android.server.pm.PackageManagerService$9.run(PackageManagerService.java:15048)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.os.HandlerThread.run(HandlerThread.java:65)
        at com.android.server.ServiceThread.run(ServiceThread.java:44)

于是加了一个为null的判断

                 /// M: Removable system app support
-                sPmsExt.updatePackageSettings(userId, pkgName, pkg, ps, allUsers,
-                        installerPackageName);
+				
+				//add by jueme for vendor app uninstall,then install NullPointerException at 20201109
+				if(allUsers!=null){
+					sPmsExt.updatePackageSettings(userId, pkgName, pkg, ps, allUsers,
+                       installerPackageName);
+				}
+				//add end

fota升级时,发现在pms_sysapp_removable_vendor_list.txt和pms_sysapp_removable_system_list.txt里面的app不能安装,恢复出厂设置可以复原,这个问题困扰了我好久,各种排查问题,一开始以为是MTK平台的问题。但是发现只要不在pms_sysapp_removable_vendor_list和pms_sysapp_removable_system_list里面的应用就可以成功安装,于是去看代码。处理这些txt都是在PmsExtImpl.java。在PackageManagerService.java的scanPackageInternalLI方法里面

    /// M: Skip an uninstalled system or vendor app
            if (sPmsExt.needSkipScanning(pkg, updatedPkg, ps, scanFile))
                return null;

 可以看到这里做了判断

 @Override
    public boolean needSkipScanning(PackageParser.Package pkg,
            PackageSetting updatedPkg, PackageSetting ps, File scanFile) {
       if (!mPms.isFirstBoot() &&
           (isRemovableSysApp(pkg.packageName) || locationIsOperator(scanFile)) &&
           (ps == null && updatedPkg == null)) {
            if (mPms.isUpgrade()) {
                if (isRemovableSysApp(pkg.packageName)
                        && !sRemovableSystemAppSetBak.contains(pkg.packageName)) {
                    Slog.d(TAG, "New added removable sys app by OTA:" + pkg.packageName);
                    return false;
                }
                if (locationIsOperator(scanFile)
                        && sUpgradeOperAppSet.contains(pkg.packageName)
                        && !sUpgradeOperAppSetBak.contains(pkg.packageName)) {
                    Slog.d(TAG, "New added operator app by OTA:" + pkg.packageName);
                    return false;
                }
            }
           Slog.d(TAG, "Skip scanning uninstalled sys package " + pkg.packageName);
           return true;
       } else if (ps == null && updatedPkg != null) {
           Slog.d(TAG, "Skip scanning uninstalled package: " + pkg.packageName);
           return true;
       }

       return false;
    }

如果返回true,就被忽略

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值