Android PackageManager
2016-04-18 18:16
429 查看
这两个管理器其实没什么好扯的,看一下源代码基本上就知道了,用途的话除了系统本身用的最多,PackageManager在桌面Launcher APP使用.
PackageManager管理器主要负责APP Package的管理,比如安装,卸载,Package的解析,Package包的各种信息,如版本,APP图标,资源,权限等等,android系统在安装APP的时候,会弹出一个提示框,提示框中就会显示包的各种信息,并且会告诉安装者APP会用到那些权限.这些都是从app package的主配置xml解析出来的,基本上可以得到一个app的所有信息.
平时直接用的比较多的就是对应用层的PackageManager.java中的getPackageInfo,getActivityInfo,getServiceInfo还有四大组件的其他组件.间接用的比较多的就是installPackage和deletePackage.PackageManager主要对于应用的,下面是是PackageManagerService.java .以getActivityInfo举例:
然后包的解析器PackageParser解析所有的信息返回.
这些包的信息最终被保存在parcel数据结构体中.
下面大致介绍一下APK安装:还是直接从PackageManagerService.java的installPackage开始,下面从这个方法开始跳到:
这个我看了大致是用户限制和UID等verify,直接看到这个最后面:
从这个地方开始,后面的安装都是通过handle根据状态完成整个安装过程.下面在看消息处理
连接服务以后,又会发送MCS_BOUND消息:
其中mContainerService是管理APK安装(如果有必要释放一部分空间,或者没有足够空间),然后开始拷贝APK,一切从startCopy()开始了:
其中:
是管理安装路径的,还可以看一下是安装在内部还是外部SD卡中.然后继续:
一直看下去:
里面:
中的:
前面那个process***的,还有一些设计恢复和备份的(BackPackage之类的)
后面的还有,这里看到scanPackageLI方法,进去一看,真的是又臭又长,哎.进入,看到createDataDirsLI方法后看到:
看到install了,你妈mInstaller是Installer.java的类:
一看,安装是需要和一个设备节点叫做installd进行通信.居然是Socket通信,那么肯定installd相当于是一个服务端,而且在系统里面常驻,并且已经启动,那么就看看init.rc文件,有一段:
其他的可以自行参考.
非常详细的步骤可以参考:http://blog.csdn.net/lilian0118/article/details/25792601进行补充.
补充一个 : 平时安装软件APP的,就是用点击安装软件,就会有一个安装软件的弹出框出来,让用户不断要点击OK,OK的,那是一个系统APP:PackageInstaller
参考google: https://android.googlesource.com/platform/packages/apps/PackageInstaller/
PackageManager管理器主要负责APP Package的管理,比如安装,卸载,Package的解析,Package包的各种信息,如版本,APP图标,资源,权限等等,android系统在安装APP的时候,会弹出一个提示框,提示框中就会显示包的各种信息,并且会告诉安装者APP会用到那些权限.这些都是从app package的主配置xml解析出来的,基本上可以得到一个app的所有信息.
平时直接用的比较多的就是对应用层的PackageManager.java中的getPackageInfo,getActivityInfo,getServiceInfo还有四大组件的其他组件.间接用的比较多的就是installPackage和deletePackage.PackageManager主要对于应用的,下面是是PackageManagerService.java .以getActivityInfo举例:
@Override public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { if (!sUserManager.exists(userId)) return null; enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "get activity info"); synchronized (mPackages) { PackageParser.Activity a = mActivities.mActivities.get(component); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); if (ps == null) return null; return PackageParser.generateActivityInfo(a, flags, ps.readUserState(userId), userId); } if (mResolveComponentName.equals(component)) { return mResolveActivity; } } return null; }
然后包的解析器PackageParser解析所有的信息返回.
public static ApplicationInfo generateApplicationInfo(Package p, int flags, PackageUserState state, int userId) { if (p == null) return null; if (!checkUseInstalled(flags, state)) { return null; } if (!copyNeeded(flags, p, state, null, userId)) { // CompatibilityMode is global state. It's safe to modify the instance // of the package. if (!sCompatibilityModeEnabled) { p.applicationInfo.disableCompatibilityMode(); } // Make sure we report as installed. Also safe to do, since the // default state should be installed (we will always copy if we // need to report it is not installed). p.applicationInfo.flags |= ApplicationInfo.FLAG_INSTALLED; if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { p.applicationInfo.enabled = true; } else if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED || state.enabled == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER) { p.applicationInfo.enabled = false; } p.applicationInfo.enabledSetting = state.enabled; return p.applicationInfo; } // Make shallow copy so we can store the metadata/libraries safely ApplicationInfo ai = new ApplicationInfo(p.applicationInfo);
... ...
这些包的信息最终被保存在parcel数据结构体中.
下面大致介绍一下APK安装:还是直接从PackageManagerService.java的installPackage开始,下面从这个方法开始跳到:
public void installPackageWithVerificationAndEncryption(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
这个我看了大致是用户限制和UID等verify,直接看到这个最后面:
final Message msg = mHandler.obtainMessage(INIT_COPY); msg.obj = new InstallParams(packageURI, observer, filteredFlags, installerPackageName, verificationParams, encryptionParams, user); mHandler.sendMessage(msg);
从这个地方开始,后面的安装都是通过handle根据状态完成整个安装过程.下面在看消息处理
void doHandleMessage(Message msg) { switch (msg.what) { case INIT_COPY: { if (DEBUG_INSTALL) Slog.i(TAG, "init_copy"); HandlerParams params = (HandlerParams) msg.obj; int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.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); } }
连接服务以后,又会发送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) { // Indicate service bind error params.serviceError(); } mPendingInstalls.clear(); } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0); if (params != null) { if (params.startCopy()) {
其中mContainerService是管理APK安装(如果有必要释放一部分空间,或者没有足够空间),然后开始拷贝APK,一切从startCopy()开始了:
final boolean startCopy() { boolean res; try { if (DEBUG_INSTALL) Slog.i(TAG, "startCopy"); if (++mRetries > MAX_RETRIES) { Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up"); mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { handleStartCopy(); res = true; } } catch (RemoteException e) { if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT"); mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } handleReturnCode(); return res; }
其中:
void handleStartCopy() throws RemoteException {
是管理安装路径的,还可以看一下是安装在内部还是外部SD卡中.然后继续:
@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); if (mTempPackage != null) { if (!mTempPackage.delete()) { Slog.w(TAG, "Couldn't delete temporary file: " + mTempPackage.getAbsolutePath()); } } } }
一直看下去:
private void installPackageLI(InstallArgs args, boolean newInstall, PackageInstalledInfo res) {
里面:
if (!args.doRename(res.returnCode, pkgName, oldCodePath)) { res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; return; }这个判断里面的doRename需要注意了,我们安装apk到系统中名字会有一点不同,比如本来是my.apk,安装后到data/app下查看,结果是my-1.apk,如果反复安装还会出现my-2.apk等等
中的:
if (replace) { replacePackageLI(pkg, parseFlags, scanMode, args.user, installerPackageName, res); } else { installNewPackageLI(pkg, parseFlags, scanMode, args.user, installerPackageName, res); }
前面那个process***的,还有一些设计恢复和备份的(BackPackage之类的)
private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, UserHandle user, String installerPackageName, PackageInstalledInfo res) { // Remember this for later, in case we need to rollback this install String pkgName = pkg.packageName; boolean dataDirExists = getDataPathForPackage(pkg.packageName, 0).exists(); synchronized(mPackages) { if (mSettings.mRenamedPackages.containsKey(pkgName)) { // A package with the same name is already installed, though // it has been renamed to an older name. The package we // are trying to install should be installed as an update to // the existing one, but that has not been requested, so bail. Slog.w(TAG, "Attempt to re-install " + pkgName + " without first uninstalling package running as " + mSettings.mRenamedPackages.get(pkgName)); res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; return; } if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) { // Don't allow installation over an existing package with the same name. Slog.w(TAG, "Attempt to re-install " + pkgName + " without first uninstalling."); res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; return; } } mLastScanError = PackageManager.INSTALL_SUCCEEDED; PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode, System.currentTimeMillis(), user);
后面的还有,这里看到scanPackageLI方法,进去一看,真的是又臭又长,哎.进入,看到createDataDirsLI方法后看到:
private int createDataDirsLI(String packageName, int uid) { int[] users = sUserManager.getUserIds(); int res = mInstaller.install(packageName, uid, uid); if (res < 0) { return res; } for (int user : users) { if (user != 0) { res = mInstaller.createUserData(packageName, UserHandle.getUid(user, uid), user); if (res < 0) { return res; } } } return res; }
看到install了,你妈mInstaller是Installer.java的类:
public final class Installer { private static final String TAG = "Installer"; private static final boolean LOCAL_DEBUG = false; InputStream mIn; OutputStream mOut; LocalSocket mSocket; byte buf[] = new byte[1024]; int buflen = 0; 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; }
一看,安装是需要和一个设备节点叫做installd进行通信.居然是Socket通信,那么肯定installd相当于是一个服务端,而且在系统里面常驻,并且已经启动,那么就看看init.rc文件,有一段:
其他的可以自行参考.
非常详细的步骤可以参考:http://blog.csdn.net/lilian0118/article/details/25792601进行补充.
补充一个 : 平时安装软件APP的,就是用点击安装软件,就会有一个安装软件的弹出框出来,让用户不断要点击OK,OK的,那是一个系统APP:PackageInstaller
参考google: https://android.googlesource.com/platform/packages/apps/PackageInstaller/
相关文章推荐
- ANDROID自定义视图——onMeasure流程,MeasureSpec详解
- Design Support Library
- android 控件 fragment 简单分析
- android手机的分区相关
- Android打包与混淆相关的一些小知识
- Android_Handler实现异步回调加载数据
- Android WebView Java和JS通信
- AIDL(AndroidInterfaceDefinitionLanguage:接口定义语言)
- android viewGroup事件分发一
- Android MVC模式
- 关于 Android 进程保活,你所需要知道的一切
- Android Inline hook跳转部分代码
- 音乐播放器源码
- Android 注解的简单使用之省去findViewById()
- 【转】android Looper 理解
- Android基本控件 - Button和ImageButton
- Android生成签名文件并用其对apk文件进行签名(Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]错误完美解决)
- android多媒体框架之流媒体具体流程篇2----base on jellybean(十二)
- 浅谈如何避免Android内存溢出
- android 流量统计