start-scan:
@startuml
participant SystemServer as SS
participant PackageManagerService as PKMS
participant ParallelPackageParser as P_PP
participant PackageParser as PP
==PKMS START and scan apk==
SS -> SS: run
SS -> SS: startBootstrapServices
activate SS
SS -> PKMS : mPackageManagerService = PackageManagerService.main
activate PKMS
PKMS -> PKMS: m = new PackageManagerService
'construct call'
activate PKMS #FF55FF
==scan apk ==
PKMS -> PKMS:scanDirTracedLI:dir
loop for file in dir
PKMS -> P_PP : parallelPackageParser.submit
P_PP -> PP: PackageParser.Package pr = packageParser.parsePackage\n(scanFile, parseFlags, true)
alt if packageFile.isDirectory()
PP -> PP: parsed = parseClusterPackage(packageFile, flags);
else
PP -> PP: parsed = parseMonolithicPackage(packageFile, flags);
activate PP #FF55FF
PP -> PP:parseBaseApk(apkFile, assets, flags)
activate PP #FFFF55
PP -> PP:parseBaseApkCommon
PP->PP: parse the AndroidManifest.xml
deactivate PP
PP -> PP:return pkg;
deactivate PP
end
PP->P_PP: return parsed
P_PP -> P_PP:mQueue.put(pr)
PKMS -> P_PP :ParallelPackageParser.ParseResult parseResult\n = parallelPackageParser.take
note left
get the parse result from the mQueue
end note
alt no error case
PKMS -> PKMS: <b>scanPackageLI</b>(parseResult.pkg,parseResult.scanFile,```)
activate PKMS #FFFF55
PKMS -> PKMS:<b>scanPackageInternalLI</b>
PKMS -> PKMS:check something about apk update
PKMS -> PKMS:collectCertificatesLI
note left
verify the apk and collect certificates,
if verify ok:
collect certificates to Package.mCertificates
if fail:
throw SignatureException/GeneralSecurityException/...
end note
PKMS -> PKMS:<b>scanPackageLI</b>(pkg, policyFlags,...)
note left
the another method of scanPackageLI
end note
PKMS -> PKMS:scanPackageDirtyLI
alt if scanFlags & SCAN_CHECK_ONLY) != 0
else else: update this package info to <b>PKMS</b>
PKMS -> PKMS:commitPackageSettings
PKMS -> PKMS:<b>mPackages.put(pkg.applicationInfo.packageName, pkg)</b>
note left
Adds a scanned package to the system(mPackages). \nWhen this method is finish
the package will be available\n for query, resolution, etc...
end note
end
deactivate PKMS
else else: if not system apk && invalid
PKMS -> PKMS: removeCodePathLI(parseResult.scanFile)
end
end
deactivate PKMS
PKMS -> PKMS: updatePermissionsLPw
note left: update if the apk can grant the permissions it request
PKMS -> PKMS: ServiceManager.addService("package", m)
PKMS -> PKMS: pmn = m.new PackageManagerNative()
PKMS -> PKMS: ServiceManager.addService("package_native", pmn)
deactivate PKMS
SS -> SS: mPackageManager = mSystemContext.getPackageManager();
deactivate SS
@enduml
adb install by adb
@startuml
participant adb_pc
participant adbd
participant shell_adbd_sub_process as shell
participant Pm.java as pm
participant PackageInstaller as pi
participant PackageMangerService as pkms
participant PackageInstallerService as pis
participant PackageInstallerSession as piss
==PKMS adb install apk==
adbd -> adbd: fdevent_install(&(t->transport_fde), t->transport_socket,\n transport_socket_events, t);
note right
register the package callback:transport_socket_events
end note
adb_pc -->adbd:adb install d:/xxx.apk
adbd->adbd: transport_socket_events
activate adbd
adbd->adbd:read_packet,handle_packet
adbd->adbd:<font color=red>services.cpp</font> service_to_fd
note right
packet is : shell:pm 'install' '/data/local/tmp/app-clientchat.apk'
end note
adbd->adbd:strncmp(name, "shell",5)\n ==> ShellService(cmd, transport)
adbd->adbd: StartSubprocess(cmd,...)
note right
StartSubprocess will fork<font color=red> new process </font>
cmd is:pm 'install' '/data/local/tmp/app-clientchat.apk'
end note
adbd->shell:fork fork<font color=red>new process</font>
shell->shell:execle(_PATH_BSHELL, _PATH_BSHELL, "-c", \ncommand_.c_str(), nullptr, cenv.data());
note right
replace the subprocess with shell
end note
shell->pm: Pm.java main(arg[0] = install)
pm->pm:runInstall
activate pm
note over pm #00FFFF:1.get the interface of IPackageManager/IPackageInstaller/
pm->pm: <b>IPackageManager</b> mPm = IPackageManager.Stub.asInterface\n(ServiceManager.getService("package"));
pm->pkms:<b>IPackageInstaller</b> mInstaller = mPm.getPackageInstaller();
pkms->pm: return new PackageInstallerService(context, this);\n it convert to IPackageInstaller
note left
get the stub interface of packageManager and PackagerInstaller
end note
note over pm #00FFFF:2.set and adopt InstallParams
pm->pm:init the InstallParams(params) with the args\n userId default is UserHandle.USER_ALL
pm->pm:ApkLite baseApk = PackageParser.parseApkLite(file, 0);\nPackageLite pkgLite = new PackageLite(null, baseApk,null,...)
pm->pm:params.sessionParams.setSize(get the file size)
note over pm #00FFFF:3.create session
pm->pis:sessionId = createSession(params, installerPackageName, userId)
pis->pis:createSessionInternal
activate pm #FF5555
pm->pis:int sessionId = <b>mInstaller.createSession</b>
pis->pkms:enforceCrossUserPermission\n(callingUid, userId, true, true, "createSession")
pis->pis:check and adopt the install params
pis->pis:<font color=red>sessionId</font> = allocateSessionIdLocked();
pis->pis:session = new <font color=red>PackageInstallerSession</font>
pis->pis:<font color=red>mSessions.put(sessionId, session)</font>;
note left
map sessionId to PackageInstallerSession
end note
pis->pis:mCallbacks.notifySessionCreated\n(session.sessionId, session.userId);
pis->pis:<b>callback</b>.onSessionCreated(sessionId)
note left
call the callback function
callback is registered by calling registerCallback
end note
/'
note over pm #FFFF00 :Pm.java
note over pi #FFFF00 :PackageInstaller
note over pkms #FFFF00: PackageMangerService
note over pis #FFFF00 :PackageInstallerService
note over piss #FFFF00 :PackageInstallerSession
'/
note over pm #00FFFF:4.write apk buffer to dest file
deactivate pm
pm->pm:doWriteSession
hnote left:Pm.java
activate pm #FF55FF
pm->pis:IPackageInstallerSession iPackageInstallerSession = <b>mInstaller.openSession(sessionId)</b>)
hnote right:PackageInstallerService
pis->pis:prepare mk dir and call \nmCallback.onSessionProgressChanged\nmCallback.onSessionPrepared
pis->pm:return <b>IPackageInstallerSession</b> which map to session id
pm->pm:<b>PackageInstaller.Session session</b> = \nnew PackageInstaller.Session(<b>iPackageInstallerSession</b>)
pm->pi:OutputStream out = session.openWrite(splitName, 0, sizeBytes)
hnote right:PackageInstaller
pi->piss:open dest file for writing: FileDescriptor targetFd = \nLibcore.os.open(target.getAbsolutePath(),O_CREAT | O_WRONLY, 0644);)
hnote right:PackageInstallerSession
piss->pi:return FileDescriptor for writing
pi->pm:return OutputStream for writing
ref over pm
while(readnum = in.read(buffer)) != -1):
out.write(buffer, 0, readnum);
float fraction = ((float) readnum / (float) info.sizeBytes)
<b>session.addProgress(fraction)</b>
end ref
pm->pm:session.fsync(out);
pm->pm:close in out stream and session
deactivate pm
note over pm #00FFFF:5.comit session
pm->pm:doCommitSession(int sessionId, boolean logSuccess)
activate pm #FF55FF
pm->pm:LocalIntentReceiver receiver = new LocalIntentReceiver();
pm->piss:session.<b>commit</b>(receiver.getIntentSender());
pm->pm:Intent result = receiver.getResult();
pm->pm:status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,\nPackageInstaller.STATUS_FAILURE);
pm->pm:return new Pair<>(result.getStringExtra\n(PackageInstaller.EXTRA_PACKAGE_NAME), status);
deactivate pm
deactivate pm
deactivate adbd
@enduml
pms class relationship
@startuml
Settings "1" o-- "n" PackageSetting
Settings "1" o-- "n" BasePermission
PackageManagerService "1" o-- "1" Settings
PackageManagerService "1" o-- "n" PackageParser.Package
class PackageManagerService{
Settings mSettings
ArrayMap<String, PackageParser.Package> mPackages
}
class PackageParser.Package{
+String packageName
+String manifestPackageName
+String[] splitNames
+String volumeUuid
+String codePath
+String baseCodePath
+String[] splitCodePaths;
+int baseRevisionCode;
+ApplicationInfo applicationInfo
+ArrayList<Permission> permissions
+ArrayList<PermissionGroup> permissionGroups
+ArrayList<Activity> activities
+ArrayList<Activity> receivers
+ArrayList<Provider> providers
+ArrayList<Service> services
+ArrayList<Instrumentation> instrumentation
+ArrayList<String> requestedPermissions
+ArrayList<String> protectedBroadcasts
+Package parentPackage
+String mSharedUserId;
..all certificates of all the signers of a apk..
+Certificate[][] mCertificates;
..convert from certificates[][],convert [][] to []..
+Signature[] mSignatures
.. the permissions this pkg defined ..
+ArrayList<Permission> permissions
+...
}
class Settings{
/** Map from package name to settings */
ArrayMap<String, PackageSetting> mPackages
/** List of packages that installed other packages */
ArraySet<String> mInstallerPackages
ArrayMap<String, BasePermission> mPermissions
ArrayMap<String, BasePermission> mPermissionTrees
ArrayMap<String, SharedUserSetting> mSharedUsers
/**id > FIRST_APPLICATION_UID 10000,
map from uid index to object like SharedUserSetting/PackageSetting*/
ArrayList<Object> mUserIds
}
note top:Holds information about dynamic settings
class BasePermission {
String name
String sourcePackage
PackageSettingBase packageSetting
int type:NORMAL/BUILTIN/DYNAMIC
int protectionLevel
PackageParser.Permission perm
PermissionInfo pendingInfo
/** UID that owns the definition of this permission */
int uid;
/** Additional GIDs given to apps granted this permission */
- int[] gids;
}
class PackageSetting extends PackageSettingBase{
int appId
PackageParser.Package pkg
SharedUserSetting sharedUser
}
abstract class PackageSettingBase extends SettingBase {
String name
String realName
String parentPackageName
List<String> childPackageNames
File codePath
String[] usesStaticLibraries
int[] usesStaticLibrariesVersions
String primaryCpuAbiString
String secondaryCpuAbiString
PackageSignatures signatures
PackageKeySetData keySetData
int installStatus
/** Package name of the app that installed this package */
String installerPackageName;
IntentFilterVerificationInfo verificationInfo;
}
class SettingBase{
}
@enduml