预装第三方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
将要执行/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目录下,这里就不多说了。