美文网首页
Launcher3 LoadTask获取安装信息-API28

Launcher3 LoadTask获取安装信息-API28

作者: ArcherZang | 来源:发表于2020-03-14 15:22 被阅读0次
  1. 在LoaderTask中获取已安装APP的信息
    /packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java
LoaderTask.java
PackageInstallerCompat mPackageInstaller = PackageInstallerCompat.getInstance(mApp.getContext());
mPackageInstaller.updateAndGetActiveSessionCache()
  1. 需要知道PackageInstallerCompat到底是谁,实际是一个PackageInstallerCompatVL
    /packages/apps/Launcher3/src/com/android/launcher3/compat/PackageInstallerCompat.java
    //PackageInstallerCompat.java
    public static PackageInstallerCompat getInstance(Context context) {
        synchronized (sInstanceLock) {
            if (sInstance == null) {
                sInstance = new PackageInstallerCompatVL(context);
            }
            return sInstance;
        }
    }
  1. 那么就看一下PackageInstallerCompatVL.updateAndGetActiveSessionCache(),
    HashMap内容是getAllVerifiedSessions方法提供
    实际是PackageInstaller的getAllSessions获取的List,
    继续下来就是PackageInstaller的实例是从PackageManager中获取
    context.getPackageManager().getPackageInstaller()
    //PackageInstallerCompatVL.java

    @Thunk final PackageInstaller mInstaller;

    PackageInstallerCompatVL(Context context) {
        mAppContext = context.getApplicationContext();
        mInstaller = context.getPackageManager().getPackageInstaller();
        mCache = LauncherAppState.getInstance(context).getIconCache();
        mWorker = new Handler(LauncherModel.getWorkerLooper());
        mInstaller.registerSessionCallback(mCallback, mWorker);
    }

    public List<SessionInfo> getAllVerifiedSessions() {
        List<SessionInfo> list = new ArrayList<>(mInstaller.getAllSessions());
        Iterator<SessionInfo> it = list.iterator();
        while (it.hasNext()) {
            if (verify(it.next()) == null) {
                it.remove();
            }
        }
        return list;
    }

    @Override
    public HashMap<String, SessionInfo> updateAndGetActiveSessionCache() {
        HashMap<String, SessionInfo> activePackages = new HashMap<>();
        UserHandle user = Process.myUserHandle();
        for (SessionInfo info : getAllVerifiedSessions()) {
            addSessionInfoToCache(info, user);
            if (info.getAppPackageName() != null) {
                activePackages.put(info.getAppPackageName(), info);
                mActiveSessions.put(info.getSessionId(), info.getAppPackageName());
            }
        }
        return activePackages;
    }
  1. 因为ActivityThread给Activity attach了ContextImpl,所以调用了
    ContextImpl的getPackageManager,
    这里返回ApplicationPackageManager,它包装了IPackageManager(IBinder),先看下
    ApplicationPackageManager.getPackageInstaller()
    //ActivityThread.java
    public static IPackageManager getPackageManager() {
            if (sPackageManager != null) {
                //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
                return sPackageManager;
            }
            IBinder b = ServiceManager.getService("package");
            //Slog.v("PackageManager", "default service binder = " + b);
            sPackageManager = IPackageManager.Stub.asInterface(b);
            //Slog.v("PackageManager", "default service = " + sPackageManager);
            return sPackageManager;
        }

    performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ContextImpl appContext = createBaseContextForActivity(r);
        activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
    }
//ContextImpl.java
    @Override
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;

        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }
  1. 返回的是PackageInstaller,可以看下PackageInstaller.getAllSessions()
    //ApplicationPackageManager.java
    @Override
    public PackageInstaller getPackageInstaller() {
      synchronized (mLock) {
          if (mInstaller == null) {
              try {
                  mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
                          mContext.getPackageName(), mContext.getUserId());
              } catch (RemoteException e) {
                  throw e.rethrowFromSystemServer();
              }
          }
          return mInstaller;
      }
    }
  1. 返回的是PackageInstaller,可以看下PackageInstaller.getAllSessions()
    使用构造方法的install,ApplicationPackageManager传的是mPM.getPackageInstaller(),
    再往上是IPackageManager pm = ActivityThread.getPackageManager()是从ServiceManager.getService("package")获取的Binder
   //PackageInstaller.java
   /** {@hide} */
   public PackageInstaller(IPackageInstaller installer,
           String installerPackageName, int userId) {
       mInstaller = installer;
       mInstallerPackageName = installerPackageName;
       mUserId = userId;
   }

   public @NonNull List<SessionInfo> getAllSessions() {
      try {
          return mInstaller.getAllSessions(mUserId).getList();
      } catch (RemoteException e) {
          throw e.rethrowFromSystemServer();
      }
   }
  1. 最终我们来到PackageManagerService,知道是一个PackageInstallerService,
    其getAllSessions(int userId)方法返回的是自己mSessions.generateInfo(false)后的内容,
    用ParceledListSlice包装通过Binder传递
    //PackageManagerService extends IPackageManager.Stub  implements PackageSender
    public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore){
        ...
        mInstallerService = new PackageInstallerService(context, this);
        ...
    }

    @Override
    public IPackageInstaller getPackageInstaller() {
        if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
            return null;
        }
        return mInstallerService;
    }
// PackageInstallerService extends IPackageInstaller.Stub
    @Override
    public ParceledListSlice<SessionInfo> getAllSessions(int userId) {
        mPermissionManager.enforceCrossUserPermission(
                Binder.getCallingUid(), userId, true, false, "getAllSessions");

        final List<SessionInfo> result = new ArrayList<>();
        synchronized (mSessions) {
            for (int i = 0; i < mSessions.size(); i++) {
                final PackageInstallerSession session = mSessions.valueAt(i);
                if (session.userId == userId) {
                    result.add(session.generateInfo(false));
                }
            }
        }
        return new ParceledListSlice<>(result);
    }

8.最终分析mSessions数据由来,有两条线,
这条SystemServer线最靠谱,最终通过利用XMLPullParser读取install_sessions.xml内容
来获取已安装APP的名字、包名、icon等等
(以后看System server进程补上run方法调用)
SystemServer.run()->SystemServer.run()->SystemServer.startOtherServices
->PackageManagerService.systemReady()->PackageInstallerService.systemReady()
->PackageInstallerService.readSessionsLocked
``` java
    mSessionsFile = new AtomicFile(
                new File(Environment.getDataSystemDirectory(), "install_sessions.xml"),
                "package-session");

    @GuardedBy("mSessions")
        private void readSessionsLocked() {
            if (LOGD) Slog.v(TAG, "readSessionsLocked()");

            mSessions.clear();

            FileInputStream fis = null;
            try {
                fis = mSessionsFile.openRead();
                final XmlPullParser in = Xml.newPullParser();
                in.setInput(fis, StandardCharsets.UTF_.name());

                int type;
                while ((type = in.next()) != END_DOCUMENT) {
                    if (type == START_TAG) {
                        final String tag = in.getName();
                        if (PackageInstallerSession.TAG_SESSION.equals(tag)) {
                            final PackageInstallerSession session;
                            try {
                                session = PackageInstallerSession.readFromXml(in, mInternalCallback,
                                        mContext, mPm, mInstallThread.getLooper(), mSessionsDir);
                            } catch (Exception e) {
                                Slog.e(TAG, "Could not read session", e);
                                continue;
                            }

                            final long age = System.currentTimeMillis() - session.createdMillis;

                            final boolean valid;
                            if (age >= MAX_AGE_MILLIS) {
                                Slog.w(TAG, "Abandoning old session first created at "
                                        + session.createdMillis);
                                valid = false;
                            } else {
                                valid = true;
                            }

                            if (valid) {
                                mSessions.put(session.sessionId, session);
                            } else {
                                // Since this is early during boot we don't send
                                // any observer events about the session, but we
                                // keep details around for dumpsys.
                                addHistoricalSessionLocked(session);
                            }
                            mAllocatedSessions.put(session.sessionId, true);
                        }
                    }
                }
            } catch (FileNotFoundException e) {
                // Missing sessions are okay, probably first boot
            } catch (IOException | XmlPullParserException e) {
                Slog.wtf(TAG, "Failed reading install sessions", e);
            } finally {
                IoUtils.closeQuietly(fis);
            }
        }
        public static PackageInstallerSession readFromXml(@NonNull XmlPullParser in,
                    @NonNull PackageInstallerService.InternalCallback callback, @NonNull Context context,
                    @NonNull PackageManagerService pm, Looper installerThread, @NonNull File sessionsDir)
                    throws IOException, XmlPullParserException {
                final int sessionId = readIntAttribute(in, ATTR_SESSION_ID);
                final int userId = readIntAttribute(in, ATTR_USER_ID);
                final String installerPackageName = readStringAttribute(in, ATTR_INSTALLER_PACKAGE_NAME);
                final int installerUid = readIntAttribute(in, ATTR_INSTALLER_UID, pm.getPackageUid(
                        installerPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, userId));
                final long createdMillis = readLongAttribute(in, ATTR_CREATED_MILLIS);
                final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR);
                final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null;
                final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID);
                final boolean prepared = readBooleanAttribute(in, ATTR_PREPARED, true);
                final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);

                final SessionParams params = new SessionParams(
                        SessionParams.MODE_INVALID);
                params.mode = readIntAttribute(in, ATTR_MODE);
                params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
                params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
                params.sizeBytes = readLongAttribute(in, ATTR_SIZE_BYTES);
                params.appPackageName = readStringAttribute(in, ATTR_APP_PACKAGE_NAME);
                params.appIcon = readBitmapAttribute(in, ATTR_APP_ICON);
                params.appLabel = readStringAttribute(in, ATTR_APP_LABEL);
                params.originatingUri = readUriAttribute(in, ATTR_ORIGINATING_URI);
                params.originatingUid =
                        readIntAttribute(in, ATTR_ORIGINATING_UID, SessionParams.UID_UNKNOWN);
                params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
                params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
                params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
                params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);

                params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);

                final File appIconFile = buildAppIconFile(sessionId, sessionsDir);
                if (appIconFile.exists()) {
                    params.appIcon = BitmapFactory.decodeFile(appIconFile.getAbsolutePath());
                    params.appIconLastModified = appIconFile.lastModified();
                }

                return new PackageInstallerSession(callback, context, pm,
                        installerThread, sessionId, userId, installerPackageName, installerUid,
                        params, createdMillis, stageDir, stageCid, prepared, sealed);
            }
  1. 另一条线给PackageInstallerService.mSessions增加元素的,没找到实际使用
    PackageInstallerService.createSession ()-> createSessionInternal()
        private int createSessionInternal(SessionParams params, String installerPackageName, int userId)
                    throws IOException {
                final int callingUid = Binder.getCallingUid();
                mPermissionManager.enforceCrossUserPermission(
                        callingUid, userId, true, true, "createSession");

                if (mPm.isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
                    throw new SecurityException("User restriction prevents installing");
                }

                if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {
                    params.installFlags |= PackageManager.INSTALL_FROM_ADB;

                } else {
                    // Only apps with INSTALL_PACKAGES are allowed to set an installer that is not the
                    // caller.
                    if (mContext.checkCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES) !=
                            PackageManager.PERMISSION_GRANTED) {
                        mAppOps.checkPackage(callingUid, installerPackageName);
                    }

                    params.installFlags &= ~PackageManager.INSTALL_FROM_ADB;
                    params.installFlags &= ~PackageManager.INSTALL_ALL_USERS;
                    params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
                    if ((params.installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) !=
                            && !mPm.isCallerVerifier(callingUid)) {
                        params.installFlags &= ~PackageManager.INSTALL_VIRTUAL_PRELOAD;
                    }
                }

                // Only system components can circumvent runtime permissions when installing.
                if ((params.installFlags & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) !=
                        && 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 ((params.installFlags & PackageManager.INSTALL_FORWARD_LOCK) !=
                        || (params.installFlags & PackageManager.INSTALL_EXTERNAL) != ) {
                    throw new IllegalArgumentException(
                            "New installs into ASEC containers no longer supported");
                }

                // Defensively resize giant app icons
                if (params.appIcon != null) {
                    final ActivityManager am = (ActivityManager) mContext.getSystemService(
                            Context.ACTIVITY_SERVICE);
                    final int iconSize = am.getLauncherLargeIconSize();
                    if ((params.appIcon.getWidth() > iconSize * )
                            || (params.appIcon.getHeight() > iconSize * )) {
                        params.appIcon = Bitmap.createScaledBitmap(params.appIcon, iconSize, iconSize,
                                true);
                    }
                }

                switch (params.mode) {
                    case SessionParams.MODE_FULL_INSTALL:
                    case SessionParams.MODE_INHERIT_EXISTING:
                        break;
                    default:
                        throw new IllegalArgumentException("Invalid install mode: " + params.mode);
                }

                // If caller requested explicit location, sanity check it, otherwise
                // resolve the best internal or adopted location.
                if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != ) {
                    if (!PackageHelper.fitsOnInternal(mContext, params)) {
                        throw new IOException("No suitable internal storage available");
                    }

                } else if ((params.installFlags & PackageManager.INSTALL_EXTERNAL) != ) {
                    if (!PackageHelper.fitsOnExternal(mContext, params)) {
                        throw new IOException("No suitable external storage available");
                    }

                } else if ((params.installFlags & PackageManager.INSTALL_FORCE_VOLUME_UUID) != ) {
                    // For now, installs to adopted media are treated as internal from
                    // an install flag point-of-view.
                    params.setInstallFlagsInternal();

                } else {
                    // For now, installs to adopted media are treated as internal from
                    // an install flag point-of-view.
                    params.setInstallFlagsInternal();

                    // Resolve best location for install, based on combination of
                    // requested install flags, delta size, and manifest settings.
                    final long ident = Binder.clearCallingIdentity();
                    try {
                        params.volumeUuid = PackageHelper.resolveInstallVolume(mContext, params);
                    } finally {
                        Binder.restoreCallingIdentity(ident);
                    }
                }

                final int sessionId;
                final PackageInstallerSession session;
                synchronized (mSessions) {
                    // Sanity check that installer isn't going crazy
                    final int activeCount = getSessionCount(mSessions, callingUid);
                    if (activeCount >= MAX_ACTIVE_SESSIONS) {
                        throw new IllegalStateException(
                                "Too many active sessions for UID " + callingUid);
                    }
                    final int historicalCount = mHistoricalSessionsByInstaller.get(callingUid);
                    if (historicalCount >= MAX_HISTORICAL_SESSIONS) {
                        throw new IllegalStateException(
                                "Too many historical sessions for UID " + callingUid);
                    }

                    sessionId = allocateSessionIdLocked();
                }

                final long createdMillis = System.currentTimeMillis();
                // We're staging to exactly one location
                File stageDir = null;
                String stageCid = null;
                if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != ) {
                    final boolean isInstant =
                            (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != ;
                    stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant);
                } else {
                    stageCid = buildExternalStageCid(sessionId);
                }

                session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
                        mInstallThread.getLooper(), sessionId, userId, installerPackageName, callingUid,
                        params, createdMillis, stageDir, stageCid, false, false);

                synchronized (mSessions) {
                    mSessions.put(sessionId, session);
                }

                mCallbacks.notifySessionCreated(session.sessionId, session.userId);
                writeSessionsAsync();
                return sessionId;
            }

相关文章

网友评论

      本文标题:Launcher3 LoadTask获取安装信息-API28

      本文链接:https://www.haomeiwen.com/subject/osrvshtx.html