1.systemupdater 位于packages\apps\Car\SystemUpdater\下,入口Activity为packages\apps\Car\SystemUpdater\src\com\android\car\systemupdater\SystemUpdaterActivity.java
在onActivityCreated方法中执行升级包校验功能
@Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); AppCompatActivity activity = (AppCompatActivity) getActivity(); mToolbar = CarUi.requireToolbar(getActivity()); mProgressBar = mToolbar.getProgressBar(); mProgressBar.setIndeterminate(true); mProgressBar.setVisible(true); showStatus(R.string.verify_in_progress); if (getArguments().getBoolean(EXTRA_RESUME_UPDATE)) { // Rejoin the update already in progress. showInstallationInProgress(); } else { // Extract the necessary information and begin the update. mPackageVerifier.execute(mUpdateFile); } }
UpdateVerifier是SystemUpdaterActivity的内部类,用于执行升级包校验,校验成功后会展示installNow的UI
/** Attempt to verify the update and extract information needed for installation. */ 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 { 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.setVisible(false); 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()); } showInstallNow(result); } }
/** 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); MenuItem installButton = MenuItem.builder(getActivity()) .setTitle(R.string.install_now) .setOnClickListener(i -> installUpdate(update)) .build(); mToolbar.setMenuItems(Collections.singletonList(installButton)); }
点击确认按钮后会执行installUpdate的流程,调用的UpdateEngine的applyPayload方法
/** Set the layout to show installation progress. */ private void showInstallationInProgress() { mInstallationInProgress = true; mProgressBar.setIndeterminate(false); mProgressBar.setVisible(true); mProgressBar.setMax(PERCENT_MAX); mToolbar.setMenuItems(null); // Remove install button showStatus(R.string.install_in_progress); mUpdateEngine.bind(mCarUpdateEngineCallback, new Handler(getContext().getMainLooper())); }
/** Attempt to install the update that is copied to the device. */ private void installUpdate(UpdateParser.ParsedUpdate parsedUpdate) { showInstallationInProgress(); mUpdateEngine.applyPayload( parsedUpdate.mUrl, parsedUpdate.mOffset, parsedUpdate.mSize, parsedUpdate.mProps); }
/** Handles events from the UpdateEngine. */ 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) { 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; showStatus(errorCode == UpdateEngine.ErrorCodeConstants.SUCCESS ? R.string.install_success : R.string.install_failed); mProgressBar.setVisible(false); mToolbar.setMenuItems(null); // Remove install now button } }
UpdateEngine位于 frameworks\base\core\java\android\os\UpdateEngine.java
/** * UpdateEngine handles calls to the update engine which takes care of A/B OTA * updates. It wraps up the update engine Binder APIs and exposes them as * SystemApis, which will be called by the system app responsible for OTAs. * On a Google device, this will be GmsCore. * * The minimal flow is: * <ol> * <li>Create a new UpdateEngine instance. * <li>Call {@link #bind}, optionally providing callbacks. * <li>Call {@link #applyPayload}. * </ol> * * In addition, methods are provided to {@link #cancel} or * {@link #suspend}/{@link #resume} application of an update. * * The APIs defined in this class and UpdateEngineCallback class must be in * sync with the ones in * {@code system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl} * and * {@code system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl}. * * {@hide} */
public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) { try { mUpdateEngine.applyPayload(url, offset, size, headerKeyValuePairs); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
/** * Prepares this instance for use. The callback will be notified on any * status change, and when the update completes. A handler can be supplied * to control which thread runs the callback, or null. */ public boolean bind(final UpdateEngineCallback callback, final Handler handler) { synchronized (mUpdateEngineCallbackLock) { mUpdateEngineCallback = new IUpdateEngineCallback.Stub() { @Override public void onStatusUpdate(final int status, final float percent) { if (handler != null) { handler.post(new Runnable() { @Override public void run() { callback.onStatusUpdate(status, percent); } }); } else { callback.onStatusUpdate(status, percent); } } @Override public void onPayloadApplicationComplete(final int errorCode) { if (handler != null) { handler.post(new Runnable() { @Override public void run() { callback.onPayloadApplicationComplete(errorCode); } }); } else { callback.onPayloadApplicationComplete(errorCode); } } }; try { return mUpdateEngine.bind(mUpdateEngineCallback); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }
/** * Creates a new instance. */ public UpdateEngine() { mUpdateEngine = IUpdateEngine.Stub.asInterface( ServiceManager.getService(UPDATE_ENGINE_SERVICE)); }
frameworks\base\core\java\android\os\UpdateEngineCallback.java
/** * Callback function for UpdateEngine. Used to keep the caller up to date * with progress, so the UI (if any) can be updated. * * The APIs defined in this class and UpdateEngine class must be in sync with * the ones in * system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl and * system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl. * * {@hide} */ @SystemApi public abstract class UpdateEngineCallback { /** * Invoked when anything changes. The value of {@code status} will * be one of the values from {@link UpdateEngine.UpdateStatusConstants}, * and {@code percent} will be valid [TODO: in which cases?]. */ public abstract void onStatusUpdate(int status, float percent); /** * Invoked when the payload has been applied, whether successfully or * unsuccessfully. The value of {@code errorCode} will be one of the * values from {@link UpdateEngine.ErrorCodeConstants}. */ public abstract void onPayloadApplicationComplete( @UpdateEngine.ErrorCode int errorCode); }
获取mUpdateEngine 实例
private static final String UPDATE_ENGINE_SERVICE = "android.os.UpdateEngineService";
/** * Creates a new instance. */ public UpdateEngine() { mUpdateEngine = IUpdateEngine.Stub.asInterface( ServiceManager.getService(UPDATE_ENGINE_SERVICE)); }
UpdateEngineService对应的是 system\update_engine\aosp\binder_service_android.h下定义的BinderUpdateEngineAndroidService
class BinderUpdateEngineAndroidService : public android::os::BnUpdateEngine, public ServiceObserverInterface { public: explicit BinderUpdateEngineAndroidService( ServiceDelegateAndroidInterface* service_delegate); ~BinderUpdateEngineAndroidService() override = default; const char* ServiceName() const { return "android.os.UpdateEngineService"; }
system\update_engine\aosp\binder_service_android.cc
Status BinderUpdateEngineAndroidService::applyPayload( const android::String16& url, int64_t payload_offset, int64_t payload_size, const vector<android::String16>& header_kv_pairs) { const string payload_url{android::String8{url}.string()}; vector<string> str_headers = ToVecString(header_kv_pairs); brillo::ErrorPtr error; if (!service_delegate_->ApplyPayload( payload_url, payload_offset, payload_size, str_headers, &error)) { return ErrorPtrToStatus(error); } return Status::ok(); }
调用了 service_delegate_的ApplyPayload方法,service_delegate_是ServiceDelegateAndroidInterface类型 定义在system\update_engine\aosp\service_delegate_android_interface.h
ServiceDelegateAndroidInterface* service_delegate_; 而ApplyPayload是纯虚函数
virtual bool ApplyPayload( const std::string& payload_url, int64_t payload_offset, int64_t payload_size, const std::vector<std::string>& key_value_pair_headers, brillo::ErrorPtr* error) = 0; virtual bool ApplyPayload( int fd, int64_t payload_offset, int64_t payload_size, const std::vector<std::string>& key_value_pair_headers, brillo::ErrorPtr* error) = 0;
实现在UpdateAttempterAndroid里 system\update_engine\aosp\update_attempter_android.h
class UpdateAttempterAndroid : public ServiceDelegateAndroidInterface, public ActionProcessorDelegate, public DownloadActionDelegate, public FilesystemVerifyDelegate, public PostinstallRunnerAction::DelegateInterface, public CleanupPreviousUpdateActionDelegateInterface {
system\update_engine\aosp\update_attempter_android.cc
bool UpdateAttempterAndroid::ApplyPayload( const string& payload_url, int64_t payload_offset, int64_t payload_size, const vector<string>& key_value_pair_headers, brillo::ErrorPtr* error) { if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) { return LogAndSetError( error, FROM_HERE, "An update already applied, waiting for reboot"); } if (processor_->IsRunning()) { return LogAndSetError( error, FROM_HERE, "Already processing an update, cancel it first."); } DCHECK_EQ(status_, UpdateStatus::IDLE); std::map<string, string> headers; if (!ParseKeyValuePairHeaders(key_value_pair_headers, &headers, error)) { return false; } string payload_id = GetPayloadId(headers); // Setup the InstallPlan based on the request. install_plan_ = InstallPlan(); install_plan_.download_url = payload_url; install_plan_.version = ""; base_offset_ = payload_offset; InstallPlan::Payload payload; payload.size = payload_size; if (!payload.size) { if (!base::StringToUint64(headers[kPayloadPropertyFileSize], &payload.size)) { payload.size = 0; } } if (!brillo::data_encoding::Base64Decode(headers[kPayloadPropertyFileHash], &payload.hash)) { LOG(WARNING) << "Unable to decode base64 file hash: " << headers[kPayloadPropertyFileHash]; } if (!base::StringToUint64(headers[kPayloadPropertyMetadataSize], &payload.metadata_size)) { payload.metadata_size = 0; } // The |payload.type| is not used anymore since minor_version 3. payload.type = InstallPayloadType::kUnknown; install_plan_.payloads.push_back(payload); // The |public_key_rsa| key would override the public key stored on disk. install_plan_.public_key_rsa = ""; install_plan_.hash_checks_mandatory = hardware_->IsOfficialBuild(); install_plan_.is_resume = !payload_id.empty() && DeltaPerformer::CanResumeUpdate(prefs_, payload_id); if (!install_plan_.is_resume) { // No need to reset dynamic_partititon_metadata_updated. If previous calls // to AllocateSpaceForPayload uses the same payload_id, reuse preallocated // space. Otherwise, DeltaPerformer re-allocates space when the payload is // applied. if (!DeltaPerformer::ResetUpdateProgress( prefs_, false /* quick */, true /* skip_dynamic_partititon_metadata_updated */)) { LOG(WARNING) << "Unable to reset the update progress."; } if (!prefs_->SetString(kPrefsUpdateCheckResponseHash, payload_id)) { LOG(WARNING) << "Unable to save the update check response hash."; } } install_plan_.source_slot = GetCurrentSlot(); install_plan_.target_slot = GetTargetSlot(); install_plan_.powerwash_required = GetHeaderAsBool(headers[kPayloadPropertyPowerwash], false); install_plan_.switch_slot_on_reboot = GetHeaderAsBool(headers[kPayloadPropertySwitchSlotOnReboot], true); install_plan_.run_post_install = GetHeaderAsBool(headers[kPayloadPropertyRunPostInstall], true); // Skip writing verity if we're resuming and verity has already been written. install_plan_.write_verity = true; if (install_plan_.is_resume && prefs_->Exists(kPrefsVerityWritten)) { bool verity_written = false; if (prefs_->GetBoolean(kPrefsVerityWritten, &verity_written) && verity_written) { install_plan_.write_verity = false; } } NetworkId network_id = kDefaultNetworkId; if (!headers[kPayloadPropertyNetworkId].empty()) { if (!base::StringToUint64(headers[kPayloadPropertyNetworkId], &network_id)) { return LogAndSetError( error, FROM_HERE, "Invalid network_id: " + headers[kPayloadPropertyNetworkId]); } if (!network_selector_->SetProcessNetwork(network_id)) { return LogAndSetError( error, FROM_HERE, "Unable to set network_id: " + headers[kPayloadPropertyNetworkId]); } } LOG(INFO) << "Using this install plan:"; install_plan_.Dump(); HttpFetcher* fetcher = nullptr; if (FileFetcher::SupportedUrl(payload_url)) { DLOG(INFO) << "Using FileFetcher for file URL."; fetcher = new FileFetcher(); } else { #ifdef _UE_SIDELOAD LOG(FATAL) << "Unsupported sideload URI: " << payload_url; #else LibcurlHttpFetcher* libcurl_fetcher = new LibcurlHttpFetcher(&proxy_resolver_, hardware_); libcurl_fetcher->set_server_to_check(ServerToCheck::kDownload); fetcher = libcurl_fetcher; #endif // _UE_SIDELOAD } // Setup extra headers. if (!headers[kPayloadPropertyAuthorization].empty()) fetcher->SetHeader("Authorization", headers[kPayloadPropertyAuthorization]); if (!headers[kPayloadPropertyUserAgent].empty()) fetcher->SetHeader("User-Agent", headers[kPayloadPropertyUserAgent]); BuildUpdateActions(fetcher); SetStatusAndNotify(UpdateStatus::UPDATE_AVAILABLE); UpdatePrefsOnUpdateStart(install_plan_.is_resume); // TODO(xunchang) report the metrics for unresumable updates ScheduleProcessingStart(); return true; } bool UpdateAttempterAndroid::ApplyPayload( int fd, int64_t payload_offset, int64_t payload_size, const vector<string>& key_value_pair_headers, brillo::ErrorPtr* error) { // update_engine state must be checked before modifying payload_fd_ otherwise // already running update will be terminated (existing file descriptor will be // closed) if (status_ == UpdateStatus::UPDATED_NEED_REBOOT) { return LogAndSetError( error, FROM_HERE, "An update already applied, waiting for reboot"); } if (processor_->IsRunning()) { return LogAndSetError( error, FROM_HERE, "Already processing an update, cancel it first."); } DCHECK_EQ(status_, UpdateStatus::IDLE); payload_fd_.reset(dup(fd)); const string payload_url = "fd://" + std::to_string(payload_fd_.get()); return ApplyPayload( payload_url, payload_offset, payload_size, key_value_pair_headers, error); }
整个升级的执行过程都在ApplyPayload方法中进行了,先是检查了参数和当前升级状态,然后构建了install_plan_,它的作用就是打印信息,将部分升级关键信息打印出来,然后初始化了fetcher,后面的DownloadAction会用到,最后就是组建action执行序列和执行序列中的action
void UpdateAttempterAndroid::BuildUpdateActions(HttpFetcher* fetcher) { CHECK(!processor_->IsRunning()); processor_->set_delegate(this); // Actions: auto update_boot_flags_action = std::make_unique<UpdateBootFlagsAction>(boot_control_); auto cleanup_previous_update_action = boot_control_->GetDynamicPartitionControl() ->GetCleanupPreviousUpdateAction(boot_control_, prefs_, this); auto install_plan_action = std::make_unique<InstallPlanAction>(install_plan_); auto download_action = std::make_unique<DownloadAction>(prefs_, boot_control_, hardware_, fetcher, // passes ownership true /* interactive */); download_action->set_delegate(this); download_action->set_base_offset(base_offset_); auto filesystem_verifier_action = std::make_unique<FilesystemVerifierAction>( boot_control_->GetDynamicPartitionControl()); auto postinstall_runner_action = std::make_unique<PostinstallRunnerAction>(boot_control_, hardware_); filesystem_verifier_action->set_delegate(this); postinstall_runner_action->set_delegate(this); // Bond them together. We have to use the leaf-types when calling // BondActions(). BondActions(install_plan_action.get(), download_action.get()); BondActions(download_action.get(), filesystem_verifier_action.get()); BondActions(filesystem_verifier_action.get(), postinstall_runner_action.get()); processor_->EnqueueAction(std::move(update_boot_flags_action)); processor_->EnqueueAction(std::move(cleanup_previous_update_action)); processor_->EnqueueAction(std::move(install_plan_action)); processor_->EnqueueAction(std::move(download_action)); processor_->EnqueueAction(std::move(filesystem_verifier_action)); processor_->EnqueueAction(std::move(postinstall_runner_action)); }
构建6个执行action,并且设置好执行顺序和关联,上一次执行完成的结果会通过管道传递到下一个action中。
这里看下最重要的一个action,postinstall_runner_action::PerformPartitionPostinstall
system\update_engine\payload_consumer\postinstall_runner_action.h
class PostinstallRunnerAction : public InstallPlanAction { public: PostinstallRunnerAction(BootControlInterface* boot_control, HardwareInterface* hardware); // InstallPlanAction overrides. void PerformAction() override; void SuspendAction() override; void ResumeAction() override; void TerminateProcessing() override; class DelegateInterface { public: virtual ~DelegateInterface() = default; // Called whenever there is an overall progress update from the postinstall // programs. virtual void ProgressUpdate(double progress) = 0; }; void set_delegate(DelegateInterface* delegate) { delegate_ = delegate; }
最后进入system\update_engine\common\subprocess.cc中:
bool LaunchProcess(const vector<string>& cmd, uint32_t flags, const vector<int>& output_pipes, brillo::Process* proc) { for (const string& arg : cmd) proc->AddArg(arg); proc->SetSearchPath((flags & Subprocess::kSearchPath) != 0); // Create an environment for the child process with just the required PATHs. std::map<string, string> env; for (const char* key : {"LD_LIBRARY_PATH", "PATH"}) { const char* value = getenv(key); if (value) env.emplace(key, value); } for (const int fd : output_pipes) { proc->RedirectUsingPipe(fd, false); } proc->SetCloseUnusedFileDescriptors(true); proc->RedirectUsingPipe(STDOUT_FILENO, false); proc->SetPreExecCallback(base::Bind(&SetupChild, env, flags)); return proc->Start(); }
cmd参数就是一开始传过来的command,这里用到了brillo/process.cc来执行命令,这里不再继续跟进了,update_engine大致的升级流程到这里就完成了,但还是有很多方面暂时没有涉及,一些详细的过程也没有去更进一步的去分析跟进,留待以后有时间或者遇到相关问题再去做进一步分析。