Android源碼有車機系統升級的demo app:SystemUpdater,使用原生settings UI畫面。該應用可用于理解應用層同系統層進行交互,觸發完成升級的邏輯流程。
該demo app是專用于汽車升級的示例apk,源碼路徑:packages/apps/Car/SystemUpdater
android/packages/apps/Car/SystemUpdater$ tree.├── AndroidManifest.xml├── Android.mk├── PREUPLOAD.cfg├── res│?? ├── .....└── src └── com └── android └── car └── systemupdater ├── DeviceListFragment.java ├── SystemUpdaterActivity.java ├── UpdateLayoutFragment.java ├── UpdateParser.java └── UpFragment.java
LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optional# 模塊src路徑加載LOCAL_SRC_FILES := $(call all-java-files-under, src)# 資源加載LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res# 定義該應用是platform appLOCAL_CERTIFICATE := platform# APP名稱LOCAL_PACKAGE_NAME := SystemUpdaterLOCAL_PRIVATE_PLATFORM_APIS := true# 是否預編譯LOCAL_DEX_PREOPT := false# 此常量為是否使用aapt2LOCAL_USE_AAPT2 := true# 控制是否開啟proguard,默認值為fullLOCAL_PROGUARD_ENABLED := disabledLOCAL_DX_FLAGS := --multi-dex# This module depends on androidx.car_car for legacy reasons.# Don't copy-paste the use of androidx.car_car# 依賴庫LOCAL_STATIC_ANDROID_LIBRARIES := androidx.car_car androidx.legacy_legacy-support-v4 androidx.appcompat_appcompatinclude $(BUILD_PACKAGE)
<!-- 包名 --><manifest xmlns:andro package="com.android.car.systemupdater"><!-- 應用外部存儲讀寫權限、重啟權限、usb權限 --> <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.REBOOT" /> <uses-feature android:name="android.hardware.usb.host" /><!-- 使用settings主題歌和標題目錄 --> <application android:label="@string/title" android:theme="@style/SystemUpdaterTheme"> <activity android:name="com.android.car.systemupdater.SystemUpdaterActivity" android:label="@string/title"> <intent-filter> <action android:name="android.intent.action.MAIN" /> </intent-filter> <intent-filter> <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> </intent-filter> <intent-filter> <action android:name="com.android.settings.action.EXTRA_SETTINGS" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <meta-data android:name="com.android.settings.title" android:resource="@string/title" /> <meta-data android:name="com.android.settings.icon" android:resource="@drawable/ic_system_update_alt_black_48dp" /> <meta-data android:name="com.android.settings.category" android:value="com.android.settings.category.ia.system" /> </activity> </application></manifest>
//packages/apps/Car/SystemUpdater/src/com/android/car/systemupdater/SystemUpdaterActivity.javapublic class SystemUpdaterActivity extends AppCompatActivity implements DeviceListFragment.SystemUpdater { private static final String FRAGMENT_TAG = "FRAGMENT_TAG"; private static final int STORAGE_PERMISSIONS_REQUEST_CODE = 0; //權限 private static final String[] REQUIRED_STORAGE_PERMISSIONS = new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.WRITE_MEDIA_STORAGE }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //check 權限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, REQUIRED_STORAGE_PERMISSIONS, STORAGE_PERMISSIONS_REQUEST_CODE); } setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); if (savedInstanceState == null) { Bundle intentExtras = getIntent().getExtras(); if (intentExtras != null && intentExtras.getBoolean(EXTRA_RESUME_UPDATE)) { //創建UpdateLayoutFragment對象,調用newResumedInstance UpdateLayoutFragment fragment = UpdateLayoutFragment.newResumedInstance(); getSupportFragmentManager().beginTransaction() .replace(R.id.device_container, fragment, FRAGMENT_TAG) .commitNow(); } else { //創建DeviceListFragment對象 DeviceListFragment fragment = new DeviceListFragment(); getSupportFragmentManager().beginTransaction() .replace(R.id.device_container, fragment, FRAGMENT_TAG) .commitNow(); } } } .....
(1) DeviceListFragment.java - onCreate
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Context context = getContext(); mItemProvider = new FileItemProvider(context); mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE); if (mStorageManager == null) { if (Log.isLoggable(TAG, Log.WARN)) { Log.w(TAG, "Failed to get StorageManager"); } Toast.makeText(context, R.string.cannot_access_storage, Toast.LENGTH_LONG).show(); return; } }
(2)調用get(int position)
函數
(3)調用onFileSelected(File file)
選中的升級包文件
(4)如果升級包存在,則調用mSystemUpdater.applyUpdate(file)
,該接口由SystemUpdaterActivity實現
//DeviceListFragment.java /** Used to request installation of an update. */ interface SystemUpdater { /** Attempt to apply an update to the device contained in the {@code file}. */ void applyUpdate(File file); }
(5)SystemUpdaterActivity.java - applyUpdate,獲取UpdateLayoutFragment對象,傳入升級路徑
@Override public void applyUpdate(File file) { //new UpdateLayoutFragment()對象 //new Bundle對象 UpdateLayoutFragment fragment = UpdateLayoutFragment.getInstance(file); getSupportFragmentManager().beginTransaction() .replace(R.id.device_container, fragment, FRAGMENT_TAG) .addToBackStack(null) .commit(); }
(6)調用UpdateLayoutFragment.java - onActivityCreated,然后調用mPackageVerifier.execute(mUpdateFile)
@Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ..... if (getArguments().getBoolean(EXTRA_RESUME_UPDATE)) { //顯示install進度 showInstallationInProgress(); } else { //執行必要的步驟開始升級 mPackageVerifier.execute(mUpdateFile); } }
//UpdateLayoutFragment.java//該類繼承AsyncTask//嘗試驗證更新并提取安裝所需的信息 private class UpdateVerifier extends AsyncTask<File, Void, UpdateParser.ParsedUpdate> { @Override protected UpdateParser.ParsedUpdate doInBackground(File... files) { Preconditions.checkArgument(files.length > 0, "No file specified"); File file = files[0]; try { //調用UpdateParser.java的parse解析升級包文件 return UpdateParser.parse(file); } catch (IOException e) { Log.e(TAG, String.format("For file %s", file), e); return null; } } @Override protected void onPostExecute(UpdateParser.ParsedUpdate result) { mProgressBar.setVisibility(View.GONE); if (result == null) { showStatus(R.string.verify_failure); return; } if (!result.isValid()) { showStatus(R.string.verify_failure); Log.e(TAG, String.format("Failed verification %s", result)); return; } if (Log.isLoggable(TAG, Log.INFO)) { Log.i(TAG, result.toString()); } //調用installUpdate,然后調用mUpdateEngine.applyPayload傳入升級所需要的url,偏移量,大小等開始升級 showInstallNow(result); } }
//packages/apps/Car/SystemUpdater/src/com/android/car/systemupdater/UpdateParser.java static ParsedUpdate parse(@NonNull File file) throws IOException { Preconditions.checkNotNull(file); long payloadOffset = 0; long payloadSize = 0; boolean payloadFound = false; String[] props = null; try (ZipFile zipFile = new ZipFile(file)) { Enumeration<? extends ZipEntry> entries = zipFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); long fileSize = entry.getCompressedSize(); if (!payloadFound) { payloadOffset += ZIP_FILE_HEADER + entry.getName().length(); if (entry.getExtra() != null) { payloadOffset += entry.getExtra().length; } } if (entry.isDirectory()) { continue; } else if (entry.getName().equals(PAYLOAD_BIN_FILE)) { payloadSize = fileSize; //payload.bin升級數據文件的大小 payloadFound = true; } else if (entry.getName().equals(PAYLOAD_PROPERTIES)) { try (BufferedReader buffer = new BufferedReader( new InputStreamReader(zipFile.getInputStream(entry)))) { props = buffer.lines().toArray(String[]::new); //hash值 } } if (!payloadFound) { payloadOffset += fileSize; //偏移量 } if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, String.format("Entry %s", entry.getName())); } } } //內部靜態類 return new ParsedUpdate(file, payloadOffset, payloadSize, props); }
調用framework java應用層的接口
//frameworks/base/core/java/android/os/UpdateEngine.java private IUpdateEngine mUpdateEngine; private IUpdateEngineCallback mUpdateEngineCallback = null; private final Object mUpdateEngineCallbackLock = new Object(); public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) { try { mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
//packages/apps/Car/SystemUpdater/src/com/android/car/systemupdater/UpdateLayoutFragment.java private ProgressBar mProgressBar; //升級進度 private File mUpdateFile; //升級包文件 private Button mSystemUpdateToolbarAction; //PowerManager對象,用于重啟 private PowerManager mPowerManager; private NotificationManager mNotificationManager; private final UpdateVerifier mPackageVerifier = new UpdateVerifier(); //創建UpdateEngine對象 private final UpdateEngine mUpdateEngine = new UpdateEngine(); private boolean mInstallationInProgress = false; //新建對象 private final CarUpdateEngineCallback mCarUpdateEngineCallback = new CarUpdateEngineCallback(); ...//UpdateLayoutFragment.java的onPostExecute函數調用 /** Show the install now button. */ private void showInstallNow(UpdateParser.ParsedUpdate update) { mContentTitle.setText(R.string.install_ready); mContentInfo.append(getString(R.string.update_file_name, mUpdateFile.getName())); mContentInfo.append(System.getProperty("line.separator")); mContentInfo.append(getString(R.string.update_file_size)); mContentInfo.append(Formatter.formatFileSize(getContext(), mUpdateFile.length())); mContentDetails.setText(null); //調用installUpdate mSystemUpdateToolbarAction.setOnClickListener(v -> installUpdate(update)); ... } /** Attempt to install the update that is copied to the device. */ private void installUpdate(UpdateParser.ParsedUpdate parsedUpdate) { //調用showInstallationInProgress showInstallationInProgress(); //調用applyPayload mUpdateEngine.applyPayload( parsedUpdate.mUrl, parsedUpdate.mOffset, parsedUpdate.mSize, parsedUpdate.mProps); } //綁定UpdateEngine,并且顯示進度 /** Set the layout to show installation progress. */ private void showInstallationInProgress() { mInstallationInProgress = true; mProgressBar.setIndeterminate(false); mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setMax(PERCENT_MAX); mSystemUpdateToolbarAction.setVisibility(View.GONE); showStatus(R.string.install_in_progress); //CarUpdateEngineCallback回調函數調用 mUpdateEngine.bind(mCarUpdateEngineCallback, new Handler(getContext().getMainLooper())); }
frameworks/base/core/java/android/os/UpdateEngine.java - UpdateStatusConstants
(抽取system/update_engine/client_library/include/update_engine/update_status.h
數據)frameworks/base/core/java/android/os/UpdateEngine.java - ErrorCodeConstants
(抽取system/update_engine/common/error_code.h
部分)//UpdateLayoutFragment.java public class CarUpdateEngineCallback extends UpdateEngineCallback { @Override //升級狀態碼和進度接收 public void onStatusUpdate(int status, float percent) { if (Log.isLoggable(TAG, Log.DEBUG)) { Log.d(TAG, String.format("onStatusUpdate %d, Percent %.2f", status, percent)); } switch (status) { //UpdateStatusConstants升級狀態碼見frameworks/base/core/java/android/os/UpdateEngine.java case UpdateEngine.UpdateStatusConstants.UPDATED_NEED_REBOOT: rebootNow(); break; case UpdateEngine.UpdateStatusConstants.DOWNLOADING: mProgressBar.setProgress((int) (percent * 100)); break; default: // noop } } @Override //升級結果接收 public void onPayloadApplicationComplete(int errorCode) { Log.w(TAG, String.format("onPayloadApplicationComplete %d", errorCode)); mInstallationInProgress = false; //錯誤碼見frameworks/base/core/java/android/os/UpdateEngine.java的ErrorCodeConstants集合定義 showStatus(errorCode == UpdateEngine.ErrorCodeConstants.SUCCESS ? R.string.install_success : R.string.install_failed); mProgressBar.setVisibility(View.GONE); mSystemUpdateToolbarAction.setVisibility(View.GONE); } }
重啟接口調用:
private void rebootNow() { if (Log.isLoggable(TAG, Log.INFO)) { Log.i(TAG, "Rebooting Now."); } mPowerManager.reboot(REBOOT_REASON); }
//frameworks/base/core/java/android/os/UpdateEngine.java /** * Status codes for update engine. Values must agree with the ones in * {@code system/update_engine/client_library/include/update_engine/update_status.h}. */ public static final class UpdateStatusConstants { //IDLE狀態 public static final int IDLE = 0; //update engine服務檢查升級 public static final int CHECKING_FOR_UPDATE = 1; //存在可獲取的升級 public static final int UPDATE_AVAILABLE = 2; //downloading下載步驟狀態 public static final int DOWNLOADING = 3; //update engine正在校驗狀態 public static final int VERIFYING = 4; //update engine正在完成一個升級 public static final int FINALIZING = 5; //請求重啟(一般是升級成功) public static final int UPDATED_NEED_REBOOT = 6; //update egnine上報一個錯誤事件 public static final int REPORTING_ERROR_EVENT = 7; //update engine試圖恢復一個升級(可能升級被中斷過) public static final int ATTEMPTING_ROLLBACK = 8; //update engine處于被禁止狀態 public static final int DISABLED = 9; }
//frameworks/base/core/java/android/os/UpdateEngine.java /** * Error codes from update engine upon finishing a call to * {@link applyPayload}. Values will be passed via the callback function * {@link UpdateEngineCallback#onPayloadApplicationComplete}. Values must * agree with the ones in {@code system/update_engine/common/error_code.h}. */ public static final class ErrorCodeConstants { //升級成功 public static final int SUCCESS = 0; //升級失敗 public static final int ERROR = 1; //文件系統拷貝失敗 public static final int FILESYSTEM_COPIER_ERROR = 4; /** * Error code: an update failed to apply due to an error in running * post-install hooks. */ //post-install運行時報錯 public static final int POST_INSTALL_RUNNER_ERROR = 5; /** * Error code: an update failed to apply due to a mismatching payload. * * <p>For example, the given payload uses a feature that's not * supported by the current update engine. */ public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6; /** * Error code: an update failed to apply due to an error in opening * devices. */ public static final int INSTALL_DEVICE_OPEN_ERROR = 7; /** * Error code: an update failed to apply due to an error in opening * kernel device. */ public static final int KERNEL_DEVICE_OPEN_ERROR = 8; /** * Error code: an update failed to apply due to an error in fetching * the payload. * * <p>For example, this could be a result of bad network connection * when streaming an update. */ //download傳輸報錯,比如U盤升級download時拔出U盤 public static final int DOWNLOAD_TRANSFER_ERROR = 9; /** * Error code: an update failed to apply due to a mismatch in payload * hash. * * <p>update engine does sanity checks for the given payload and its * metadata. */ public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10; /** * Error code: an update failed to apply due to a mismatch in payload * size. */ public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; /** * Error code: an update failed to apply due to failing to verify * payload signatures. */ public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12; /** * Error code: an update failed to apply due to a downgrade in payload * timestamp. * * <p>The timestamp of a build is encoded into the payload, which will * be enforced during install to prevent downgrading a device. */ //版本時間戳校驗,如果不支持回滾,則回滾升級會報錯 public static final int PAYLOAD_TIMESTAMP_ERROR = 51; /** * Error code: an update has been applied successfully but the new slot * hasn't been set to active. * * <p>It indicates a successful finish of calling {@link #applyPayload} with * {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}. */ public static final int UPDATED_BUT_NOT_ACTIVE = 52; }
本文由 貴州做網站公司 整理發布,部分圖文來源于互聯網,如有侵權,請聯系我們刪除,謝謝!
網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...
在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...
在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...
有沒有人花888充值淘寶88會員?懂的人說說怎么樣吧?過來看看,有個傻女孩[羅斯],因為她一年前是88kai的會員,但續約時沒注意。當時規定1000分以下需要888分。我沒注意[遮住我的臉]。當我發現的時候,它已經在支付界面上了。當時,我的手機是華為榮耀。返回按鈕和指紋支付按鈕是相同的。當我想按返回按鈕時,付款成功了。后來聯系淘寶客服,他們還給我了??头χf不相信有人會買888。初衷是讓大家有一...
我的電腦的flash打不開了怎么辦?瀏覽器有時會提示Flash版本太低,無法使用。該解決方案包括:1.首先,檢查一下自己有沒有安裝。如果你不 t,下載安裝。2.開始菜單/控制面板/Flash播放器/更新/立即更新。按確定就行了。3.還有一種方法就是用騰訊電腦管家來修復。打開管家后,你會發現電腦診所的Flash版本太低,然后馬上點擊修復。flash插件安裝上也不能播放怎么弄?系統中可能有緩存,或者瀏...
蘋果手機QQ顯示2G在線怎么設置?有兩種情況1.是可以表示用蘋果手機登陸后的,但是是2g網絡,同理可證,3g是手機3g在線,另外無線網絡標志意思是是手機wifi在線,電腦標志應該是電腦免費。2.要是是對方的屬于什么掛機的或退圈于桌面本來以前的那是2g然后他剛刪號時間不長也會會如此總是顯示.蘋果手機上的QQ只顯示4G,沒有顯示Wifi,這是什么情況?應該怎么辦?直接點擊可以設置,下拉到點開,再點可以...