您的位置:首页 > 移动开发 > Android开发

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举例:

@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/


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: