Android's silent installation seems like an interesting and tempting thing to do, but in common practice it seems difficult to install silently if the phone does not have root privileges, because Android does not provide the intent call that is displayed, typically by installing APK in the following ways:
Intent Intent = new Intent (intent.action_view);
Intent.setdataandtype (uri.fromfile (file), "application/vnd.android.package-archive");
StartActivity (Intent);
However, this does not really implement the silent installation, because there is a user interface that will let the user know. So, how to silently install apk in the background? Can only try to see the Android system source code normal installation apk process, I downloaded the source code is the Android5.0 system, the size of 5 G, but perhaps because Android5.0 has some security updates, there is a certain gap with the previous version, but, learn a later to learn another similar process, it is much simpler, like learning C language, and then learn Java, is not What a difficult thing.
The Android system divides all permission (permissions) into four levels based on their potential risk, namely "normal", "dangerous", "signature", "Signatureorsystem". The APK installation corresponds to the install_packages, and the permission level belongs to the latter two. Therefore, finally want to realize the silent installation of apk, must need some special processing, the implementation of the installation process, must be the system process.
So let's take a look at how Android itself implements installation apk. The command to install is PM install ... We locate the/frameworks/base/cmds/pm/src/com/android/commands/pm/of the system source. Pm.java This file, he implemented the PM command, we look at the Runinstall method, this is the APK installation process.
private void Runinstall () {int installflags = 0;
int userId = Userhandle.user_all;
String installerpackagename = null;
String opt;
String originatinguristring = null;
String referrer = null;
String abi = null; while ((Opt=nextoption ())!= null) {if (Opt.equals ("L")) {installflags |= Packagemanager.install_forward_lo
CK;
else if (Opt.equals ("R")) {installflags |= packagemanager.install_replace_existing;
else if (opt.equals ("I")) {installerpackagename = Nextoptiondata ();
if (Installerpackagename = = null) {System.err.println ("Error:no value specified for-i");
Return
} else if (Opt.equals ("T")) {installflags |= packagemanager.install_allow_test;
else if (opt.equals ("s")) {//Override if-s option is specified.
Installflags |= packagemanager.install_external; else if (Opt.equals ("F")) {//Override if-s option is specified.
Installflags |= packagemanager.install_internal;
else if (opt.equals ("D")) {installflags |= packagemanager.install_allow_downgrade;
else if (opt.equals ("--originating-uri")) {originatinguristring = Nextoptiondata ();
if (originatinguristring = = null) {SYSTEM.ERR.PRINTLN ("error:must supply argument for--originating-uri");
Return
} else if (Opt.equals ("--referrer")) {referrer = Nextoptiondata ();
if (referrer = = null) {SYSTEM.ERR.PRINTLN ("error:must supply argument for--referrer");
Return
} else if (Opt.equals ("--abi")) {abi = Checkabiargument (Nextoptiondata ());
else if (opt.equals ("--user")) {userId = Integer.parseint (Nextoptiondata ());
else {System.err.println ("error:unknown option:" + opt);
Return
} if (userId = = Userhandle.user_all) {userId = Userhandle.user_owner; Installflags |= PaCkagemanager.install_all_users;
Final Uri Verificationuri;
Final Uri Originatinguri;
Final Uri Referreruri;
if (originatinguristring!= null) {Originatinguri = Uri.parse (originatinguristring);
else {Originatinguri = null;
} if (referrer!= null) {Referreruri = Uri.parse (referrer);
else {Referreruri = null;
}//Populate Apkuri, must be present final String Apkfilepath = Nextarg ();
System.err.println ("\tpkg:" + Apkfilepath);
if (Apkfilepath = = null) {System.err.println ("Error:no package specified");
Return
}//Populate Verificationuri, optionally present final String Verificationfilepath = Nextarg ();
if (Verificationfilepath!= null) {System.err.println ("\tver:" + Verificationfilepath);
Verificationuri = Uri.fromfile (new File (Verificationfilepath));
else {Verificationuri = null; Localpackageinstallobserver obs = new Localpackageinstallobserver ();
try {verificationparams verificationparams = new Verificationparams (Verificationuri, Originatinguri, ref
Erreruri, verificationparams.no_uid, NULL); Mpm.installpackageasuser (Apkfilepath, Obs.getbinder (), Installflags, Installerpackagename, VerificationParams, AB I, userId); Attention!!
The end result is the synchronized (OBS) {while (!obs.finished) {try {obs.wait ()) that this method is called to install.
catch (Interruptedexception e) {}} if (Obs.result = = packagemanager.install_succeeded) {
System.out.println ("Success");
else {System.err.println ("failure [" + installfailuretostring (OBS) + "]");
A catch (RemoteException e) {System.err.println (e.tostring ());
System.err.println (Pm_not_running_err);
}
}
After you know the process, you probably know what to do. Now that the bottom of the system has blocked the API, try to bypass the mask to use it. The first thought is to use aidl, do not know aidl this thing, first ask Niang go ~ ~ In the above code, the final implementation of the installation of the sentence, Mpm.installpackageasuser (...), mPm is what? It's not hard to find, Ipackagemanager type, so where does this class come from? Search, located in/frameworks/base/core/java/android/content/pm this bag, copy to our engineering directory, the package name can not be changed, only copy this file, it must be not, will report some other aidl can not find, Accordingly also copies come over. Android5.0, aidl change is still relatively large, so to copy a lot of things come over, but also to make some changes ... It took me a long time to change to him without an error.
Finally, the project catalogue is as follows ~ ~
So, how do you use it?
- 1, first access to system services Android.os.ServiceManager, this is hidden, how to do? The time has come to test the level of Java ~ ~ Yes, with the reflection mechanism to obtain the ServiceManager class, and the method inside the class;
- 2, with the service, we will go to get ipackagemanager this object;
- 3, call the Ipackagemanager inside the InstallPackage method to install;
The implementation code is as follows:
Package com.example.autoinstall;
Import Java.io.File;
Import Java.io.FileOutputStream;
Import java.io.IOException;
Import Java.io.InputStream;
Import Java.io.OutputStream;
Import Java.lang.reflect.Method;
Import android.app.Activity;
Import android.content.Intent;
Import Android.content.pm.IPackageInstallObserver2;
Import Android.content.pm.IPackageManager;
Import Android.content.pm.VerificationParams;
Import Android.net.Uri;
Import Android.os.Bundle;
Import Android.os.IBinder;
Import android.os.RemoteException;
Import Android.view.View; public class Mainactivity extends activity {@Override protected void onCreate (Bundle savedinstancestate) {s
Uper.oncreate (savedinstancestate);
Setcontentview (R.layout.activity_main);
/** * button Click event * @param view/public void Install (view view) {String path = "";
if (Fileutils.issdcardready ()) {path = Fileutils.getsdcardpath (); else {path = FileuTils.getcachepath (this);
String fileName = path + "/aidlserverdemo.apk";
File File = new file (fileName);
try {if (!file.exists ()) COPYAPK2SD (fileName);
Uri uri = uri.fromfile (new File (FileName));
Obtain Android.os.ServiceManager class<?> clazz = Class.forName ("Android.os.ServiceManager") through the Java reflection mechanism;
Method method = Clazz.getmethod ("GetService", String.class);
IBinder IBinder = (ibinder) method.invoke (NULL, "package");
Ipackagemanager IPM = IPackageManager.Stub.asInterface (IBinder); @SuppressWarnings ("deprecation") verificationparams verificationparams = new Verificationparams (null, NULL, NULL, V
Erificationparams.no_uid, NULL); Perform the installation (method and detailed parameters, which may vary depending on the system) Ipm.installpackage (FileName, New Packageinstallobserver (), 2, NULL, Verificationparams,
"");
catch (Exception e) {//TODO auto-generated catch block E.printstacktrace ();
}
} Used to display the result class Packageinstallobserver extends Ipackageinstallobserver2.stub {@Override public void OnUs Eractionrequired (Intent Intent) throws RemoteException {//TODO auto-generated method stub} @Overri De public void onpackageinstalled (string basepackagename, int returncode, String msg, Bundle extras) throws Remoteexc eption {//returncode<span style= "font-family:arial, Helvetica, Sans-serif;"
> 1, is the installation Success </span>}}; /** * Copy assets folder APK plugin to SD * * @param stroutfilename * @throws ioexception/private void copyAPK2
SD (String stroutfilename) throws IOException {Fileutils.createdippath (stroutfilename);
InputStream myinput = This.getassets (). Open ("aidlserverdemo.apk");
OutputStream myoutput = new FileOutputStream (stroutfilename);
byte[] buffer = new byte[1024];
int length = myinput.read (buffer); while (length > 0) {myoutput.write (buffer, 0, Length);
Length = myinput.read (buffer);
} myoutput.flush ();
Myinput.close ();
Myoutput.close ();
}
}
Each version of the system source code inside the Aidl may not be the same, so the specific methods and parameters of the call, but also according to the actual situation, you need to carefully read Pm.java this document source code.
In other versions, you may only need to copy these 4 files: Packagemanager.java, Ipackagedeleteobserver.aidl, Ipackagerinstallobserver.aidl, Ipackagemoveobserver.aidl
You will then need to add Install_package permissions in the configuration manifest file
The application's UID is then set to the system level, with the following attributes added under the Manifest tab
In this case, there is no silent installation, because the system does not think that your app is a system-level application, so you should also be the application of the APK system signature (note: Not the silent installation of the APK, is the implementation of the silent installer apk). The signature process is as follows:
A total of three files are required:
- 1, Signapk.jar% system source%/out/host/linux-x86/framework/signapk.jar
- 2, Platform.x509.pem% system source%/build/target/product/security/platform.x509.pem
- 3, Platform.pk8% system source%/build/target/product/security/platform.pk8
Open the terminal, execute the command java-jar signapk.jar platform.x509.pem platform.pk8 unsigned apk after signing apk, for example
Java-jar Signapk.jar Platform.x509.pem platform.pk8 autoinstall.apk autoinstall_new.apk
After the signature of the APK installed to the mobile phone, open, click Silent Installation, in the go to the program page to see, found installation success ~ ~
This article is mainly to provide a way to achieve silent installation of ideas, but specifically how to do compatible with each system, extrapolate,