概述

一讲到APK装置流程,它有四种装置办法:

  • 体系运用和预制运用装置,开机时完结,没有装置界面,在PKMS的构造函数中欧冠完结装置
  • 网络下载运用装置,经过运用商店来完结,调用PackageManager.installPackages(),有装置界面
  • ADB东西装置,没有装置界面,它经过发动pm脚本的办法,然后调用com.android.commands.pm.Pm类,之后调用到PMS.installStage()完结装置
  • 第三方运用装置,经过SD卡里的APK文件装置,有装置界面,由packageinstaller.apk运用处理装置及卸载进程的界面.

均是经过PackageInstallObserver来监听装置是否成功。

运用装置涉及到如下几个目录

system/app —————体系自带的运用程序,获得adb root权限才干删去

data/app —————用户程序装置的目录。用户 装置时把apk文件 仿制 到此目录 data/data —————寄存运用程序的数据 data/dalvik-cache——–将apk中的dex文件装置到dalvik-cache目录下(dex文件是dalvik虚拟机的可履行文件, 其巨细约为原始apk文件巨细的四分之一)

装置进程:

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

卸载进程:

删去 装置进程中在上述三个目录下创立的文件及目录。

装置运用的进程解析

一.开机装置 PackageManagerService处理各种 运用的装置,卸载,办理等工作,开机时 由systemServer发动此服务

(源文件途径:android\frameworks\base\services\java\com\android\server\PackageManagerService.java)

PackageManagerService服务 发动的流程:

1 .首要 扫描装置 “system\framework” 目录下的jar包

// Find base frameworks (resource packages without code).
•      mFrameworkInstallObserver = new AppDirObserver(
•        mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
•      mFrameworkInstallObserver.startWatching();
•      scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
•          | PackageParser.PARSE_IS_SYSTEM_DIR,
•          scanMode | SCAN_NO_DEX, 0);

2.扫描 装置体系system/app的运用程序

// Collect all system packages.
•      mSystemAppDir = new File(Environment.getRootDirectory(), "app");mSystemInstallObserver = new AppDirObserver(
•        mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
•      mSystemInstallObserver.startWatching();
•      scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
•          | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

3.制造商的目录下/vendor/app运用包

// Collect all vendor packages.
•      mVendorAppDir = new File("/vendor/app");mVendorInstallObserver = new AppDirObserver(
•        mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
•      mVendorInstallObserver.startWatching();
•      scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
•          | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

4.扫描 “data\app”目录,即用户装置的第三方运用

**scanDirLI**(mAppInstallDir, 0, scanMode, 0);

5.扫描” data\app-private”目录,即装置DRM维护的APK文件(一个受维护的歌曲或受保 护的视频是运用 DRM 维护的文件)

scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
•          scanMode, 0);

扫描办法的代码清单

private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
•    String[] files = dir.list();
•    if (files == null) {
•      Log.d(TAG, "No files in app dir " + dir);
•      return;
•    }
•    if (false) {
•      Log.d(TAG, "Scanning app dir " + dir);
•    }
•    int i;
•    for (i=0; i<files.length; i++) {
•      File file = new File(dir, files[i]);
•      if (!isPackageFilename(files[i])) {
•        // Ignore entries which are not apk's
•        continue;
•      }
•      PackageParser.Package pkg = **scanPackageLI**(file,
•          flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
•      // 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
•        Slog.w(TAG, "Cleaning up failed install of " + file);
•        file.delete();
•      }
•    }
  }

而且从该扫描办法中能够看出调用了scanPackageLI()

private PackageParser.Package scanPackageLI(File scanFile,
int parseFlags, int scanMode, long currentTime)

跟踪scanPackageLI()办法后发现,程序经过很屡次的if else 的筛选,最终判定 能够装置apk后,调用了 mInstaller.install

if (mInstaller != null) {
•          int ret = **mInstaller****.install**(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,pkg.applicationInfo.uid);
•          if(ret < 0) {
•            // Error from installer
•            mLastScanError =   PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
•            return null;
•          }
•        }
mInstaller.install() 经过  
 LocalSocketAddress address = new LocalSocketAddress(
•        "**installd**", LocalSocketAddress.Namespace.RESERVED);

指挥installd在C言语的文件中完结工作

PackageManagerService末节 :

1)从apk, xml中载入pacakge信息, 存储到内部成员变量中, 用于后面的查找. 要害的办法是scanPackageLI(). 2)各种查询操作, 包括query Intent操作. 3)install package和delete package的操作. 还有后面的要害办法是installPackageLI().

二、从网络上下载运用:

下载完结后,会主动调用Packagemanager的装置办法installPackage()

  /* Called when a downloaded package installation has been confirmed by the user */

由英文注释可见PackageManagerService 类的installPackage()函数为 装置程序 的进口

public void installPackage(
•      final Uri packageURI, final IPackageInstallObserver observer, final int flags,
•      final String installerPackageName) {
•    mContext.enforceCallingOrSelfPermission(
•        android.Manifest.permission.INSTALL_PACKAGES, null);
•    Message msg = mHandler.obtainMessage(INIT_COPY);
•    msg.obj = new InstallParams(packageURI, observer, flags,
•        installerPackageName);
•    **mHandler****.sendMessage**(msg);
  }

其间是经过PackageHandler的实例mhandler.sendMessage(msg)把信息发给继承Handler的类HandleMessage()办法


class PackageHandler extends Handler{
•         
*****************省掉若干********************
•     public void handleMessage(Message msg) {
•      try {
•        doHandleMessage(msg);
•      } finally {
•        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
•      }
•    }
  ******************省掉若干**********************
 }

把信息发给doHandleMessage()办法,办法中用switch()语句进行判定传来Message


 void doHandleMessage(Message msg) {
•      switch (msg.what) {
•      
•        case INIT_COPY: {
•          if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy");
•          HandlerParams params = (HandlerParams) msg.obj;
•          int idx = mPendingInstalls.size();
•          if (DEBUG_SD_INSTALL) Log.i(TAG, "idx=" + idx);
•          // If a bind was already initiated we dont really// need to do anything. The pending install// will be processed later on.if (!mBound) {
•            // If this is the only one pending we might// have to bind to the service again.if (!connectToService()) {
•              Slog.e(TAG, "Failed to bind to media container service");
•              params.serviceError();
•              return;
•            } else {
•              // Once we bind to the service, the first// pending request will be processed.
•              mPendingInstalls.add(idx, params);
•            }
•          } else {
•            mPendingInstalls.add(idx, params);
•            // Already bound to the service. Just make// sure we trigger off processing the first request.if (idx == 0) {
•              mHandler.sendEmptyMessage(MCS_BOUND);
•            }
•          }
•          break;
•        }
•        case MCS_BOUND: {
•          if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound");
•          if (msg.obj != null) {
•            mContainerService = (IMediaContainerService) msg.obj;
•          }
•          if (mContainerService == null) {
•            // Something seriously wrong. Bail out
•            Slog.e(TAG, "Cannot bind to media container service");
•            for (HandlerParams params : mPendingInstalls) {
•              mPendingInstalls.remove(0);
•              // Indicate service bind errorparams.serviceError();
•            }
•            mPendingInstalls.clear();
•          } else if (mPendingInstalls.size() > 0) {
•            HandlerParams params = mPendingInstalls.get(0);
•            if (params != null) {
•              params.startCopy();
•            }
•          } else {
•            // Should never happen ideally.
•            Slog.w(TAG, "Empty queue");
•          }
•          break;
•        }
•      ****************省掉若干**********************
}
}       
public final boolean sendMessage ([Message](http://developer.android.com/reference/android/os/Message.html) msg)
public final boolean sendEmptyMessage (int what)

两者参数有别。

然后调用抽象类HandlerParams中的一个startCopy()办法

abstract class HandlerParams {
final void startCopy() {
  ***************若干if语句判定否这打回handler音讯*******
handleReturnCode();
}
}

handleReturnCode()复写了两次其间有一次是删去时要调用的,只列出装置调用的一个办法

@Override
•    void handleReturnCode() {
•      // If mArgs is null, then MCS couldn't be reached. When it// reconnects, it will try again to install. At that point, this// will succeed.
•      if (mArgs != null) {
•        processPendingInstall(mArgs, mRet);
•      }
•    }

这时能够清楚的看见 processPendingInstall()被调用。

其间run()办法如下

run(){
synchronized (mInstallLock) {
•            ************省掉*****************
•            installPackageLI(args, true, res);
•          
 }
}

instaPacakgeLI()args,res参数分析


//InstallArgs 是在PackageService界说的static abstract class InstallArgs 静态抽象类。

static abstract class InstallArgs {

其间界说了flag标志,packageURL,创立文件,复制apk,修正包称号,

还有一些删去文件的清理,释放存储函数。

}
 class PackageInstalledInfo {
•    String name;
•    int uid;
•    PackageParser.Package pkg;
•    int returnCode;
•    PackageRemovedInfo removedInfo;
 }

private void installPackageLI(InstallArgs args,
boolean newInstall, 
PackageInstalledInfo res) { int pFlags = args.flags; String installerPackageName = args.installerPackageName; 
File tmpPackageFile = new File(args.getCodePath());
boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
boolean replace = false;
int scanMode = (onSd ? 0 : SCAN_MONITOR) 
| SCAN_FORCE_DEX 
| SCAN_UPDATE_SIGNATURE
| (newInstall ? SCAN_NEW_INSTALL : 0);
// Result object to be returned res.returnCode = PackageManager.INSTALL_SUCCEEDED; 
// Retrieve PackageSettings and parse package int parseFlags = PackageParser.PARSE_CHATTY 
| (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 
0) | (onSd ? PackageParser.PARSE_ON_SDCARD : 0); 
parseFlags |= mDefParseFlags;
PackageParser pp = new PackageParser(tmpPackageFile.getPath()); 
pp.setSeparateProcesses(mSeparateProcesses); 
final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, null, mMetrics, parseFlags);
if (pkg == null) { res.returnCode = pp.getParseError();
return; 
} String pkgName = res.name = pkg.packageName; 
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) 
{ 
if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) { res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY; 
return; 
} 
} 
if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) 
{ res.returnCode = pp.getParseError();
return; 
} // Get rid of all references to package scan path via parser. pp = null; 
String oldCodePath = null;
boolean systemApp = false; 
synchronized (mPackages)
{ 
// Check if installing already existing package if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) { String oldName = mSettings.mRenamedPackages.get(pkgName); 
if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName) && mPackages.containsKey(oldName)) { 
// This package is derived from an original package, // and this device has been updating from that original
// name. We must continue using the original name, so 
// rename the new package here. pkg.setPackageName(oldName); 
pkgName = pkg.packageName; replace = true;
} 
else if (mPackages.containsKey(pkgName))
{ 
// This package, under its official name, already exists
// on the device; we should replace it. replace = true;
} 
} 
PackageSetting ps = mSettings.mPackages.get(pkgName); 
if (ps != null) { oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
if (ps.pkg != null && ps.pkg.applicationInfo != null) 
{ 
systemApp = (ps.pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
}
}
if (systemApp && onSd) 
{ 
// Disable updates to system apps on sdcard Slog.w(TAG, "Cannot install updates to system apps on sdcard"); 
res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; return;
} 
if 
(!args.doRename(res.returnCode, pkgName, oldCodePath))
{
res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
return; 
} 
// Set application objects path explicitly after the rename setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) { replacePackageLI(pkg, parseFlags, scanMode, installerPackageName, res); 
} 
else 
{ 
installNewPackageLI(pkg, parseFlags, scanMode, installerPackageName,res);
} 
}

最终判断 假如曾经 不存在 那么调用installNewPackageLI()

private void installNewPackageLI
(PackageParser.Package pkg, int parseFlags,
int scanMode, 
String installerPackageName,
PackageInstalledInfo res)
{ **********省掉若干************** PackageParser.Package newPackage = **scanPackageLI**(pkg, parseFlags, scanMode, 
System.currentTimeMillis());
*******省掉若干*****}

最终终于 回到了和 开机装置 相同的当地. 与开机办法装置 调用统一办法。

三、从ADB东西装置

进口函数 源文件为pm.java

(源文件途径:android\frameworks\base\cmds\pm\src\com\android\commands\pm\Pm.java)

其间\system\framework\pm.jar 包办理库

包办理脚本 \system\bin\pm 解析

*Pm.java *文件里的 showUsage就是运用办法

private static void showUsage()
{ 
System.err.println("usage: pm [list|path|install|uninstall]"); 
System.err.println(" pm list packages [-f]"); 
System.err.println(" pm list permission-groups"); 
System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); 
System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); 
System.err.println(" pm list features"); System.err.println(" pm path PACKAGE");
 System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH"); 
System.err.println(" pm uninstall [-k] PACKAGE"); System.err.println(" pm enable PACKAGE_OR_COMPONENT");
System.err.println(" pm disable PACKAGE_OR_COMPONENT"); 
System.err.println(" pm setInstallLocation [0/auto] [1/internal] [2/external]");
**************省掉**************
}

装置时分 会调用 runInstall()办法

private void runInstall()
{ 
int installFlags = 0; 
String installerPackageName = null; 
String opt; 
while ((opt=nextOption()) != null) 
{ 
if (opt.equals("-l")) 
{ 
installFlags |= PackageManager.INSTALL_FORWARD_LOCK; } 
else if (opt.equals("-r")) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
} 
else if (opt.equals("-i")) { installerPackageName = nextOptionData(); 
if (installerPackageName == null) { System.err.println("Error: no value specified for -i"); 
showUsage(); 
return; 
} 
} 
else if (opt.equals("-t"))
{ 
installFlags |= PackageManager.INSTALL_ALLOW_TEST;
} 
else if (opt.equals("-s")) 
{ // Override if -s option is specified. installFlags |= PackageManager.INSTALL_EXTERNAL;
} 
else if (opt.equals("-f"))
{ 
// Override if -s option is specified. installFlags |= PackageManager.INSTALL_INTERNAL;
}
else { System.err.println("Error: Unknown option: " + opt); 
showUsage(); 
return;
} 
} String apkFilePath = nextArg(); System.err.println("\tpkg: " + apkFilePath); 
if (apkFilePath == null) { System.err.println("Error: no package specified"); showUsage(); 
return;
} 
**PackageInstallObserver** obs = new PackageInstallObserver(); 
try { mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags, installerPackageName);
synchronized (obs) { while (!obs.finished) { try { obs.wait(); 
} catch (InterruptedException e) { 
} 
} 
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); 
} 
}

其间

PackageInstallObserver obs = new PackageInstallObserver(); 
•      mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
•          installerPackageName);

假如 装置成功

obs.result == PackageManager.INSTALL_SUCCEEDED)

又由于有

IPackageManage mPm;

mPm = IpackageManager.Stub.asInterface(ServiceManager.getService(“package”));

Stub是接口IPackageManage的静态抽象类,asInterface是返回IPackageManager代理的静态办法。

由于class PackageManagerService extends IPackageManager.Stub

所以mPm.installPackage 调用

  /* Called when a downloaded package installation has been confirmed by the user */
  public void **installPackage**(
•      final Uri packageURI, final IPackageInstallObserver observer, final int flags,final String installerPackageName) 

这样 最终 就是 相当于 调用 从网络下载装置进口了。

四,从SD卡装置

体系调用 PackageInstallerActivity.java

源码途径:android/packages/ apps/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java

进入这个Activity会判断信息是否有错,然后调用

private void initiateInstall() 判断 是否 曾经有过 同名包的装置,或者包现已装置

经往后 履行private void startInstallConfirm() 点击OK按钮后经过一系列的装置信息的判断 Intent跳转到

public class **InstallAppProgress**
extends Activity implements View.OnClickListener, OnCancelListener public void onCreate(Bundle icicle)
 { 
super.onCreate(icicle); 
Intent intent = getIntent(); 
mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO); 
mPackageURI = intent.getData();
**initView**(); 
}

办法中调用了initView()办法

public void initView() { requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.op_progress);
int installFlags = 0;
PackageManager pm = getPackageManager(); 
try { PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName, PackageManager.GET_UNINSTALLED_PACKAGES); 
if(pi != null) { installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
} 
} 
catch (NameNotFoundException e) { } 
if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0)
{ Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
} 
PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo, mPackageURI); 
mLabel = as.label; PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet); 
mStatusTextView = (TextView)findViewById(R.id.center_text); mStatusTextView.setText(R.string.installing); 
mProgressBar = (ProgressBar) findViewById(R.id.progress_bar); mProgressBar.setIndeterminate(true); 
// Hide button till progress is being displayed mOkPanel = (View)findViewById(R.id.buttons_panel);
 mDoneButton = (Button)findViewById(R.id.done_button); mLaunchButton = (Button)findViewById(R.id.launch_button); 
mOkPanel.setVisibility(View.INVISIBLE); 
String installerPackageName = getIntent().getStringExtra( Intent.EXTRA_INSTALLER_PACKAGE_NAME);
 PackageInstallObserver observer = new PackageInstallObserver();
pm.**installPackage**(mPackageURI, observer, installFlags, installerPackageName); 
}

以上就是Android中apk的装置流程具体解析;如需更多进阶Android技术交流能够前往下方链接:
传送直达↓↓↓docs.qq.com/doc/DUkNRVF…

总结:

1.体系运用装置――开机时完结

2.网络下载运用装置――最终 会 调用 体系运用装置scanPackageLI 接口;

3.ADB东西装置――最终 会 调用 网络下载运用装置installPackage 接口,然后 相当于 走的 还是体系运用装置 的 途径;

4.第三方运用装置――由 packageinstaller.apk 运用处理装置及卸载,最终也会 调用 网络下载运用装置installPackage 接口,然后 相当于 走的 还是体系运用装置 的 途径。