Install applications silently with INSTALL_PACKAGES permission

I am trying to quietly install apk on a system. My application is located in / system / app and the permission "android.permission.INSTALL_PACKAGES" has been successfully granted

However, I cannot find how to use this permission. I tried copying files to / data / app and was unsuccessful. I also tried using this code

Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType( Uri.parse("file:///sdcard/app.apk"), "application/vnd.android.package-archive"); startActivity(intent); 

But this code opens a standard installation dialog. How can I easily install a non root application with android.permission.INSTALL_PACKAGES provided?

PS I am writing an application that will install a lot of apks from a folder into the system at the first start (replace the Installation Wizard). I need to simplify the firmware.

If you think I'm writing a virus: all programs are installed in / data / app. Install_packages permission can only be granted to system level programs located in / system / app or signed with the system key. Thus, the virus cannot get there.

As stated at http://www.mail-archive.com/android-porting@googlegroups.com/msg06281.html , applications can be installed without installation if they have install_packages permission. In addition, you do not need Install_packages permission to install packages not quietly. Plus http://www.androidzoom.com/android_applications/tools/silent-installer_wgqi.html

+82
android install silent
Apr 27 '11 at 12:21
source share
15 answers

Your first bet is to look at the Android native PackageInstaller . I would recommend changing this application the way you like, or simply extracting the required functionality.




In particular, if you look at PackageInstallerActivity and its onClickListener method:

  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(); } } 

Then you will notice that the actual installer is in the InstallAppProgress class. By checking this class, you will find that initView is the main installation, and the last thing it does is call the PackageManager installPackage function:

 public void initView() { ... pm.installPackage(mPackageURI, observer, installFlags, installerPackageName); } 

The next step is to check the PackageManager , which is an abstract class. You will find the installPackage(...) function there. The bad news is that it is marked with @hide. This means that it is not directly accessible (you cannot compile it with a call to this method).

  /** * @hide * .... */ public abstract void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,String installerPackageName); 

But you can access these methods using reflection.

If you are interested in how PackageManager installPackage , see PackageManagerService .

Summary

You need to get the package manager object via Context getPackageManager() . Then you call the installPackage function through reflection.

+59
Apr 27 2018-11-11T00:
source share

I checked how ADB installs applications.
- It copies the APK to / data / local / tmp
- it launches the shell: pm install / data / local / tmp / app.apk '

I tried to reproduce this behavior by doing: (on a PC using a usb cable)
adb push app.apk /sdcard/app.apk
adb shell
$ pm install /sdcard/app.apk
It works. The application is installed.

I made an application (named AppInstall) that should install another application.
(installed normally, not fixed device)
He does:
Runtime.getRuntime().exec("pm install /sdcard/app.apk").waitFor();
But this gives an error:
java.lang.SecurityException: Neither user 10019 nor current process has android.permission.INSTALL_PACKAGES.
It appears that the error is generated by pm, not AppInstall.
Because SecurityException is not caught by AppInstall, and the application does not crash.

I tried the same thing on the root device (same application and AppInstall) and it worked like a charm.
(Also usually installed, not in / system or something else)
AppInstall did not even ask for root permission.
But this is because the shell is always # instead of $ on this device.

By the way, you need to install root to install the application in / system, fix it?
I tried adb remount on an unmanaged device and got:
remount failed: Operation not permitted.
That is why I could not try the / system thing on an undisturbed device.

Conclusion: you must use a rooted device
Hope this helps :)

+11
May 20 '12 at 13:51
source share

You must identify

 <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> 

in your manifest, if you are in the system partition (/ system / app) or you have an application signed by the manufacturer, you will have INSTALL_PACKAGES permission.

My suggestion is to create a small Android project with a compatibility level of 1.5, used to call installPackages via reflection and to export the jar using the package installation methods and calling real methods. Then, by importing the jar into your project, you will be ready to install the packages.

+8
Feb 13 '12 at 11:21
source share

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.

+7
Nov 05 '16 at 16:39
source share

I tried on root Android 4.2.2 and this method works for me:

 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(); } } } 
+5
Feb 20 '14 at 9:44
source share

I had no idea how to do this, because no one answered at this time, and I did not find documentation about this permission. So I found my solution. This is worse than yours, but it is a decision anyway.

I installed busybox, which set the 777 permission to / data / app (I don't care about security). Then just executed busybox install from the application. This works, but has a big security leak. If you set permissions to 777, root is not required.

+4
Jul 19. '11 at 11:25
source share

You can use the hidden android.content.pm.IPackageInstallObserver API by reflection:

 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(); } } } 

Import android.content.pm.IPackageInstallObserver into your project. Your application must be systemic. You must activate the permission android.permission.INSTALL_PACKAGES in the manifest file.

+4
Nov 27 '14 at 13:21
source share

Here is a very good post on this topic. It helped me a lot.

+3
Jul 04 '13 at 18:29
source share

You can simply use the adb install command to install / update the APK. Code example below

 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(); } } } 
+3
Aug 29 '13 at 10:37
source share

I made a test application for silent installation using the PackageManager.installPackage method.

I get the installPackage method through reflection and made the android.content.pm.IPackageInstallObserver interface in my src folder (because it is hidden in the android.content.pm package).

When I run installPackage, I got a SecurityException indicating the line that my application does not have android.permission.INSTALL_PACKAGES, but it is defined in AndroidManifest.xml.

So, I think that using this method is impossible.

PS. I tested on Android SDK 2.3 and 4.0. Perhaps it will work with earlier versions.

0
Feb 13 '13 at 18:48
source share

Try executing LD_LIBRARY_PATH=/vendor/lib:/system/lib before pm install. It works well.

0
Feb 04 '14 at 5:10
source share

A third-party application cannot install an Android application at the same time. However, a third-party application may ask the Android OS to install the application.

So you should define this:

 Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(Uri.parse("file:///sdcard/app.apk", "application/vnd.android.package-archive"); startActivity(intent); 

You can also try installing it as a system application to grant permission and ignore this definition. (Root required)

You can run the following command in a third-party application to install the application on the root device.

The code is:

 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(); } } } 

I hope this answer is helpful to you.

0
Feb 16 '18 at 17:55
source share

You can make a silent installation on Android 6 and above. Using the function provided in the answer of Boris Treuhov, ignore everything else in the post, the root is also not required.

Install your application as a device administrator, you can have a full kiosk mode with automatic installation of updates in the background.

0
Jan 27 '19 at 17:13
source share

Prerequisite:

Your APK must be signed by the system, as previously stated correctly. One way to achieve this is to create the AOSP image yourself and add the source code to the assembly.

The code:

After installation, as a system application, you can use the package manager methods to install and remove the APK as follows:

Installation:

 public boolean install(final String apkPath, final Context context) { Log.d(TAG, "Installing apk at " + apkPath); try { final Uri apkUri = Uri.fromFile(new File(apkPath)); final String installerPackageName = "MyInstaller"; context.getPackageManager().installPackage(apkUri, installObserver, PackageManager.INSTALL_REPLACE_EXISTING, installerPackageName); return true; } catch (Exception e) { e.printStackTrace(); return false; } } 

Removal:

 public boolean uninstall(final String packageName, final Context context) { Log.d(TAG, "Uninstalling package " + packageName); try { context.getPackageManager().deletePackage(packageName, deleteObserver, PackageManager.DELETE_ALL_USERS); return true; } catch (Exception e) { e.printStackTrace(); return false; } } 

To get a call back after your APK is installed / removed, you can use this:

 /** * Callback after a package was installed be it success or failure. */ private class InstallObserver implements IPackageInstallObserver { @Override public void packageInstalled(String packageName, int returnCode) throws RemoteException { if (packageName != null) { Log.d(TAG, "Successfully installed package " + packageName); callback.onAppInstalled(true, packageName); } else { Log.e(TAG, "Failed to install package."); callback.onAppInstalled(false, null); } } @Override public IBinder asBinder() { return null; } } /** * Callback after a package was deleted be it success or failure. */ private class DeleteObserver implements IPackageDeleteObserver { @Override public void packageDeleted(String packageName, int returnCode) throws RemoteException { if (packageName != null) { Log.d(TAG, "Successfully uninstalled package " + packageName); callback.onAppUninstalled(true, packageName); } else { Log.e(TAG, "Failed to uninstall package."); callback.onAppUninstalled(false, null); } } @Override public IBinder asBinder() { return null; } } /** * Callback to give the flow back to the calling class. */ public interface InstallerCallback { void onAppInstalled(final boolean success, final String packageName); void onAppUninstalled(final boolean success, final String packageName); } 

===> Tested on Android 8.1 and worked well.

-one
Jul 26 '18 at 17:06
source share

! / 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 

This works for me. I run this on ubuntu 12.04, on a shell terminal.

-6
Jun 06 '14 at 5:53 on
source share



All Articles