Home > Android > How to install an application in background on Android

How to install an application in background on Android

First of all:

1 – This technique is only useful if you are building an application for a specific device that you have its certificate (ROM’s certificate) or if your device is rooted.
2 – Doing this technique you will access classes that the Google doesn’t guarantee its portability for future versions;
3 – This post has been written at the moment Android was 2.2, but other people have proved it still works for 4.4;
4 – Add the correct permission in your AndroidManifest.xml.

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

A video have been added to Youtube to showcase the feature working:

I also recommend you read the previous post.

Let’s get started. Today I’ll tell my story of how digged into Android’s code to figure out how install APKs in background without any user interaction. At the moment I’m writing this post there were no other source talking about this on the web (at least I haven’t been able to find any useful help Googling it). Beyond that, reading this post you can learn a little more about how the Android framework works.

I needed this solution so much because in my case the app is a private app where the user can’t get out the app and can’t use other APKs or any other activity from Android. Besides that, the update is mandatory. The user can’t choose for not update the app or cancel the installation (option that is given if you send the user to the default screen installation). As I said, a case where the update should happen and is mandatory, the user liking it or not.

So let’s begin where I began. First of all, I wondered how the Android System does to uninstall applications. You can see it in [Settings -> Applications -> Manage applications -> “choose any app” -> “click in Uninstall”]. I digged into Android’s code and searched for the source code of this activity. There is a text “Uninstall application?”, then I searched for this string:

find . -name *.xml | xargs grep Uninstall application

./packages/apps/PackageInstaller/res/values/strings.xml:
<string name="uninstall_application_question">Uninstall application?</string>

I found the string with the name “uninstall_application_question”. So I searched for the activity that uses that:

find . -name *.java | xargs grep uninstall_application_question

./packages/apps/PackageInstaller/src/com/android/
packageinstaller/UninstallerActivity.java:
question.setText(R.string.uninstall_application_question);

I found UninstallerActivity.java. In UninstallerActivity class there is a button “mOk” that sends you to UninstallAppProgress.java. In this class we see PackageDeleteObserver that removes the application. It extends android.content.pm.IPackageDeleteObserver. Let’s search for this class:

find . -name IPackageDeleteObserver.java

./out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/
src/core/java/android/content/pm/IPackageDeleteObserver.java

In this package we also have IPackageInstallObserver.java. In this class we see:

/**
 * API for installation callbacks from the Package Manager.
 * @hide
 */

Looks like we found what we want, although it is not possible to import this class. It throws an error saying that it doesn’t exist in android.jar. Bad news, Android system have access to it and we don’t. But, have you read my previous post where I say how Google removes access from its Android’s framework? They have this @hide annotation on the methods and classes that should not be exposed to us developers.

Here is the trick: even though theses classes and method are not in android.jar, we still can access those through reflection since they are loaded into the JVM. Taaa-Daaa!

Android.jar is basically our interface and the proper and safe way to talk with the SO, but it doesn’t mean that the other stuffs that we can’t access through this jar is not there. Android.jar is meant anyway just to compile our app. It doesn’t even have any code, only classes and methods signatures. Android.jar is a stub! In run time android.jar is not used and is replaced somehow with the real code. It is logical, all applications on device share the same Android framework, so those classes that I digged for, are already loaded and running on the device even before the app starts. That means: you can access any of those framework’s class through reflection.

So finally let’s to write the code to install the app skipping android.jar API. First, download my code and find the code bellow:

final ApplicationManager am = new ApplicationManager(InstallInBackgroundSample.this);
am.setOnInstalledPackaged(new OnInstalledPackaged() {

	public void packageInstalled(String packageName, int returnCode) {
		if (returnCode == ApplicationManager.INSTALL_SUCCEEDED) {
			Log.d(TAG, "Install succeeded");
		} else {
			Log.d(TAG, "Install failed: " + returnCode);
		}
	}
});

...

Button btnInstall = (Button) findViewById(R.id.btnInstall);
btnInstall.setOnClickListener(new OnClickListener() {

	@Override
	public void onClick(View arg0) {

		try {
			am.installPackage(txtApkFilePath.getText().toString());
		} catch (Exception e) {
			logError(e);
		}
	}
});

Check ApplicationManager.java:

public void installPackage(Uri apkFile) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
	method.invoke(pm, new Object[] {apkFile, observer, INSTALL_REPLACE_EXISTING, null});
}

As you can see, I invoked the method through reflection:

public ApplicationManager(Context context) throws SecurityException, NoSuchMethodException {

    observer = new PackageInstallObserver();
    pm = context.getPackageManager();

    Class<?>[] types = new Class[] {Uri.class, IPackageInstallObserver.class, int.class, String.class};
	method = pm.getClass().getMethod("installPackage", types);
}

To determine whether the app is installed successfully, we need to create a class to implement the callback “packageInstalled”. We must pass an observer in the parameter of the method “installPackage”. Thus we need to extend IPackageInstallObserver.Stub to obtain the result:

class PackageInstallObserver extends IPackageInstallObserver.Stub {

	public void packageInstalled(String packageName, int returnCode) throws RemoteException {
		if (onInstalledPackaged != null) {
			onInstalledPackaged.packageInstalled(packageName, returnCode);
		}
	}
}

IPackageInstallObserver class is @hide in SDK as the other ones. The problem here is that how to extend a class using reflection? Well, I still don’t have the answer, but I do have a workaround to solve this.

We know that IPackageInstallObserver class is already loaded in the VM, so how about we create our own stub? The class exists there, so make a copy of it. Copy the class with the same same package structure and the method signatures, all stubbed out, such as android.jar does. So now you can normally compile your app. In run time, Android will ensure that the original class will be used, not yours stubbed class ;).

That’s it. I hope this has helped you. If you use this code sample and improve it, please consider making a contribution making a pull request. 🙂

The complete source code is in Github here

Thanks! 🙂

Advertisements
  1. mouna
    6 de July de 2011 at 08:05

    hi,
    I try use your project code without modify but i found an error:
    “java.lang.reflect.InvocationTargetException……….”

    • 13 de February de 2013 at 15:54

      I got the same exception. And SecurityException as cause, with string indication, that app has no android.permission.INSTALL_PACKAGES permission.

      I tested in on SDK 2.3 and 4.0.

      So, this method works only on earlier versions.

  2. 7 de July de 2011 at 00:33

    Hi! I tested it again in a device with Android 2.2 and also in the emulator with Android 2.2 and it works fine! I decided to test it in a device with Android 2.3.4 and I got the same error as you, so I think that it may have been blocked by Google, but I not sure, this is my conclusion for now. Please test the application in an emulator with the 2.2 version and see if works and let me know about that. Thanks for your feedback!

  3. mouna
    7 de July de 2011 at 04:45

    Hi
    I tested it in emulator 2.2 but i have the same error 😦
    I used the project code provided by this link: ” https://github.com/paulononaka/Android-InstallInBackgroundSample“.

  4. ashish
    10 de July de 2011 at 12:13

    Hi
    I am downloading apk file from remote server, i am storing it in SD card, and trying to install it using your code but i am getting protection level 3 exception, can you please help where should i keep my apk file , so your code will execute without any exception
    Please help.

  5. 10 de July de 2011 at 13:22

    Hi guys, I found the problem and unfortunately my news is not good. I discovered that this technique only works for me because I use the security certificate of the simulator (the same certificate used by my device in my case). I researched and saw that there are two ways to use the API hidden:

    – Put your application pre-installed into a system folder on the ROM
    – Compile your application using the manufacturer’s security certificate

    So this will just be useful for you if you will make an application to a specific device and you have the certificate of it, just like me. I apologize for not notifying it before, but I did not know that. I’ll update my post and I’ll warn about it at first. Thank you for the feedback.

  6. Alexandre
    27 de July de 2011 at 01:34

    Paulo,

    Ótimo post, mas tive um problema diferente.

    07-27 01:00:05.404: ERROR/AndroidRuntime(18551): FATAL EXCEPTION: main
    07-27 01:00:05.404: ERROR/AndroidRuntime(18551): java.lang.NoClassDefFoundError: com.paulononaka.apihelper.ApplicationManager$PackageInstallObserver
    07-27 01:00:05.404: ERROR/AndroidRuntime(18551): at com.paulononaka.apihelper.ApplicationManager.(ApplicationManager.java:36)
    07-27 01:00:05.404: ERROR/AndroidRuntime(18551): at com.paulononaka.InstallInBackgroundSample.onCreate(InstallInBackgroundSample.java:28)
    07-27 01:00:05.404: ERROR/AndroidRuntime(18551): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)

    Tem alguma ideia do que pode ser??

    Estou fazendo um atualizador e o seu código é exatamente o que eu preciso. Como é um app privado, numa versão fixa do android e ele vai bloquear todos os acessos ao SO, não preciso me preocupar tanto, posso usar o certificado que vc falou, mas tenho um porém. Como fazer isso? vc tem alguma dica ou link pra me ajudar???

    Parabéns pelo post e pelo blog!!

    Abraços!

  7. 27 de July de 2011 at 02:49

    Opa, então vamos descobrir o teu problema! Algumas perguntas:

    – Você está usando qual versão do Android?
    – Experimentou no simulador? Fiz o vídeo acima no simulador com Android 2.2.
    – Você manteve a classe IPackageInstallObserver dentro do pacote android.content.pm?

    Quanto ao certificado, eu ainda vou escrever um post sobre como gerá-lo, mas por enquanto você pode baixar ele aqui: http://goo.gl/Onpfs

    Você deve escolher esse certificado no momento de exportar a sua APK. A senha é “android”. Ambos os alias (plataform ou androiddebugkey) irão funcionar. Mas se você gostaria de assinar a sua apk com esse certificado em momento de debug, você precisa inseri-lo no Eclipse em [Window > Preferences > Android > Build > Custom debug keystore]. Nesse segundo caso, lembre-se de dar clean no projeto antes de rodar para que ele possa ser compilado e assinado com o novo certificado.

  8. Alexandre
    28 de July de 2011 at 00:25

    Paulo,

    Funcionou perfeito!!!! Está de parabéns!!! Você é O CARA!!

    Continue assim!!

    Abraços!!

  9. johann l. loureiro gomig
    28 de July de 2011 at 16:23

    ola paulo, mt joia essa sua aplicaçao.
    Vc que ja tem uma experiencia com aplicaçoes em background, eu precisava de uma aplicaçao que pegasse os dados de gps, e mandasse para um servidor, registrando de tempos em tempos, ate ai td bem, o problema é que eu preciso que ela seja totalmente em background, sem nenhuma interface grafica, eu tentei tornar ela um service, mas ai nao consigo enviar os dados de forma algum, nem por clientehttp. nem por socket, vc tem alguma luz pra me dar. vlw

  10. johann l. loureiro gomig
    29 de July de 2011 at 14:26

    opa paulo, ja implementei e funcionou perfeitamente. É pra conectar em um servlet que eu tenho pronto aqui, vou tentar fazer as adaptaçoes nessessarias pra isso.

    Brigadao cara, salvo minha vida 😛

    • 29 de July de 2011 at 14:35

      😀

      • mouna
        6 de March de 2012 at 14:13

        Hi,
        can you publish the source code of your project after the corrections because I can not download from megaupload.

        Thanks for advance.

  11. 24 de August de 2011 at 07:42

    Unfortunately this has been patched. They up’d the permission for INSTALL_APP or whatever to applications signed with the manufacturer’s certificate, or if the phone is rooted. :/ Sorry guys.

  12. 28 de September de 2011 at 03:34

    Hello ,
    Very tutorial and project ,,
    However I am facing some problem in using the code might be some where i m wrong ………

    i have modified ur code a little bit
    I have changed this ……..
    to
    try
    {
    //my path to apk
    am.installPackage(“/mnt/sdcard/PopupTest.apk”);
    }
    catch (Exception e)
    {

    logError(e);
    }

    then I am getting the Toast saying that “an error occured plz check log”;

    But der is nothing in logcat…
    Am I wrong some where Please help me out …
    Thanks in advanced…..

    • Mr. Bachelor
      19 de October de 2011 at 17:28

      it worked great for me using the path “/sdcard/your.apk” instead of “/mnt/sdcard/your.apk”

      • mouna
        13 de January de 2012 at 07:47

        hello,
        I try to use this project but i have the same problem like Mr.Vipin Sahu

        Please there is any way to solve this problem?
        thanks

  13. Mr. Bachelor
    19 de October de 2011 at 17:23

    I was able to get your awesome code to work on the emulator (in Eclipse I needed to set the path to the certificate/keystore you provided because the default debug keystore won’t permit the INSTALL_PACKAGES permission).

    My question is, how did you get the google_certificate.keystore ? Is it publicly available ?

  14. Mr. Bachelor
    19 de October de 2011 at 17:35

    Also, now I want to give the app to the firmware engineer so that he can include it in the firmware. My question is: how do I build the APK ? Do I use the same Google keystore – but it asks me for a password when I export.

  15. 19 de October de 2011 at 18:54

    Hello all, I wrote a new post about sign you apk with system privileges.
    https://paulononaka.wordpress.com/2011/10/19/apk-with-system-privileges/
    Sorry for my delay in answer.

    • Vishal
      16 de April de 2015 at 07:02

      Is it going to work on all devices ???

  16. Mr. Bachelor
    20 de October de 2011 at 16:23

    I have two final questions on this topic…
    1) does the flag INSTALL_REPLACE_EXISTING ensure that app-data is kept, i.e. database ?
    2) why does the ActivityManager force stop the newly installed/reinstalled package ? Is there a flag to prevent the force stop ? See my log below…

    DEBUG/PackageManager(59): Scanning package hello.world
    INFO/PackageManager(59): /data/app/hello.world-1.apk changed; unpacking
    DEBUG/installd(35): DexInv: — BEGIN ‘/data/app/hello.world-1.apk’ —
    DEBUG/dalvikvm(3861): DexOpt: load 23ms, verify 4ms, opt 1ms
    DEBUG/installd(35): DexInv: — END ‘/data/app/hello.world-1.apk’ (success) —
    DEBUG/PackageManager(59): Activities: hello.world.ActivityMain
    INFO/ActivityManager(59): Force stopping package hello.world uid=10038
    INFO/installd(35): move /data/dalvik-cache/data@app@hello.world-1.apk@classes.dex -> /data/dalvik-cache/data@app@hello.world-1.apk@classes.dex
    DEBUG/PackageManager(59): New package installed in /data/app/hello.world-1.apk

    • 20 de October de 2011 at 17:13

      1) Yes, the app-data are kept!
      2) The new application will not be stopped! The old application is stopped to allow the new application replace it.

  17. DavidYoon
    12 de January de 2012 at 00:02

    Hi!
    thanks for a good tip!!
    it` very useful for me.

    I have a one question.
    my customer request API to install apk in background.
    but your project has many java files
    he want to use it like a method, not including extra files 😦

    Is it possible to intergrate files or decrease the number of files?

    thanks in advanced

  18. syed m
    30 de January de 2012 at 09:24

    I am not able to run keytool-importkeypair on windows 7?

  19. syed m
    30 de January de 2012 at 09:26

    could anyone help me?

  20. Rose R.
    1 de March de 2012 at 06:58

    paulonona, the firmware engineer I work with is upgrading from Android 2.2 to Android 2.3 and it seems that it’s no longer working:

    D/installd( 885): DexInv: — BEGIN ‘/system/app/customInstaller.apk’ —
    D/dalvikvm( 2011): creating instr width table
    D/dalvikvm( 2011): DexOpt: ‘Landroid/content/pm/IPackageInstallObserver;’ has an earlier definition; blocking out
    D/dalvikvm( 2011): DexOpt: ‘Landroid/content/pm/IPackageInstallObserver$Stub;’ has an earlier definition; blocking out
    D/dalvikvm( 2011): DexOpt: not verifying ‘Landroid/content/pm/IPackageInstallObserver;’: multiple definitions
    D/dalvikvm( 2011): DexOpt: not verifying ‘Landroid/content/pm/IPackageInstallObserver$Stub;’: multiple definitions
    I/dalvikvm( 2011): DexOpt: not resolving ambiguous class ‘Landroid/content/pm/IPackageInstallObserver$Stub;’
    I/dalvikvm( 2011): DexOpt: not resolving ambiguous class ‘Landroid/content/pm/IPackageInstallObserver;’
    D/dalvikvm( 2011): DexOpt: load 9ms, verify+opt 10ms
    D/installd( 885): DexInv: — END ‘/system/app/customInstaller.apk’ (success) —

    Do you have any suggestions ?

    Looking at the JavaDoc, it seems there’s no longer a IPackageInstallObserver

    http://www.androidjavadoc.com/2.3/android/content/pm/package-summary.html

  21. pomatu
    6 de June de 2012 at 13:55

    But I still can’t uninstall apps the same way
    Can you check this? Where is a mistake?
    http://stackoverflow.com/questions/10900928/uninstall-app-silently-with-system-priveleges

  22. Kuchinashi
    14 de June de 2012 at 08:38

    What is the license of this API?
    Can I use this API to products?

  23. 9 de July de 2012 at 08:56

    Hi thanks for sharing!
    I have a question – for this to work, do I need to Export my application as signed Android application, using the “Android tools -> Export as signed..” with the certificate you provided in the certificate folder?

    If so, what’s the certificate password? I used “android” and it seem to work… but I have to copy the APK and put it in /system/app and only then install it.

    Can you verify what i’m doing is OK?

  24. 31 de August de 2012 at 16:16

    Hi thanks for code but I get the follow error:

    08-31 16:14:33.271: W/System.err(5322): Caused by: java.lang.SecurityException: Neither user 10106 nor current process has android.permission.INSTALL_PACKAGES.

    I already insert the INSTALL_PACKAGES in the manifest.

    I’m using android 2.3.3

  25. meriam
    19 de November de 2012 at 07:06

    can you post your version in another site please , I can’t access to this link.
    Thanks

  26. Anand
    21 de November de 2012 at 07:16

    Hi i just download your project and run without modified the code in emulator its working properly but when i connect device it gives an error

    [2012-11-21 15:45:55 – InstallInBackgroundSample] Installation error: INSTALL_FAILED_INVALID_INSTALL_LOCATION
    [2012-11-21 15:45:55 – InstallInBackgroundSample] Please check logcat output for more details.
    [2012-11-21 15:45:56 – InstallInBackgroundSample] Launch canceled!

  27. FlashAsh
    3 de December de 2012 at 07:01

    Hi, I have tried this on my custom android build and it works like a charm. Thanks!

    The issue I have is that I kick off downloading and installing of the apk with an intent service…

    Downloading runs on the intent service fine, but the service is not blocked when installPackage is called (as this is handled and returns asynchronously).

    Is there anyway I block the intent service thread until onPackageInstalled has completed.

  28. FlashAsh
    3 de January de 2013 at 07:54

    Hi, I have the following issue when the (installer) app is installed in the systems apps folder.

    12-29 15:50:37.704 E/JavaBinder( 2592): *** Uncaught remote exception! (Exceptions are not yet supported across processes.)

    12-29 15:50:37.704 E/JavaBinder( 2592): java.lang.AbstractMethodError: abstract method not implemented

    12-29 15:50:37.704 E/JavaBinder( 2592): at android.content.pm.IPackageInstallObserver$Stub.packageInstalled(IPackageInstallObserver.java)

    12-29 15:50:37.704 E/JavaBinder( 2592): at android.content.pm.IPackageInstallObserver$Stub.onTransact(IPackageInstallObserver.java:56)

    12-29 15:50:37.704 E/JavaBinder( 2592): at android.os.Binder.execTransact(Binder.java:338)

    12-29 15:50:37.704 E/JavaBinder( 2592): at dalvik.system.NativeStart.run(Native Method)

    12-29 15:50:37.704 W/dalvikvm( 2592): threadid=9: thread exiting with uncaught exception (group=0x40a5d9d8)

    12-29 15:50:37.704 E/AndroidRuntime( 2592): FATAL EXCEPTION: Binder Thread #2

    12-29 15:50:37.704 E/AndroidRuntime( 2592): java.lang.AbstractMethodError: abstract method not implemented

    12-29 15:50:37.704 E/AndroidRuntime( 2592): at android.content.pm.IPackageInstallObserver$Stub.packageInstalled(IPackageInstallObserver.java)

    12-29 15:50:37.704 E/AndroidRuntime( 2592): at android.content.pm.IPackageInstallObserver$Stub.onTransact(IPackageInstallObserver.java:56)

    12-29 15:50:37.704 E/AndroidRuntime( 2592): at android.os.Binder.execTransact(Binder.java:338)

    12-29 15:50:37.704 E/AndroidRuntime( 2592): at dalvik.system.NativeStart.run(Native Method)

    Any clues?

    • FlashAsh
      3 de January de 2013 at 11:00

      Seems like proguard was the culprit obfuscating IPackageInstallObserver class. I have now added it to the proguard config file so it’s kept

  29. Alkesh
    15 de March de 2013 at 03:59

    Hi,

    What is manufacturer’s security certificate and how we get it and compile with this certificate

    Thanks in Adavance

  30. FlashAsh
    20 de May de 2013 at 07:53

    Is there anyway to retrieve the permissions (and possibly the localized permission text) from the apk file that is about to be installed, prior to installing it?

  31. 24 de October de 2013 at 15:51

    Olá, tenho o seguinte cenário: tenho uma aplicação que terá outras aplicações embutidas, sendo que quando eu fosse desinstalar a aplicação pai, as filhas iriam ser desinstaladas também sem que fosse lançado a confirmação na tela, assim evitando pedir autorização para o usuário de cada aplicação filha. No caso essa sua solução seria viável para este cenário?

    Obg.

  32. meenakshisudaram selvaraj
    12 de November de 2013 at 08:32

    hai IPackageInstallObserver class not , i did get any return code …….. let me know what the reason

  33. 20 de March de 2014 at 12:44

    hey i have two question regarding this code.
    is it working with >4.0 android version ?
    how do i can give install app permission in my app b’z it gives error …

  34. Vishal
    15 de April de 2015 at 12:31

    I am always getting RuntimeException while trying to initiate ApplicationManager class :

    final ApplicationManager am = new ApplicationManager(InstallInBackgroundSample.this);

    • Vishal
      15 de April de 2015 at 13:01

      Exception returns Stub as detail message

      • Vishal
        16 de April de 2015 at 07:01

        Sorry i got the issue, had to make different package android.content.pm 😛

  35. Taufik
    11 de December de 2015 at 01:27

    is this source code can working on up to 4.0 or newer ?

  36. 10 de April de 2016 at 13:00

    Hey WindSekirui, nice work you have done over there!

    Although I have a small suggestion. How about you make a pull request in the original repository instead of creating a new one? Currently this repository has 41 different forks where people have made changes to meet their needs, but I think we could centralize people’s improvements in a single and central repository, where everyone could get benefits of each collaboration.

    Please, let’s start doing it. Make a pull request and I will accept your improvements and you will become a contributor of this code that has helped so many people. 🙂

  37. simone
    27 de January de 2017 at 09:41

    27/01/2017.

    I donwloaded and installed the android studio project.
    It doesn’t work!

  38. 30 de August de 2017 at 18:04

    I’ve Ƅeen browsing oonline moге than thrеe hoսrs t᧐day,
    yet I never foսnd any interestіng article ⅼike yoᥙrs.
    It’s pretty worth enough fߋr me. Personally,
    if ɑll webmasters аnd bloggdrs mаde ցood content aѕ yoս did,
    tһe net ѡill be а lot mote uѕeful thɑn eveг
    Ьefore.

  1. 8 de June de 2012 at 09:29
  2. 27 de August de 2012 at 20:31
  3. 10 de April de 2015 at 05:11
  4. 13 de August de 2015 at 10:58
  5. 3 de November de 2017 at 15:16

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: