首页 > 其他分享 >Android systemupdater

Android systemupdater

时间:2023-08-01 15:15:27浏览次数:39  
标签:void update payload headers action Android public systemupdater

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大致的升级流程到这里就完成了,但还是有很多方面暂时没有涉及,一些详细的过程也没有去更进一步的去分析跟进,留待以后有时间或者遇到相关问题再去做进一步分析。

   

标签:void,update,payload,headers,action,Android,public,systemupdater
From: https://www.cnblogs.com/wanglongjiang/p/17596538.html

相关文章

  • Android gradle 各种版本下载
    来气经常缺少gradle包.今天网络极佳,各种all版本都down下来官方地址官方下载gradel地址不FQ不能下载司机下载地址gradle-2.0-all下载gradle-2.1-all下载gradle-2.2-all下载gradle-2.3-all下载gradle-2.4-all下载gradle-2.5-all下载gradle-2.6-all下载gradle-2.7-all下载gradle-2......
  • android重复点击问题
    openclassSingleClickListener(privatevalintervalMils:Long=1000):OnClickListener{privatevalTAG=this.javaClass.nameprivatevarmLastClickTime=0LoverridefunonClick(p0:View?){Logger.logger(TAG,"onClick")......
  • Android2.1消息应用(Messaging)…
    我想首先应该从AndroidManifest.xml文件开始,该文件是Android应用(APK)的打包清单,其中提供了关于这个应用程序的基本信息,如名称(application/@label),图标(application/@icon),等常量信息,但该文件最重要的功能仍然是:向Android系统声明应用程序所包含的组件,包括Activity、Service、Receiv......
  • Android那些事儿(二)安卓手机交…
    Android那些事儿(二)安卓手机交互特性接上文《android那些事儿(一)成长中的Android》。本文描述了与其它触屏手机系统和桌面系统不同的Android平台特性,这些特性需要更多的表现在我们开发的应用程序中,以保证这是一款Android手机的应用。这些特性可能对于习惯了其它手机操作系统的......
  • 混淆Android代码
    在工程的"default.properties"中添加这样一句话“proguard.config=proguard.cfg”,如上图:......
  • android RGB颜色参考
    <?xmlversion="1.0"encoding="utf-8"?><resources><colorname="white">#FFFFFF</color><!--白色--><colorname="ivory">#FFFFF0</color><!--象牙色--><colorna......
  • android UI界面更新之通知与服务结…
    网上看到的,实际操作了下,例子代码如下。加深对BroadcastReceiver与Service理解packageorg.yihu;importandroid.app.Activity;importandroid.content.BroadcastReceiver;importandroid.content.Context;importandroid.content.Intent;importandroid.content.IntentFil......
  • android UI小知识点
    android小知识点4.如何在string.xml资源文件中定义变量第一步:定义string.xml资源文件<resourcesxmlns:android="http://schemas.android.com/apk/res/android"   <stringname="tipTitle">请设置</string> <stringname="test_fmt">\n\n"......
  • Android应用程序架构学习之一
    Android应用程序架构学习之一 核心类: MessagingController是一个线程控制类,通过put方法构造Command类放入队列依次执行Command类实现线程. 方法为command请求和MessageingListener实例提供服务 listener作为一个registeredlistener通过addListener()方法被增加 当......
  • android中使用startActivityForRes…
    网上找的一个通俗易懂,放在这以后好查阅假设:我这里有两个Activity:A和B,从A中向B中传递数据的时候采用的是Bundle封装数据,然后从A中跳转到B中,当B有需求将数据封装起来回传给A并跳转回A。那么A中接收数据时还要先判断Bundle是否为空,因为第一次访问A的时候(即B还没有回传的时候),Bundle......