上一篇說了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)升級流程
- 向服務(wù)器請求系統(tǒng)更新信息辕宏;
- 獲取到返回信息后,判斷是否有更新版本砾莱,若有更新瑞筐,進入步驟3;
- 下載服務(wù)器對應(yīng)的更新文件恤磷;
- 下載完成后驗證更新文件面哼;
- 系統(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ù) file 為DownloadManager已經(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)的目錄
可以看到每次通過make命令編譯后生成的image文件既是 SP Flash Tool 燒錄需要用到的固件。
ota打包
make otapackage
打包完成后命令行打印的結(jié)果
這里有兩個文件需要注意的菇爪,一個在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)工具蛔添,里面包含了制作差分包的腳本
這里需要注意,執(zhí)行差分包命令時必須在根目錄下執(zhí)行兜辞,因為腳本里面寫定了相對路徑的引用文件迎瞧。
制作差分包需要準(zhǔn)備兩個不同版本的文件(out/target/product/CM01B/obj/PACKAGING/target_files_intermediates目錄下的),假設(shè)分別為a.zip和b.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)通過差分包升級,安裝時進入刷機界面编检,完成后自動重啟胎食,升級完成
如果差分包有不正確或者沒保存到內(nèi)部存儲中會報錯
以上
源碼和設(shè)備相關(guān)聯(lián)的,這次就不給了允懂。完厕怜。:)