Directorio de artículos
fondo
El desarrollo de aplicaciones basadas en un sistema de tableta personalizado puede obtener el soporte de la capa de código fuente de Android.
Sistema Android8.1.
Objetivo
- De forma predeterminada, se obtienen todos los permisos necesarios y no se solicita autorización en ninguna ventana emergente.
- Una actualización silenciosa instala una nueva versión.
lograr
Obtener permisos de aplicación del sistema
A través de sharedUserId
esta configuración, el proceso de aplicación actual se configura como un proceso de aplicación del sistema y se pueden obtener todos los permisos.
principio
A través de la identificación de usuario compartida, se pueden configurar múltiples APK con la misma identificación de usuario para que se ejecuten en el mismo proceso, por lo que, de forma predeterminada, pueden acceder a cualquier información entre sí y, al mismo tiempo, pueden acceder a bases de datos y archivos en el directorio de datos. de otros APK, al igual que acceder a los datos de este programa es lo mismo.
Para evitar que otras aplicaciones obtengan el ID de usuario compartido y abusen de él, el sistema Android restringe que el mismo ID de usuario debe usar la misma firma para instalarse en el mismo dispositivo. Por lo tanto, si desea configurarlo como un proceso compartido del sistema, debe ser coherente con la firma de la aplicación del sistema.
La lógica para que el sistema firme la aplicación:
build/target/product/security
Hay cuatro conjuntos de firmas predeterminadas en el directorio del código fuente del sistema Android.mk
para usar en la compilación del APK, que LOCAL_CERTIFICATE
se implementan especificando campos, que son:
testkey
: APK normal, usado por defecto.platform
: El APK completa algunas funciones básicas del sistema. Luego de la prueba de acceso a las carpetas existentes en el sistema, el UID del proceso donde se compila el APK de esta forma es sistema.shared
: El APK necesita compartir datos con el proceso de inicio/contactos.media
: El APK es parte del sistema de medios/descargas
Es utilizado por aplicaciones ordinarias.Si testkey
es una aplicación del sistema, se puede especificar como platform
.
El principio y la introducción se refieren a este artículo : Mecanismo de permisos de Android: mecanismo de "caja de arena" sharedUserId y firma
lograr
Consulte este artículo para implementar : Firma del sistema Android apk
1. Requisito previo:
la firma de la aplicación no puede ser una firma personalizada, pero debe ser una firma del sistema. El proveedor del sistema debe proporcionar el archivo de firma, incluidos varios archivos, como platform.pk8
, platform.x509.pem
, signapk.jar
etc.. Si no se puede proporcionar este paso, no sharedUserId
hay solución a través de la configuración.
2. ConfigurarsharedUserId
el aumento de nodos
en :AndroidManifest.xml
manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.moore.systemapk"
android:sharedUserId="android.uid.system">
</manifest>
3.
Método de firma 1:
en la capa de código fuente del sistema, configure la aplicación como Android.mk
el tipo de aplicación del sistema entre los cuatro tipos predeterminados en el principio correspondienteLOCAL_CERTIFICATE
platform
Método 2:
cree el paquete apk sin firmar y firme la aplicación a través del método de comando.
java -jar signapk.jar platform.x509.pem platform.pk8 unsigned.apk signed.apk
Reemplace su nombre y ruta de apk unsigned.apk
con signed.apk
la ruta de salida.
Método 3:
según el archivo de firma proporcionado por el sistema, genere un archivo jks o keystone, que se puede empaquetar y firmar directamente en el AS sin firma adicional.
- generar
shared.priv.pem
archivo
openssl pkcs8 -in platform.pk8 -inform DER -outform PEM -out shared.priv.pem -nocrypt
- generar
shared.pk12
archivo
openssl pkcs12 -export -in platform.x509.pem -inkey shared.priv.pem -out shared.pk12 -name moore
- generar
jks
okeystone
archivar
keytool -importkeystore -deststorepass android -destkeypass android -destkeystore moore.jks -srckeystore shared.pk12 -srcstoretype PKCS12 -srcstorepass android -alias moore
Después de la generación, se puede configurar en gradle, o elegir la ruta donde se encuentra la firma al empaquetar
4. Problemas
En el proceso de operación real, si usa el método de comando para firmar, existe una alta probabilidad no conscrypt_openjdk_jni in java.library.path:
de errores. Obtenga el proporcionado por el fabricante libconscrypt_openjdk_jni.so
, vuelva a firmar e informe otro error: FATAL ERROR in native method: RegisterNatives failed for 'org/conscrypt/NativeCrypto'
intente cambiar la computadora o system (windows, mac, linux) No hay solución Es normal que la computadora del lado del fabricante ejecute el comando, así que me rendí y lo ejecuté generando una firma jks.
5. Instalación
Dado que se ha cambiado la firma, si la aplicación está instalada en el dispositivo donde se instaló originalmente, debe desinstalarse antes. El mismo nombre de paquete tiene una firma diferente, y la instalación obviamente no se realizó correctamente.
instalación silenciosa
La aplicación realiza la función de actualización automática y existen varios métodos de instalación:
- Llame al instalador del sistema y pase la ruta apk (se requiere autorización para permitir la instalación de aplicaciones)
- Ejecute el comando de shell para instalar silenciosamente apk (requiere autoridad de root)
- Use
PackageInstaller
el código para instalar, simule el proceso de instalación del sistema (debe ser una aplicación del sistema)
Instalación de actualización normal
En primer lugar, la página de instalación aparecerá de esta manera, lo que no satisface nuestras necesidades, pero se encontraron algunos problemas durante el proceso de instalación, por lo que los enumeraremos para futuras referencias.
1. Método
Después de descargar el apk del paquete de actualización, use directamente Intent para invocar la intención de instalación del sistema. Cabe señalar que se requiere personalización para las versiones superiores a la 8.0 FileProvider
, de lo contrario, no se puede obtener la ruta y se generará una excepción FileUriExposedException
.
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri fileUri = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
//自定义的FileProvider,需要在清单文件中声明
String authority = XUpdate.getContext().getPackageName() + ".updateFileProvider";
fileUri = FileProvider.getUriForFile(XUpdate.getContext(), authority, file);
} else {
fileUri = Uri.fromFile(file);
}
intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
context.startActivity(intent)
2. Problema
Aquí viene el problema, de acuerdo con el proceso de aplicación normal, este método no es un problema, todo es normal, pero nuestra aplicación se ha configurado ** android:sharedUserId="android.uid.system"
**, es un poco problemático.
Al iniciar la instalación, se informa un error: hubo un problema al analizar el paquete
He confirmado que no hay ningún problema con el paquete de instalación descargado. La instalación se puede iniciar a través de la administración de archivos y otras aplicaciones, y se puede instalar normalmente después de eliminar el systemUid. El problema es el sharedUserId.
Motivo:
Al rastrear el programa fuente del proceso de instalación del sistema, se encontró el siguiente código:
final int callingAppId = UserHandle.getAppId(callingUid);
if ((callingAppId == SYSTEM_UID) || (callingAppId == ROOT_UID)) {
if ("com.android.settings.files".equals(grantUri.uri.getAuthority())) {
// Exempted authority for cropping user photos in Settings app
} else {
Slog.w(TAG, "For security reasons, the system cannot issue a Uri permission"
+ " grant to " + grantUri + "; use startActivityAsCaller() instead");
return -1;
}
}
ok, para solucionar el caso, porque somos una aplicación configurada en SystemUid, pero nuestro proveedor no lo es com.android.settings.files
, por lo que directamente está bloqueado return -1
, y com.android.settings.files
este proveedor está definido en la aplicación del sistema de Configuración, es decir, solo la aplicación SystemUid de Configuración can Invoca el proceso de instalación normal.
solución:
- No podemos cambiar el nuestro al
android:authorities
disponible arribacom.android.settings.files
, porque este es el único valor en todo el sistema, y no se puede instalar en el dispositivo si se cambia al mismo valor. empeñar. - Elimine systemUid, se puede instalar normalmente, si puede eliminarlo, no se molestará en estudiarlo. empeñar.
- ¡Modifica el código fuente! En el juicio anterior, agregue una condición o, agregue la nuestra
authorities
, pero si desea modificar el código fuente, puede usarlo condicionalmente
Para obtener un análisis detallado de este problema, consulte el artículo : La llamada de aplicación de Android android.uid.system no puede instalar apk
instalación de comandos de shell
Como sugiere el nombre, se instala directamente ingresando comandos para ejecutar. Todos sabemos que el kernel de Android es Linux, por lo que el principio es usar la cuenta raíz para comandar directamente la instalación.
Primero debe determinar si tiene privilegios de root:
public static boolean isDeviceRooted() {
String su = "su";
String[] locations = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/",
"/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/"};
for (String location : locations) {
if (new File(location + su).exists()) {
return true;
}
}
return false;
}
Si tiene permiso, el comando de empalme filePath
es la ruta apk
String command = "pm install -i " + packageName + " --user 0 " + filePath;
Luego ejecute el comando a través del método de ShellUtils .execCommand
Si tiene permiso de root, este método es factible y no habrá interfaz, pero los dispositivos que lanzamos al mundo exterior no abrirán el permiso de root, por lo que este método solo se puede usar durante el desarrollo y las pruebas, y no se puede operar en línea. .
Simular el flujo del instalador del sistema
Antes de la introducción, puede consultar estos dos artículos para comprender el proceso de la aplicación de instalación del sistema y la lógica del código
Mecanismo de administración de paquetes de Android (1) Inicialización de PackageInstaller
Mecanismo de administración de paquetes de Android (2) APK de instalación de PackageInstaller
Lo que tenemos que hacer es analizar y llamar a la página de instalación del sistema, qué operaciones hace la capa lógica después de hacer clic en instalar, y luego implementar este proceso directamente en nuestra aplicación.
flujo general
- Defina una devolución de llamada de escucha para recibir notificaciones sobre el inicio, el progreso y el final de la instalación
- Obtenga el objeto de
PackageManager
GetPackageInstaller
, obtenga el archivo apk Objeto de archivo - Cree una sesión de instalación
Session
y obtenga la identificación de la sesión - Lea el archivo apk y escriba el archivo como una secuencia
session
- Cree uno
PendingIntent
para invocar la lógica de instalación de PMS - Confirme esta sesión e ingrese a la instalación de PMS
Introducción a la instalación de PMS:
- Después de recibir la confirmación de la sesión, se ensamblará en un
PackageInstallObserverAdapter
objeto,Handler
que será procesado por PMS enviando el mensajePackageManagerService
La lógica de instalaciónPMSHandler
estáIMediaContainerService
relacionada con varias clases.PMSHandler
Procese la lógica de los mensajes de vinculación, los nuevos mensajes de instalación, etc. Solo cuando la vinculación se realiza correctamente se puede realizar la siguiente operación de instalación.- Vincule el servicio a través de la carpeta, analice y copie el apk (operación que consume mucho tiempo, abra un nuevo proceso de servicio en el sistema Android)
InstallParams
YInstallArgs
operaciones específicas como inspección previa a la instalación, confirmación del lugar de instalación, copiar y mover, etc.- Una vez que la instalación es exitosa, se distribuye un mensaje a través del PMS para notificar al usuario de la aplicación, actualizar la configuración y preparar los datos para la aplicación recién instalada. Si la instalación falla, el apk se eliminará.
- desconectar la carpeta
Artículo de referencia: : Mecanismo de administración de paquetes de Android (3) PMS maneja la instalación de APK
clave
int count;
int sessionId;
byte[] buffer = new byte[65536];
InputStream inputStream;
OutputStream outputStream;
//拿到apkFile,拿到packageInstaller对象
File apkFile = new File(apkFilePath);
long apkFileLength = apkFile.length();
PackageManager pm = context.getPackageManager();
PackageInstaller packageInstaller = pm.getPackageInstaller();
packageInstaller.registerSessionCallback(忽略回调实现);
//创建会话
PackageInstaller.Session session = null;
PackageInstaller.SessionParams sessionParams;
try {
sessionParams = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
sessionId = packageInstaller.createSession(sessionParams);
session = packageInstaller.openSession(sessionId);
inputStream = new FileInputStream(apkFile);
outputStream = session.openWrite(apkName, 0, apkFileLength);
//写入
while ((count = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, count);
float progress = ((float) count / (float) apkFileLength);
session.setStagingProgress(progress);
}
session.fsync(outputStream);
inputStream.close();
outputStream.flush();
outputStream.close();
//创建PendingIntent
Intent intent = new Intent();
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
//绑定并提交
session.commit(pendingIntent.getIntentSender());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (session != null) {
session.abandon();
}
}
En este punto, la instalación silenciosa se puede realizar, pero todavía hay un problema. Normalmente, nuestra actualización del sistema necesita reiniciar la aplicación después de que se complete la actualización. Sin embargo, debido a que nuestra aplicación se elimina durante el proceso de instalación, por lo tanto, la devolución de llamada configurado al crear la sesión no puede recibir la devolución de llamada para completar la instalación. !
La instalación está completa y reinicia.
Idea:
al comienzo de la instalación, cree una tarea de AlarmManager y vuelva a abrir la aplicación después de 10 segundos (dependiendo del tamaño del apk).
Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
PendingIntent restartIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT);
AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 6.0及以上
mgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 10000, restartIntent);
}
De esta manera, se puede lograr una instalación silenciosa y la aplicación se reiniciará una vez que se complete la instalación.