预装第三方apk,并不是装到/system/app下,而是装到/data/app/下,这两者是有区别是,
前者用户是不可以卸载的,后者用户可以卸载,我们现在实现的就是后者。
1 pm.jar包中添加preinstall命令[ 这一步可以省略 可以直接使用pm.jar包中的install 命令 ]
修改:frameworks/base/cmds/pm/src/com/android/commands/pm/pm.java
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -106,6 +106,10 @@ public final class Pm {
runInstall();
return;
}
+ if ("preinstall".equals(op)) {
+ preInstall();
+ return;
+ }
if ("uninstall".equals(op)) {
runUninstall();
@@ -763,7 +767,50 @@ public final class Pm {
System.err.println(PM_NOT_RUNNING_ERR);
}
}
-
+ private void preInstall() {
+ String path = nextArg();
+ int i;
+
+ System.err.println("\t preInstall path: " + path);
+ if (path == null) {
+ System.err.println("Error: no package specified");
+ showUsage();
+ return;
+ }
+
+ File[] files = new File(path).listFiles();
+
+ for(File apkFilePath : files) {
+ System.err.println("\tpkg: " + apkFilePath);
+ PackageInstallObserver obs = new PackageInstallObserver();
+ try {
+ mPm.installPackage(Uri.fromFile(apkFilePath), obs, 0,null);
+ System.err.println("\t pkg----1------: ");
+ synchronized (obs) {
+ while (!obs.finished) {
+ try {
+ System.err.println("\t pkg----2------: ");
+ obs.wait();
+ System.err.println("\t pkg----3------: ");
+ } catch (InterruptedException e) {
+ System.err.println("\t pkg----4------: ");
+ }
+ }
+ 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);
+ }
+ }
+ System.err.println("\t preInstall path: " + path + " ok");
+ }
private void runInstall() {
int installFlags = 0;
String installerPackageName = null;
2 在init.rc中定义一个preinstall服务
该服务去执行一个脚本,在脚本里面调用pm preinstall命令。
service preinstall /system/xbin/busybox sh /system/bin/preinstall.sh
user root
group root
disabled
oneshot
on property:sys.boot_completed=1
start preinstall
有了以上定义之后,当系统启动完成首,启动preinstall服务,该服务呢,
将要执行/system/bin/preinstall.sh脚本完成预装动作,这个服务只能执行一次(oneshot)
一般开机广播之后 执行成功的时间由apk的大小而定 如果比较大的 可能需要10多秒才能安装完成.
好了,下面看看执行pm preinstall命令的脚本
3 执行执行pm preinstall命令的脚本preinstall.sh
#!/system/xbin/busybox sh
BUSYBOX="/system/xbin/busybox"
if [ ! -e /data/system.notfirstrun ]; then
echo "do preinstall job"
/system/bin/sh /system/bin/pm preinstall /system/preinstall
$BUSYBOX touch /data/system.notfirstrun
echo "preinstall ok"
fi
将 /system/preinstall作为参数(其实就是预装apk的目录),传给pm,将该目录下的apk一次预装。
pm preinstall 最终将调用到frameworks/base/cmds/pm/src/com/android/commands/pm/pm.java
文件中,一次安装apk。
此外,要使init 进程能够启动自定义的Service 需要将系统的SELINUX关闭
diff --git a/android/system/core/init/init.cpp b/android/system/core/init/init.cpp
index 05c0c05..d0920f6 100644
--- a/android/system/core/init/init.cpp
+++ b/android/system/core/init/init.cpp
@@ -982,6 +982,7 @@ static void selinux_initialize(bool in_kernel_domain) {
}
bool is_enforcing = selinux_is_enforcing();
+ is_enforcing = 0;
security_setenforce(is_enforcing);
if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {
所以,要预装apk,还需要将预装的第三方apk拷贝到/system/preinstall目录下, Android.mk写法模板
LOCAL_PATH := $(call my-dir)
#########################
include $(CLEAR_VARS)
LOCAL_MODULE := YourApk
LOCAL_MODULE_TAGS := optional
LOCAL_DEX_PREOPT :=false
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_PATH := $(TARGET_OUT)/preinstall
LOCAL_MODULE_CLASS := APPS
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
include $(BUILD_PREBUILT)
Reference :http://blog.csdn.net/fe421504975/article/details/8272663#