PMS指的是PackageManagerService
1:什么是PMS 即PackageManagerService
PackageManagerService 负责应用程序的安装,卸载,应用信息查询
一个应用对应一个包
PackageManagerService 类关系图
下图的左侧是Client端,其余的右侧是Servier端
从上层调用的时候,Android studio中写一个测试方法
try {
context.getPackageManager().getPackageInfo("", 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
这里的context.getPackageManager返回的是PackageManager,然后我们在搜索一下PackageManager,他是一个抽象类,里面有很多抽象方法。
public abstract class PackageManager {
public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
throws NameNotFoundException;
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
public abstract PackageInfo getPackageInfoAsUser(String packageName,
@PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
public abstract String[] currentToCanonicalPackageNames(String[] names);
public abstract String[] canonicalToCurrentPackageNames(String[] names);
public abstract @Nullable Intent getLaunchIntentForPackage(@NonNull String packageName);
//省略.....
}
我们怎么才能知道他的实现类是什么?
接着我们再搜索ApplicationPackageManager
public class ApplicationPackageManager extends PackageManager {
//重写PackageManager中的所有抽象方法
@Override
public PackageInfo getPackageInfo(String packageName, int flags)
throws NameNotFoundException {
return getPackageInfoAsUser(packageName, flags, mContext.getUserId());
}
@Override
public PackageInfo getPackageInfo(VersionedPackage versionedPackage, int flags)
throws NameNotFoundException {
try {
PackageInfo pi = mPM.getPackageInfoVersioned(versionedPackage, flags,
mContext.getUserId());
if (pi != null) {
return pi;
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(versionedPackage.toString());
}
}
//这里我们重点看一下 他是如何拿到ApplicationPackageManager ,因为只有拿到它,才能获取到Server端中定义的那些内容
我们主要看一下这个方法,我们知道PackageManager的实现类是ApplicationPackageManager,所以我们去这里找一下这个方法,
后我们找到了 mPM这个变量。
private final IPackageManager mPM;
IPackageManager 无法查看源码,我们去android的源码查看一下
位置:
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
是一个aidl文件,我们练习AIDL的时候知道,客户端和服务端都需要实现AIDL文件,点击运行的时候都会默认生成一个Stub的实现类和Proxy代理类,
interface IPackageManager {
void checkPackageStartable(String packageName, int userId);
boolean isPackageAvailable(String packageName, int userId);
PackageInfo getPackageInfo(String packageName, int flags, int userId);
PackageInfo getPackageInfoVersioned(in VersionedPackage versionedPackage,
int flags, int userId);
//省略,。。。。。
}
类似于这样,
public interface MyIPackageManager extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.asyn.task.mypmsdemo.MyIPackageManager {
private static final java.lang.String DESCRIPTOR = "com.asyn.task.mypmsdemo.MyIPackageManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.asyn.task.mypmsdemo.MyIPackageManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.asyn.task.mypmsdemo.MyIPackageManager))) {
return ((com.asyn.task.mypmsdemo.MyIPackageManager) iin);
}
return new com.asyn.task.mypmsdemo.MyIPackageManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
//省略
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.asyn.task.mypmsdemo.MyIPackageManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException {
//省略
mRemote.transact(Stub.TRANSACTION_getPackageInfo, _data, _reply, 0);
//省略
return _result;
}
}
static final int TRANSACTION_getPackageInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException;
}
//
// 服务连接
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iLogin = ILoginInterface.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
开始调用mPM中的方法,而mPm又是一个aidl文件,从以前的文章中我们知道,Server向Binder声明注册成为ServerManager的时候,会现在本地创建一个Binder对象,并起名字,然后再将binder对象的引用和名字打包发送给ServerManager,插入链表结构。所以当Client端通过ServiceConnection连接服务器的时候,通过回调asInterface方法,将当前的Ibinder对象
aidl分两部分:
server端需要提供一个Interface 向外说明自己能够提供哪些方法,实现哪些功能
build后,发现编译器已经帮我们实现了IPackageManager.Stub,里面包括像client提供的
asInterface
例子
public static com.netease.binder.ILoginInterface asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.netease.binder.ILoginInterface))) {
return ((com.netease.binder.ILoginInterface) iin);
}
return new com.netease.binder.ILoginInterface.Stub.Proxy(obj);
}
方法,通过queryLocalInterface查询是否是本地的指向Java Binder对象的原始本机指针。如果有就返回本地指针,如果没有就返回代理对象。
然后我们再次回到上面的图:
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
调用到mPM这一层,就已经到了Servier端,我们看一下是如何调用到这里的。
我们从源码层拷贝一下
IPackageManager
interface MyIPackageManager {
PackageInfo getPackageInfo(String packageName, int flags, int userId);
}
然后我们运行一下,在MainActivity中写个变量,然后进入源码查看这个方法:
public interface MyIPackageManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.asyn.task.mypmsdemo.MyIPackageManager {
private static final java.lang.String DESCRIPTOR = "com.asyn.task.mypmsdemo.MyIPackageManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.asyn.task.mypmsdemo.MyIPackageManager interface,
* generating a proxy if needed.
*/
public static com.asyn.task.mypmsdemo.MyIPackageManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.asyn.task.mypmsdemo.MyIPackageManager))) {
return ((com.asyn.task.mypmsdemo.MyIPackageManager) iin);
}
return new com.asyn.task.mypmsdemo.MyIPackageManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getPackageInfo: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
int _arg1;
_arg1 = data.readInt();
int _arg2;
_arg2 = data.readInt();
android.content.pm.PackageInfo _result = this.getPackageInfo(_arg0, _arg1, _arg2);
reply.writeNoException();
if ((_result != null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
reply.writeInt(0);
}
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.asyn.task.mypmsdemo.MyIPackageManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.content.pm.PackageInfo _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(packageName);
_data.writeInt(flags);
_data.writeInt(userId);
mRemote.transact(Stub.TRANSACTION_getPackageInfo, _data, _reply, 0);
_reply.readException();
if ((0 != _reply.readInt())) {
_result = android.content.pm.PackageInfo.CREATOR.createFromParcel(_reply);
} else {
_result = null;
}
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getPackageInfo = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException;
}
我们分析一下这个类,MyIPackageManager 里面我们找到了getPackageInfo方法,我们知道MyIPackageManager是一个接口方法,那么它的实现方法是谁,是Proxy,我们看到Proxy实现了getPackageInfo这个方法,而这个方法最后调用了
private android.os.IBinder mRemote;
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
而Stub是IBinder的实现类
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
转存失败 重新上传 取消
转存失败重新上传取消
![]()
这个是客户端通过Binder发送远程请求,我们接着看它法发送到了哪里
我们从上面找到了Stub,这个里面实现了
onTransact
方法,我们再次看上图
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
通过代理方法发送远程请求发送出去以后,我们开始找接收方, 找到源码
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
我们发现PackageManagerService的类属性:
public class PackageManagerService extends IPackageManager.Stub implements PackageSender {
这里面有getPackageInfo方法
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
flags, Binder.getCallingUid(), userId);
}
@Override
public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
int flags, int userId) {
return getPackageInfoInternal(versionedPackage.getPackageName(),
versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
}
/**
* Important: The provided filterCallingUid is used exclusively to filter out packages
* that can be seen based on user state. It's typically the original caller uid prior
* to clearing. Because it can only be provided by trusted code, it's value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
private PackageInfo getPackageInfoInternal(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForPackage(flags, userId, packageName);
mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "get package info");
// reader
synchronized (mPackages) {
// Normalize package name to handle renamed packages and static libs
packageName = resolveInternalPackageNameLPr(packageName, versionCode);
final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
if (matchFactoryOnly) {
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
if (ps != null) {
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
}
}
PackageParser.Package p = mPackages.get(packageName);
if (matchFactoryOnly && p != null && !isSystemApp(p)) {
return null;
}
if (DEBUG_PACKAGE_INFO)
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
final PackageSetting ps = (PackageSetting) p.mExtras;
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (ps != null && filterAppAccessLPr(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
}
if (!matchFactoryOnly && (flags & MATCH_KNOWN_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
if (ps == null) return null;
if (filterSharedLibPackageLPr(ps, filterCallingUid, userId, flags)) {
return null;
}
if (filterAppAccessLPr(ps, filterCallingUid, userId)) {
return null;
}
return generatePackageInfo(ps, flags, userId);
}
}
return null;
}
到这为止,就已经将数据和请求发送到了服务端。
我们复习一下:
1:IBinder:是一个接口,代表跨进程通讯的能力或者功能,只要实现这个接口就可以跨进程传输了
2:IInterface:代表Server进程对象代表能够提供什么样的功能,什么样的方法,对应的就是AIDL定义的接口。
3:Binder:java层的Binder类,代表的就是Binder的本地对象,这里需要;了解这个BinderProxy,我们需要一个本地的代理来操 作Binder,通过BinderProxy来操作Binder。
4:Stub:就是Aidl的时候,编译工具会自动生成一个stub的静态内部类,他是继承了Binder,实现了IInterface的接口,表明具备了服务端对Clinet承诺接口的能力。他是一个抽象类,具体的实现需要我们自己去做
我们从上层调用了getPackageManager()方法,调用了PackageManager的子类的ApplicationPackageManager的getPackageInfo()方法,getPackageInfo通过代理对象来操控Binder,即将数据发送给服务端,而getPackageInfo就调用了Proxy代理类中的
mRemote.transact(Stub.TRANSACTION_getPackageInfo, _data, _reply, 0);方法,
mRemote又是 private android.os.IBinder mRemote; 实现了跨进程传输的能力。
之后我们找到PackageManagerService,发现它是继承IPackageManager.Stub,即我们自定义的MyIPackageManager,这样通信就被建立起来了。
界面安装分为有界面安装和无界面安装
有界面安装
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
有界面安装,调用的是PackageInstallerActivity
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
我们从源码分析一下
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
private void startInstall() {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO,
mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallInstalling.class);
String installerPackageName = getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (mOriginatingURI != null) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_URI, mOriginatingURI);
}
if (mReferrerURI != null) {
newIntent.putExtra(Intent.EXTRA_REFERRER, mReferrerURI);
}
if (mOriginatingUid != PackageInstaller.SessionParams.UID_UNKNOWN) {
newIntent.putExtra(Intent.EXTRA_ORIGINATING_UID, mOriginatingUid);
}
if (installerPackageName != null) {
newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME,
installerPackageName);
}
if (getIntent().getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)) {
newIntent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
}
newIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
if(localLOGV) Log.i(TAG, "downloaded app uri="+mPackageURI);
startActivity(newIntent);
finish();
}
2:无界面安装,就是通过adb push
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
调用的是C的代码,
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
int adb_commandline(int argc, const char** argv) {
int no_daemon = 0;
//省略..
}
static int install_app(int argc, const char** argv);
static int install_multiple_app(int argc, const char** argv);
static int uninstall_app(int argc, const char** argv);
static int install_app_legacy(int argc, const char** argv);
static int uninstall_app_legacy(int argc, const char** argv);
这里有安装和卸载的方法
因为我们知道上层调用到了PackageManagerService,我们来看一下
@Override
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, int userId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId,
true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");
if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
try {
if (observer != null) {
observer.onPackageInstalled("", INSTALL_FAILED_USER_RESTRICTED, null, null);
}
} catch (RemoteException re) {
}
return;
}
if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
installFlags |= PackageManager.INSTALL_FROM_ADB;
} else {
// Caller holds INSTALL_PACKAGES permission, so we're less strict
// about installerPackageName.
installFlags &= ~PackageManager.INSTALL_FROM_ADB;
installFlags &= ~PackageManager.INSTALL_ALL_USERS;
}
UserHandle user;
if ((installFlags & PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
} else {
user = new UserHandle(userId);
}
// Only system components can circumvent runtime permissions when installing.
if ((installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0
&& mContext.checkCallingOrSelfPermission(Manifest.permission
.INSTALL_GRANT_RUNTIME_PERMISSIONS) == PackageManager.PERMISSION_DENIED) {
throw new SecurityException("You need the "
+ "android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS permission "
+ "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
}
if ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0
|| (installFlags & PackageManager.INSTALL_EXTERNAL) != 0) {
throw new IllegalArgumentException(
"New installs into ASEC containers no longer supported");
}
final File originFile = new File(originPath);
final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
final Message msg = mHandler.obtainMessage(INIT_COPY);
final VerificationInfo verificationInfo = new VerificationInfo(
null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
null /*packageAbiOverride*/, null /*grantedPermissions*/,
null /*certificates*/, PackageManager.INSTALL_REASON_UNKNOWN);
params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
msg.obj = params;
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
System.identityHashCode(msg.obj));
Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
System.identityHashCode(msg.obj));
mHandler.sendMessage(msg);
}
总结:
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
转存失败重新上传取消
Apk的安装原理
安装其实就是把apk文件copy到了对应的目录:
1:data/app/包名-------安装时apk文件复制到此目录,---可以将文件取出并安装,和我们本身的apk一样。
data/data/packagename/(test.apk)
2 :data/data/包名----开辟存放应用程序的文件数据的文件夹,包括i哦应用的so库,缓存文件等等
data/data/packagename/(db,cache)
3:将apk中的dex文件安装到data/dalvik-cache目录下(dex文件是dalvik虚拟机的可执行文件,其大小为原始apk文件大小的1/4
data/dalvik-cache/(profiles.x86)