Android PackageManager

本文详细探讨了Android系统的PackageManager服务,包括其在安装、卸载应用程序时的角色,以及如何获取和解析APP信息。重点关注PackageManagerService的installPackage和deletePackage方法,解析流程涉及Parcel数据结构、安装路径管理和与installd服务的Socket通信。此外,还提到了PackageInstaller系统APP在用户交互中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这两个管理器其实没什么好扯的,看一下源代码基本上就知道了,用途的话除了系统本身用的最多,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.youkuaiyun.com/lilian0118/article/details/25792601进行补充.


补充一个 : 平时安装软件APP的,就是用点击安装软件,就会有一个安装软件的弹出框出来,让用户不断要点击OK,OK的,那是一个系统APP:PackageInstaller

参考google: https://android.googlesource.com/platform/packages/apps/PackageInstaller/















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值