Trabajo diario 2022.4.19 El servicio PackageManager escanea el directorio APK.
Está claro que la opción del usuario de actualizar witen 5.1 a bturnc 5.3 no vincula imei;
6 Escanee el directorio APK
En el constructor de PackageManagerService Llame al método scanDirTracedLI para escanear un directorio en busca de archivos apk.
En Android 10.0, PKMS escanea principalmente la información del APK en las siguientes rutas:
/Vendor/Coverage
/Product/Coverage
/Productos/Servicios/Cobertura
/ODM/Cobertura
/OEM/Cobertura
/Sistema/Marco
/Sistema/Privado Aplicaciones
/Sistema/Aplicaciones
/Proveedor/Aplicaciones privadas
/Proveedor/Aplicaciones
/odm /priv-app p>
/odm/app
/oem/app
/oem/priv-app
/product/privacy Aplicaciones
/Productos/Aplicaciones
/Productos y Servicios/Aplicaciones de Privacidad
/Productos y Servicios/Aplicaciones
/Productos Servicio/Aplicaciones de Privacidad
Usamos scanDirTracedLI() como punto de entrada para analizar:
6.1[ParallelPackageParser.java]scanDirTracedLI()
De la siguiente función se puede ver que la entrada de scanDirTracedLI es muy simple. Primero agregue algunos rastros de registro de systtrace y luego llame a scanDirLI() para su análisis.
private void scanDirTracedLI(Archivo scanDir, final int parseFlags, int scanFlags, long currentTime) {
TRACE TRACE begin(TRACE _ TAG _ PACKAGE _ MANAGER, " scanDir[" scanDir. .getabsolutepath() "]");
Prueba {
scanDirLI(scanDir, parseFlags, scanFlags, hora actual);
}Finalmente {
TRACE . TRACE end(TRACE _ TAG _ PACKAGE _ MANAGER
}
}
6.2[ParallelPackageParser.java] Scandi ); p>
ScanDirLI() utiliza el objeto ParallelPackageParser, que es una cola. Aquí tomamos las APK de todos los sistemas de telefonía móvil, luego las eliminamos de estas colas y luego llamamos a PackageParser para analizarlas.
private void scanDirLI(File scanDir, int parseFlags, int scanFlags, long currentTime) {
final File[]files = scandir lista de archivos();
Log.d(label, "No hay archivos en el directorio de la aplicación" scanDir);
Return;
}
if(escaneo de paquete de depuración){
Log.d(label, "Escanear directorio de aplicaciones" scanDir " scan flags = " scan flags
" flags = 0x " integer . tohexstring(parse flags));
}
//parallelPackageParser es una cola para recopilar archivos apk del sistema.
// Luego saque los apk uno por uno de esta cola y llame a PackageParser para analizarlos.
try(ParallelPackageParser ParallelPackageParser = new ParallelPackageParser(
mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
mparallelpackaparsercallback)){
// Envíe archivos en paralelo para su análisis
int file count = 0;
for(file file: file){
//Es un archivo o directorio Apk.
El valor booleano final es paquete =(isApkFile(archivo)| | archivo. es directorio())
amp amp! servicio de instalación del paquete . isstagename(file . getname());
Filtre los archivos que no sean apk; si no, omita y continúe escaneando.
if (!isPackage) {
//Ignorar entradas que no sean paquetes
Continuar;
}
El objeto mQueue que almacena información APK en paraleloPackageParser asigna la función PackageParser() al miembro pkg en la cola.
//Cita [6.3]
parallelpackageparser .submit(archivo, analizar indicadores);
filecount;
}
//Procesa los resultados uno por uno
for(; file count gt0; file count - ) {
//Obtiene la información de la cola apk de paraleloPackageParser.
ParallelPackageParser. resultado del análisis resultado del análisis = paralelopackageparser . take();
throwable throwable = análisis del resultado throwable;
int errorCode = PackageManager.
INSTALL _ SUCCEEDED
if (throwable == null) {
// TODO(toddke): bajar en la cadena de escaneo
//Biblioteca compartida estática Hay un nombre de paquete sintetizado
if(parse result . pkg . application info . isstaticsharedlibrary()){
renameStaticSharedLibraryPackage(parse result . pkg);
}
Pruebe {
//Llame al método scanPackageChildLI para escanear un archivo apk específico.
//Las instancias de esta clase representan un archivo apk, por lo que es la estructura de datos correspondiente al archivo APK.
//Cita [6.4]
scanPackageChildLI(resultado del análisis. pkg, parseFlags, scanFlags,
currentTime, null
); } catch(PackageManagerException e){
errorCode = e.error
Slog.w(TAG, "Error al escanear" resultado del análisis. archivo de escaneo ":" e. getmessage() );
}
} else if(instancia arrojable del analizador de paquetes. PackageParserException) {
PackageParser. excepción del analizador de paquetes e = (package parser.PackageParserException)
Throwable;
errorCode = e.error
Slog.w(TAG, "Análisis fallido" análisis resultado . escanear archivo ": " e . getmessage());
} De lo contrario {
Lanza una nueva IllegalStateException("Se produjo una excepción inesperada durante el análisis"
parseResult.scanFile, throwable);
}
//Eliminar aplicaciones de datos de usuario no válidas
//Si se trata de una apk que no pertenece al sistema, el análisis falla .
if((scan flags amp; SCAN_AS_SYSTEM) == 0. amp
Código de error!= PackageManager. Instalación exitosa) {
logCriticalInfo(Log. Advertencia ,
"Elimine el paquete no válido en "parseResult.scanFile");
//Error en el análisis del paquete fuera del sistema. Elimine el archivo.
removeCodePathLI( analizar resultado . archivo de escaneo);
}
}
}
}
6.3[ParallelPackageParser. java] Enviar
Coloque el APK y otro contenido en la ruta de escaneo en la cola mQueue y asigne parsePackage() a ParseResult para llamadas posteriores.
public void submit(archivo de escaneo de archivos, int parseFlags) {
mservice submit(()- gt; {
resultado del análisis pr = nuevo resultado del análisis. ();
TRACE . TRACE comenzar(TRACE _ TAG _ PACKAGE _ MANAGER, " análisis paralelo PAQUETE[" archivo de escaneo "]"); p>analizador de paquetes PP = nuevo analizador de paquetes();
PP . setseparateprocesses(mSeparateProcesses);
PP setonlycoresses(solo núcleo);
pp. setDisplayMetrics(metric);
PP . setcachedir(mCacheDir);
PP set callback(mPackageParserCallback);
pr . /p>
pr.pkg = parsePackage(pp, scanFile, parse flags);
} catch(throwable e) {
pr . >
p>
}Finalmente {
TRACE . TRACE end(TRACE _ TAG _ PACKAGE _ MANAGER
}
Prueba {
mqueue . put(pr);
} captura (InterruptedException e) {
Thread.currentThread().
// Propagar el resultado a la persona que llama de take()
//Esto ayuda a evitar que el hilo principal se atasque mientras espera
// ParallelPackageParser finaliza al interrumpirse
mInterruptedInThread = hilo. hilo actual().getName();
}
});
}
Analizar apk a través de parsePackage . Si el archivo de paquete entrante es un directorio, llame a parseClusterPackage() para analizarlo.
Si se llama al archivo APK entrante, se llama a parseMonolithicPackage() para su análisis.
Paquete de análisis de paquete público (archivo de paquete de archivos, indicador de número entero, caché de uso booleano)
Lanza PackageParserException {
...
if (packageFile.isDirectory()) {
// Si el packageFile pasado es un directorio, llame a parseClusterPackage() para analizarlo.
parsed = parseClusterPackage(archivo de paquete, banderas);
} De lo contrario {
//Si es un archivo APK, llame a parseMonolithicPackage() para analizarlo.
parsed = parsimonolicipackage(archivo de paquete, banderas);
}
...
Devolver analizado;
}
Echemos un vistazo a la función parseClusterPackage()
: analiza todas las aplicaciones contenidas en un directorio determinado y las procesa como un solo paquete. Esto también puede realizar comprobaciones de cordura, como requerir el mismo nombre de paquete y código de versión, un APK base único y un nombre dividido único.
Primero use parseClusterPackageLite() para analizar el archivo apk en el directorio. La principal diferencia es si es una aplicación principal o no principal. Solo hay una aplicación principal y puede haber varias aplicaciones no principales o ninguna. La función de las aplicaciones no básicas es principalmente ahorrar recursos y código. Luego llame a parseBaseApk en la aplicación principal para analizar y generar el paquete. Las aplicaciones no principales llaman a parseSplitApk y los resultados del análisis se colocan en el objeto del paquete anterior.
El paquete privado parseClusterPackage(archivo packageDir, int flags) lanza PackageParserException {
//Obtiene el objeto PackageLite del directorio de la aplicación, que almacena aplicaciones principales y no El nombre del núcleo solicitud.
final package lite = parseClusterPackageLite(package dir, 0);
//Si no hay una aplicación principal en lite, salga.
if (mOnlyCoreApps amp amp!lite.coreApp) {
lanza una nueva PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_formatted,
"Aplicación no principal: "directorio del paquete);
p>
}
//Generar un árbol de dependencia dividido.
//Construir árbol de dependencias de particiones
SparseArray split dependencies = null;
Final SplitAssetLoader AssetLoader
if(lite. Amplificador de divisiones aisladas ; amp! utilidades de matriz . isempty(lite . nombres divididos)){
prueba {
dividir dependencias = splitassetdependencyloader . cargador de activos = new SplitAssetDependencyLoader(lite, splitDependencies, flags);
} catch(SplitAssetDependencyLoader.
IllegalDependencyException e) {
Lanzar nueva PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST, e.getmessage());
}
} De lo contrario, {
activo loader = new DefaultSplitAssetLoader(lite, flags);
}
Prueba {
administrador de activos final activos = active loader.getbase administrador de activos(); p>
Archivo final baseApk = archivo nuevo (ruta del código base lite);
//Aplicación central de análisis
Paquete final del paquete = parseBaseApk(baseApk, activos, banderas) ;
if (pkg == null) {
Lanzar nueva PackageParserException(INSTALL _ PARSE _ FAILED _ NOT _ APK
No se puede resolver el APK base: " base apk");
}
if (!array utils . isempty(lite . nombres divididos)){
final int num = lite . nombres divididos longitud;
pkg . nombres divididos = lite . nombres divididos;
paquete de rutas de códigos divididos = .
pkg . split flags = new int[num];
pkg . splitprivateflags = new int[num];
pkg información de la aplicación. pkg . nombres divididos;
información de la aplicación pkg . dependencias divididas = dependencias divididas;
información de la aplicación pkg = nueva cadena[núm] for(int I = 0; iltnumi) {
administrador de activos final activos divididos = cargador de activos getsplitassetmanager(I);
>Procesamiento de aplicaciones no principales
.parsplitapk(pkg, I, splitAssets, flags);
}
}
setcodepath(paquete dir. getcanonicalpath());<. /p>
paquete . setuse 32 bitabi(lite . use 32
bitabi);
Devolver paquete
} catch (IOException e) {
Lanzar nueva PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
No se puede obtener la ruta : "lite.baseCodePath,e");
}Finalmente {
iou tils.closequietly(asset loader);
}
}
Veamos nuevamente parseMonolithicPackage(). Su función es analizar un archivo APK determinado y tratarlo como un único paquete de software.
ParseBaseApk() también se llama para realizar el análisis. A continuación, echemos un vistazo a parsebasepk().
El paquete público parseMonolithicPackage(archivo apkFile, int flags) lanza PackageParserException {
paquete final lite = parsimonolicipackagelite(archivo apk, flags
if (monlycrepse); {
Si (!lite.coreApp) {
Lanza una nueva PackageParserException(INSTALL _ PARSE _ FAILED _ MANIFEST _ formateado,
"Aplicación no principal: " apk);
}
}
cargador de activos SplitAssetLoader final = nuevo DefaultSplitAssetLoader(lite, flags);
Pruebe {
//Analizar la aplicación principal
Paquete final pkg = parseBaseApk(apkFile, cargador de activos. getbaseassetmanager(), flags
setcodepath (archivo apk). getcanonicalpath());
pkg . setuse 32 bitabi(lite . use 32 bitabi
devolver paquete
} catch (IOException e ) { p>
Lanza una nueva excepción PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
No se puede obtener la ruta: "apkFile, e");
}Finalmente {
cierre silenciosamente. (cargador de activos);
}
}
ParseBaseApk() analiza principalmente AndroidManifest.xml, toda la información analizada se coloca en el objeto Paquete.
Paquete privado parseBaseApk(archivo apkFile, activo del administrador de activos, indicador int)
Lanza PackageParserException {
Cadena final ruta apk = archivo apk getabsolutepath ();
...
XmlResourceParser parser = null
...
final int cookie = activos findcookieforpath(ruta apk);
if (cookie == 0) {
Lanza una nueva PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
Error al agregar activos Ruta de acceso: "ruta de apk";
}
//Obtenga el objeto de análisis de recursos XML y analice el archivo AndroidManifest.xml del APK
parser = activexmlresourceparser(cookie,ANDROID_MANIFEST_FILENAME);
Recurso final res = nuevo recurso(activo, matriz, vacío);
Cadena final[]out error = nueva Cadena[1 ];
//Llamar al sobrecargado función parseBaseApk() y finalmente obtiene parseBaseApkCommon(). Después de analizar AndroidManifest.xml, obtiene un objeto Paquete
El paquete final pkg = parseBaseApk(apkPath, res, parser, flags, out error ); p>
...
pkg . setvolumeuuid(volumen uuid);
pkg . setapplicationvolumeuuid(volumen uuid);
p>pkg . (ruta de apk);
pkg . establecer detalles de firma (detalles de firma. Desconocido)
Devolver paquete
.. .
}
Obtenga el nombre de la etiqueta de AndroidManifest.xml, analice el contenido de cada elemento de la etiqueta y guárdelo en el objeto Paquete.
Por ejemplo, obtenga la etiqueta "aplicación", "permiso"
Paquete privado parseBaseApkCommon(paquete de paquete, conjunto de etiquetas aceptadas, resolución de recursos,
analizador XmlResourceParser, int flags, String[] outError) arroja XmlPullParserException,
IOException {
matriz escrita sa = RES . obtiene atributos (parser,
com. Android. internal. . r . styleable . Android manifest);
//Obtener el ID de usuario compartido en AndroidManifest.xml generalmente incluye "android.uid.system" y otra información.
string str = sa . getnonconfigurationstring(
com . Android . internal . r . styleable . Android manifest _ ID de usuario compartido,
while (( type = parser.next())! = XmlPullParser. end_document
amp amp(type! = XmlPullParser. END_TAG | >
//Obtener el nombre de la etiqueta de AndroidManifest.xml
string tagName = parser . getname();
// Si la etiqueta leída en AndroidManifest.xml es "aplicación", ejecute el análisis parseBaseApplication().
if(nombre de etiqueta . igual a(TAG _ APLICACIÓN)){
if (aplicación encontrada) {
...
}
foundApp = true
//Analiza la información de la "aplicación" y asígnala al paquete.
if (!parseBaseApplication(pkg, res, parser, flags, outError)) {
Devuelve nulo
}
.. .
//Si la etiqueta es "permiso"
else if(tagname .quals(TAG _ PERMISSION)){
//Analizar "permiso"
if (!parsePermission(pkg, res, parser, outError)) {
Devolver nulo
}
....
}
}
}
}
AndroidManifest.xml se analiza arriba.
Obtendrá información como "Aplicación", "Cobertura", "Permiso", "Uso-Permiso", etc.
Analicemos la “aplicación” e ingresemos a la función parseBaseApplication().
ParseBaseApplication booleano privado (propietario del paquete, resolución de recursos,
analizador XmlResourceParser, indicadores int, String[] outError)
while ((tipo = analizador .next ())!=XmlPullParser.end_document
amp amp(type!= >//Obtiene el contenido de la etiqueta de la subpestaña "Aplicación".
string tagName = parser . getname();
//Si la etiqueta es "actividad"
if(tagname .quals(" actividad "){
//Analiza la información de la actividad y agrega la actividad al objeto del paquete
Actividad a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
//Analiza la información de la actividad y agrega la actividad al objeto del paquete. p>
propietario. hardware base acelerado);
if (a == null) {
mParseError = PackageManager _ PARSE _ FAILED _ MANIFEST _ Mal formado p>
Devuelve falso
}
hasActivityOrder |= (a.order!= 0);
actividades del propietario.
p>} else if(tagname .quals(" receptor "){
//Si la etiqueta es "receptor", obtenga la información del receptor y agregue el objeto Paquete.
Actividad a = parseActivity(propietario, res, analizador, banderas, outError, cachedArgs,
verdadero,
if (a == nulo) {
mParseError = PackageManager. INSTALL_PARSE_FAILED_MANIFEST_MALformed;
Devuelve falso
}
hasReceiverOrder |= (a.order!= 0);
propietario . receptores . add(a);
} else if(tagname .quals(" service ")){
//If etiqueta Si es "servicio", obtenga la información del servicio y agregue el objeto del paquete
Service s = parseService(owner, res, parser, flags, outError, cache dargs
if (s); == nulo) {
mParseError = PackageManager.
INSTALL _ PARSE _ FAILED _ MANIFEST _ Mal formado;
Devuelve falso
}
hasServiceOrder |= (s.order!= 0);
propietario. servicios. agregar;
} else if(nombre de etiqueta. igual ("proveedor"){
//Si la etiqueta es "proveedor", obtenga la información del proveedor. , agregue el objeto del paquete
Provider p = parseProvider(owner, res, parser, flags, outError, cache dargs
if (p == null) {
);mParseError = PackageManager. INSTALL_PARSE_FAILED_MANIFEST_MALformed;
Devuelve falso
}
propietario add(p);
}
...
}
}
Después de que PackageParser escanea el APK, el sistema AndroidManifest.xml en el APK crea un objeto de paquete completo.
El siguiente paso es agregar el paquete al sistema. La función llamada en este momento es otro scanPackageChildLI
6.4[ PackageManagerService.java]scanPackageChildLI()<. /p>
Cuando se inicializa la plataforma, llame a addForInitLI() para agregar el contenido del paquete a la estructura de datos interna
Paquete scanPackageChildLI(paquete analizador. Paquete Paquete,
. final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime,
@Nullable UserHandle usuario)
lanza PackageManagerException {
...
//Escanear padre
PackageParser. paquete escaneado pkg = addForInitLI(pkg, parseFlags,
scanFlags, currentTime, usuario);
//Escanear niños
final int recuento de niños =(pkg . paquetes infantiles! = nulo)? pkg . paquetes secundarios . tamaño():
for(int i = 0; i lt los niños cuentan; i ) {
PackageParser. paquete paquete secundario = pkg paquetes secundarios . get(I);
//Agrega nuevos paquetes a las estructuras de datos internas durante la inicialización de la plataforma.
//Cuando se inicializa la plataforma, agregue el contenido del paquete a la estructura de datos interna.
addForInitLI(subpaquete, indicadores de análisis, indicadores de escaneo,
horaactual, usuario);
}
if((indicadores de escaneo amp ; solo verificación de escaneo) ! = 0) {
return scanPackageChildLI(pkg, parseFlags, scanFlags, currentTime, user);
}
} p >
En addForInitLI(), verifique el paquete de instalación, verifique la firma, actualice el apk y agregue el paquete al sistema.
Parser de paquetes privado. paquete addForInitLI(paquete analizador. paquete paquete,
@ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime
@Nullable UserHandle usuario)
lanza PackageManagerException {
//Determinar si es necesario actualizar las aplicaciones del sistema.
Sincronización (paquete múltiple) {
//Actualizar subaplicaciones
if (isSystemPkgUpdated) {
...< / p>
}
if (isSystemPkgBetter) {
//Actualiza el paquete de instalación en la partición del sistema.
Sincronización (paquete múltiple){
//Eliminar solo las entradas cargadas de la lista de paquetes
m packages remove(pkg settings . name);
}
...
//Crear parámetros de instalación InstallArgs
instalación final args args = createInstallArgsForExisting(
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(configuración de paquete));
args
Sincronización (paquete múltiple) {.
m configuración . enablesystempackagelpw(configuración del paquete . nombre
}
}
//Verificación del paquete de instalación
collectCertificatesLI(configuración de paquete, paquete, forceCollect, omitir verificación
...
try(paquete congelador congelador = congelar paquete(paquete. nombre del paquete,
" scanPackageInternalLI "){
//Si las dos firmas de apk no coinciden, llame al método deletePackageLIF para borrar el archivo apk y sus datos.
deletePackageLIF(pkg. nombre del paquete, nulo, verdadero, nulo, 0, nulo, falso, nulo
}
...
//Actualizar el programa apk del sistema
instalar args args = createInstallArgsForExisting(
pkgSetting.codePathString,
pkgSetting.resourcePathString, getAppDexInstructionSets(configuración del paquete) );
Sincronización (bloqueo mínimo){
args .cleanupresourcesli();
}
}
if (shouldHideSystemApp) {
Sincronización (paquete múltiple){
m configuración .disablesystempackagelpw(pkg. nombre del paquete, verdadero
);}
}
}
Revise todo el proceso de escaneo de APK:
Según la aplicación principal> aplicación del sistema gt otras aplicaciones tienen prioridad Escanee el APK, analice el archivo AndroidManifest.xml y obtenga el contenido de cada etiqueta.
Después de que PackageParser escanea un APK, el sistema ha creado un objeto Paquete completo basado en AndroidManifest.xml en el APK. El siguiente paso es agregar el paquete al sistema.
Error en el análisis de paquetes ajenos al sistema y se están eliminando archivos.