I recently implemented an installation without user consent - this is a kiosk application for API level 21+, where I had full control over the environment.
Primary requirements:
- API Level 21+
- root access to install the update as a privileged application.
The following method reads and installs the APK from an 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; }
The following code causes the installation
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(); }
for all you need, you desperately need INSTALL_PACKAGES permission, or the code above will not work silently
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
To get this permission, you must install the APK as a system application that REQUIRES root (however, AFTER you installed the update application, it works as WITHOUT root)
To install as a system application, I created a signed APK and clicked it
adb push updater.apk /sdcard/updater.apk
and then moved it to system/priv-app , which requires system/priv-app FS (so root is required)
adb shell su mount -o rw,remount /system mv /sdcard/updater.apk /system/priv-app chmod 644 /system/priv-app/updater.apk
for some reason it did not work with a simple version of debugging, but logcat shows useful information if your application in priv-app not picked up for some reason.