- 在LoaderTask中获取已安装APP的信息
/packages/apps/Launcher3/src/com/android/launcher3/model/LoaderTask.java
LoaderTask.java
PackageInstallerCompat mPackageInstaller = PackageInstallerCompat.getInstance(mApp.getContext());
mPackageInstaller.updateAndGetActiveSessionCache()
- 需要知道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;
}
}
- 那么就看一下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;
}
- 因为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;
}
- 返回的是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;
}
}
- 返回的是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();
}
}
- 最终我们来到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);
}
- 另一条线给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;
}
网友评论