应用安装是智能机的主要特点,即用户可以把各种应用(如游戏等)安装到手机上,并可以对其进行卸载等管理操作。APK是Android Package的缩写,即Android安装包。APK是类似Symbian Sis或Sisx的文件格式。通过将APK文件直接传到Android模拟器或Android手机中执行即可安装。Android应用安装有如下四种方式
1. 系统应用安装――开机时完成,没有安装界面
2. 网络下载应用安装――通过et应用完成,没有安装界面
3. ADB工具安装――没有安装界面。
4. 第三方应用安装――通过SD卡里的APK文件安装,有安装界面,由packageinstaller.apk应用处理安装及卸载过程的界面。
应用安装的流程及路径
应用安装涉及到如下几个目录:
system/app  系统自带的应用程序,无法删除
data/app 用户程序安装的目录,有删除权限。
安装时把apk文件复制到此目录
data/data 存放应用程序的数据
Data/dalvik-cache 将apk中的dex文件安装到dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小约为原始apk文件大小的四分之一) 安装过程:复制APK安装包到data/app目录下,解压并扫描安装包,把dex文件(Dalvik字节码)保存到dalvik-cache目录,并data/data目录下创建对应的应用数据目录。
卸载过程:删除安装过程中在上述三个目录下创建的文件及目录。
 一、系统应用安装:
PackageManager Service处理各种应用的安装,卸载,管理等工作,开机时由systemServer启动此服务
(源文件路径:android\frameworks\base\services\java\com\android\server\ PackageManagerService.java)
 
 
PackageManager Service服务启动的流程:
1. 首先扫描安装“system\framework”目录下的jar包
1. scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM,
                    scanMode | SCAN_NO_DEX);
 
 
2.第二步扫描安装“system\app”目录下的各个系统应用
scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);
 
3.第三步扫描“data\app”目录,即用户安装的第三方应用
scanDirLI(mAppInstallDir, 0, scanMode);
 
4.第四步扫描" data\app-private"目录,即安装DRM保护的APK文件(目前没有遇到过此类的应用)。
scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode | SCAN_FORWARD_LOCKED);安装应用的过程
1.scanDirLI(File dir, int flags, int scanMode)  遍历安装指定目录下的文件2.scanPackageLI(File scanFile,
            File destCodeFile, File destResourceFile, int parseFlags,
            int scanMode)                安装package文件3.scanPackageLI(
        File scanFile, File destCodeFile, File destResourceFile,
        PackageParser.Package pkg, int parseFlags, int scanMode)
通过解析安装包parsePackage获取到安装包的信息结构 4.mInstaller.install(pkgName, pkg.applicationInfo.uid,
              pkg.applicationInfo.uid);   实现文件复制的安装过程
(源文件路径:frameworks\base\cmds\installd\installd.install)
 
二、从et上下载应用:
Google Market应用需要使用gmail账户登录才可以使用,选择某一应用后,开始下载安装包,此过程中,在手机的信号区有进度条提示,下载完成后,会自动调用Packagemanager的接口安装,调用接口如下:
public void installPackage(final Uri packageURI, final IPackageInstallObserver observer, final int flags)
final Uri packageURI:文件下载完成后保存的路径
final IPackageInstallObserver observer:处理返回的安装结果
final int flags:安装的参数,从et上下载的应用,安装参数为-r (replace)
installPackage接口函数的安装过程:
1.public void installPackage(
            final Uri packageURI, final IPackageInstallObserver observer, final int flags,
            final String installerPackageName)
final String installerPackageName:安装完成后此名称保存在settings里,一般为null,不是关键参数
2.File tmpPackageFile = copyTempInstallFile(packageURI, res);
把apk文件复制到临时目录下的临时文件
3.private void installPackageLI(Uri pPackageURI,
            int pFlags, boolean newInstall, String installerPackageName,
            File tmpPackageFile, PackageInstalledInfo res)
解析临时文件,获取应用包名pkgName = PackageParser.parsePackageName(
                    tmpPackageFile.getAbsolutePath(), 0);
4.判断如果带有参数INSTALL_REPLACE_EXISTING,则调用replacePackageLI(pkgName,
                        tmpPackageFile, 
                        destFilePath, destPackageFile, destResourceFile,
                        pkg, forwardLocked, newInstall, installerPackageName,
                        res)
5.如果没有,则调用installNewPackageLI(pkgName,
                        tmpPackageFile, 
                        destFilePath, destPackageFile, destResourceFile,
                        pkg, forwardLocked, newInstall, installerPackageName,
                        res);
6.private PackageParser.Package scanPackageLI(
        File scanFile, File destCodeFile, File destResourceFile,
        PackageParser.Package pkg, int parseFlags, int scanMode)
scanPackageLI以后的流程,与开机时的应用安装流程相同。
三、从ADB工具安装
Android Debug Bridge (adb) 是SDK自带的管理设备的工具,通过ADB命令行的方式也可以为手机或模拟器安装应用,其入口函数源文件为pm.java 
(源文件路径:android\frameworks\base\cmds\pm\src\com\android\commands\pm\pm.java)
ADB命令行的形式为adb install <path_to_apk> ,还可以带安装参数如:"-l" "-r" "-i" "-t"
函数runInstall()中判断参数
"-l"――INSTALL_FORWARD_LOCK
 "-r"—— INSTALL_REPLACE_EXISTING  
"-i" ——installerPackageName
"-t"——INSTALL_ALLOW_TEST
我们常用的参数为-r,表示覆盖安装手机上已安装的同名应用。从et上下载的应用,也是直接传入这个参数安装的。
runInstall与et调用同样的接口完成应用安装。
public void installPackage(android.net.Uri packageURI, android.content.pm.IPackageInstallObserver observer, int flags, java.lang.String installerPackageName)
四、第三方应用安装――通过SD卡里的APK文件安装
把APK安装包保存在SD卡中,从手机里访问SD卡中的APK安装包,点击就可以启动安装界面,系统应用Packageinstaller.apk处理这种方式下的安装及卸载界面流程,如下图:
 
PackageInstallerActivity负责解析包,判断是否是可用的Apk文件
创建临时安装文件/data/data/com.android.packageinstaller/files/ApiDemos.apk
并启动安装确认界面startInstallConfirm,列出解析得到的该应用基本信息。如果手机上已安装有同名应用,则需要用户确认是否要替换安装。
确认安装后,启动InstallAppProgress,调用安装接口完成安装。
pm.installPackage(mPackageURI, observer, installFlags);
其它:
1. PackageManagerService.java的内部类AppDirObserver实现了监听app目录的功能:当把某个APK拖到app目录下时,可以直接调用scanPackageLI完成安装。
2.手机数据区目录“data/system/packages.xml”文件中,包含了手机上所有已安装应用的基本信息,如安装路径,申请的permission等信息。
 

解决方案 »

  1.   

    Android110427: PackageManagerService注记
    Email:    [email protected]
    Blog    http://zcatt.blog.chinaunix.net
     
    内容提要
    Android如何寻找intent受体.以供备忘和参考。声明
    仅限学习交流,禁止商业用途。转载需注明出处。版本记录
    Date        Ver        Note
    2011-04-27    0.1        Draft.  zcatt, Beijing
     
    PackageManagerService的方法大致可以分成这样几类,
    1)从apk, xml中载入pacakge信息, 存储到内部成员变量中, 用于后面的查找. 关键的方法是scanPackageLI().
    2)各种查询操作, 包括query Intent操作. 
    3)install package和delete package的操作. 关键的方法是installPackageLI().
    4)其它操作, 包括permission, signature, freeStorage等等.首先看看PacakgeManagerService用到的几个重要的支撑类, 然后罗列几个PackageManagerService的几个关键内部数据成员变量. 最后注记几个关键流程.PackageManagerService用到了几个重要的支撑类:PackageParser, 这个类主要用于解析apk, 分析其AndroidManifest.xml得到package的各种信息. 前已有注记文章,此不赘述. 特别的PackageParser.Package这个类用于容纳解析出的信息. PackageManagerService.Settings, 用于容纳当前有效的package信息, 它是动态的. 例如, user id, shareUser, permission, signature以及origPackage(也就是mRenamedPackages)相关信息. 所谓的install package就包括从要安装的package中抽取信息更新PackageManagerService.Settings中的内容. 特别的, Settings针对shareUser和origPackage做了特别的关照. 另外, 为了加速启动速度, Settings的内容会写入到/data/system/packages.xml, packages-backup.xml, 和packages.list中, 下次启动时会直接载入.Installer, 这个类协助安装过程, 更多的是将针对文件/路径的操作放到了c/cpp实现. 真正的工作是是由installd承担的, Installer只是通过named socket "installd"连接installd, 使用简单的cmd-respond协议指挥installd完成工作. 在其'install'命令中可以看到, 其实只是创建了/data/data/<pkgName>目录而已.PackageManagerService中的几个关键成员变量:
    // (pkgName => Package), package is the one installed.final HashMap<String, PackageParser.Package> mPackages =            new HashMap<String, PackageParser.Package>();// current package settings info, such as userid, origPackage// , shareUser, permission, signature, etcfinal Settings mSettings;// (system uid => permission), permissions read from /system/etc/permissions/<files> are stored here.// especially /system/etc/permissions/platform.xmlfinal SparseArray<HashSet<String>> mSystemPermissions =            new SparseArray<HashSet<String>>();//(pkgName => sharedLib), corresponding to <library> tagfinal HashMap<String, String> mSharedLibraries =            new HashMap<String, String>();// All available activities, for resolving intentfinal ActivityIntentResolver mActivities =            new ActivityIntentResolver();// All available receivers, for resolving intentfinal ActivityIntentResolver mReceivers =            new ActivityIntentResolver();// All available services, for resolving intentfinal ServiceIntentResolver mServices =            new ServiceIntentResolver();
    几个关键流程,初始化过程
    --------------PackageManagerService由SystemServer在创建ActivityManagerService后调用main创建, 是单实例的.
        Slog.i(TAG, "Power Manager");    power = new PowerManagerService();    ServiceManager.addService(Context.POWER_SERVICE, power);    Slog.i(TAG, "Activity Manager");    context = ActivityManagerService.main(factoryTest);    Slog.i(TAG, "Telephony Registry");    ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));    AttributeCache.init(context);    Slog.i(TAG, "Package Manager");    pm = PackageManagerService.main(context,            factoryTest != SystemServer.FACTORY_TEST_OFF);    ActivityManagerService.setSystemProcess();    mContentResolver = context.getContentResolver();在构造函数中, PackageManagerService会做这些工作,1)启动自己的handlerThread, 生成自己的mHandler. 
    2)从/system/etc/permissions/的所有xml文件中, 尤其是platform.xml, 读入systemPermissions. 这些是系统默认的permission配置.
    3)扫描/system/framework/, /system/app/, /data/app/, 和/data/app-private/下的apk文件, 收集package各种信息, 更新到内部成员变量中. 这些将在PackageManagerService执行各种功能时用到. 尤其是query intent.更详尽的笔记,
    PackageManagerService
        mHandlerThread.start();    mHandler = new PackageHandler(mHandlerThread.getLooper());    readPermissions();    mRestoredSettings = mSettings.readLP();    --/system/framework/
        scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode | SCAN_NO_DEX);    --/system/app/
        scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode);    --Prune any system packages that no longer exist.    --clean up any incomplete package installations    --delete tmp files    --/data/app/
        scanDirLI(mAppInstallDir, 0, scanMode);    --/data/app-private/
        scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK, scanMode);    mSettings.writeLP();private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanMode) 
        PackageParser pp = new PackageParser(scanPath);    pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags);    collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags)    setApplicationInfoPaths(pkg, codePath, resPath);    scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
            --set mAndroidApplication and mResolveActivity to'Android' package        --Check all shared libraries and map to their actual file path.            --check pkg.usesLibraries are contained in mSharedLibraries.            --fill in pkg.usesLibraryFiles according to pkg.usesLibraries and pkg.usesOptionalLibraries            --check pkg.reqFeatures in mAvailableFeatures        --if not in mSettings, create one ShareUserSettings and insert into mSettings.        --Check and note if we are renaming from an original package name        pkgSetting = mSettings.getPackageLP(pkg, origPackage, realName, suid, destCodeFile, destResourceFile, pkg.applicationInfo.flags, true, false);        verifySignaturesLP(pkgSetting, pkg);        --Verify that this new package doesn't have any content providers that conflict with existing packages.        --get data dir. if not exists, install or create the data dir. if exists but uid not correct, reinstall.        --Perform shared library installation and dex validation and optimization, if this is not a system app.        --Request the ActivityManager to kill the process(only for existing packages)        mSettings.insertPackageSettingLP(pkgSetting, pkg);    --Add the new setting to mSettings        mPackages.put(pkg.applicationInfo.packageName, pkg);        --set mProvidersByComponent and mProviders according to pkg.providers        --set mServices according to pkg.services        --set mReceivers according to pkg.receivers        --set mActivites according to pkg.activities        --set mPermissionGroups according to pkg.permissionGroups        --set mSettings.mPermissionTrees or mSettings.mPermissions according to pkg.permissions        --set mInstrumentation according to pkg.instrumentation        --set mProtectedBroadcasts according to pkg.protectedBroadcasts
    install package过程
    --------------install package的入口是installPackage(). install package通常是个耗时的过程, 因此会使用到android的handler机制.
    首先, 参数封装成INIT_COPY message, 发到handlerThread.
    handlerThread收到message后, 将参数排队到mPendingInstalls中. 随后,MCS_BOUND流程将会处理这个队列, 执行安装.
    MCS_BOUND的整个安装流程借助了几个InstallParams和InstallArgs完成其中的参数和安装结果的传递. 最终会调用processPendingInstall(), 进而调用到install过程的核心 installPackageLI().
    installPackageLI()的复杂性很大程度上是考虑了1)新安装还是升级情况, 2)origPackage情况.
      

  2.   

    Android110418: PackageParser和AndroidManifest.xml注记
    Email:    [email protected]
    Blog    http://zcatt.blog.chinaunix.net
     
    内容提要
    PackageParser和AndroidManifest.xml.以供备忘和参考。声明
    仅限学习交流,禁止商业用途。转载需注明出处。版本记录
    Date        Ver        Note
    2011-04-18    0.1        Draft.  zcatt, Beijing
     
    apk包中的AndroidManifest.xml文件包含了package的各种描述信息. 分析和获取这些信息的工作是由PackageParser完成的. 这里简述之. 首先我们先罗列AndroidManifest.xml文件的简要结构, 其次在大致整理PackageParser的逻辑.AndroidManifest.xml的简要结构
    ====================================
    AndroidManifest.xml的内容在frameworks/base/core/res/res/values/attrs_manifest.xml中定义. 这里简要罗列, 按照层进关系, xml element用 "tagName, Name"的形式标记, 对于某些xml element的重要属性(attribute), 用"attr NAME"标记.AndridManifest.xml
        manifest, AndroidManifest
                attr versionCode
                attr versionName
                attr sharedUserId
                attr sharedUserLabel
                attr installLocation        permission, AndroidManifestPermission
                    attr name, label, icon
                    attr permissionGroup
                    attr protectionLevel        permission-group, AndroidManifestPermissionGroup
                    attr name, label, icon        permission-tree, AndroidManifestPermissionTree
                    attr name, label, icon        uses-sdk, AndroidManifestUsesSdk        uses-permission, AndroidManifestUsesPermission
                    attr name        uses-configuration, AndroidManifestUsesConfiguration
                    attr reqTouchScreen
                    attr requKeyboardType
                    attr reqHardKeyboard
                    attr reqNavigation
                    attr reqFiveWayNav        application, AndroidManifestApplication
                    attr name, label, icon
                    attr permission
                    attr process
                    attr taskAffinity
                    attr persistent            service, AndroidManifestService
                        attr name, label, icon
                        attr permission
                        attr process
                        attr enabled
                        attr exported            receiver, AndroidManifestReceiver
                        attr name, label, icon
                        attr permission
                        attr process
                        attr enabled
                        attr exported            provider, AndroidManifestProvider
                        attr name, label, icon
                        attr process, authorities, syncable
                        attr readPermission, writePermission, grantUriPermissions
                        attr permission
                        attr mulitprocess
                        attr enabled
                        attr exported
                    grant-uri-permission, AndroidManifestGrantUriPermission
                            attr path, pathPrefix, pathPattern                    path-permission, AndroidManifestPathPermission
                            attr path, pathPrefix, pathPattern
                            attr permission, readPermission, writePermission            activity, AndroidManifestActivity
                        attr name, label, icon
                        attr theme, launchMode, screenOrientation
                        attr configChanges, permission, multiprocess
                        attr process, taskAffinity, allowTaskReparenting
                        attr finishOnTaskLaunch, finishOnCloseSystemDialogs
                        attr clearTaskOnLauch, noHistory
                        attr alwaysRetainTaskState, stateNotNeeded
                        attr excludeFromRecents
                        attr enabled, exported
                        attr windowSoftInputMode            activity-alias, AndroidManifestActivityAlias
                        attr name, label, icon
                        attr targetActivity
                        attr permission
                        attr enabled, exported
                    
                uses-library, AndroidManifestUsesLibrary
                        attr name
                        attr required        instrumentation, AnroidManifestInstrumentation
                    attr name, label, icon
                    attr targetPackage, handleProfiling
                    attr functionalTest        uses-feature, AndroidManifestUsesFeature
                    attr glEsVersion
                    attr name
                    attr required        supports-screens, AndroidManifestSupportsScreens
                    attr smallScreens, normalScreens, largeScreens
                    attr resizeable, anyDensity        protected-broadcast, AndroidManifestProtectedBroadcast
                    attr name
            
            adopt-permissions, AndroidManifestOriginalPackage
                    attr name还有几个特别的xml element, 可以有多个parent element.
        application
        activity, receiver, provider, service
        permission, permissionGroup
        instrumentation
            meta-data, AndroidManifestMetaData
                    attr name, value, resource    activity, receiver, service
            intent-filter, AndroidManifestIntentFilter
                    attr label, icon, priority
                
                action, AndroidManifestAction
                        attr name            data, AndroidManifestData
                        attr mimeType, scheme, host
                        attr port, path, pathPrefix
                        attr pathPattern            category, AndroidManifestCategory
                        attr name    intent, Intent
                attr action, data, mimeType
                attr targetPackage, targetClass        category, IntentCategory
                    attr name
            
            extra, Extra
                    attr name, value
    PackageParser的逻辑
    ====================================
    PackageParser的parsePackage()方法会读取apk包中的AndroidManifest.xml文件, 调用各子par***XX()方法, 解析出包信息. 同时, PackageParser定义了一些class, 容纳这些解析得到的信息. 下面是对应的关系.class                   xml elements
    -------------           --------------------------------------
    Package                 package
    Permission              permission, permission-tree
    PermissionGroup         permission-group
    Activity                activity, activity-alias, receiver
    Service                    service
    Provider                provider
    Instrumentation         instrumentation
    ActivityIntentInfo        intent-filter @ activity or receiver
    ServiceIntentInfo       intent-filter @ servicePacakgeParser的结果主要被PackageManagerService使用.
      

  3.   

    楼上讲的比较详尽了
    我的疑问是:有的apk程序必须install才可以使用,无论adb push或系统编译copy过去都是无法使用的,我暂时怀疑是install的时候对apk的自带库做了操作,其他还不能很确定,如何修改源码还没有一点头绪,此问题很纠结,求解!
      

  4.   

    将需要安装的apk放到系统扫描目录即可自动安装。不知道你想实现什么功能?
      

  5.   

    你这样的方法需要root的,不用root去安装.apk是不行的,你将软件和系统一起编译并加入编译条件,这样你编译的那个软件也就是和系统一样的软件可以无root去安装.但是只能针对你编译时所用的系统.