Android 应用程序管理机制
来源:互联网 发布:js 中隐藏控件 编辑:程序博客网 时间:2024/06/05 09:40
android应用程序管理主要由PackageManager这个类来管理,实现PackageManager这个抽象类的是ContextImpl.java。在ContextImpl.java中,有一个内部静态类叫ApplicationPackageManager,实现了所有PackageManager的接口。
static
final
class
ApplicationPackageManager
extends
PackageManager {
..........
}
ApplicationPackageManager又是通过对IPackageManager封装调用,来实现的。
public
PackageInfo getPackageInfo(String packageName,
int
flags)
throws
NameNotFoundException {
try
{
PackageInfo pi = mPM.getPackageInfo(packageName, flags);
if
(pi !=
null
) {
return
pi;
}
}
catch
(RemoteException e) {
throw
new
RuntimeException(
"Package manager has died"
, e);
}
throw
new
NameNotFoundException(packageName);
}
这里的mPM就是IPackageManager,PackageManagerService就是对IPackageManager的实现。所以我们平时对PackageManager的调用,最终是的在PackageManagerService.java中实现的。在PackageManagerService.java每个方法的实现。
PackageManagerService启动流程:
PackageManagerService(context, factoryTest)是包管理服务的主进程。它完成了对/system/app,/data/app,/system/framework,/data/app-private下的apk文件的解析。详细流程如下:
1.建立java层的installer与c层的installd的socket联接,使得在上层的install,remove,dexopt等功能最终由installd在底层实现
2.建立PackageHandler消息循环,用于处理外部的apk安装请求消息,如adb install,packageinstaller安装apk时会发送消息
3.解析/system/etc/permission下xml文件(framework/base/data/etc/),包括platform.xml和系统支持的各种硬件模块的feature.主要工作:
(1)建立底层user ids和group ids 同上层permissions之间的映射;可以指定一个权限与几个组ID对应。当一个APK被授予这个权限时,它也同时属于这几个组。
(2)给一些底层用户分配权限,如给shell授予各种permission权限;把一个权限赋予一个UID,当进程使用这个UID运行时,就具备了这个权限。
(3) library,系统增加的一些应用需要link的扩展jar库;
(4) feature,系统每增加一个硬件,都要添加相应的feature.将解析结果放入mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures等几个集合中供系统查询和权限配置使用。
4.检查/data/system/packages.xml是否存在,这个文件是在解析apk时由
writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,version,uesrid等信息,这些信息主要通过apk的
AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保
存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk
升级,安装或删除时会更新这个文件。
5.检查BootClassPath,mSharedLibraries及/system/framework下的jar
是否需要dexopt,需要的则通过dexopt进行优化
6.启动AppDirObserver线程监测/system/framework,/system/app,/data/app,/data/
app-private目录的事件,主要监听add和remove事件。对于目录监听底层通过
inotify机制实现,inotify 是一种文件系统的变化通知机制,如文件增加、删除
等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持。
当有add event时调用scanPackageLI(File , int , int)处理;
当有remove event时调用removePackageLI()处理;
7.对于以上几个目录下的apk逐个解析,主要是解析每个apk的AndroidMa-
nifest.xml文件,处理asset/res等资源文件,建立起每个apk的配置结构信息,
并将每个apk的配置信息添加到全局列表进行管理。f
8.将解析的每个apk的信息保存到packages.xml和packages.list文件里,
packages.list记录了如下数据:pkgName,userId,debugFlag,dataPath(包的数据路径)
dexopt:
如果我们想要求运行时的性能有进一步提高,就仍然需要对DEX文件进行进一步优化。优化DEX会产生一个可以快速载入执行的classes.dex文件,会进行包括byte-swapping,structure realigning与basic structure checks,更新ODEX header ,为了确保产生ODEX流程的正确性,Android提供了一个dexopt工具,用来做为虚拟机的辅助工具,可以在系統启动时,透過Dalvik虚拟机對載入的DEX文件執行佳化操作。优化发生的时机有两个:
对于预置应用,可以在系统编译后,生成优化文件,以ODEX 结尾。这样在发布时除
APK 文件(不包含 DEX)以外,还有一个相应的 ODEX 文件;对于非预置应用,包含在 APK 文件里的 DEX 文件会在运行时通过dexopt进行优化,优化后的文件将被保存在缓存中(data/dalvik-cache)。
android安全机制概述:
Android是一个权限分离的系统 ,这是利用Linux已有的权限管理机制,通过为每一个Application分配不同的uid和gid, 从而使得不同的Application之间的私有数据和访问(native以及java层通过这种sandbox机制)达到隔离的目的 。与此同时,Android还在此基础上进行扩展,提供了permission机制,它主要是用来对Application可以执行的某些具体操作进行权限细分和访问控制,同时提供了per-URI permission机制,用来提供对某些特定的数据块进行访问。
Application 级别通过user ID和group Id实现安全控制;component级别通过permission来限制对于某一组件的访问;在data级别通过基于permission的per URI进行安全控制。
uid gid gids:
Android 的权限分离的基础是建立在 Linux 已有的 uid 、 gid 、 gids 基础上的 。UID :Android 在 安装一个应用程序,就会为 它 分配一个 uid 。其中普通 Android 应用程序的 uid 是从 10000 开始分配 (Process.FIRST_APPLICATION_UID ), 10000 以下是系统进程的 uid 。
GID :对 于普通应用程序来说, gid 等于 uid 。由于每个应用程序的 uid 和 gid 都不相同, 因此不管是 native 层还是 java 层都能够达到保护私有数据的作用 。
GIDS : gids 是由框架在 Application 安装过程中生成,与 Application 申请的具体权限相关。 如果 Application 申请的相应的 permission 被 granted ,而且中有对应的 gids , 那么这个Application 的 gids 中将包含这个gids 。
installer类:
构造方法中,首先会进行一些成员变量的初始化,比如mContext, mFactoryTest, mMetrics, mSettings等。最重要的是初始化mInstaller这个变量:
Installer installer =
new
Installer();
if
(installer.ping() && Process.supportsProcesses()) {
mInstaller = installer;
}
else
{
mInstaller =
null
;
}
Installer这个是PackageManager与底层C模块进行通信的工具类,同socket进行通信,PackageManager所有对apk的安装,卸载等操作都是通过Installer进行的。对Installer的调用首先会调用ping()来判断socket是否已经连接。
连接方法:connect:
private
boolean
connect() {
if
(mSocket !=
null
) {
return
true
;
}
Slog.i(TAG,
"connecting..."
);
try
{
mSocket =
new
LocalSocket();
LocalSocketAddress address =
new
LocalSocketAddress(
"installd"
, LocalSocketAddress.Namespace.RESERVED);
mSocket.connect(address);
mIn = mSocket.getInputStream();
mOut = mSocket.getOutputStream();
}
catch
(IOException ex) {
disconnect();
return
false
;
}
return
true
;
}
private
synchronized
String transaction(String cmd) {
if
(!connect()) {
Slog.e(TAG,
"connection failed"
);
return
"-1"
;
}
if
(!writeCommand(cmd)) {
/* If installd died and restarted in the background
* (unlikely but possible) we'll fail on the next
* write (this one). Try to reconnect and write
* the command one more time before giving up.
*/
Slog.e(TAG,
"write command failed? reconnect!"
);
if
(!connect() || !writeCommand(cmd)) {
return
"-1"
;
}
}
// Slog.i(TAG,"send: '"+cmd+"'");
if
(readReply()) {
String s =
new
String(buf,
0
, buflen);
// Slog.i(TAG,"recv: '"+s+"'");
return
s;
}
else
{
// Slog.i(TAG,"fail");
return
"-1"
;
}
}
执行命令的方法:execute(String cmd):
private
int
execute(String cmd) {
String res = transaction(cmd);
try
{
return
Integer.parseInt(res);
}
catch
(NumberFormatException ex) {
return
-
1
;
}
}
public
int
install(String name,
int
uid,
int
gid) {
StringBuilder builder =
new
StringBuilder(
"install"
);
builder.append(
' '
);
builder.append(name);
builder.append(
' '
);
builder.append(uid);
builder.append(
' '
);
builder.append(gid);
return
execute(builder.toString());
}
其他方法:
(1) dexopt(String apkPath, int uid, boolean isPublic);优化dex文件
(2)movedex(String srcPath, String dstPath); 移动dex文件
(3)rmdex(String codePath);删除dex文件
(4)remove(String name);移动apk
(5)rename(String oldname, String newname);重命名
(6)deleteCacheFiles(String name);删除cache文件
(7)clearUserData(String name);删除user data
(8)freeCache(long freeStorageSize);释放cache空间
(9)setForwardLockPerm(String packagePathSuffix, int gid) 为apk文件增加前缀
(10)getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath, PackageStats pStats) 获取apk信息
(11) moveFiles();移动文件。
转帖:http://www.open-open.com/lib/view/open1327556525374.html
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
Package manager has died
最近了发现一个奇怪的异常:
java.lang.RuntimeException: Package manager has died
android.app.ApplicationPackageManager.getApplicationInfo(ApplicationPackageManager.java:207)
查看代码,发现调用在调用PackageManager.getApplicationInfo或PackageManager.getPackageInfo 在某些机型上会抛出上述异常(SDK接口不可靠呀!!)
查阅代码发现,IPackageManager是一个IPC接口,因此ApplicationPackageManager的实现是一个IPC调用了,我们看下getPackageInfo的实现:
@Override public PackageInfo More ...getPackageInfo(String packageName, int flags) throws NameNotFoundException { try { PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId()); if (pi != null) { return pi; } } catch (RemoteException e) { throw new RuntimeException("Package manager has died", e); } throw new NameNotFoundException(packageName); }
通过源码,我们可以推测导致PM died的原因:
1、远程PackageManager处于不可用状态,导致此场景可以是某些应该正在(覆盖)安装
2、IPC调用过程中Binder使用的Buffer大小有限制(The Binder transaction buffer has a limited fixed size, currently 1Mb, which is shared by all transactions in progress for the process. ),获取应用程序的信息通常会包含Icon,有可能Buffer溢出,特别在低端,国产Rom上出现概率可能更大。
此问题暂无完全的解决方法,除非 google在源码上加以保证IPC调用稳定性。目前可以做的是捕捉此异常,避免应该程序Crash。
- android应用程序管理机制
- Android 应用程序管理机制
- Android 应用程序管理机制
- Android窗口管理机制
- android内存管理机制
- android 低内存管理机制
- Android中的内存管理机制
- Android内存管理机制详解
- Android内存管理机制详解
- android窗口管理机制
- Android内存管理机制详解
- Android内存管理机制
- Android内存管理机制详解
- Android内存管理机制
- Android电源管理机制剖析
- android内存管理机制
- Android内存管理机制详解
- Android内存管理机制
- linux网络代理设置(终端命令行的网络代理设置)
- MFC修改button的颜色、背景、边框、对话框标题
- 黑马程序员——iOS基础第一篇
- delphi xe7 fmx 复制到剪切板
- 使用JAVA调用中科院ICTCLAS2015分词系统
- Android 应用程序管理机制
- Normalized Cut(归一化割)
- Android解析包时出现问题
- 证券 基础知识 真题
- UVA536 - Tree Recovery
- iOS UITableViewCell重用以及自定义Cell
- Linux 的make及makefile文件格式
- golang技术随笔(二)理解goroutine
- 循环-16. 猴子吃桃问题(15)