1. First, let's take a look at the steps to enter the system update, set-up about phone--System update
① Settings interface to enter the system Update settings interface for the settings module under the Deviceinfosettings.java class, the corresponding preference is device_info_settings.xml in the following:
<com.android.settings.xxupdatepreference android:key= "System_update_settings"
android:title= "@string/system_update_settings_list_item_title"
android:summary= "@string/system_update_settings_list_item_summary" >
<intent android:action= "Android.settings.SYSTEM_UPDATE_SETTINGS"/>
</com.android.settings.XXUpdatePreference>
② We listen to the preference in Deviceinfosettings.java, and when the user triggers a click event, the XXX app receives the broadcast and initiates XXX to make the next step. As shown below:
else if (Preference.getkey (). Equals (Key_dmsw_update)) {
/m:for DMSW to broadcast @{
Intent i = new Intent ();
I.setaction ("Com.mediatek.DMSWUPDATE");
Getactivity (). Sendbroadcast (i);
// /@}
}
2. In general, due to the Android original ecosystem of the system update experience generally, our mobile phone system update applications are vendor-specific, that is, we click on the system update is generally entered into the manufacturer's custom system update application, here we do not repeat, Subsequent blog post will perform an analysis of the native System update application.
① Here we skip, select the local upgrade only in the vendor-specific app, then go to the Setup Warning screen Systemupgradechooseractivity.java (during the upgrade, do not remove the battery, SIM card and memory card ... ), then we click OK and go to the Upgrade Alert screen (the upgrade will be completed in five minutes ...). ), some of the code is as follows:
Case R.id.okbutton://Whether hanging in SDcard
if (!hassdcard ()) {
Showtoast (R.string.no_sd_card);
Return
}//update package is present
if (file = = NULL | |!file.exists ()) {
Showtoast (R.string.no_update_file);
Return
}//Enter the Upgrade alert screen
Intent Intent = new Intent (systemupgradechooseractivity.this,updatetostart.class);
StartActivity (Intent);
Break
② At this time we go through intent into the upgrade alert interface Updatetostart.java, here we click OK to start installing the update package, the detailed code is as follows:
Buttonokup.setonclicklistener (New Onclicklistener () {
@Override
public void OnClick (View v) {
try {//Whether hanging in SDcard
if (!hassdcard ()) {
Showtoast (R.string.no_sd_card);
Return
}//update file is presentFile File = new file (environment.getexternalstoragedirectory () + "/dload/update.zip");
if (file = = NULL | |!file.exists ()) {
Showtoast (R.string.no_update_file);
Return
}//Install the update package, which is the new key for the upper system
Recoverysystem.installpackage (Getapplicationcontext (), file);
}
catch (Exception e) {
//
}
}
});
3. We understand that the update package is installed by calling the Recoverysystem.installpackage () method. Here's how: /**
* In order to install the update package will restart the device, in addition to call the method need to add reboot permissions in the manifest file
* Parameters Context Context
* Parameter PackageFile A file object that encapsulates information such as update package paths.
*/
public static void InstallPackage (context context, File PackageFile)
Throws IOException {
String filename = Packagefile.getcanonicalpath ();
LOG.W (TAG, "!!! REBOOTING to INSTALL "+ filename +"!!! ");
///parameter stitching, this parameter will eventually be written to BCB, which means that after the device restarts into recovery mode, Recovery.cpp will parse the parameter and, depending on the parameters, it will be passed into the Bootcommand (context,arg) function.
String arg = "--update_package=" + filename +
"\n--locale=" + Locale.getdefault (). toString ();
Bootcommand (context, ARG);
}
4. The following is an analysis of the Bootcommand.
private static void Bootcommand (context context, String Arg) throws IOException {
Recovery_dir. Mkdirs ();//Create/cache/recovery directory
Command_file. Delete ();//delete command file, initialize
Log_file. Delete ();//delete log file for initialization
LOG.D (TAG, "Preapre to write command:" + arg + "\ n");
Writebyfdsync(Command_file,arg);//write parameters to the command file
LOG.D (TAG, "Success to write command:" + arg + "\ n");
LOG.D (TAG, "Current Build Type is:" + build.type + "\ n");
Readinandprint(Command_file);//Read the command file and print the log
Having written the command file, go ahead and reboot
PowerManager pm = (powermanager) context.getsystemservice (Context.power_service);//Get PowerManager instances from System services
Pm.
reboot("Recovery");// restart
LOG.D (TAG, "!!! Pm.reboot failed!!! \ n ");
throw new IOException ("Reboot failed (no permissions?)");
}
The following method call process is Powermanager:reboot ("recovery")-->powermanagerservice:reboot (reason)
-->powermanagerservice:shtudownorrebootinternal (false,confirm,reason,wait)
-->powermanagerservice:shutdownorrebootinternal (...)
-->shutdownthread:reboot (mcontext, Reason, confirm);
-->shutdownthread:run (): Running () ...
@Override//Binder Call
public void
reboot(Boolean confirm, String reason, Boolean wait) {
Mcontext.enforcecallingorselfpermission (Android. Manifest.permission.REBOOT, NULL);
SLOG.I (TAG, "reboot call PID:" + binder.getcallingpid () + "UID:" + binder.getcallinguid ());
Final Long ident = Binder.clearcallingidentity ();
try {
Shutdownorrebootinternal (false, confirm, reason, wait);
} finally {
Binder.restorecallingidentity (ident);
}
}
private void
shutdownorrebootinternal(Final Boolean shutdown, final Boolean confirm,
Final String reason, Boolean wait) {
if (Mhandler = = NULL | |!msystemready) {
throw new IllegalStateException ("Too Early to call shutdown () or reboot ()");
}
Runnable Runnable = new Runnable () {
@Override
public void Run () {
Synchronized (this) {
if (shutdown) {
Shutdownthread.shutdown (Mcontext, confirm);
} else {
Shutdownthread.reboot (mcontext, Reason, confirm);
}
}
}
};
Shutdownthread must run on a looper capable of displaying the UI.
Message msg = Message.obtain (Mhandler, runnable);
Msg.setasynchronous (TRUE);
Mhandler.sendmessage (msg);
Powermanager.reboot () is documented not to return so just wait for the inevitable.
if (wait) {
Synchronized (runnable) {
while (true) {
try {
Runnable.wait ();
} catch (Interruptedexception e) {
}
}
}
}
}
public static void
reboot(Final context context, String reason, Boolean confirm) {
Mreboot = true;
Mrebootsafemode = false;
Mrebootreason = reason;
LOG.D (TAG, "reboot");
if (Mspew) {
stacktraceelement[] stack = new Throwable (). Getstacktrace ();
for (Stacktraceelement Element:stack)
{
LOG.D (TAG, "|----" + element.tostring ());
}
}
Shutdowninner (context, confirm);
}
Here in the Run method, the running method writes the restart reason to the System properties file.
。。。。。。
{
String reason = (mreboot? "1": "0") + (Mrebootreason! = null? Mrebootreason: "");
Systemproperties.set (shutdown_action_property, reason);
}
。。。。。。
Finally, restart the device.
Android local upgrade principles and processes (one, upper)