Android OTA版本更新流程记录
2017-02-15 本文已影响179人
星海2017
主要文件说明
- 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中的配置信息,自动检测版本。