预装第三方apk,并不是装到/system/app下,而是装到/data/app/下,这两者是有区别是,
前者用户是不可以卸载的,后者用户可以卸载,我们现在实现的就是后者。
1 pm.jar包中添加preinstall命令
修改: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/bin/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)
好了,下面看看执行pm preinstall命令的脚本
#!/system/bin/busybox sh BUSYBOX="/system/bin/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。
所以,要预装apk,还需要将预装的第三方apk拷贝到/system/preinstall目录下,这里就不多说了。