base.apk.rename下载苹果版

我下的apk.rename文件怎么安卓手机打不开_百度知道手机接收别人传的xxx.apk文件,看见的是xxx.apk,下载完之后就变成xxx.apk.rename,为什么,怎么解决_百度知道教大家如何删除小米自带的没用的应用,付应该对照表和跑分
教大家如何删除小米自带的没用的应用,付应该对照表和跑分
教大家如何删除小米自带的系统应用。上午在命令模式下看了小米手机运行的进程,一看吓死我了,有不下于40个的进程在运行,很多是几乎不会用到的系统自带的应用的进程,比如指南针一类的,删除像指南针~计算器一类基本用不上的应用还可以给小米内存释放,跑得更加快,更加省电~~哈哈~~~以“玩机手册”为例:拿到小米的人,一定都想把那个:“玩机手册”给删除了~~看到它就不舒服。按官方删除桌面图标的办法根本不管用,提示:“系统自带的关键应用无法卸载”那要怎么样才把它删除呢?
14:47 上传
18:07 上传
下面的方法只一个特例,其它不想要的系统自带的应用都可以照做删除,但千万不要删除比如:电话拨号等关键应用了,除非你不想打电话了。嘿嘿~小米自带的系统应该都在system/app/下面第一步:先安装个Root Explorer RE文件管理软件,打开软件:打开system/app/
14:48 上传
第二步:在最下面一个叫Userbook.apk的文件,对啦就是这个啦~Userbook.apk这个就是桌面上的“玩机手册”按住:Userbook.apk一小会,弹出一个菜单:
14:54 上传
选择Permissions,弹出的菜单里Write下面只是对应的Others那里是没标记的,灰色的
14:48 上传
,我们把位子上点一下标记上,以示可写,然后点OK
14:48 上传
然后再按住:Userbook.apk一会,弹出的菜单里,你可以选择删除。本人建议选择:Rename,修改一下名字。我是在最后面加一个点,点OK
14:48 上传
,会提示:Rename Successful。好啦,返回去看一下那个Userbook.apk文件,图标变了吧。
14:48 上传
,说明成功了。返回原来的桌面,发现“玩机手册”不见了
14:48 上传
注:带*号的千万不能删*AccountAndSyncSettings.apk 同步与帐户设定 *ApplicationsProvider.apk 应用程序支持服务Bluetooth.apk 蓝牙(删了就没有蓝牙了)Browser.apk 谷歌浏览器(喜欢UC的可用UC替代)Calculator.apk 计算器(自带计算器较弱,可用其他替代)Calendar.apk 日历(不用日历的可删)CalendarProvider.apk 日历程序支持服务(不用日历的可删)Camera.apk 自带相机(用360的可删)*CertInstaller.apk 证书服务ChsPack.apk touchpal输入法拼音语言包(可删)-ChtPack.apk touchpal输入法注音语言包(从来不用注音的删)Contacts.apk 通讯录/联系人(用第三方通讯录的可删)*ContactsProvider.apk 通讯录/联系人数据存储服务*DefaultContainerService.apk 默认通讯录服务DeskClock.apk 自带闹钟(用第三方闹钟的可删)*DownloadProvider.apk 下载管理器*DrmProvider.apk DRM受保护数据存储服务Email.apk Email(不用自带email接受邮件的可删)-facebook.apk facebook(用不到的删)fmradio.apk 收音机(可删)Gallery.apk 相机相框 (可删)GenieWidget.apk 天气与新闻(我自己不用他看新闻,删了)Gmail.apk Gmail邮件(可删)GoogleBackupTransport.apk 谷歌备份(可删)GoogleCalendarSyncAdapter.apk 谷歌日历同步适配器(可删)GoogleContactsSyncAdapter.apk 谷歌联系人同步适配器(可删)GoogleFeedback.apk 谷歌反馈(可删)GooglePartnerSetup.apk Google合作伙伴设置(可删)GoogleQuickSearchBox.apk 谷歌搜索(删了影响到桌面的搜索插件)GoogleServicesFramework.apk 谷歌同步支持服务框架(删了不能同步联系人,不能登录google)HTMLViewer.apk HTML浏览器(本地看html,用不到可删)HWCalla_TaiWan.apk 繁体中文手写输入法(可写简体的,不用手写的可删)LatinIME.apk android键盘输入法(可删)LatinImeTutorial.apk android键盘输入法设置(可删)Launcher2.apk 2.2原生桌面(用ADW和PRO的可删,删了以后第三方桌面要在开机以后从电脑安装,91,豌豆助手都可)LiveWall**s.apk 动态壁纸(可删)LiveWall**sPicker.apk 同上动态壁纸(可删)Maps.apk Google地图(可删,自行换成brust版本)MarketUpdater.apk 谷歌市场升级(软件更新用到,可删)*MediaProvider.apk 媒体数据存储服务MediaUploader.apk 媒体上传(可删)MMITest_II.apk 工程模式里用到的手机测试程序(可删)Mms.apk 自带信息(可删,用第三方短信的就删了吧,提示:删了后,用handsms的的弹出短信框会变得延时,chomp没自带短信甚至不能使用)Music.apk 自带音乐(可删,换成其他播放器)NetworkLocation.apk 网络位置(可删)NotePad.apk 记事本(可删)*PackageInstaller.apk 程序安装*Phone.apk 电话拨号程序PicoTts.apk 可删(文字语言转换的语音合成引擎,设置-语音输入与输出中)ProjectMenuAct.apk 工程菜单-Protips.apk 桌面小绿人插件(可删,就是有提示怎么玩手机)*Settings.apk 系统设置*SettingsProvider.apk 设置服务程序SetupWizard.apk 开机引导(在定制rom时不可删,刷好机可用rootexplorer删掉,恢复出厂前要装回去)SoundRecorder.apk 录音机(可用第三方录音软件替代)Stk.apk sim卡服务(可删,有机油把联系人复制在sim卡上的就不要删它,删了可解决信号问题)Street.apk 谷歌街道(可删,对于国内街道无效果的貌似,与地图关联)Superuser.apk 授权程序(就是程序列表上面那个,用这个获取root才有的)Talk.apk 谷歌talk(可删,但删了就用不了电子市场)*TelephonyProvider.apk 拨号记录存储服务TouchPal.apk TouchPal输入法(可删,但自带的三种输入法最好至少保留一种)TtsService.apk Google TTS(Text-to-speech)语音库服务(可删)-TwidroydFree342-Huawei-rev1.apk twitter客户端(不用的删了)Updataonline.apk 在线升级(可删)UserDictionaryProvider.apk 用户数据字典服务(可删)Vending.apk 电子市场(可删,不过不建议,很多软件的自动升级时候有它很方便)-VisualizationWall**s.apk 动态音乐背景壁纸 (删了)VoiceSearch.apk 语音搜索(可删,虽然看上去很美好,事实上我从未用过)***Services.apk ***服务(***服务,可删)-YouTube.apk YouTube视频(要***才能看,删了)本人建议删除的小米自带的应用表,释放内存:手电同(Torch.apk)指北针(Compass.apk)电子邮件(Email.apk)计算器(Calculator.apk)文件管理(FileExplorer.apk)收音机(FM.apk)SIM卡(Stk.apk)应用超市(SuperMarket.apk)附上:[attach]RE文件管理器[/attach]
(48.56 KB, 下载次数: 16)
14:47 上传
下载次数: 16
(80.96 KB, 下载次数: 4)
14:47 上传
下载次数: 4
(75.74 KB, 下载次数: 6)
14:47 上传
下载次数: 6
(73.23 KB, 下载次数: 5)
14:48 上传
下载次数: 5
15:00 上传
下载次数: 2052下载积分 经验 -1 米
272.03 KB, 阅读权限: 20, 下载次数: 2052
发表评论:
TA的最新馆藏6407人阅读
Android(48)
原文地址:http://blog.csdn.net/jinzhuojun/article/details/
其实对于apk包的安装,4.4和之前版本没大的差别。Android中app安装主要有以下几种情况:系统启动时安装,adb命令安装,Google
Play上下载安装和通过PackageInstaller安装。安装的最核心方法是scanPackageLI(),以上几个安装方式最后都是调用这个函数完成主要工作的,区别在于在此之前的处理过程不同。本文以前两种为主,简要介绍这四种安装过程。
一个最一般的apk包(不是系统app,没有共享lib,不是装在sd上或是forward-lock的app)装完后内容会体现在这么几个目录:
/data/app& // apk包
/data/app-lib// native lib
/data/data //数据目录,其中的lib目录指向上面的/data/app-lib目录
/data/dalvik-cache/data@app@&package-name&.apk@classes.dex& //优化或编译后的Java bytecode
一、启动时安装
Android启动时会把已有的app安装一遍,过程主要分三部分:读取安装信息,扫描安装,写回安装信息。读取和写回主要是针对于一坨安装信息文件。这些信息保证了启动后app与上一次的一致。关键步是扫描指定目录下的apk并安装。Android中apk主要分布在以下几个目录,意味着启动时要扫描的主要也是这几个目录:
系统核心应用:/system/priv-app
系统app:/system/app
非系统app:/data/app(安装于手机存储的一般app)或/mnt/asec/&pkgname-number&/pkg.apk(sdcard或forward-locked)
受DRM保护app:/data/app-private
vendor-specific的app: /vendor/app
资源型app:/system/framework
整个启动时安装的流程大体如下:
几个同名函数一开始看得会有些混淆,内层scanPackageLI()比较复杂这里省略细节。下面更加详细地分析下流程。故事从System Server开始,实现在/frameworks/base/services/java/com/android/server/SystemServer.java中:
pm = PackageManagerService.main(context, installer,
factoryTest != SystemServer.FACTORY_TEST_OFF,
onlyCore);调用PMS的main()函数,其实现位于/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java:
public static final IPackageManager main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
ServiceManager.addService(&package&, m);
这里构造了PMS并加到ServiceManager中,这样其它的组件就可以用该服务了。PMS的构造函数中:
mSettings = new Settings(context); // 用于存放和操作动态安装信息,具体地说,如uid, permission等。
mInstaller =
// installd daemon的proxy类。
mHandlerThread.start(); // 启动PMS的工作线程。
mHandler = new PackageHandler(mHandlerThread.getLooper()); // PMS会通过mHandler丢活给工作线程。
File dataDir = Environment.getDataDirectory(); // /data
mAppDataDir = new File(dataDir, &data&); // /data/data
mAppInstallDir = new File(dataDir, &app&); // /data/app
mAppLibInstallDir = new File(dataDir, &app-lib&); // /data/app-lib
可以看到PMS除了主线程,还会有一个叫PackageManager的工作线程。它主要是用在其它安装方式中,因为启动时没什么用户交互,基本上不需要把工作交给后台。
final HandlerThread mHandlerThread = new HandlerThread(&PackageManager&,
Process.THREAD_PRIORITY_BACKGROUND);权限信息在/etc/permissions目录中,由readPermissions()函数读取,保存在Settings中的mPermissions中。接下来在PMS构造函数中调用readLPw()来解析packages.xml文件得到上次的安装信息。
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);Android启动时要扫描和安装现有app。或许是为了防止corrupted信息的存在,或许是为了能在升级系统或更新系统属性后保持app也valid,亦或是因为有些信息(如uid)必须是动态生成和调整的。总之,为了要还原现有app的安装信息,这些信息被放在/data/system/packages.xml里,由Settings管理。另外/data/system/packages.list记录了app的uid和数据路径等信息。readLPw()就是用于恢复这些信息,实现位于/frameworks/base/services/java/com/android/server/pm/Settings.java。readLPw()先打开packages.xml,再通过XmlPullParser类来解析其内容。它会根据不同的tag调用相应的函数来读取信息:
String tagName = parser.getName();
if (tagName.equals(&package&)) {
readPackageLPw(parser);
} else if (tagName.equals(&permissions&)) {
readPermissionsLPw(mPermissions, parser);
} else if (tagName.equals(&permission-trees&)) {
readPermissionsLPw(mPermissionTrees, parser);
} else if (tagName.equals(&shared-user&)) {
readSharedUserLPw(parser);
} else if (tagName.equals(&preferred-packages&)) {
// no longer used.
} else if (tagName.equals(&preferred-activities&)) {
// Upgrading from old single-
// these are the preferred activities for user 0.
readPreferredActivitiesLPw(parser, 0);
} else if (tagName.equals(&updated-package&)) {
readDisabledSysPackageLPw(parser);
packages.xml中的一个apk包对应的package结构大体如下:
&package name=&&codePath=&& nativeLibraryPath=&& sharedUserId=&&or userId=&&&
&/package&
其中readPackageLPw()调用addPackageLPw()注册app信息到变量mPackages中,uid信息到mUserIds/mOtherUserIds中,准确地说,应该是把这些信息从文件恢复回去。addPackageLPw()会创建PackageSetting,该类描述了该apk包的安装信息。
p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString,
vc, pkgFlags);
if (addUserIdLPw(uid, p, name)) {
mPackages.put(name, p);
注意Android中app的uid的范围区间是FIRST_APPLICATION_UID
~LAST_APPLICATION_UID,即10000 ~ 99999,FIRST_APPLICATION_UID之下的给系统应用。
碰到shared user就更麻烦了,因为有时多个app为了共享权限会共享一个uid。如果一个app要用共享uid,需要在apk的AndroidManifest.xml文件中申明android:sharedUserId=&...&,详见 /guide/topics/manifest/manifest-element.html。 这时就要先为其创建PendingPackage并放到mPendingPackages等共享uid部分搞定了再处理。在packages.xml中共享用户表示为:
&shared-user name=&& userId=&&&
&/shared-user&
readSharedUserLPw()用来处理app安装信息中的共享用户部分。它会调用addSharedUserLPw()来添加共享用户。addSharedUserLPw()为共享用户创建SharedUserSetting类(SharedUserSetting包含了一个PackageSetting的集合),再调用addUserIdLPw()函数注册到mUserIds中(或mOtherUserIds),成功的话另外还会写入mSharedUsers中。
s = new SharedUserSetting(name, pkgFlags);
s.userId =
if (addUserIdLPw(uid, s, name)) {
mSharedUsers.put(name, s);
}综合上面的信息,就有了下面这样的结构:
我们知道packages.xml放了app在之前安装时的配置信息。这里可以有两点推论:当一个app卸载后packages.xml中该app的信息也被删除了。当卸载以后下一次安装同一个app时会重新生成,uid不会被保留。
回到readLPw()后,处理前面那些因为用了共享用户而待处理的app,也就是mPendingPackages里的那坨。完了再回到PackageManagerService()。mSharedLibraries里放的一些共享的java库,这里会调用dexopt()对它们进行优化。
if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
alreadyDexOpted.add(lib);
mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
didDexOpt =
}alreadyDexOpted记录已经运行过dexopt的文件,像启动类和上面的共享库。下面是对framework里的包和类进行优化。
for (int i=0; i&frameworkFiles. i++) {
if (dalvik.system.DexFile.isDexOptNeeded(path)) {
mInstaller.dexopt(path, Process.SYSTEM_UID, true);接下来,监控/system/framework目录并扫描该目录。
// Find base frameworks (resource packages without code).
mFrameworkInstallObserver = new AppDirObserver(
frameworkDir.getPath(), OBSERVER_EVENTS, true, false);这里用Observer模式来监视目录变动。它依赖于Linux kernel提供的Inotify机制。实现主要位于/frameworks/base/core/java/android/os/FileObserver.java和/frameworks/base/core/jni/android_util_FileObserver.cpp。对于它的继承类(如AppDirObserver),只要实现onEvent()方法来处理文件或目录变动即可。onEvent()的实现比如/frameworks/base/services/java/com/android/server/pm/PackageManagerService.java中:
public void onEvent(int event, String path) {
p = scanPackageLI(fullPath, flags,
SCAN_MONITOR | SCAN_NO_PATHS | SCAN_UPDATE_TIME,
System.currentTimeMillis(), UserHandle.ALL);
synchronized (mPackages) {
updatePermissionsLPw(p.packageName, p,
p.permissions.size() & 0 ? UPDATE_PERMISSIONS_ALL : 0);
synchronized (mPackages) {
mSettings.writeLPr();
}扫描该目录的目的是要安装里边的apk包。主要实现函数是scanDirLI():
scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanMode | SCAN_NO_DEX, 0);对于其它几个目录(/system/priv-app,/system/app,/vendor/app, /data/app, /data/app-private),也是一样的:
mAppInstallObserver = new AppDirObserver(
mAppInstallDir.getPath(), OBSERVER_EVENTS, false, false);
mAppInstallObserver.startWatching();
scanDirLI(mAppInstallDir, 0, scanMode, 0);
…全安装好了就可以更新权限信息并且写回安装信息了。
updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL
| (regrantPermissions
? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL)
// can downgrade to reader
mSettings.writeLPr();这样启动时安装主要工作就差不多完成了。下面回头看一下重头戏 - 目录的扫描和安装,也就是scanDirLI()函数:
scanDirLI()
scanPackageLI(file, flags|PackageParser.PARSE_MUST_BE_APK, scanMode, currentTime, null);
PackageParser pp = new PackageParser(scanPath);
final PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags);
assmgr = new AssetManager();
parser = assmgr.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
pkg = parsePackage(res, parser, flags, errorText); // parse AndroidManifest.xml
PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user);可以看到scanPackageLI()和parsePackage()皆有重载版本。基本上内层的版本才是做事的。内层的parsePackage(res, ...)函数用于解析AndroidManifest.xml文件。实现在/frameworks/base/core/java/android/content/pm/PackageParser.java。至于AndroidManifest.xml是apk中必不可少的配置文件。详见/guide/topics/manifest/manifest-intro.html,没有的话Android压根不让你装。
String tagName = parser.getName();
if (tagName.equals(&application&)) {
if (foundApp) {
if (RIGID_PARSER) {
outError[0] = &&manifest& has more than one &application&&;
mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
Slog.w(TAG, &&manifest& has more than one &application&&);
XmlUtils.skipCurrentTag(parser);
foundApp =
if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
} else if (tagName.equals(&keys&)) {
if (!parseKeys(pkg, res, parser, attrs, outError)) {
} else if (tagName.equals(&permission-group&)) {
if (parsePermissionGroup(pkg, flags, res, parser, attrs, outError) == null) {
} else if (tagName.equals(&permission&)) {
if (parsePermission(pkg, res, parser, attrs, outError) == null) {
} else if (tagName.equals(&permission-tree&)) {
if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
} else if (tagName.equals(&uses-permission&)) {
if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
比较重要的如parseApplication()是解析application标签里的东西。application标签里包含Android四大组件(Activity, Receiver, Service, Content Provider)信息和库等信息。一顿解析后,返回结果PackageParser.Package对象pkg,这个类基本上就包含了AndroidManifest.xml里的信息。接下来scanPackageLI(pkg, ...)被调用,前面返回的解析结果pkg被当作参数传入。scanPackageLI(pkg,
...)干的事还挺多的。如处理共享用户,注册包信息,调用NativeLibraryHelper和Installer的相关函数进行安装等等。
如果该app使用了共享用户,则调用getSharedUserLPw()函数获取该共享uid的SharedUserSetting,没有的话就新建,然后分配uid:
SharedUserSetting getSharedUserLPw(String name,
int pkgFlags, boolean create) {
SharedUserSetting s = mSharedUsers.get(name);
if (s == null) {
if (!create) {
s = new SharedUserSetting(name, pkgFlags);
s.userId = newUserIdLPw(s);
Log.i(PackageManagerService.TAG, &New shared user & + name + &: id=& + s.userId);
// & 0 means we couldn' fall out and return
// s, which is currently null
if (s.userId &= 0) {
mSharedUsers.put(name, s);
}在scanPackageLI(pkg, ...)函数中,下面调用getPackageLPw()得到该apk包的PackageSetting对象,有些在前面readPackageLPw()时就已经恢复好了,还没有的那些这儿就会新建:
// Just create the setting, don't add it yet. For already existing packages
// the PkgSetting exists already and doesn't have to be created.
pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
destResourceFile, pkg.applicationInfo.nativeLibraryDir,
pkg.applicationInfo.flags, user, false);
getPackageLPw()实现在/frameworks/base/services/java/com/android/server/pm/Settings.java中:
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
String nativeLibraryPathString, int vc, int pkgFlags,
UserHandle installUser, boolean add, boolean allowInstall) {
p = new PackageSetting(name, realName, codePath, resourcePath,
nativeLibraryPathString, vc, pkgFlags);
// Assign new user id
p.appId = newUserIdLPw(p);
newUserIdLPw()函数为app分配uid。这样,该应用对应的uid就设置好了。
回到scanPackageLI()中,下面设置进程名,进程名默认就是包名。所以我们在ps里看到的都是包名。
pkg.applicationInfo.processName = fixProcessName(
pkg.applicationInfo.packageName,
pkg.applicationInfo.processName,
pkg.applicationInfo.uid);对于大部分全新安装的一般应用而言,接下来为应用创建数据目录:
private int createDataDirsLI(String packageName, int uid, String seinfo) {
int[] users = sUserManager.getUserIds();
int res = mInstaller.install(packageName, uid, uid, seinfo);
for (int user : users) {
if (user != 0) {
res = mInstaller.createUserData(packageName,
UserHandle.getUid(user, uid), user);Installer是一个代理类,它会和后台的installd通信并让installd完成具体工作。installd的实现位于/frameworks/native/cmds/installd/commands.c,install()会创建app目录(/data/data/&package-name&),并作lib目录的软链接,如/data/data/xxx/lib -& /data/app-lib/xxx。
下面设置原生库目录为/data/data/&package- name&/lib,它指向/data/app-lib。再把原生库文件(如有)解压到该目录下。
if (pkgSetting.nativeLibraryPathString == null) {
setInternalAppNativeLibraryPath(pkg, pkgSetting);
pkg.applicationInfo.nativeLibraryDir = pkgSetting.nativeLibraryPathS
if (pkg.applicationInfo.nativeLibraryDir != null) {
File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
Slog.e(TAG, &Unable to copy native libraries&);
mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
这里调用copyNativeLibrariesForInternalApp(),它会调用NativeLibraryHelper.copyNativeBinariesIfNeededLI()把apk里的原生库解压出来放到/data/app-lib的对应目录下。
接下来PMS调用performDexOptLI()优化Java的bytecode,即dex文件。
if ((scanMode&SCAN_NO_DEX) == 0) {
if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
== DEX_OPT_FAILED) {
mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
}真正的工作还是在后台installd进程中完成, installd中的dexopt()函数会根据当前是运行dalvik还是art虚拟机来选择调用run_dexopt()或run_dex2oat()。
if (strncmp(persist_sys_dalvik_vm_lib, &libdvm&, 6) == 0) {
run_dexopt(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
} else if (strncmp(persist_sys_dalvik_vm_lib, &libart&, 6) == 0) {
run_dex2oat(zip_fd, out_fd, apk_path, out_path, dexopt_flags);
/* Unexpected persist.sys.dalvik.vm.lib value */
}前者适用于dalvik,将dex优化成odex文件。后者适用于art,将dex直接一步到位编译成oat文件(也就是可执行代码)了。由于下层是执行了/system/bin/dexopt或/system/bin/dex2oat文件,dexopt()将之放到子进程去做,自己作为父进程等待它结束。以art为例,/system/bin/dex2oat被调用(实现位于/art/dex2oat/dex2oat.cc)。输出的elf文件放在/data/dalvik-cache/data@app@&package-name&@classes.dex。注意对于dalvik和art,这个文件名称相同但性质截然不同。dalvik下,该文件为优化后的bytecode。而art下,这个就是可执行文件了。
如果是更新已有的app,还要让ActivityManager调用killApplication()把进程杀掉。app都更新了,老的还留内存里跑,这不合适。
killApplication(pkg.applicationInfo.packageName,
pkg.applicationInfo.uid, &update pkg&);之后将安装的app注册到PMS的mPackages中,mPackges是个Hash表,保存了从包名到PackageParser.Package的映射。注意Settings里也有个mPackages,那里保存的是包名到PackageSetting的映射。前者主要是app配置文件中的信息,而后者是安装过程中的信息。可以粗略理解为一个是静态信息,一个是动态信息。
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// PackageSetting &= PackageParser.Package
addPackageSettingLPw(p, pkg.packageName, p.sharedUser)
mPackages.put(name, p);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);下面把app中的组件信息(content provider, service, receiver, activity)记录到系统中。另外根据前面app配置文件中的权限信息进行初始化。
int N = pkg.providers.size();
StringBuilder r =
for (i=0; i&N; i++) {
PackageParser.Provider p = pkg.providers.get(i);
p.info.processName = fixProcessName(pkg.applicationInfo.processName,
p.info.processName, pkg.applicationInfo.uid);
mProviders.addProvider(p);
N = pkg.services.size();
N = pkg.receivers.size();
N = pkg.activities.size();
N = pkg.permissionGroups.size();
N = pkg.permissions.size();
回到PMS构造函数中。下面就是收尾工作了。主要包括更新共享库信息,更新权限信息,以及写回安装信息。所有包都解析完了,意味着所有共享库信息都已解析,这儿就可以调用updateAllSharedLibrariesLPw()为那些使用动态库的app绑定动态库信息了。下面updatePermissionsLPw()函数用于赋予app相应权限:
private void updatePermissionsLPw(String changingPkg,
PackageParser.Package pkgInfo, int flags) {
// Now update the permissions for all packages, in particular
// replace the granted permissions of the system packages.
if ((flags&UPDATE_PERMISSIONS_ALL) != 0) {
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg != pkgInfo) {
grantPermissionsLPw(pkg, (flags&UPDATE_PERMISSIONS_REPLACE_ALL) != 0);
}在AndroidManifest.xml中app会申请一些权限,比如读取位置信息,读取联系人,操作摄像头等等。AndroidManifest.xml中的格式如:
&uses-permission android:name=&permission_name&&
这里的permission_name被放到requestedPermissions,代表该app申请该权限。经过grantPermissionsLPw()里判断能否给予相应权限,如果允许则授予权限(即把权限对应的gid加到app的gid列表中,因为权限在Linux中对应物就是group,由gid表示),并把该权限加到grantedPermissions中,代表已授予该权限。
private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace) {
final int N = pkg.requestedPermissions.size();
for (int i=0; i&N; i++) {
if (!gp.grantedPermissions.contains(perm)) {
changedPermission =
gp.grantedPermissions.add(perm);
gp.gids = appendInts(gp.gids, bp.gids);
} else if (!ps.haveGids) {
gp.gids = appendInts(gp.gids, bp.gids);
}最后,writeLPr()将安装信息写回packages.xml文件,这也是一开始readLPw()读的那个文件。这样下次启动时就可以按照这里边的信息重新安装了。
void writeLPr() {
serializer.startTag(null, &permission-trees&);
for (BasePermission bp : mPermissionTrees.values()) {
writePermissionLPr(serializer, bp);
serializer.endTag(null, &permission-trees&);
serializer.startTag(null, &permissions&);
for (BasePermission bp : mPermissions.values()) {
writePermissionLPr(serializer, bp);
serializer.endTag(null, &permissions&);
for (final PackageSetting pkg : mPackages.values()) {
writePackageLPr(serializer, pkg);
}总结下几个主要类的用途:
PackageManagerService: apk包安装服务
Settings: 管理app的安装信息
PackageSetting: &app的动态安装信息
SharedUserSetting: 共享Linux用户
PackageParser.Package: app的静态配置信息。
Pm: pm命令实现类
Installer: &installd daemon代理类
HandlerThread: PMS工作线程
它们之间的大致关系:
二、adb install安装
通过adb install命令安装时流程略有不同,主要是scanPackageLI()之前的流程不同。host机上的adb从/system/core/adb/adb.c中的main()开始:main()-&adb_commandline()-&install_app()-&pm_command()-&send_shellcommand(),其中会把安装包从host传到guest上的临时目录。
接下来guest里的pm命令(/frameworks/base/cmds/pm/src/com/android/commands/pm/Pm.java)接手,大体流程如下:
runInstall()
installPackageWithVerificationAndEncryption()
doHandleMessage() // INIT_COPY
doHandleMessage() // MCS_BOUND
startCopy()
InstallParams.handleStartCopy()
InstallArgs args = createInstallArgs(this)
args.copyApk() // FileInstallArgs或AsecInstallArgs,取决于是否是forward-lock或装在sd card上。
createCopyFile() // 拷贝生成类似于/data/app/vmdl-.tmp这样的临时文件,因为这时候包都没解析,不知道包名。
handleReturnCode()
processPendingInstall() //异步方式安装,因为安装过程可能较长。
installPackageLI()这里用到了一开始提到的PMS工作线程,doHandleMessage()就是工作线程用于处理丢给它的消息的。
这里有几个设计模式值得学习的。首先,Pm中得到PMS的代理类,然后调用installPackageWithVerificationAndEncryption()进行安装。
mPm = IPackageManager.Stub.asInterface(ServiceManager.getService(&package&));
mPm.installPackageWithVerificationAndEncryption(apkURI, obs, installFlags,
installerPackageName, verificationParams, encryptionParams);由于安装时间一般较长,这里的obs用了Observer模式来监视安装完成事件。
其次,InstallArgs用了Strategy模式,而createInstallArgs()使用了简单工厂模式。在handleStartCopy()中,只要根据安装类型生成相应的InstallArgs对象,然后调用统一接口copyApk()等就行了。
另外,HandlerParams和其继承类采用了Template method模式。其中基类中的startCopy()是模板函数,继承类实现handleStartCopy(),handleServiceError()和handleReturnCode()来完成不同工作。HandlerParams包含了要工作线程做的工作内容,工作线程只要取出HandlerParams对象,调用其startCopy()接口,因此这里也用了Command模式的思想。
将HandlerParams和InstallArgs组合起来看,它们又组成bridge pattern的变体。
这样把本来一棵层数更深的类树给压扁了,从而通过维度分解降低了复杂性,增强了灵活性。
这里的installPackageLI()做了很多前一种安装方式中scanPackageLI(file, ...)的工作,接着它会根据该app是否是全新安装调用replacePackageLI()或installNewPackageLI()。
if (!args.doRename(res.returnCode, pkgName, oldCodePath)) { // 前面拷贝apk时是随机取了临时名字的,这里用doRename()函数为其“正名”。
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res);
installNewPackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res);
}如果是全新的apk,调用installNewPackageLI()进行安装。它调用scanPackageLI()完成主要安装工作。
private void installNewPackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res) {
PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode,
System.currentTimeMillis(), user);从这开始就熟悉了吧,和启动时安装的流程差不多了,最后调用updateSettingsLI()来更新安装信息。
三、Google Play网络下载安装&
Google Play的包名为com.android.vending。由于是闭源的,看不了源码。不过从反汇编粗略地看,应该是先把apk包下载到:
/data/data/com.android.providers.downloads/cache/downloadfile.apk
然后调用installPackage()安装,类似于:
PackageManager pm = context.getPackageManager();
pm.installPackage(packageURI, observer, flags, null);接着就和上面一样了:installPackage()-&installPackageWithVerification()-&installPackageWithVerificationAndEncryption()。
四、点选apk文件安装
这种情况下,会通过PackageInstaller安装app。在/packages/apps/PackageInstaller/src/com/android/packageinstaller/InstallAppProgress.java中:
pm.installPackageWithVerificationAndEncryption(mPackageURI, observer, installFlags,
installerPackageName, verificationParams, null);后面的故事又都熟悉了吧。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:795586次
积分:10021
积分:10021
排名:第1199名
原创:188篇
转载:114篇
评论:327条
(1)(2)(2)(1)(2)(1)(2)(2)(1)(2)(1)(2)(1)(1)(2)(1)(1)(3)(1)(1)(1)(2)(1)(1)(2)(3)(4)(2)(3)(9)(4)(6)(2)(9)(3)(15)(17)(13)(3)(3)(9)(8)(9)(4)(7)(3)(4)(6)(10)(4)(2)(1)(1)(1)(1)(5)(1)(3)(5)(8)(2)(1)(1)(1)(1)(1)(2)(1)(1)(1)(1)(5)(2)(9)(3)(1)(1)(2)(9)(2)(8)(1)(1)(1)(1)(3)(1)(1)(1)(2)(3)(2)(6)

我要回帖

更多关于 base.apk苹果下载 的文章

 

随机推荐