/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_ODREFRESH_ODREFRESH_H_ #define ART_ODREFRESH_ODREFRESH_H_ #include #include #include #include #include #include #include #include #include "android-base/function_ref.h" #include "android-base/result.h" #include "base/os.h" #include "com_android_apex.h" #include "com_android_art.h" #include "exec_utils.h" #include "odr_artifacts.h" #include "odr_config.h" #include "odr_metrics.h" #include "odrefresh/odrefresh.h" #include "tools/cmdline_builder.h" namespace art { namespace odrefresh { class OnDeviceRefresh; struct BootImages { static constexpr int kMaxCount = 2; bool primary_boot_image : 1; bool boot_image_mainline_extension : 1; int Count() const; OdrMetrics::BcpCompilationType GetTypeForMetrics() const; }; struct CompilationOptions { // If not empty, generate the boot images for ISAs in the list. std::vector> boot_images_to_generate_for_isas; // If not empty, compile the system server jars in the list. std::set system_server_jars_to_compile; static CompilationOptions CompileAll(const OnDeviceRefresh& odr); int CompilationUnitCount() const; }; struct CompilationResult { OdrMetrics::Status status = OdrMetrics::Status::kOK; std::string error_msg; int64_t elapsed_time_ms = 0; std::optional dex2oat_result; static CompilationResult Ok() { return {}; } static CompilationResult Dex2oatOk(int64_t elapsed_time_ms, const ExecResult& dex2oat_result) { return {.elapsed_time_ms = elapsed_time_ms, .dex2oat_result = dex2oat_result}; } static CompilationResult Error(OdrMetrics::Status status, const std::string& error_msg) { return {.status = status, .error_msg = error_msg}; } static CompilationResult Dex2oatError(const std::string& error_msg, int64_t elapsed_time_ms, const ExecResult& dex2oat_result) { return {.status = OdrMetrics::Status::kDex2OatError, .error_msg = error_msg, .elapsed_time_ms = elapsed_time_ms, .dex2oat_result = dex2oat_result}; } bool IsOk() { return status == OdrMetrics::Status::kOK; } void Merge(const CompilationResult& other) { // Accumulate the compilation time. elapsed_time_ms += other.elapsed_time_ms; // Only keep the first failure. if (status == OdrMetrics::Status::kOK) { status = other.status; error_msg = other.error_msg; dex2oat_result = other.dex2oat_result; } } }; class PreconditionCheckResult { public: static PreconditionCheckResult NoneOk(OdrMetrics::Trigger trigger) { return PreconditionCheckResult(trigger, /*primary_boot_image_ok=*/false, /*boot_image_mainline_extension_ok=*/false, /*system_server_ok=*/false); } static PreconditionCheckResult BootImageMainlineExtensionNotOk(OdrMetrics::Trigger trigger) { return PreconditionCheckResult(trigger, /*primary_boot_image_ok=*/true, /*boot_image_mainline_extension_ok=*/false, /*system_server_ok=*/false); } static PreconditionCheckResult SystemServerNotOk(OdrMetrics::Trigger trigger) { return PreconditionCheckResult(trigger, /*primary_boot_image_ok=*/true, /*boot_image_mainline_extension_ok=*/true, /*system_server_ok=*/false); } static PreconditionCheckResult AllOk() { return PreconditionCheckResult(/*trigger=*/std::nullopt, /*primary_boot_image_ok=*/true, /*boot_image_mainline_extension_ok=*/true, /*system_server_ok=*/true); } bool IsAllOk() const { return !trigger_.has_value(); } OdrMetrics::Trigger GetTrigger() const { return trigger_.value(); } bool IsPrimaryBootImageOk() const { return primary_boot_image_ok_; } bool IsBootImageMainlineExtensionOk() const { return boot_image_mainline_extension_ok_; } bool IsSystemServerOk() const { return system_server_ok_; } private: // Use static factory methods instead. PreconditionCheckResult(std::optional trigger, bool primary_boot_image_ok, bool boot_image_mainline_extension_ok, bool system_server_ok) : trigger_(trigger), primary_boot_image_ok_(primary_boot_image_ok), boot_image_mainline_extension_ok_(boot_image_mainline_extension_ok), system_server_ok_(system_server_ok) {} // Indicates why the precondition is not okay, or `std::nullopt` if it's okay. std::optional trigger_; bool primary_boot_image_ok_; bool boot_image_mainline_extension_ok_; bool system_server_ok_; }; class OnDeviceRefresh final { public: explicit OnDeviceRefresh( const OdrConfig& config, android::base::function_ref setfilecon, android::base::function_ref restorecon); // Constructor with injections. For testing and internal use only. OnDeviceRefresh( const OdrConfig& config, android::base::function_ref setfilecon, android::base::function_ref restorecon, const std::string& cache_info_filename, std::unique_ptr exec_utils, android::base::function_ref check_compilation_space); // Returns the exit code and specifies what should be compiled in `compilation_options`. WARN_UNUSED ExitCode CheckArtifactsAreUpToDate(OdrMetrics& metrics, /*out*/ CompilationOptions* compilation_options) const; WARN_UNUSED ExitCode Compile(OdrMetrics& metrics, CompilationOptions compilation_options) const; WARN_UNUSED bool RemoveArtifactsDirectory() const; // Returns a set of all system server jars. std::set AllSystemServerJars() const { return {all_systemserver_jars_.begin(), all_systemserver_jars_.end()}; } const OdrConfig& Config() const { return config_; } private: time_t GetExecutionTimeUsed() const; time_t GetExecutionTimeRemaining() const; time_t GetSubprocessTimeout() const; android::base::Result CreateStagingDirectory() const; // Gets the `ApexInfo` for active APEXes. std::optional> GetApexInfoList() const; // Reads the ART APEX cache information (if any) found in the output artifact directory. android::base::Result ReadCacheInfo() const; // Writes ART APEX cache information to `kOnDeviceRefreshOdrefreshArtifactDirectory`. android::base::Result WriteCacheInfo() const; std::vector GenerateBootClasspathComponents() const; std::vector GenerateDex2oatBootClasspathComponents() const; std::vector GenerateSystemServerComponents() const; // Returns the list of BCP jars in the ART module. std::vector GetArtBcpJars() const; // Returns the list of BCP jars for the boot image framework extension. std::vector GetFrameworkBcpJars() const; // Returns the list of BCP jars for the boot image mainline extension. std::vector GetMainlineBcpJars() const; // Returns the symbolic primary boot image location (without ISA). If `minimal` is true, returns // the symbolic location of the minimal boot image. std::string GetPrimaryBootImage(bool on_system, bool minimal) const; // Returns the real primary boot image location (with ISA). If `minimal` is true, returns the // real location of the minimal boot image. std::string GetPrimaryBootImagePath(bool on_system, bool minimal, InstructionSet isa) const; // Returns the symbolic boot image framework extension location (without ISA). Note that this only // applies to boot images on /system. std::string GetSystemBootImageFrameworkExtension() const; // Returns the real boot image framework extension location (with ISA). Note that this only // applies to boot images on /system. std::string GetSystemBootImageFrameworkExtensionPath(InstructionSet isa) const; // Returns the symbolic boot image mainline extension location (without ISA). std::string GetBootImageMainlineExtension(bool on_system) const; // Returns the real boot image mainline extension location (with ISA). std::string GetBootImageMainlineExtensionPath(bool on_system, InstructionSet isa) const; // Returns the best combination of symbolic boot image locations (without ISA) based on file // existence. std::vector GetBestBootImages(InstructionSet isa, bool include_mainline_extension) const; std::string GetSystemServerImagePath(bool on_system, const std::string& jar_path) const; // Removes files that are not in the list. android::base::Result CleanupArtifactDirectory( OdrMetrics& metrics, const std::vector& artifacts_to_keep) const; // Loads artifacts to memory and writes them back. This is a workaround for old versions of // odsign, which encounters "file exists" error when it adds existing artifacts to fs-verity. This // function essentially removes existing artifacts from fs-verity to avoid the error. android::base::Result RefreshExistingArtifacts() const; // Returns whether the primary boot image is present. // If `on_system` is true, checks both the primary boot image and the framework extension on // /system. // If `minimal` is true, checks the minimal boot image. // If `checked_artifacts` is present, adds checked artifacts to `checked_artifacts`. WARN_UNUSED bool PrimaryBootImageExist( bool on_system, bool minimal, InstructionSet isa, /*out*/ std::string* error_msg, /*out*/ std::vector* checked_artifacts = nullptr) const; // Returns whether the boot image mainline extension exists. WARN_UNUSED bool BootImageMainlineExtensionExist( bool on_system, InstructionSet isa, /*out*/ std::string* error_msg, /*out*/ std::vector* checked_artifacts = nullptr) const; // Checks whether all system_server artifacts are present. The artifacts are checked in their // order of compilation. Returns true if all are present, false otherwise. // Adds the paths to the jars that are missing artifacts in `jars_with_missing_artifacts`. // If `checked_artifacts` is present, adds checked artifacts to `checked_artifacts`. bool SystemServerArtifactsExist( bool on_system, /*out*/ std::string* error_msg, /*out*/ std::set* jars_missing_artifacts, /*out*/ std::vector* checked_artifacts = nullptr) const; // Returns true if all of the system properties listed in `kSystemProperties` are set to the // default values. This function is usually called when cache-info.xml does not exist (i.e., // compilation has not been done before). WARN_UNUSED bool CheckSystemPropertiesAreDefault() const; // Returns true if none of the system properties listed in `kSystemProperties` has changed since // the last compilation. This function is usually called when cache-info.xml exists. WARN_UNUSED bool CheckSystemPropertiesHaveNotChanged( const com::android::art::CacheInfo& cache_info) const; // Returns true if the system image is built with the right userfaultfd GC flag. WARN_UNUSED bool CheckBuildUserfaultFdGc() const; // Returns whether the precondition for using artifacts on /system is met. Note that this function // does not check the artifacts. WARN_UNUSED PreconditionCheckResult CheckPreconditionForSystem(const std::vector& apex_info_list) const; // Returns whether the precondition for using artifacts on /data is met. Note that this function // does not check the artifacts. WARN_UNUSED PreconditionCheckResult CheckPreconditionForData(const std::vector& apex_info_list) const; // Checks whether all boot classpath artifacts are up to date. Returns the boot images that need // to be (re-)generated. If `checked_artifacts` is present, adds checked artifacts to // `checked_artifacts`. WARN_UNUSED BootImages CheckBootClasspathArtifactsAreUpToDate(OdrMetrics& metrics, InstructionSet isa, const PreconditionCheckResult& system_result, const PreconditionCheckResult& data_result, /*out*/ std::vector* checked_artifacts) const; // Checks whether all system_server artifacts are up to date. The artifacts are checked in their // order of compilation. Returns the paths to the jars that need to be compiled. // If `checked_artifacts` is present, adds checked artifacts to `checked_artifacts`. WARN_UNUSED std::set CheckSystemServerArtifactsAreUpToDate( OdrMetrics& metrics, const PreconditionCheckResult& system_result, const PreconditionCheckResult& data_result, /*out*/ std::vector* checked_artifacts) const; WARN_UNUSED CompilationResult RunDex2oat(const std::string& staging_dir, const std::string& debug_message, InstructionSet isa, const std::vector& dex_files, const std::vector& boot_classpath, const std::vector& input_boot_images, const OdrArtifacts& artifacts, tools::CmdlineBuilder&& extra_args, /*inout*/ std::vector>& readonly_files_raii) const; WARN_UNUSED CompilationResult RunDex2oatForBootClasspath(const std::string& staging_dir, const std::string& debug_name, InstructionSet isa, const std::vector& dex_files, const std::vector& boot_classpath, const std::vector& input_boot_images, const std::string& output_path) const; WARN_UNUSED CompilationResult CompileBootClasspath(const std::string& staging_dir, InstructionSet isa, BootImages boot_images, const std::function& on_dex2oat_success) const; WARN_UNUSED CompilationResult RunDex2oatForSystemServer(const std::string& staging_dir, const std::string& dex_file, const std::vector& classloader_context) const; WARN_UNUSED CompilationResult CompileSystemServer(const std::string& staging_dir, const std::set& system_server_jars_to_compile, const std::function& on_dex2oat_success) const; // Configuration to use. const OdrConfig& config_; // Path to cache information file that is used to speed up artifact checking. const std::string cache_info_filename_; // The raw list from DEX2OATBOOTCLASSPATH. This is the list of jars that should be compiled into // the primary boot image. std::vector dex2oat_boot_classpath_jars_; // The raw list from BOOTCLASSPATH. This is the list of all BCP jars. std::vector boot_classpath_jars_; // Set of system_server components in SYSTEMSERVERCLASSPATH that should be compiled. std::unordered_set systemserver_classpath_jars_; // List of all system_server components, including those in SYSTEMSERVERCLASSPATH and those in // STANDALONE_SYSTEMSERVER_JARS (jars that system_server loads dynamically using separate // classloaders). std::vector all_systemserver_jars_; const time_t start_time_; std::unique_ptr exec_utils_; android::base::function_ref check_compilation_space_; android::base::function_ref setfilecon_; android::base::function_ref restorecon_; DISALLOW_COPY_AND_ASSIGN(OnDeviceRefresh); }; } // namespace odrefresh } // namespace art #endif // ART_ODREFRESH_ODREFRESH_H_