Android OTA版本更新流程記錄

主要文件說(shuō)明

  • MainEntry : 主界面
  • SystemUpdateService:版本檢測(cè)服務(wù)蔗喂,
  • SessionStateControlThread:去執(zhí)行檢測(cè)和下載的線程忘渔;
  • HttpManager:網(wǎng)絡(luò)請(qǐng)求的發(fā)起和數(shù)據(jù)解析,版本檢測(cè)狀態(tài)通知的發(fā)出者
  • OtaPkgManagerActivity:顯示版本狀態(tài)缰儿,下載和安裝的入口
  • DownloadInfo 狀態(tài)的保存與查詢接口
  • SystemUpdateRecever 廣播接收器畦粮,開機(jī)自動(dòng)檢測(cè)版本等

主要流程

MainEntry 在啟動(dòng)時(shí)綁定服務(wù),并調(diào)用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 啟動(dòng)線程去執(zhí)行版本的檢查,


QQ圖片20170215163851.png

SessionControlThread 的執(zhí)行方法如下乖阵,它負(fù)責(zé)查詢和下載的具體任務(wù)宣赔。


QQ圖片20170215164221.png

查詢線程啟動(dòng)HttpManager 中的查詢接口checkNewVersion,訪問(wèn)OTA服務(wù)器瞪浸,并對(duì)查詢結(jié)果進(jìn)行解析儒将,如果有新版本信息,就會(huì)更新DownloadInfo中的狀態(tài)值对蒲,然后發(fā)送查詢結(jié)束的廣播钩蚊。


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());
      ...解析服務(wù)器返回的數(shù)據(jù)
        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 發(fā)送查詢結(jié)束的廣播后,EntryActivity 收到此廣播蹈矮,更新UI,顯示由新版本砰逻。

private Handler mUiHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
       ...
        case SystemUpdateService.MSG_NOTIFY_QUERY_DONE:

            processOtaBehavior();

            break;

刷新界面,跳轉(zhuǎn)到OtaPkgManagerActivity含滴,此時(shí)顯示界面上的更新記錄和下載按鈕诱渤,點(diǎn)擊下載按鈕后丐巫,

    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一啟動(dòng)谈况,就會(huì)根據(jù)DownloadInfo中的狀態(tài)值來(lái)顯示相應(yīng)的界面和進(jìn)行相應(yīng)的處理。上一步查詢到有新版本的時(shí)候递胧,已經(jīng)把狀態(tài)設(shè)置為STATE_NEWVERSION_READY了碑韵,這里就會(huì)顯示下載按鈕。下載的動(dòng)作又會(huì)回到SystemUpdateService中的 startDlPkg()接口缎脾,啟動(dòng)一個(gè)SessionControlThread 進(jìn)行下載祝闻,下載的網(wǎng)絡(luò)處理還是由HttpManager 來(lái)處理,實(shí)際操作在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;
}

在下載完成后進(jìn)行包的解壓和校驗(yàn)工作,成功后進(jìn)入安裝步驟联喘,安裝時(shí)啟動(dòng)的另外一個(gè)App中的服務(wù)华蜒,然后重啟系統(tǒng),進(jìn)入recovery模式豁遭,完成系統(tǒng)升級(jí)叭喜。

     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中會(huì)接收系統(tǒng)開機(jī)廣播蓖谢,并判斷是周幾捂蕴,然后根據(jù)util中的配置信息,自動(dòng)檢測(cè)版本闪幽。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末啥辨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子盯腌,更是在濱河造成了極大的恐慌溉知,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腕够,死亡現(xiàn)場(chǎng)離奇詭異着倾,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)燕少,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門卡者,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人客们,你說(shuō)我怎么就攤上這事崇决。” “怎么了底挫?”我有些...
    開封第一講書人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵恒傻,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我建邓,道長(zhǎng)盈厘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任官边,我火速辦了婚禮沸手,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘注簿。我一直安慰自己契吉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開白布诡渴。 她就那樣靜靜地躺著捐晶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惑灵,一...
    開封第一講書人閱讀 51,482評(píng)論 1 302
  • 那天山上,我揣著相機(jī)與錄音,去河邊找鬼英支。 笑死胶哲,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潭辈。 我是一名探鬼主播鸯屿,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼把敢!你這毒婦竟也來(lái)了寄摆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤修赞,失蹤者是張志新(化名)和其女友劉穎婶恼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體柏副,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勾邦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了割择。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片眷篇。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖荔泳,靈堂內(nèi)的尸體忽然破棺而出蕉饼,到底是詐尸還是另有隱情,我是刑警寧澤玛歌,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布昧港,位于F島的核電站,受9級(jí)特大地震影響支子,放射性物質(zhì)發(fā)生泄漏创肥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一值朋、第九天 我趴在偏房一處隱蔽的房頂上張望叹侄。 院中可真熱鬧,春花似錦吞歼、人聲如沸圈膏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春糯俗,著一層夾襖步出監(jiān)牢的瞬間尿褪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工得湘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留杖玲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓淘正,卻偏偏與公主長(zhǎng)得像摆马,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸿吆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,117評(píng)論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理囤采,服務(wù)發(fā)現(xiàn),斷路器惩淳,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 國(guó)家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說(shuō)閱讀 10,967評(píng)論 6 13
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)蕉毯、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,103評(píng)論 4 62
  • 人們都是在面對(duì)對(duì)手時(shí)思犁,才會(huì)緊張一段感情代虾,情敵的出現(xiàn)告訴你這段感情該重視了。有的時(shí)候也許是倦怠激蹲,逃離現(xiàn)在的世界棉磨,到圍...
    Ruru鳳閱讀 571評(píng)論 0 0