【Android OTA】系統(tǒng)的更新升級

timg-3.jpeg

原文鏈接

上一篇說了Android應(yīng)用的升級姥宝,這篇來介紹下關(guān)于整個系統(tǒng)的升級感帅。公司的車載系統(tǒng)使用了MTK的板子土居,深度定制的Android系統(tǒng)桑滩,平時開發(fā)過程中的修改可以直接重新燒錄固件,但設(shè)備量產(chǎn)投入市場之后的修改只能通過OTA的方式進行更新颠放。

系統(tǒng)升級一般通過差分包的方式排惨,因為整包更新需要的安裝包有幾百M,一般的小更新打個差分包的話也就幾M十幾M而已碰凶,能省不少流量暮芭。

設(shè)備檢測更新的流程基本和上一篇文章一樣,系統(tǒng)可以在設(shè)置界面上增加檢測升級的入口欲低。

系統(tǒng)升級流程

  1. 向服務(wù)器請求系統(tǒng)更新信息辕宏;
  2. 獲取到返回信息后,判斷是否有更新版本砾莱,若有更新瑞筐,進入步驟3;
  3. 下載服務(wù)器對應(yīng)的更新文件恤磷;
  4. 下載完成后驗證更新文件面哼;
  5. 系統(tǒng)重啟進入recovery模式進行升級,升級完成后設(shè)備重啟扫步。

更新信息的請求和返回信息的處理過程與應(yīng)用的更新升級一致魔策。

更新文件的下載這次使用了系統(tǒng)自帶的類 DownloadManager

DownloadManager 能自動管理系統(tǒng)的下載任務(wù)河胎,在聯(lián)網(wǎng)發(fā)生變化闯袒、系統(tǒng)開關(guān)機、斷點續(xù)傳等情況自行進行處理游岳。

創(chuàng)建下載任務(wù)政敢,設(shè)置指定下載目錄

mDownloadManager = (DownloadManager)getSystemService(DOWNLOAD_SERVICE);

DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
request.setDestinationInExternalPublicDir(OTAUtil.otaFolderName(), OTAUtil.otaFileName());
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_HIDDEN);
request.setVisibleInDownloadsUi(false);
mDownloadId = mDownloadManager.enqueue(request);

DownloadManager 下載進度可以顯示在通知欄中,也可以選擇只在特定聯(lián)網(wǎng)情況下(如wifi胚迫、移動信號)進行任務(wù)喷户。

監(jiān)聽下載狀態(tài)

class CompleteReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        long completeDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
        if (completeDownloadId == mDownloadId) {
            // download successful
            String msg;
            switch (OTAUtil.getOTADownloadStatus(completeDownloadId, mDownloadManager)) {
                case DownloadManager.STATUS_FAILED:
                    msg = "Download failed!";
                    break;

                case DownloadManager.STATUS_PAUSED:
                    msg = "Download paused!";
                    break;

                case DownloadManager.STATUS_PENDING:
                    msg = "Download pending!";
                    break;

                case DownloadManager.STATUS_RUNNING:
                    msg = "Download in progress!";
                    break;

                case DownloadManager.STATUS_SUCCESSFUL:
                    break;

                default:
                    msg = "Download is nowhere in sight";
                    break;
            }

            Log.i(TAG, "CompleteReceiver onReceive...." + msg);
        }
    }
}

用來更新界面的進度條

class DownloadChangeObserver extends ContentObserver {

    public DownloadChangeObserver() {
        super(mHandler);
    }

    @Override
    public void onChange(boolean selfChange) {

        int progress = OTAUtil.getOTADownloadPro(mDownloadId, mDownloadManager);

        Message msg = mHandler.obtainMessage();
        msg.what = UPDATE_DOWNLOAD_PROGRESS;
        msg.arg1 = progress;
        mHandler.sendMessage(msg);
    }
}

其中getOTADownloadPro 方法通過id獲取指定下載任務(wù)的進度值

public static int getOTADownloadPro(long id, DownloadManager downloadManager) {
    double progress = 0.0;

    DownloadManager.Query q = new DownloadManager.Query();
    q.setFilterById(id);

    Cursor c = downloadManager.query(q);
    if (c.moveToFirst()) {
        int sizeIndex = c.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
        int downloadedIndex = c.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
        long size = c.getInt(sizeIndex);
        long downloaded = c.getInt(downloadedIndex);

        if (size != -1) {
            progress = downloaded * 100.0 / size;
        }
    }
    c.close();

    return (int)progress;
}

這里有一個注意問題,正常情況下使用DownloadManager下載的文件只能保存在系統(tǒng)的外部存儲中(系統(tǒng)級的DownloadManager有個私有方法能將文件保存在內(nèi)部存儲)访锻,而調(diào)用系統(tǒng)的接口更新升級時褪尝,recovery模式下系統(tǒng)文件路徑會重定向闹获,此時無法找到原來保存在外部存儲的文件。所以為了保證能正常安裝河哑,下載好的更新文件要保存到內(nèi)部存儲中避诽。

將更新文件從外部存儲拷貝到/data/recovery/ota.zip路徑下,這里使用了第三方庫 RootTools璃谨,能夠以命令行的方式沙庐,將文件從源目錄拷貝到指定目錄。

因為要對內(nèi)部存儲進行讀寫佳吞,所以記得加上對應(yīng)的權(quán)限

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

安裝更新的函數(shù)具體實現(xiàn)

public static boolean installOtaPackageAuto(final Context context, File file) {

    String internalPath = "/data/recovery/ota.zip";
    String cmd = "cat " + file.getAbsolutePath() + " > " + internalPath;

    String res = Tools.shell(cmd, false);
    Log.i(TAG, "shell: " + res);

    File otaPackageFile = new File(internalPath);

    try {
        RecoverySystem.verifyPackage(otaPackageFile , null , null);
    }
    catch ( IOException e ) {
        ((HDUpdateActivity)context).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "RecoverySystem verifyPackage failed, file doesn't exist", Toast.LENGTH_LONG).show();
            }
        });
        e.printStackTrace( );
        return false;
    }
    catch ( GeneralSecurityException e ) {
        ((HDUpdateActivity)context).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "RecoverySystem verifyPackage failed, invalid package", Toast.LENGTH_LONG).show();
            }
        });
        e.printStackTrace( );
        return false;
    }

    try {
        RecoverySystem.installPackage( context , otaPackageFile );
    }
    catch ( IOException e ) {
        ((HDUpdateActivity)context).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "RecoverySystem installPackage error, failed to install", Toast.LENGTH_LONG).show();
            }
        });
        e.printStackTrace( );
        return false;
    }
    return true;
}

傳入的參數(shù) fileDownloadManager已經(jīng)下載到外部存儲的OTA更新文件拱雏,通過執(zhí)行cat命令,將更新文件保存到內(nèi)部存儲/data/recovery/ota.zip

String internalPath = "/data/recovery/ota.zip";
String cmd = "cat " + file.getAbsolutePath() + " > " + internalPath;

String res = Tools.shell(cmd, false);

調(diào)用了系統(tǒng)方法verifyPackage驗證更新包是否合法底扳,若驗證失敗則安裝過程終止

RecoverySystem.verifyPackage(otaPackageFile , null , null);

接下來直接調(diào)用系統(tǒng)安裝更新的方法

RecoverySystem.installPackage( context , otaPackageFile );

若成功則設(shè)備重啟古涧,并進入recovery模式更新升級,升級完成后設(shè)備重啟花盐。

制作差分包

MTK系統(tǒng)的目錄

1.jpg

可以看到每次通過make命令編譯后生成的image文件既是 SP Flash Tool 燒錄需要用到的固件。

ota打包

make otapackage

打包完成后命令行打印的結(jié)果

2.jpg

這里有兩個文件需要注意的菇爪,一個在out/target/product/CM01B目錄下算芯,一個在out/target/product/CM01B/obj/PACKAGING/target_files_intermediates目錄下(CM01B為產(chǎn)品編號,每個項目不一樣)凳宙,雖然文件名一樣熙揍,但前者有400多M,后者800多M氏涩,和image固件大小差不多届囚。

out/target/product/CM01B目錄下的文件為完全更新的包,可以用來給系統(tǒng)進行完全升級是尖。

out/target/product/CM01B/obj/PACKAGING/target_files_intermediates目錄下的文件主要用來生成差分包(具體能不能直接用來升級沒嘗試過)意系,通過兩個這種包可以生成差分包文件。

系統(tǒng)生成差分包的工具在這個位置饺汹,官方標(biāo)準(zhǔn)工具蛔添,里面包含了制作差分包的腳本

3.jpg

這里需要注意,執(zhí)行差分包命令時必須在根目錄下執(zhí)行兜辞,因為腳本里面寫定了相對路徑的引用文件迎瞧。

制作差分包需要準(zhǔn)備兩個不同版本的文件(out/target/product/CM01B/obj/PACKAGING/target_files_intermediates目錄下的),假設(shè)分別為a.zipb.zip

將兩個文件拷貝到根目錄下逸吵,然后運行命令

./build/tools/releasetools/ota_from_target_files -i a.zip b.zip ota.zip

最終生成的差分包文件為ota.zip凶硅,即b相對于a修改了的內(nèi)容,只能用在a上將a升級成b扫皱。ota.zip差分包的升級使用要求當(dāng)前系統(tǒng)必須是a足绅,否則無法進行升級捷绑。

系統(tǒng)升級

系統(tǒng)通過差分包升級,安裝時進入刷機界面编检,完成后自動重啟胎食,升級完成

4.jpg

如果差分包有不正確或者沒保存到內(nèi)部存儲中會報錯

5.jpg

以上

源碼和設(shè)備相關(guān)聯(lián)的,這次就不給了允懂。完厕怜。:)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蕾总,隨后出現(xiàn)的幾起案子粥航,更是在濱河造成了極大的恐慌,老刑警劉巖生百,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件递雀,死亡現(xiàn)場離奇詭異,居然都是意外死亡蚀浆,警方通過查閱死者的電腦和手機缀程,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來市俊,“玉大人杨凑,你說我怎么就攤上這事“诿粒” “怎么了撩满?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長绅你。 經(jīng)常有香客問我伺帘,道長,這世上最難降的妖魔是什么忌锯? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任伪嫁,我火速辦了婚禮,結(jié)果婚禮上偶垮,老公的妹妹穿的比我還像新娘礼殊。我一直安慰自己,他們只是感情好针史,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布晶伦。 她就那樣靜靜地躺著,像睡著了一般啄枕。 火紅的嫁衣襯著肌膚如雪婚陪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天频祝,我揣著相機與錄音泌参,去河邊找鬼脆淹。 笑死,一個胖子當(dāng)著我的面吹牛沽一,可吹牛的內(nèi)容都是我干的盖溺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铣缠,長吁一口氣:“原來是場噩夢啊……” “哼烘嘱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝗蛙,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蝇庭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后捡硅,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體哮内,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年壮韭,在試婚紗的時候發(fā)現(xiàn)自己被綠了北发。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡喷屋,死狀恐怖鲫竞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逼蒙,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布寄疏,位于F島的核電站是牢,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏陕截。R本人自食惡果不足惜驳棱,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望农曲。 院中可真熱鬧社搅,春花似錦、人聲如沸乳规。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽暮的。三九已至笙以,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冻辩,已是汗流浹背猖腕。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工拆祈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人倘感。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓放坏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親老玛。 傳聞我的和親對象是個殘疾皇子淤年,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,116評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)逻炊,斷路器互亮,智...
    卡卡羅2017閱讀 134,656評論 18 139
  • 原文鏈接 Android應(yīng)用經(jīng)常會內(nèi)置檢測版本更新的功能,在有版本更新的時候余素,通過下載更新文件進行本地的升級豹休。本文...
    msq3閱讀 10,752評論 0 19
  • 【作者】唐志燕 【指導(dǎo)老師】劉艷老師 【內(nèi)容解說】這是金庫老師今天給家長上的V導(dǎo)師課程筆記。 主要講了兩個板塊的內(nèi)...
    靜心和閱讀 190評論 0 0
  • 春來花香 雨來草長 晨來鳥唱 花香四溢只春一季 草長鶯飛皆因潤雨 鳥聲歡啼以慰晨意 我一心一念獨為等你 你來我喜 ...
    笨笨的平凡生活閱讀 170評論 0 0