Preinstall功能解析

平台:Android4.0
场景:全志方案上的preinstall的解析。
时间:2012.6.20

在A13的4.0平台上,在init.rc文件的最后有这样一段代码
service preinstall /system/bin/busybox sh /system/bin/preinstall.sh
user root
group root
disabled
oneshot
此处定义了一个服务preinstall,其操作是去执行system/bin下面的preinstall.sh脚本。
在preinstall.sh脚本中,有一个if判断,if [ ! -e /data/system.notfirstrun ];当一次开机的时候,data目录必然是没有system.notfirstrun这个文件的,因此if下的一些操作被执行。最后touch /data/system.notfirstrun生成此文件,从而保证下次开机的时候不再进行第一次开机需要执行的操作。
在preinstall.sh的if下面,有一句很有趣的代码
/system/bin/sh /system/bin/pm preinstall /system/preinstall
pm的实现代码在frameworks\base\cmds\pm下面,preinstall为其参数,/system/preinstall参数为文件夹路径。而pm.java中默认是没有对preinstall做处理的。我们知道可以使用pm install apk路径去安装一个apk。因为在pm.java中,全志定制了对参数preinstall的处理,其后参数为一个文件夹的路径,基于install的方式通过一个for循环实现了对目标文件夹下的apk文件的遍历和安装。

    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");  
    }

还需要注意的是,此服务在何时启动?其对应的代码依然在init.rc文件中
on property:sys.boot_completed=1
start preinstall
当sys.boot_completed被设置为1时,服务启动。而sys.boot_completed是在ActivityManagerService.java中设置的,此时系统已基本完成boot。Flash目录此时也已经挂载到mnt/sdcard的设备节点下。

从上面的描述中可以知道,我们基本上可以学习到三个点:
(1).类似于init.rc中的service与on property的配合使用,我们可以将一些需要执行的操作以service的形式加载,当需要使用的时候,通过属性系统的设置来启动。
(2).在第一次开机的初始化操作中,on property:sys.boot_completed=1的时机是在系统已基本上boot的情况下,此时,一些关于flash的操作(例如在flash上mkdir,以及将内置在rom中的文件cp到flash上都是OK的。注意:若flash的文件分区没有mount到mnt/sdcard之前去mkdir,cp,都是可以成功的,但是建立的都是临时文件,重启后便自动丢失)
(3).类似pm.java中的定制,可根据自己的具体需求,对一些命令做一些基于之前实现的扩展,也会达到意想不到的效果。

你可能感兴趣的:(Preinstall功能解析)