Project Practice: OTA system upgrade and ota system upgrade

Source: Internet
Author: User

Project Practice: OTA system upgrade and ota system upgrade


This section summarizes the previous OTA System Upgrade Project, including four parts: Introduction to the OTA system, preparation of the OTA package, code structure, and issues to be improved.


1. OTA introduction:

OTA is the full name over the air. OTA update is a standard software upgrade method provided by the Android system. It is powerful and provides full upgrade and incremental upgrade modes. It can be upgraded through the SD card or through the network. During system upgrade, the whole package and differential package are compiled locally and placed on the server for users to choose from.


2. Create an OTA package:

The complete package is the OTA package generated by the entire system, which may be about several hundred MB in size, but it is more stable than the OTA differential package. The size of the differential package is relatively small and easy to upgrade, this depends on the user's choice. In linux, the complete package generation method is: make clean; make otapackage; after the out/target/product/torsby will generate a zip package: vargo_torsby-ota.zip, this is a complete package that can be upgraded directly. At the same time, the difference package is also generated in the out/target/product/torsby/obj/PACKAGING/packages, there is an ota_from_target_files built-in script in the build/tools/releasetools directory. in linux :. /build/tools/releasetools/ota_from_target_files-I ~ /Old.zip ~ /New.zip ~ /Update.zip, the update.zip differential package will be generated in the current directory. Note that you should put the two ota packages in the current directory to execute this command. In this case, the update.zipdifference package is upgraded to the old.zips system to get the new.zip version.


3. project structure:

The function of the entire project is that after the user enters the system upgrade from the settings, the user will automatically request the server to check whether there is a version to be updated. If not, enter a prompt interface: Your system is already up to date! If it is not the latest system, the current system version number, the latest system version number, and more version updates are displayed on the page. Click Install now to go to a version list, the above are all the finer-grained versions returned by the server. You can select a version to install and update it.

The core class of the Code is IradarUpdateSystemFragment. class, which inherits from PreferenceFragment to maintain synchronization with the uidesign of Settings, and then belongs to IradarUpdateSystemActivity, so the real code implementation is in this fragment. In the onCreate () method, initialize the actionBar and Preference, and then use the company's encapsulated network framework RequestManager to request the server to obtain the latest version. Note the following: before using RequestManager to request the server, you must first initialize:

Options opts = new Options.Builder().enableNet().enablePush().build();     VargoHelper.Init(this,opts);

I put this initialization in the Custom OTAApplication, but for the sake of security, I still wait for the initialization period before calling the RequestManager request method. So I used handler to control the scheduled execution, request again after Ms. Data is transmitted in json throughout the request process. The request parameter is getDeviceData (), mainly the current version number and the DeviceId of the current machine, the use of RequestManager does not describe how to use the size function number to request the server. At the same time, bind the ResponseListener to obtain the request result. In onReceived (), obtaining the Response is the result we want, in other methods, there are some error responses, and so on. We can also provide some UI prompts. Here, it should be noted that RequestManager has been specially processed and can be called directly in the UI thread, and the UI can be updated directly in the result. I didn't use handler. ResponseCode is used to identify whether a version is updated. If there is an update, the result will be uploaded to updatePreference () to update our interface.

Here is the Preference "Learn More", which is used to view the Update log: Click to jump to UpdateLogActivity, which is the implementation of a window Activity, using WebView. load an Update log using the loadUrl () method.

After the page is updated, if the current version can be updated, a version list will pop up after you click "Install now". Prior to this, there will be a wi-fi and power rating, we require that you must connect to WIFI and the power is no less than 50% before you can continue to update. Check whether the WIFI is Enabled:

// Check whether the current network is WIFIprivate Boolean isWifiNet () {ConnectivityManager connectionManager = (ConnectivityManager) context. getSystemService (context. CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectionManager. getActiveNetworkInfo (); if (networkInfo = null) {return false;} else {String netState = networkInfo. getTypeName (); if (netState. equals ("WIFI") {return true;} else return false ;}}

Check whether the current power is less than 50% of the Code:

// Directly obtain the current battery private boolean getBattery () {String s = ""; boolean isOk = false; try {fr = new FileReader (file ); bufferedReader br = new BufferedReader (fr); if (s = br. readLine ())! = Null) {if (Integer. parseInt (s)> 49) {isOk = true; Log. d (LOG_TAG, "current power is >>>>>>>>>>" + s) ;}else {isOk = false ;}} catch (FileNotFoundException e) {// TODO Auto-generated catch blocke. printStackTrace ();} catch (IOException e) {// TODO Auto-generated catch blocke. printStackTrace ();} return isOk ;}

One note: the conventional method for obtaining power consumption is to bind a broadcast. When the power usage changes, it will receive a system broadcast from ACTION_BATTERY_CHANGED. However, this problem is that it is not instant, after clicking the button, the user should get the broadcast, so the above method is used: in the android system, the File "/sys/class/power_supply/battery/capacity" actually stores the current power and reads it directly from the new File!

When both the power and WIFI meet the conditions, you can download and install the system version. Download this part of the DownloadManager framework that comes with the system. The android native system uses this framework and has encapsulated notification bars. The functions are still very complete. The following describes how to use DownloadManager in this project:

DownloadManager is a download management class, which is obtained in OnCreate :.

manger=(DownloadManager)getActivity().getSystemService(context.DOWNLOAD_SERVICE) ;

DownloadManager. A Request is a download task. You can set download parameters, such as whether the notification bar is visible, network limitation, and download directory. Call DownloadManager after setting. the enqueue method starts downloading. It returns an ID that is the ID of the current download task. It can be seen that it supports multiple tasks! The code below shows that the ID is set as a global variable, and the current download progress can be queried through this ID:

DownloadManager. request down = new DownloadManager. request (Uri. parse (url); // down. addRequestHeader (header, value); down. seticationicationvisibility (android. app. downloadManager. request. VISIBILITY_VISIBLE); down. setAllowedNetworkTypes (DownloadManager. request. NETWORK_WIFI); down. setTitle (getActivity (). getResources (). getString (R. string. down_title); if (getFile (OtaConstant. romName ). exists () {boolean isDel Ete = getFile (OtaConstant. romName). delete (); Log. d (LOG_TAG, "delete the original update.zip? >>>>>>> "+ IsDelete);} down. setDestinationInExternalPublicDir (Environment. DIRECTORY_DOWNLOADS, OtaConstant. romName); downloadId = manger. enqueue (down); SharedPreferences sharedPreferences = getActivity (). getSharedPreferences ("ota", Context. MODE_PRIVATE); // Private Data Editor = sharedPreferences. edit (); // get the editor. putLong ("downloadId", downloadId); editor. commit (); // submit the modification

Download has actually started here, but we want to update our progress bar and listen to the download progress of a specific ID. We use ContentResolver () to listen to the URI of a system. Remember to go to onDestroy () unbind! :

context.getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true,downloadObserver);

// Listen to the download progress class DownloadChangeObserver extends ContentObserver {public DownloadChangeObserver () {super (handler) ;}@ Overridepublic void onChange (boolean selfChange) {updateView (); Log. d (LOG_TAG, "Listening to download") ;}} public void updateView () {SharedPreferences sharedPreferences = getActivity (). getSharedPreferences ("ota", Context. MODE_PRIVATE); downloadId = sharedPreferences. getLong ("downloadId",-1L); Log. d (LOG _ TAG, "re-enter OTA to continue downloadId >>>>>>" + downloadId); if (downloadId! =-1) {int [] bytesAndStatus = getBytesAndStatus (downloadId); handler. sendMessage (handler. obtainMessage (0, bytesAndStatus) ;}} public int [] getBytesAndStatus (long downloadId) {int [] bytesAndStatus = new int [] {-1,-1, 0, 0}; DownloadManager. query query = new DownloadManager. query (). setFilterById (downloadId); Cursor c = null; try {c = manger. query (query); if (c! = Null & c. moveToFirst () {bytesAndStatus [0] = c. getInt (c. getColumnIndexOrThrow (DownloadManager. COLUMN_BYTES_DOWNLOADED_SO_FAR); bytesAndStatus [1] = c. getInt (c. getColumnIndexOrThrow (DownloadManager. COLUMN_TOTAL_SIZE_BYTES); bytesAndStatus [2] = c. getInt (c. getColumnIndex (DownloadManager. COLUMN_STATUS); bytesAndStatus [3] = c. getInt (c. getColumnIndex (DownloadManager. COLUMN_REASON); Log. d (LOG_TAG, "CO LUMN_STATUS >>>>>>>>> "+ bytesAndStatus [2] +" COLUMN_REASON >>>>>>>>> "+ bytesAndStatus [3]);} finally {if (c! = Null) {c. close () ;}return bytesAndStatus ;}

In the above code, we can see some download information during the download process, such as: Download start, pause, and download... the current download size, total size, and so on. Use handler to update the UI. there is a problem here, that is, I do not know the download status DownloadManager. when will the pause and failure in COLUMN_STATUS be triggered? Sometimes, when the download is in progress, I shut down the network and start the system, he can continue to download. Sometimes he directly prompts that the download failed and will not continue to download, I still have no full control. Another one is that it supports resumable data transfer, but I have not found how to manually pause it. It can only be paused in some cases!

What I need to do is to download it in the background, even if it is shut down and restarted, I will re-enter the software, and the progress bar will be able to display the current download. So I saved the ID with SharedPreferences right away when starting the download, and cleared the ID before starting a download. After the next download, I checked whether the ID has a value: if yes, it indicates that the download is in progress, and there is no value (in fact, the-1 default value given by the Code). This is a new download. This is the entire download process. In practice, the download process is basically smooth. After completion, we will see the update.zip update package in the domloadfile folder of the sdks. The installation method is as follows:

// Execute the installation and update package private void installRom () {// compare the MD5 to determine the integrity Log of the rom. d (LOG_TAG, "the md5 of the downloaded file is >>>>>>>>>" + Utils. getFileMD5 (getFile (OtaConstant. romName); SharedPreferences sp = context. getSharedPreferences ("ota", 0); String romMd5 = sp. getString ("md5", ""); Log. d (LOG_TAG, "the md5 given by the server is >>>>>>>>>" + romMd5); if (Utils. getFileMD5 (getFile (OtaConstant. romName )). repeated signorecase (romMd5) {try {RecoverySystem. installPa Ckage (context, getFile (OtaConstant. romName);} catch (IOException e) {// TODO Auto-generated catch blocke. printStackTrace () ;}} else {Toast. makeText (getActivity (), getActivity (). getResources (). getString (R. string. system_broken), 1 ). show (); getActivity (). finish ();} if (startInstall! = Null) {startInstall. dismiss ();}}

The above Code indicates that there is an MD5 verification of the installation package before installation. The downloaded installation package must be consistent with the information provided to me by the server. Otherwise, the file is damaged and needs to be downloaded again! The core of installing the OTA package is this: RecoverySystem. installPackage (context, getFile (OtaConstant. romName); the process is not detailed, and the process is uncontrollable. If a problem occurs during installation, it should be the problem of the installation package, and a common error is: the error message "unable to find the SD card Mount path" is displayed! This is generally a problem with the system recovery. I have no in-depth understanding of this detailed execution process.

There is another problem with OTA: We can't expect users to wait for download on the current interface to complete the installation. This installation may be completed in the background. Therefore, you must put this installation process in the service, is the InstallService class in the code. However, the subsequent practices tell me that it is not enough to simply put the installation on the service, because the download may fail, and a failure prompt must be given, so the entire download progress process should be placed on the service, this was not clearly considered at the time. In fact, fragment does not need to be downloaded or installed. This part of code is not yet simplified. Another option is manual installation and automatic installation. The project requires automatic installation starting 15 days after the download is complete, or you can directly click Install now. Use handler to control this part, add a FLAG and mark it as manual and automatic. Do not install either of them. the implementation of the custom notification bar for failed download is as follows:

<Pre name = "code" class = "java"> private void shwonovel (Context context) {Log. d (LOG_TAG, "start to show a status bar"); micationicationmanager = (icationicationmanager) getSystemService (Context. NOTIFICATION_SERVICE); RemoteViews view_custom = new RemoteViews (getPackageName (), R. layout. view_custom); view_custom.setImageViewResource (R. id. custom_icon, R. drawable. update); view_custom.setTextViewText (R. id. TV _custom_title, context. getResources (). getString (R. string. service_prompt); view_custom.setTextViewText (R. id. TV _custom_content, context. getResources (). getString (R. string. system_broken); mBuilder = new Builder (this); mBuilder. setContent (view_custom ). setWhen (System. currentTimeMillis ()). setContentIntent (getDefalutIntent (Notification. FLAG_AUTO_CANCEL )). setWhen (System. currentTimeMillis ())//. setTicker (context. getResources (). getString (R. string. service_prompt )). setPriority (Notification. PRIORITY_DEFAULT )//. setOngoing (false )//. setSmallIcon (R. drawable. update); Notification producer y = mBuilder. build (); policy. contentView = view_custom; mNotificationManager. Y (policyid, policy); Log. d (LOG_TAG, "End show a status bar");} public PendingIntent getDefalutIntent (int flags) {Intent intent = new Intent (); intent. setClassName ("cn.com. vargo. ota "," cn.com. vargo. ota. iradarUpdateSystemActivity "); PendingIntent pendingIntent = PendingIntent. getActivity (this, 1, intent, flags); return pendingIntent ;}


The two tools in Utils are attached. One is to get the MD5 of the file and the other is to get the MAC address of the machine: 

Public class Utils {/*** calculate the MD5 of the file * @ param File * @ return */public static String getFileMD5 (file File) {if (! File. isFile () {return "";} MessageDigest digest = null; FileInputStream in = null; byte buffer [] = new byte [1024]; int len; try {digest = MessageDigest. getInstance ("MD5"); in = new FileInputStream (file); while (len = in. read (buffer, 0, 1024 ))! =-1) {digest. update (buffer, 0, len);} in. close ();} catch (Exception e) {e. printStackTrace (); return null;} BigInteger bigInt = new BigInteger (1, digest. digest (); return bigInt. toString (16 ). toUpperCase ();}/*** // obtain the mac address: * @ param context * @ return */public static String getMacAddress (Context context) {String macAddress = "000000000000 "; try {WifiManager wifiMgr = (WifiManager) context. GetSystemService (Context. WIFI_SERVICE); WifiInfo info = (null = wifiMgr? Null: wifiMgr. getConnectionInfo (); if (null! = Info) {if (! TextUtils. isEmpty (info. getMacAddress () macAddress = info. getMacAddress (). replace (":", ""); else return macAddress ;}} catch (Exception e) {// TODO Auto-generated catch block e. printStackTrace (); return macAddress;} return macAddress ;}}


4. to be resolved:

From the above description, we can see that there are still several questions to be improved:

First, DownloadManager supports resumable data transfer, but does not know how to manually pause it. The pause or failure status is provided in the case of Shenma, which is not very sure yet.

Second, the installation process of the OTA package has not been studied in depth, and the download and installation should be all removed from the fragment and only placed on the service.


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.