預裝第三方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目錄下,這裏就不多說了。