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! 🙂
hi,
I try use your project code without modify but i found an error:
“java.lang.reflect.InvocationTargetException……….”
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.
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!
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“.
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.
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.
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!
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.
Paulo,
Funcionou perfeito!!!! Está de parabéns!!! Você é O CARA!!
Continue assim!!
Abraços!!
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
Opa, blz Johann?
É isso mesmo, você deve criar um service. Fazer uma chamada http deve ser o suficiente para você. Criei aqui a aplicação que você precisa:
https://github.com/paulononaka/Android-ServiceLocalization
Tá lá, boa sorte!
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 😛
😀
Hi,
can you publish the source code of your project after the corrections because I can not download from megaupload.
Thanks for advance.
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.
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…..
it worked great for me using the path “/sdcard/your.apk” instead of “/mnt/sdcard/your.apk”
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
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 ?
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.
Hello all, I wrote a new post about sign you apk with system privileges.
Sorry for my delay in answer.
Is it going to work on all devices ???
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
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.
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
I am not able to run keytool-importkeypair on windows 7?
could anyone help me?
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
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
nevermind, figured that out
Here is the solution
http://stackoverflow.com/a/10967776/705297
What is the license of this API?
Can I use this API to products?
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?
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
can you post your version in another site please , I can’t access to this link.
Thanks
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!
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.
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?
Seems like proguard was the culprit obfuscating IPackageInstallObserver class. I have now added it to the proguard config file so it’s kept
Hi,
What is manufacturer’s security certificate and how we get it and compile with this certificate
Thanks in Adavance
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?
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.
hai IPackageInstallObserver class not , i did get any return code …….. let me know what the reason
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 …
I am always getting RuntimeException while trying to initiate ApplicationManager class :
final ApplicationManager am = new ApplicationManager(InstallInBackgroundSample.this);
Exception returns Stub as detail message
Sorry i got the issue, had to make different package android.content.pm 😛
is this source code can working on up to 4.0 or newer ?
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. 🙂
27/01/2017.
I donwloaded and installed the android studio project.
It doesn’t work!
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.
I installed it on my device and it worked as I have the system keys however I didn’t get the event when the installation is done. Any ideas?
Is it work on first time installation and valid for all android handsets??? …
I’m looking for a solution in which application download from website/company and install automatically without user permission and run in background???
Great Post Thanks for this information.