Android APK安装过程及原理详解
FROM:http://blog.csdn.net/hdhd588/article/details/6739281
=============================================================
应用程序包的安装是android的特点
APK---AndroidPackage
Android应用安装有如下四种方式:
1.系统应用安装---开机时完成,没有安装界面
2.网络下载应用安装---通过market应用完成,没有安装界面
3.ADB工具安装---没有安装界面。
4.第三方应用安装---通过SD卡里的APK文件安装,有安装界面,由 packageinstaller.apk应用处理安装及卸载过程的界面。
应用安装的流程及路径
应用安装涉及到如下几个目录:
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 的筛选,最后判定可以安装后调用了 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 error
- params.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 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 解析
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(/home/zhongda/androidSRC/vortex-8inch-for-hoperun/packages/apps/PackageInstaller/src/com/android/packageinstaller)
进入这个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);
- }
方法最后我们可以看到再次调用安装接口installPackage()完成安装。