美文网首页
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