主要文件說明
- MainEntry : 主界面
- SystemUpdateService:版本檢測服務,
- SessionStateControlThread:去執行檢測和下載的線程;
- HttpManager:網絡請求的發起和數據解析,版本檢測狀態通知的發出者
- OtaPkgManagerActivity:顯示版本狀態,下載和安裝的入口
- DownloadInfo 狀態的保存與查詢接口
- SystemUpdateRecever 廣播接收器,開機自動檢測版本等
主要流程
MainEntry 在啟動時綁定服務,并調用SystemUpdateService 的版本查詢接口
@Override
protected void onStart()
{
...
if (activityId < 0) {
SdPkgInstallActivity.stopSelf();
OtaPkgManagerActivity.stopSelf();
Intent serviceIntent = new Intent(this, SystemUpdateService.class);
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE);
} }
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = ((SystemUpdateService.ServiceBinder) service).getService();
if (mService != null) {
mService.setHandler(mUiHandler);
}
boolean needRescan = mDownloadInfo.getIfNeedRefresh();
if (needRescan
|| (!loadHistoryPackage()
&& DownloadInfo.STATE_NEWVERSION_READY
!= mDownloadInfo.getDLSessionStatus())) {
queryPackagesInternal();
} else {
Xlog.d(TAG, "[onServiceConnected], DON'T need query, load from file");
refreshUI();
}
}
};
private void queryPackagesInternal() {
...
if (mService != null) {
mService.queryPackages();
}
}
SystemUpdateServcie 啟動線程去執行版本的檢查,
QQ圖片20170215163851.png
SessionControlThread 的執行方法如下,它負責查詢和下載的具體任務。
QQ圖片20170215164221.png
查詢線程啟動HttpManager 中的查詢接口checkNewVersion,訪問OTA服務器,并對查詢結果進行解析,如果有新版本信息,就會更新DownloadInfo中的狀態值,然后發送查詢結束的廣播。
queryNewVersion.png
private boolean checkNewVersion() {
...
HttpResponse response = doPost(url, null, bnvpa);
if (response == null) {
Xlog.i(TAG, "onCheckNewVersion: response = null");
mErrorCode = HTTP_UNKNOWN_ERROR;
return false;
}
StatusLine status = response.getStatusLine();
...
String content = getChunkedContent(response.getEntity());
...解析服務器返回的數據
HttpResponseContent res = parseCheckVersionInfo(content);
if (res == null) {
return false;
}
if (res.mFileSize <= 0 || res.mPkgId < 0) {
mErrorCode = HTTP_RESPONSE_NO_NEW_VERSION;
Xlog.i(TAG, "onCheckNewVersion, fileSize = " + res.mFileSize + ", deltaId = "
+ res.mPkgId);
return false;
}
if ((!res.mIsFullPkg) && (!checkFingerPrint(res.mFingerprint))) {
mErrorCode = HTTP_RESPONSE_NO_NEW_VERSION;
return false;
}
mDownloadInfo.setDLSessionDeltaId(res.mPkgId);
mDownloadInfo.setFullPkgFlag(res.mIsFullPkg);
mDownloadInfo.setUpdateImageSize(res.mFileSize);
mDownloadInfo.setVersionNote(res.mReleaseNote);
mDownloadInfo.setVerNum(res.mVersionName);
mDownloadInfo.setAndroidNum(res.mAndroidNum);
mDownloadInfo.setDLSessionStatus(DownloadInfo.STATE_NEWVERSION_READY);
return true;
} catch (IOException e) {
e.printStackTrace();
mErrorCode = HTTP_RESPONSE_AUTHEN_ERROR;
return false;
}
}
HttpMangager 發送查詢結束的廣播后,EntryActivity 收到此廣播,更新UI,顯示由新版本。
private Handler mUiHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case SystemUpdateService.MSG_NOTIFY_QUERY_DONE:
processOtaBehavior();
break;
刷新界面,跳轉到OtaPkgManagerActivity,此時顯示界面上的更新記錄和下載按鈕,點擊下載按鈕后,
private void refreshUI() {
int size = (mUpdateInfoList == null) ? 0 : mUpdateInfoList.size();
mParentPreference.removeAll();
boolean isOtaExist = isOtaPackageExist();
if (isOtaExist || size > 0) {
mIsFoundNewVersion = true;
if (mIsStopping && mIsQuerying) {
Xlog.v(TAG, "[refreshUI] is stopping, show notification instead");
mNotification.showNewVersionNotification();
mIsFoundNewVersion = false;
return;
}
mIsQuerying = false;
}
if (isOtaExist) {
if (size == 0) {
Xlog.v(TAG, "[refreshUI] Only OTA package exists, start OTA detail");
Intent intent = getInfoIntent(null);
mIsTurnToDetail = true;
startActivity(intent);
finish();
return;
}
在OtaPackageManagerActivity一啟動,就會根據DownloadInfo中的狀態值來顯示相應的界面和進行相應的處理。上一步查詢到有新版本的時候,已經把狀態設置為STATE_NEWVERSION_READY了,這里就會顯示下載按鈕。下載的動作又會回到SystemUpdateService中的 startDlPkg()接口,啟動一個SessionControlThread 進行下載,下載的網絡處理還是由HttpManager 來處理,實際操作在onDownloadImage()中
private void showUILayout(int state) {
switch (state) {
case DownloadInfo.STATE_QUERYNEWVERSION:
requeryPackages();
break;
case DownloadInfo.STATE_NEWVERSION_READY:
setContentView(R.layout.ota_package_download);
mDownloadBtn = (Button) this.findViewById(R.id.btn_download);
mDownloadBtn.setText(R.string.btn_download);
mDownloadBtn.setOnClickListener(mDlListener);
removeProBar();
mMenuStatus = MenuStatus.Menu_Download;
invalidateOptionsMenu();
initWifiOnlyCheckbox(true, true);
fillPkgInfo(mDownloadInfo.getAndroidNum(), mDownloadInfo.getVerNum(), mDownloadInfo.getUpdateImageSize(),
Util.getPackageFileName(this));
break;
case DownloadInfo.STATE_DOWNLOADING:
showDlInterface();
break;
void onDownloadImage() {
mNotification.showDownloadingNotificaton(mDownloadInfo.getVerNum(), (int) (((double) Util
.getFileSize(Util
.getPackageFileName(mContext)) / (double) mDownloadInfo
.getUpdateImageSize()) * 100), true);
if (mIsDownloading) {
return;
}
mIsDownloading = true;
notifyDlStarted();
boolean isunzip = mDownloadInfo.getDLSessionUnzipState();
boolean isren = mDownloadInfo.getDLSessionRenameState();
if (isren && isunzip) {
setNotDownload();
UpgradePkgManager.deleteCrashPkgFile(Util.getPackagePathName(mContext));
onDownloadPackageUnzipAndCheck();
return;
}
mDownloadInfo.setDLSessionStatus(DownloadInfo.STATE_DOWNLOADING);
String strNetWorkType = mDownloadInfo.getIfWifiDLOnly() ? NETTYPE_WIFI : "";
if (!Util.isNetWorkAvailable(mContext, strNetWorkType)) {
mErrorCode = HTTP_RESPONSE_NETWORK_ERROR;
sendErrorMessage();
setPauseState();
setNotDownload();
return;
}
HttpResponse response = doPost(url, null, bnvpa);
if (mDownloadInfo.getDLSessionStatus() != DownloadInfo.STATE_DOWNLOADING) {
Xlog.i(TAG, "onDownloadImage: status not right");
setNotDownload();
return;
}
...
StatusLine status = response.getStatusLine();
Intent service = new Intent(mContext, SystemUpdateService.class);
service.setAction(Util.Action.ACTION_LCA_PROTECT);
mContext.startService(service);
int ret = writeFile(response, currentSize);
mContext.stopService(service);
// Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
Xlog.i(TAG, "onDownloadImage, download result = " + ret);
if (ret == 0) {
int downloadStatus = mDownloadInfo.getDLSessionStatus();
if (downloadStatus == DownloadInfo.STATE_PAUSEDOWNLOAD
|| downloadStatus == DownloadInfo.STATE_QUERYNEWVERSION) {
setNotDownload();
return;
}
}
if (ret == HTTP_DETECTED_SDCARD_CRASH_OR_UNMOUNT) {
// resetDescriptionInfo();
resetDownloadFile();
sendErrorMessage();
setNotDownload();
return;
}
if (ret == HTTP_RESPONSE_NETWORK_ERROR) {
setNotDownload();
checkIfAutoDl();
return;
}
if (ret == HTTP_FILE_NOT_EXIST) {
setNotDownload();
return;
}
onDownloadPackageUnzipAndCheck();
mIsDownloading = false;
}
在下載完成后進行包的解壓和校驗工作,成功后進入安裝步驟,安裝時啟動的另外一個App中的服務,然后重啟系統,進入recovery模式,完成系統升級。
class InstallPkgThread extends Thread {
/**
* Main executing function of this thread.
*/
public void run() {
if (checkUpgradePackage() && setInstallInfo(mPkgPath, mTarVer)) {
notifyUserInstall();
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.mediatek.systemupdate.sysoper",
"com.mediatek.systemupdate.sysoper.RebootRecoveryService"));
startService(intent);
} else {
return;
}
}
}
private boolean setInstallInfo(String strPkgPath, String strTarVer) {
Xlog.i(TAG, "onSetRebootRecoveryFlag");
try {
IBinder binder = ServiceManager.getService("GoogleOtaBinder");
SystemUpdateBinder agent = SystemUpdateBinder.Stub.asInterface(binder);
if (agent == null) {
Xlog.e(TAG, "agent is null");
return false;
}
if (Util.isEmmcSupport()) {
if (!agent.clearUpdateResult()) {
Xlog.e(TAG, "clearUpdateResult() false");
return false;
}
}
DownloadInfo dlInfo = DownloadInfo.getInstance(getApplicationContext());
dlInfo.setTargetVer(strTarVer);
Xlog.i(TAG, "setTargetVer");
if (!agent.setRebootFlag()) {
Xlog.e(TAG, "setRebootFlag() false");
return false;
}
Xlog.i(TAG, "setRebootFlag");
dlInfo.setUpgradeStartedState(true);
dlInfo.resetDownloadInfo();
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.mediatek.systemupdate.sysoper",
"com.mediatek.systemupdate.sysoper.WriteCommandService"));
intent.putExtra(COMMAND_PART2, OTA_PATH_IN_RECOVERY_PRE + strPkgPath);
startService(intent);
return true;
} catch (RemoteException e) {
e.printStackTrace();
return false;
}
}
其中,在SystemUpdateRecever中會接收系統開機廣播,并判斷是周幾,然后根據util中的配置信息,自動檢測版本。