android - seguridad - Instala aplicaciones de forma silenciosa, con permiso concedido de INSTALL_PACKAGES
permisos para desarrollar en android (13)
! / bin / bash
f=/home/cox/myapp.apk #or $1 if input from terminal.
#backup env var
backup=$LD_LIBRARY_PATH
LD_LIBRARY_PATH=/vendor/lib:/system/lib
myTemp=/sdcard/temp.apk
adb push $f $myTemp
adb shell pm install -r $myTemp
#restore env var
LD_LIBRARY_PATH=$backup
Esto funciona para mí Ejecuto esto en ubuntu 12.04, en el shell terminal.
Intento instalar silenciosamente apk en el sistema. Mi aplicación se encuentra en / system / app y se le otorgó permiso con éxito "android.permission.INSTALL_PACKAGES"
Sin embargo, no puedo encontrar en ninguna parte cómo usar este permiso. Intenté copiar archivos en / data / app y no tuve éxito. También traté de usar este código
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.parse("file:///sdcard/app.apk"),
"application/vnd.android.package-archive");
startActivity(intent);
Pero este código abre el diálogo de instalación estándar. ¿Cómo puedo instalar la aplicación de forma silenciosa sin root con android.permission.INSTALL_PACKAGES
?
PD. Estoy escribiendo una aplicación que instalará muchos archivos de la carpeta en el sistema el primer inicio (reemplace el Asistente de configuración). Lo necesito para hacer el firmware más ligero.
Si crees que estoy escribiendo un virus: Todos los programas están instalados en / data / app. Permiso Los paquetes de instalación solo se pueden otorgar a programas de nivel de sistema ubicados en / system / app o firmados con la clave del sistema. Entonces el virus no puede llegar allí.
Como se dijo, las aplicaciones http://www.mail-archive.com/[email protected]/msg06281.html pueden instalarse silenciosamente si tienen el permiso install_packages. Además, no necesita el permiso Install_packages para instalar paquetes de forma no silenciosa. Además, http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html
Debes definir
<uses-permission
android:name="android.permission.INSTALL_PACKAGES" />
en su manifiesto, si está en la partición del sistema (/ sistema / aplicación) o si su aplicación está firmada por el fabricante, tendrá el permiso INSTALL_PACKAGES.
Mi sugerencia es crear un pequeño proyecto de Android con un nivel de compatibilidad de 1.5 utilizado para llamar a los paquetes de instalación a través de la reflexión y para exportar un archivo jar con métodos para instalar paquetes y llamar a los métodos reales. Luego, al importar el jar en su proyecto, estará listo para instalar paquetes.
He comprobado cómo ADB instala aplicaciones.
- Copia la APK a / data / local / tmp
- ejecuta ''shell: pm install /data/local/tmp/app.apk''
He tratado de replicar este comportamiento haciendo: (en la PC, usando un cable usb)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
Esto funciona. La aplicación está instalada.
Hice una aplicación (llamada AppInstall) que debería instalar la otra aplicación.
(instalado normalmente, dispositivo no rooteado)
Lo hace:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
Pero esto da el error:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
Parece que el error lo genera pm, no AppInstall.
Debido a que SecurityException no es atrapado por AppInstall y la aplicación no falla.
Intenté lo mismo en un dispositivo rooteado (la misma aplicación y AppInstall) y funcionó a las mil maravillas.
(También normalmente instalado, no en / sistema ni nada)
AppInstall ni siquiera pidió permiso de root.
Pero eso es porque el shell siempre es #
lugar de $
en ese dispositivo.
Por cierto, necesitas root para instalar una aplicación en / system, ¿correcto?
Probé el remontaje de adb en el dispositivo no rooteado y obtuve:
remount failed: Operation not permitted.
Es por eso que no pude probar el elemento / system en el dispositivo no rooteado.
Conclusión: debes usar un dispositivo rooteado
Espero que esto ayude :)
He estado implementando la instalación sin el consentimiento del usuario recientemente: era una aplicación de kiosco para API nivel 21+ donde tenía control total sobre el medio ambiente.
Los requisitos básicos son
- Nivel de API 21+
- acceso raíz para instalar el actualizador como una aplicación privilegiada del sistema.
El siguiente método lee e instala APK desde InputStream:
public static boolean installPackage(Context context, InputStream in, String packageName)
throws IOException {
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
params.setAppPackageName(packageName);
// set params
int sessionId = packageInstaller.createSession(params);
PackageInstaller.Session session = packageInstaller.openSession(sessionId);
OutputStream out = session.openWrite("COSU", 0, -1);
byte[] buffer = new byte[65536];
int c;
while ((c = in.read(buffer)) != -1) {
out.write(buffer, 0, c);
}
session.fsync(out);
in.close();
out.close();
Intent intent = new Intent(context, MainActivity.class);
intent.putExtra("info", "somedata"); // for extra data if needed..
Random generator = new Random();
PendingIntent i = PendingIntent.getActivity(context, generator.nextInt(), intent,PendingIntent.FLAG_UPDATE_CURRENT);
session.commit(i.getIntentSender());
return true;
}
El siguiente código llama a la instalación
try {
InputStream is = getResources().openRawResource(R.raw.someapk_source);
installPackage(MainActivity.this, is, "com.example.apk");
} catch (IOException e) {
Toast.makeText(MainActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
para que todo funcione, necesita desesperadamente el permiso INSTALL_PACKAGES
, o el código anterior fallará silenciosamente
<uses-permission
android:name="android.permission.INSTALL_PACKAGES" />
para obtener este permiso, debe instalar su APK como aplicación del Sistema que REQUIERE la raíz (sin embargo DESPUÉS de que haya instalado su aplicación de actualización, parece que funciona SIN raíz)
Para instalar como aplicación del sistema, creé una APK firmada y la empujé con
adb push updater.apk /sdcard/updater.apk
y luego lo movió a system/priv-app
, que requiere volver a montar FS (esta es la razón por la cual se requiere la raíz)
adb shell
su
mount -o rw,remount /system
mv /sdcard/updater.apk /system/priv-app
chmod 644 /system/priv-app/updater.apk
por alguna razón, no funcionó con la versión de depuración simple, pero Logcat muestra información útil si su aplicación en priv-app
no se recoge por alguna razón.
Hice una aplicación de prueba para instalaciones silenciosas, usando el método PackageManager.installPackage.
Obtengo el método installPackage a través de la reflexión, y realizo la interfaz android.content.pm.IPackageInstallObserver en mi carpeta src (porque está oculta en el paquete android.content.pm).
Cuando ejecuto installPackage, recibo SecurityException con indicación de cadena, que mi aplicación no tiene android.permission.INSTALL_PACKAGES, pero se definió en AndroidManifest.xml.
Entonces, creo, no es posible usar este método.
PD. Probé en Android SDK 2.3 y 4.0. Tal vez funcionará con versiones anteriores.
Intenté Android rooteado 4.2.2 y este método funciona para mí:
private void installApk(String filename) {
File file = new File(filename);
if(file.exists()){
try {
final String command = "pm install -r " + file.getAbsolutePath();
Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
proc.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
}
No tenía idea de cómo hacer esto, porque nadie respondió esa vez, y no encontré documentación sobre este permiso. Entonces encontré mi propia solución. Es peor que el tuyo, pero esta es una solución de todos modos.
Instalé busybox, que establece el permiso 777 para / data / app (no me importa la seguridad). Luego, acaba de ejecutar "busybox install" desde la aplicación. Esto funciona, pero tiene una gran fuga de seguridad. Si establece permisos 777, no se requiere una raíz.
Pruebe este LD_LIBRARY_PATH=/vendor/lib:/system/lib
antes de la instalación pm. Funciona bien.
Puede usar la API oculta android.content.pm.IPackageInstallObserver
por reflexión:
public class PackageManagement {
public static final int INSTALL_REPLACE_EXISTING = 0x00000002;
public static final int INSTALL_SUCCEEDED = 1;
private static Method installPackageMethod;
private static Method deletePackageMethod;
static {
try {
installPackageMethod = PackageManager.class.getMethod("installPackage", Uri.class, IPackageInstallObserver.class, Integer.TYPE, String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void installPackage(PackageManager pm, Uri mPackageUri, IPackageInstallObserver observer, int installFlags, String installerPackageName) {
try {
installPackageMethod.invoke(pm, mPackageUri, observer, installFlags, installerPackageName);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Importe android.content.pm.IPackageInstallObserver
a su proyecto. Tu aplicación debe ser un sistema. Debes activar el permiso android.permission.INSTALL_PACKAGES
en tu archivo de manifiesto.
Simplemente puede usar el comando de instalación de adb para instalar / actualizar el APK de forma silenciosa. El código de muestra está debajo
public static void InstallAPK(String filename){
File file = new File(filename);
if(file.exists()){
try {
String command;
filename = StringUtil.insertEscape(filename);
command = "adb install -r " + filename;
Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
proc.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Su primera apuesta es mirar el PackageInstaller nativo de Android. Recomendaría modificar esa aplicación de la manera que desee, o simplemente extraer la funcionalidad requerida.
Específicamente, si observa PackageInstaller y su método onClickListener
:
public void onClick(View v) {
if(v == mOk) {
// Start subactivity to actually install the application
Intent newIntent = new Intent();
...
newIntent.setClass(this, InstallAppProgress.class);
...
startActivity(newIntent);
finish();
} else if(v == mCancel) {
// Cancel and finish
finish();
}
}
Entonces notará que el instalador real está ubicado en la clase InstallAppProgress . Al inspeccionar esa clase, encontrará que initView
es la función de instalador principal, y lo último que hace es llamar a la función installPackage
PackageManager
:
public void initView() {
...
pm.installPackage(mPackageURI, observer, installFlags, installerPackageName);
}
El siguiente paso es inspeccionar PackageManager , que es una clase abstracta. Encontrará la función installPackage(...)
allí. La mala noticia es que está marcado con @hide. Esto significa que no está disponible directamente (no podrá compilar con una llamada a este método).
/**
* @hide
* ....
*/
public abstract void installPackage(Uri packageURI,
IPackageInstallObserver observer,
int flags,String installerPackageName);
Pero podrá acceder a estos métodos a través de la reflexión.
Si está interesado en cómo se implementa la función installPackage
PackageManager
, eche un vistazo a PackageManagerService .
Resumen
Deberá obtener el objeto del gestor de paquetes a través de getPackageManager()
Context
. Luego llamará a la función installPackage
través de la reflexión.
Una aplicación de un tercero no puede instalar una aplicación de Android sliently. Sin embargo, una aplicación de un tercero puede solicitar al sistema operativo Android que instale una aplicación.
Entonces deberías definir esto:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file:///sdcard/app.apk", "application/vnd.android.package-archive");
startActivity(intent);
También puede intentar instalarlo como una aplicación de sistema para otorgar el permiso e ignorar esta definición. (Raiz necesario)
Puede ejecutar el siguiente comando en su aplicación de terceros para instalar una aplicación en el dispositivo rooteado.
El código es:
private void installApk(String filename) {
File file = new File(filename);
if(file.exists()){
try {
final String command = "pm install -r " + file.getAbsolutePath();
Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", command });
proc.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Espero que esta respuesta sea útil para ti.
Here hay una muy buena publicación sobre este tema. Me ayudó mucho.