应用程序包的安装是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包

    1. // Find base frameworks (resource packages without code).
    2. mFrameworkInstallObserver = new AppDirObserver(
    3. mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
    4. mFrameworkInstallObserver.startWatching();
    5. scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM
    6. | PackageParser.PARSE_IS_SYSTEM_DIR,
    7. scanMode | SCAN_NO_DEX, 0);

    2.扫描安装系统system/app的应用程序

    1. // Collect all system packages.
    2. mSystemAppDir = new File(Environment.getRootDirectory(), "app");
    3. mSystemInstallObserver = new AppDirObserver(
    4. mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
    5. mSystemInstallObserver.startWatching();
    6. scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM
    7. | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

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

    1. // Collect all vendor packages.
    2. mVendorAppDir = new File("/vendor/app");
    3. mVendorInstallObserver = new AppDirObserver(
    4. mVendorAppDir.getPath(), OBSERVER_EVENTS, true);
    5. mVendorInstallObserver.startWatching();
    6. scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
    7. | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

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

    1. scanDirLI(mAppInstallDir, 0, scanMode, 0);

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

    1. scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
    2. scanMode, 0);

    扫描方法的代码清单

    1. private void scanDirLI(File dir, int flags, int scanMode, long currentTime) {
    2. String[] files = dir.list();
    3. if (files == null) {
    4. Log.d(TAG, "No files in app dir " + dir);
    5. return;
    6. }
    7. if (false) {
    8. Log.d(TAG, "Scanning app dir " + dir);
    9. }
    10. int i;
    11. for (i=0; i<files.length; i++) {
    12. File file = new File(dir, files[i]);
    13. if (!isPackageFilename(files[i])) {
    14. // Ignore entries which are not apk's
    15. continue;
    16. }
    17. PackageParser.Package pkg = scanPackageLI(file,
    18. flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime);
    19. // Don't mess around with apps in system partition.
    20. if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
    21. mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
    22. // Delete the apk
    23. Slog.w(TAG, "Cleaning up failed install of " + file);
    24. file.delete();
    25. }
    26. }
    27. }

    并且从该扫描方法中可以看出调用了scanPackageLI()

    private PackageParser.Package scanPackageLI(File scanFile,

    int parseFlags, int scanMode, long currentTime)

    跟踪scanPackageLI()方法后发现,程序经过很多次的if else 的筛选,最后判定可以安装后调用了 mInstaller.install

    1. if (mInstaller != null) {
    2. int ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,pkg.applicationInfo.uid);
    3. if(ret < 0) {
    4. // Error from installer
    5. mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    6. return null;
    7. }
    8. }
    9. mInstaller.install() 通过
    10. LocalSocketAddress address = new LocalSocketAddress(
    11. "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()函数为安装程序入口。

    1. public void installPackage(
    2. final Uri packageURI, final IPackageInstallObserver observer, final int flags,
    3. final String installerPackageName) {
    4. mContext.enforceCallingOrSelfPermission(
    5. android.Manifest.permission.INSTALL_PACKAGES, null);
    6. Message msg = mHandler.obtainMessage(INIT_COPY);
    7. msg.obj = new InstallParams(packageURI, observer, flags,
    8. installerPackageName);
    9. mHandler.sendMessage(msg);
    10. }

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

    1. class PackageHandler extends Handler{
    2. *****************省略若干********************
    3. public void handleMessage(Message msg) {
    4. try {
    5. doHandleMessage(msg);
    6. } finally {
    7. Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    8. }
    9. }
    10. ******************省略若干**********************
    11. }

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

    1. void doHandleMessage(Message msg) {
    2. switch (msg.what) {
    3. case INIT_COPY: {
    4. if (DEBUG_SD_INSTALL) Log.i(TAG, "init_copy");
    5. HandlerParams params = (HandlerParams) msg.obj;
    6. int idx = mPendingInstalls.size();
    7. if (DEBUG_SD_INSTALL) Log.i(TAG, "idx=" + idx);
    8. // If a bind was already initiated we dont really
    9. // need to do anything. The pending install
    10. // will be processed later on.
    11. if (!mBound) {
    12. // If this is the only one pending we might
    13. // have to bind to the service again.
    14. if (!connectToService()) {
    15. Slog.e(TAG, "Failed to bind to media container service");
    16. params.serviceError();
    17. return;
    18. } else {
    19. // Once we bind to the service, the first
    20. // pending request will be processed.
    21. mPendingInstalls.add(idx, params);
    22. }
    23. } else {
    24. mPendingInstalls.add(idx, params);
    25. // Already bound to the service. Just make
    26. // sure we trigger off processing the first request.
    27. if (idx == 0) {
    28. mHandler.sendEmptyMessage(MCS_BOUND);
    29. }
    30. }
    31. break;
    32. }
    33. case MCS_BOUND: {
    34. if (DEBUG_SD_INSTALL) Log.i(TAG, "mcs_bound");
    35. if (msg.obj != null) {
    36. mContainerService = (IMediaContainerService) msg.obj;
    37. }
    38. if (mContainerService == null) {
    39. // Something seriously wrong. Bail out
    40. Slog.e(TAG, "Cannot bind to media container service");
    41. for (HandlerParams params : mPendingInstalls) {
    42. mPendingInstalls.remove(0);
    43. // Indicate service bind error
    44. params.serviceError();
    45. }
    46. mPendingInstalls.clear();
    47. } else if (mPendingInstalls.size() > 0) {
    48. HandlerParams params = mPendingInstalls.get(0);
    49. if (params != null) {
    50. params.startCopy();
    51. }
    52. } else {
    53. // Should never happen ideally.
    54. Slog.w(TAG, "Empty queue");
    55. }
    56. break;
    57. }
    58. ****************省略若干**********************
    59. }
    60. }

    public final boolean sendMessage (Message msg)

    public final boolean sendEmptyMessage (int what)

    两者参数有别。

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

    1. abstract class HandlerParams {
    2. final void startCopy() {
    3. ***************若干if语句判定否这打回handler消息*******
    4. handleReturnCode();
    5. }
    6. }

    handleReturnCode()复写了两次其中有一次是删除时要调用的,只列出安装调用的一个方法

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

    这时可以清楚的看见 processPendingInstall()被调用。

    其中run()方法如下

    1. run(){
    2. synchronized (mInstallLock) {
    3. ************省略*****************
    4. installPackageLI(args, true, res);
    5. }
    6. }
    7. instaPacakgeLI()args,res参数分析

    //InstallArgs 是在PackageService定义的static abstract class InstallArgs 静态抽象类。

    1. static abstract class InstallArgs {
    2. *********************************************************************
    3. 其中定义了flag标志,packageURL,创建文件,拷贝apk,修改包名称,
    4. 还有一些删除文件的清理,释放存储函数。
    5. *********************************************************************
    6. }
    7. class PackageInstalledInfo {
    8. String name;
    9. int uid;
    10. PackageParser.Package pkg;
    11. int returnCode;
    12. PackageRemovedInfo removedInfo;
    13. }

    1. private void installPackageLI(InstallArgs args,
    2. boolean newInstall, PackageInstalledInfo res) {
    3. int pFlags = args.flags;
    4. String installerPackageName = args.installerPackageName;
    5. File tmpPackageFile = new File(args.getCodePath());
    6. boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
    7. boolean onSd = ((pFlags & PackageManager.INSTALL_EXTERNAL) != 0);
    8. boolean replace = false;
    9. int scanMode = (onSd ? 0 : SCAN_MONITOR) | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE
    10. | (newInstall ? SCAN_NEW_INSTALL : 0);
    11. // Result object to be returned
    12. res.returnCode = PackageManager.INSTALL_SUCCEEDED;
    13. // Retrieve PackageSettings and parse package
    14. int parseFlags = PackageParser.PARSE_CHATTY |
    15. (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) |
    16. (onSd ? PackageParser.PARSE_ON_SDCARD : 0);
    17. parseFlags |= mDefParseFlags;
    18. PackageParser pp = new PackageParser(tmpPackageFile.getPath());
    19. pp.setSeparateProcesses(mSeparateProcesses);
    20. final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile,
    21. null, mMetrics, parseFlags);
    22. if (pkg == null) {
    23. res.returnCode = pp.getParseError();
    24. return;
    25. }
    26. String pkgName = res.name = pkg.packageName;
    27. if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) {
    28. if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) {
    29. res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY;
    30. return;
    31. }
    32. }
    33. if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) {
    34. res.returnCode = pp.getParseError();
    35. return;
    36. }
    37. // Get rid of all references to package scan path via parser.
    38. pp = null;
    39. String oldCodePath = null;
    40. boolean systemApp = false;
    41. synchronized (mPackages) {
    42. // Check if installing already existing package
    43. if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
    44. String oldName = mSettings.mRenamedPackages.get(pkgName);
    45. if (pkg.mOriginalPackages != null
    46. && pkg.mOriginalPackages.contains(oldName)
    47. && mPackages.containsKey(oldName)) {
    48. // This package is derived from an original package,
    49. // and this device has been updating from that original
    50. // name. We must continue using the original name, so
    51. // rename the new package here.
    52. pkg.setPackageName(oldName);
    53. pkgName = pkg.packageName;
    54. replace = true;
    55. } else if (mPackages.containsKey(pkgName)) {
    56. // This package, under its official name, already exists
    57. // on the device; we should replace it.
    58. replace = true;
    59. }
    60. }
    61. PackageSetting ps = mSettings.mPackages.get(pkgName);
    62. if (ps != null) {
    63. oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
    64. if (ps.pkg != null && ps.pkg.applicationInfo != null) {
    65. systemApp = (ps.pkg.applicationInfo.flags &
    66. ApplicationInfo.FLAG_SYSTEM) != 0;
    67. }
    68. }
    69. }
    70. if (systemApp && onSd) {
    71. // Disable updates to system apps on sdcard
    72. Slog.w(TAG, "Cannot install updates to system apps on sdcard");
    73. res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
    74. return;
    75. }
    76. if (!args.doRename(res.returnCode, pkgName, oldCodePath)) {
    77. res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
    78. return;
    79. }
    80. // Set application objects path explicitly after the rename
    81. setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
    82. pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
    83. if (replace) {
    84. replacePackageLI(pkg, parseFlags, scanMode,
    85. installerPackageName, res);
    86. } else {
    87. installNewPackageLI(pkg, parseFlags, scanMode,
    88. installerPackageName,res);
    89. }
    90. }

    最后判断如果以前不存在那么调用installNewPackageLI()

    1. private void installNewPackageLI(PackageParser.Package pkg,
    2. int parseFlags,int scanMode,
    3. String installerPackageName, PackageInstalledInfo res) {
    4. ***********************省略若干*************************************************
    5. PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
    6. System.currentTimeMillis());
    7. ***********************省略若干**************************************************
    8. }

    最后终于回到了和开机安装一样的地方.与开机方式安装调用统一方法。

    三、从ADB工具安装

    其入口函数源文件为pm.java

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

    其中\system\framework\pm.jar 包管理库

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

    showUsage就是使用方法

    1. private static void showUsage() {
    2. System.err.println("usage: pm [list|path|install|uninstall]");
    3. System.err.println(" pm list packages [-f]");
    4. System.err.println(" pm list permission-groups");
    5. System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]");
    6. System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]");
    7. System.err.println(" pm list features");
    8. System.err.println(" pm path PACKAGE");
    9. System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
    10. System.err.println(" pm uninstall [-k] PACKAGE");
    11. System.err.println(" pm enable PACKAGE_OR_COMPONENT");
    12. System.err.println(" pm disable PACKAGE_OR_COMPONENT");
    13. System.err.println(" pm setInstallLocation [0/auto] [1/internal] [2/external]");
    14. **********************省略**************************
    15. }

    安装时候会调用 runInstall()方法

    1. private void runInstall() {
    2. int installFlags = 0;
    3. String installerPackageName = null;
    4. String opt;
    5. while ((opt=nextOption()) != null) {
    6. if (opt.equals("-l")) {
    7. installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
    8. } else if (opt.equals("-r")) {
    9. installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
    10. } else if (opt.equals("-i")) {
    11. installerPackageName = nextOptionData();
    12. if (installerPackageName == null) {
    13. System.err.println("Error: no value specified for -i");
    14. showUsage();
    15. return;
    16. }
    17. } else if (opt.equals("-t")) {
    18. installFlags |= PackageManager.INSTALL_ALLOW_TEST;
    19. } else if (opt.equals("-s")) {
    20. // Override if -s option is specified.
    21. installFlags |= PackageManager.INSTALL_EXTERNAL;
    22. } else if (opt.equals("-f")) {
    23. // Override if -s option is specified.
    24. installFlags |= PackageManager.INSTALL_INTERNAL;
    25. } else {
    26. System.err.println("Error: Unknown option: " + opt);
    27. showUsage();
    28. return;
    29. }
    30. }
    31. String apkFilePath = nextArg();
    32. System.err.println("\tpkg: " + apkFilePath);
    33. if (apkFilePath == null) {
    34. System.err.println("Error: no package specified");
    35. showUsage();
    36. return;
    37. }
    38. PackageInstallObserver obs = new PackageInstallObserver();
    39. try {
    40. mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
    41. installerPackageName);
    42. synchronized (obs) {
    43. while (!obs.finished) {
    44. try {
    45. obs.wait();
    46. } catch (InterruptedException e) {
    47. }
    48. }
    49. if (obs.result == PackageManager.INSTALL_SUCCEEDED) {
    50. System.out.println("Success");
    51. } else {
    52. System.err.println("Failure ["
    53. + installFailureToString(obs.result)
    54. + "]");
    55. }
    56. }
    57. } catch (RemoteException e) {
    58. System.err.println(e.toString());
    59. System.err.println(PM_NOT_RUNNING_ERR);
    60. }
    61. }

    其中的

    PackageInstallObserver obs = new PackageInstallObserver();

    1. mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags,
    2. installerPackageName);

    如果安装成功

    obs.result == PackageManager.INSTALL_SUCCEEDED)

    又因为有

    IPackageManage mPm;

    1. mPm = IpackageManager.Stub.asInterface(ServiceManager.getService(&#34;package&#34;));

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

    因为class PackageManagerService extends IPackageManager.Stub

    所以mPm.installPackage 调用

    1. /<em> Called when a downloaded package installation has been confirmed by the user </em>/
    2. public void installPackage(
    3. 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会判断信息是否有错,然后调用

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

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

    1. public class InstallAppProgress extends Activity implements View.OnClickListener, OnCancelListener
    2. public void onCreate(Bundle icicle) {
    3. super.onCreate(icicle);
    4. Intent intent = getIntent();
    5. mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
    6. mPackageURI = intent.getData();
    7. initView();
    8. }

    方法中调用了initView()方法

    1. public void initView() {
    2. requestWindowFeature(Window.FEATURE_NO_TITLE);
    3. setContentView(R.layout.op_progress);
    4. int installFlags = 0;
    5. PackageManager pm = getPackageManager();
    6. try {
    7. PackageInfo pi = pm.getPackageInfo(mAppInfo.packageName,
    8. PackageManager.GET_UNINSTALLED_PACKAGES);
    9. if(pi != null) {
    10. installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
    11. }
    12. } catch (NameNotFoundException e) {
    13. }
    14. if((installFlags & PackageManager.INSTALL_REPLACE_EXISTING )!= 0) {
    15. Log.w(TAG, "Replacing package:" + mAppInfo.packageName);
    16. }
    17. PackageUtil.AppSnippet as = PackageUtil.getAppSnippet(this, mAppInfo,
    18. mPackageURI);
    19. mLabel = as.label;
    20. PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
    21. mStatusTextView = (TextView)findViewById(R.id.center_text);
    22. mStatusTextView.setText(R.string.installing);
    23. mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);
    24. mProgressBar.setIndeterminate(true);
    25. // Hide button till progress is being displayed
    26. mOkPanel = (View)findViewById(R.id.buttons_panel);
    27. mDoneButton = (Button)findViewById(R.id.done_button);
    28. mLaunchButton = (Button)findViewById(R.id.launch_button);
    29. mOkPanel.setVisibility(View.INVISIBLE);
    30. String installerPackageName = getIntent().getStringExtra(
    31. Intent.EXTRA_INSTALLER_PACKAGE_NAME);
    32. PackageInstallObserver observer = new PackageInstallObserver();
    33. pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
    34. }

    方法最后我们可以看到再次调用安装接口完成安装。