当前位置: 代码迷 >> Android >> Android怎么安装系统应用,及自己增加安装系统应用的接口
  详细解决方案

Android怎么安装系统应用,及自己增加安装系统应用的接口

热度:44   发布时间:2016-04-28 02:56:46.0
Android如何安装系统应用,及自己增加安装系统应用的接口

                           根据SIM卡安装系统应用

功能:

1:如何安装系统应用,apk放在system/app系统分区下面。
2:根据SIM卡的归属国家选择性的安装应用。

一:本人使用方法:

        在开机的服务里面添加接口(PackageManagerService.java),检测到SIM卡的信息调用该接口。
下面是具体的方法:
       系统服务PackageManager服务调用的是aidl接口,所以添加接口要添加两个地方,一个是IpackageManager.aidl,还有一个是PackageManagerService.java里面添加接口。下面在PackageManagerService.java里面添加的接口
   private static String[] mAddedApks = { "HandwritePack.apk", "PinyinPack.apk",	»       »       »       "ChtPack_.apk", "TouchPal.apk" };         public String[] getApks(){	    »       return mAddedApks;	    }	    	    public void scanApkAndInstallAll(){»       »       File systemAppDir = new File(Environment.getRootDirectory(), "app");»       »       for (String appName : mAddedApks) {»       »       »       File installApp = new File(systemAppDir, appName);»       »       »       if(!installApp.exists()){»       »       »       »       continue;	»       »       »       }»       »       »       »       »       »       String addedPackage = null;	»       »       »       int addedAppId = -1;	»       »       »       int[] addedUsers = null;	»       »       »       /*	»       »       »        * if (!isPackageFilename(installApp)) { // Ignore entries which are»       »       »        * not apk's continue; }	»       »       »        */	»       »       »       // Set flag to monitor and not change apk file paths when	»       »       »       // scanning install directories.	»       »       »       int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME;»       »       »       int flags = (PackageParser.PARSE_IS_SYSTEM	»       »       »       »       »       | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_CHATTY);»       »       »       if (mNoDexOpt) {	»       »       »       »       scanMode |= SCAN_NO_DEX;	»       »       »       }	»       »       »       synchronized (mInstallLock) {»       »       »       »       PackageParser.Package pkg = scanPackageLI(installApp, flags	»       »       »       »       »       »       | PackageParser.PARSE_MUST_BE_APK, scanMode,	»       »       »       »       »       »       System.currentTimeMillis(), UserHandle.ALL);	»       »       »       »       // Don't mess around with apps in system partition.	»       »       »       »       if (pkg == null	1547»       »       »       »       »       »       && (flags & PackageParser.PARSE_IS_SYSTEM) == 0»       »       »       »       »       »       && mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {	»       »       »       »       »       // Delete the apk	»       »       »       »       »       installApp.delete();	»       »       »       »       }	»       »       »       »       if (pkg != null) {	»       »       »       »       »       /*	»       »       »       »       »        * TODO this seems dangerous as the package may have changed	»       »       »       »       »        * since we last acquired the mPackages lock.	»       »       »       »       »        */	»       »       »       »       »       // writer	»       »       »       »       »       synchronized (mPackages) {	»       »       »       »       »       »       updatePermissionsLPw(	»       »       »       »       »       »       »       »       pkg.packageName,	»       »       »       »       »       »       »       »       pkg,	»       »       »       »       »       »       »       »       pkg.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL	»       »       »       »       »       »       »       »       »       »       : 0);	»       »       »       »       »       }	»       »       »       »       »       addedPackage = pkg.applicationInfo.packageName;»       »       »       »       »       addedAppId = UserHandle.getAppId(pkg.applicationInfo.uid);	»       »       »       »       »       addedUsers = sUserManager.getUserIds();»       »       »       »       »       // reader	»       »       »       »       »       synchronized (mPackages) {	»       »       »       »       »       »       mSettings.writeLPr();	»       »       »       »       »       }	»       »       »       »       }	»       »       »       }	»       »       »       if (addedPackage != null) {	»       »       »       »       Bundle extras = new Bundle(1);»       »       »       »       extras.putInt(Intent.EXTRA_UID, addedAppId);	»       »       »       »       sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,	»       »       »       »       »       »       extras, null, null, addedUsers);	»       »       »       }	»       »       }	    }	»       public void scanApkAndInstall(String apkName) {	»       »       File systemAppDir = new File(Environment.getRootDirectory(), "app");	»       »       File installApp = new File(systemAppDir, apkName);	»       »       if (!installApp.exists()) {	»       »       »       return;	»       »       }	»       »       String addedPackage = null;	»       »       int addedAppId = -1;	»       »       int[] addedUsers = null;	»       »       /*	»       »        * if (!isPackageFilename(installApp)) { // Ignore entries which are not	»       »        * apk's continue; }	»       »        */	»       »       // Set flag to monitor and not change apk file paths when	»       »       // scanning install directories.	»       »       int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME;	»       »       int flags = (PackageParser.PARSE_IS_SYSTEM	»       »       »       »       | PackageParser.PARSE_IS_SYSTEM_DIR | PackageParser.PARSE_CHATTY);	»       »       if (mNoDexOpt) {	»       »       »       scanMode |= SCAN_NO_DEX;	»       »       }	»       »       synchronized (mInstallLock) {	»       »       »       PackageParser.Package pkg = scanPackageLI(installApp, flags	»       »       »       »       »       | PackageParser.PARSE_MUST_BE_APK, scanMode,	»       »       »       »       »       System.currentTimeMillis(), UserHandle.ALL);	»       »       »       // Don't mess around with apps in system partition.	»       »       »       if (pkg == null	»       »       »       »       »       && (flags & PackageParser.PARSE_IS_SYSTEM) == 0	»       »       »       »       »       && mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {	»       »       »       »       // Delete the apk	»       »       »       »       installApp.delete();	»       »       »       }	»       »       »       if (pkg != null) {	»       »       »       »       /*	»       »       »       »        * TODO this seems dangerous as the package may have changed	»       »       »       »        * since we last acquired the mPackages lock.	»       »       »       »        */	»       »       »       »       // writer	»       »       »       »       synchronized (mPackages) {	»       »       »       »       »       updatePermissionsLPw(pkg.packageName, pkg,	»       »       »       »       »       »       »       pkg.permissions.size() > 0 ? UPDATE_PERMISSIONS_ALL	»       »       »       »       »       »       »       »       »       : 0);	»       »       »       »       }	»       »       »       »       addedPackage = pkg.applicationInfo.packageName;	»       »       »       »       addedAppId = UserHandle.getAppId(pkg.applicationInfo.uid);	»       »       »       »       addedUsers = sUserManager.getUserIds();	»       »       »       »       // reader	»       »       »       »       synchronized (mPackages) {	»       »       »       »       »       mSettings.writeLPr();	»       »       »       »       }	»       »       »       }	»       »       }	»       »       if (addedPackage != null) {	»       »       »       Bundle extras = new Bundle(1);	»       »       »       extras.putInt(Intent.EXTRA_UID, addedAppId);	»       »       »       sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage,»       »       »       »       »       extras, null, null, addedUsers);	»       »       }	»       }
scanApkAndInstallAll()是安装预先放在system/app里面的文件,安装为系统app,而不是普通应用。
scanApkAndInstall(String apk),安装system/app下面的其他的文件。
IPackageManager.aidl文件里面添加对应的接口(如果你想开放该接口)。
    void scanApkAndInstall(String apkName);    void scanApkAndInstallAll();	   


二:下面我们看看APK安装过程:

   Android应用安装有如下四种方式:

   1.系统应用安装---开机时完成,没有安装界面--------->>重要:既然我们需要选择安装,所以第一次开机就不需要安装某些APK(以后检测到SIM卡在安装)

   2.网络下载应用安装---通过market应用完成,没有安装界面。

   3.ADB工具安装---没有安装界面。 --------->其实adb push到/system/app,system/priv-app的时候执行了安装动作,只是没有界面。

   4.第三方应用安装---通过SD卡里的APK文件安装,有安装界面,由  packageinstaller.apk应用处理安装及卸载过程的界面。


应用安装的流程及路径 
应用安装涉及到如下几个目录:        

system/app ---------------系统自带的应用程序,获得adb root权限才能删除

data/app  ---------------用户程序安装的目录。安装时把apk文件复制到此目录

data/data ---------------存放应用程序的数据

data/dalvik-cache--------将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件)

  安装过程:

  复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。

  卸载过程:

  删除安装过程中在上述三个目录下创建的文件及目录。

  所以,为了避免开机的时候安装,我们需要过滤某些检测到SIM卡之后才安装的apk。我们在PackageManagerService.java的函数
  private void scanDirLI(File dir, int flags, int scanMode, long currentTime)
  里面过滤这些apk。
  private boolean isContainsMyApks(String appName){	    »       if(appName == null){	    »       »       return false;	    »       }	    »       for(String app:mAddedPHICOMMApks){	    »       »       if(app.equals(appName)){	    »       »       »       return true;	    »       »       };    »       }	    »       return false;	    »       				    }

for (i = 0; i < files.length; i++) {    if (dir.getPath().equals(mSystemAppPath)  && isContainsMyApks(files[i])) { } else {     File file = new File(dir, files[i]);     if (!isPackageFilename(files[i])) {         continue;     }     PackageParser.Package pkg = scanPackageLI(file, flags .............下面的省略


三:使用这些接口。

    我们在接收到SIM卡为ready的广播后,调用这个方法安装系统应用。我在settings里面写的接收广播。AndroidManifests.xml里面加上
<receiver android:name=".SIMStateReceiver">	            <intent-filter>	                <action android:name="android.intent.action.SIM_STATE_CHANGED" />	            </intent-filter>	        </receiver>
    
package com.android.settings;	2import android.app.Service;	import android.content.BroadcastReceiver;	import android.content.Context;	import android.content.Intent;	import android.content.pm.IPackageManager;	import android.os.RemoteException;	import android.os.ServiceManager;	import android.os.SystemProperties;	import android.telephony.TelephonyManager;	import android.util.Log;	/**	 * This doucment was added by haiyong.liu to install system/app if SIM iccid is from taiwan .	 * @author  *	 */	public class SIMStateReceiver extends BroadcastReceiver	{»       private static final String PERSIST_SYS_SIMAPK_INSTALL = "persist.sys.simapkinstall";	»       private static boolean isInstalling = false;	»       @Override	»       public void onReceive(Context context, Intent intent) {	»       »       if (intent.getAction()	»       »       »       »       .equals("android.intent.action.SIM_STATE_CHANGED")) {	»       »       »       TelephonyManager tm = (TelephonyManager) context	»       »       »       »       »       .getSystemService(Service.TELEPHONY_SERVICE);	»       »       »       int state = tm.getSimState();	»       »       »       switch (state) {	»       »       »       case TelephonyManager.SIM_STATE_READY:	»       »       »       »       Log.e("haiyong.liu", "SIM_STATE_READY");	»       »       »       »       if (!isInstalling) {	»       »       »       »       »       isInstalling = true;	»       »       »       »       »       installPHICOMMApksAndOther(tm);	»       »       »       »       }	»       »       »       »       break;	»       »       »       default:	»       »       »       »       break;	»       »       »       }	»       »       }	»       }	
 private void installPHICOMMApksAndOther(TelephonyManager tm) {	»       »       String propSimString = SystemProperties.get(PERSIST_SYS_SIMAPK_INSTALL);	»       »       String iccidString = tm.getSimSerialNumber();	»       »       if (iccidString.startsWith("8988")	»       »       »       »       && (propSimString == null || propSimString.equals(""))) {	»       »       »       IPackageManager iPackageManager = IPackageManager.Stub	»       »       »       »       »       .asInterface(ServiceManager.getService("package"));	注意该接口的使用,因开机注册的时候使用的是"package""»       »       »       try {	»       »       »       »       iPackageManager.scanPHICOMMApkAndInstallAll();»       »       »       } catch (RemoteException e) {	»       »       »       »       Log.e("haiyong.liu", "SIMStateReceiver RemoteException:" + e);	»       »       »       }	»       »       »       SystemProperties.set(PERSIST_SYS_SIMAPK_INSTALL, "installed");	»       »       } else if (propSimString.equals("installed")) {	»       »       }	»       }	} 


这些,为了避免开机重复安装,我们使用Systemproperties.set()往系统属性里面添加一个系统值,如果安装,则写入值,开机的时候读取这个值,避免重复安装。
  相关解决方案