summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Stefano Cianciulli <scianciulli@google.com> 2022-10-03 14:09:05 +0000
committer Stefano Cianciulli <scianciulli@google.com> 2022-10-18 07:47:34 +0000
commit6eb814ce3a0d53126f066cb2148be69a4679dd7a (patch)
tree9a0fa6c6f81c205feeeffbb2f0605ac19db19ee1
parent6e18f436561a678a3a10e4fb7354b92fb7a10c2a (diff)
Report Odrefresh compilation status, exit code and signal to statsd
As part of the changes done in aosp/2223024, we are now collecting some additional information about the compilation for primary/secondary architecture and system_server in dex2oat: - result status - exit code (if status is Exited) - signal (if status is Signaled) This CL reports this new data points to statsd as part of the already existing OdrefreshReported atom, so that this new information can be extracted and analysed. Bug: 246534524 Test: atest ArtGtestsTargetChroot (in particular art_standalone_odrefresh_tests) Change-Id: I9705845a6bae0716d091400adde6415c20eda3de
-rw-r--r--odrefresh/odr_metrics.cc32
-rw-r--r--odrefresh/odr_metrics.h2
-rw-r--r--odrefresh/odr_metrics_record.cc69
-rw-r--r--odrefresh/odr_metrics_record.h28
-rw-r--r--odrefresh/odr_metrics_record_test.cc246
-rw-r--r--odrefresh/odr_metrics_test.cc123
-rw-r--r--odrefresh/odr_statslog_android.cc11
-rw-r--r--runtime/exec_utils.h3
8 files changed, 421 insertions, 93 deletions
diff --git a/odrefresh/odr_metrics.cc b/odrefresh/odr_metrics.cc
index b59ed717a8..296dce69db 100644
--- a/odrefresh/odr_metrics.cc
+++ b/odrefresh/odr_metrics.cc
@@ -135,19 +135,31 @@ int32_t OdrMetrics::GetFreeSpaceMiB(const std::string& path) {
OdrMetricsRecord OdrMetrics::ToRecord() const {
return {
- .odrefresh_metrics_version = kOdrefreshMetricsVersion,
- .art_apex_version = art_apex_version_,
- .trigger = static_cast<int32_t>(trigger_),
- .stage_reached = static_cast<int32_t>(stage_),
- .status = static_cast<int32_t>(status_),
- .cache_space_free_start_mib = cache_space_free_start_mib_,
- .cache_space_free_end_mib = cache_space_free_end_mib_,
- .primary_bcp_compilation_millis = primary_bcp_compilation_millis_,
- .secondary_bcp_compilation_millis = secondary_bcp_compilation_millis_,
- .system_server_compilation_millis = system_server_compilation_millis_,
+ .odrefresh_metrics_version = kOdrefreshMetricsVersion,
+ .art_apex_version = art_apex_version_,
+ .trigger = static_cast<int32_t>(trigger_),
+ .stage_reached = static_cast<int32_t>(stage_),
+ .status = static_cast<int32_t>(status_),
+ .cache_space_free_start_mib = cache_space_free_start_mib_,
+ .cache_space_free_end_mib = cache_space_free_end_mib_,
+ .primary_bcp_compilation_millis = primary_bcp_compilation_millis_,
+ .secondary_bcp_compilation_millis = secondary_bcp_compilation_millis_,
+ .system_server_compilation_millis = system_server_compilation_millis_,
+ .primary_bcp_dex2oat_result = ConvertExecResult(primary_bcp_dex2oat_result_),
+ .secondary_bcp_dex2oat_result = ConvertExecResult(secondary_bcp_dex2oat_result_),
+ .system_server_dex2oat_result = ConvertExecResult(system_server_dex2oat_result_),
};
}
+OdrMetricsRecord::Dex2OatExecResult OdrMetrics::ConvertExecResult(
+ const std::optional<ExecResult>& result) {
+ if (result.has_value()) {
+ return OdrMetricsRecord::Dex2OatExecResult(result.value());
+ } else {
+ return {};
+ }
+}
+
void OdrMetrics::WriteToFile(const std::string& path, const OdrMetrics* metrics) {
OdrMetricsRecord record = metrics->ToRecord();
diff --git a/odrefresh/odr_metrics.h b/odrefresh/odr_metrics.h
index 79311ad8d5..75e75b0027 100644
--- a/odrefresh/odr_metrics.h
+++ b/odrefresh/odr_metrics.h
@@ -127,6 +127,8 @@ class OdrMetrics final {
static void WriteToFile(const std::string& path, const OdrMetrics* metrics);
void SetCompilationTime(int32_t millis);
+ static OdrMetricsRecord::Dex2OatExecResult
+ ConvertExecResult(const std::optional<ExecResult>& result);
const std::string cache_directory_;
const std::string metrics_file_;
diff --git a/odrefresh/odr_metrics_record.cc b/odrefresh/odr_metrics_record.cc
index b8c2f80fea..14ccb0c154 100644
--- a/odrefresh/odr_metrics_record.cc
+++ b/odrefresh/odr_metrics_record.cc
@@ -14,13 +14,14 @@
* limitations under the License.
*/
-#include "android-base/logging.h"
#include "odr_metrics_record.h"
-#include "tinyxml2.h"
#include <iosfwd>
#include <string>
+#include "android-base/logging.h"
+#include "tinyxml2.h"
+
namespace art {
namespace odrefresh {
@@ -55,10 +56,56 @@ android::base::Result<int32_t> ReadInt32(tinyxml2::XMLElement* parent, const cha
}
}
+android::base::Result<int32_t> ReadInt32Attribute(tinyxml2::XMLElement* element,
+ const char* element_name,
+ const char* attribute_name,
+ int min_value,
+ int max_value) {
+ int32_t value;
+ tinyxml2::XMLError result = element->QueryAttribute(attribute_name, &value);
+ if (result != tinyxml2::XML_SUCCESS) {
+ return Errorf("Expected Odrefresh metric {}.{} is not an int32", element_name, attribute_name);
+ }
+
+ if (value < min_value || value > max_value) {
+ return Errorf(
+ "Odrefresh metric {}.{} has a value ({}) outside of the expected range ([{}, {}])",
+ element_name,
+ attribute_name,
+ value,
+ min_value,
+ max_value);
+ }
+
+ return value;
+}
+
+android::base::Result<OdrMetricsRecord::Dex2OatExecResult> ReadExecResult(
+ tinyxml2::XMLElement* parent, const char* nodeName) {
+ tinyxml2::XMLElement* element = parent->FirstChildElement(nodeName);
+ if (element == nullptr) {
+ return Errorf("Expected Odrefresh metric {} not found", nodeName);
+ }
+
+ return OdrMetricsRecord::Dex2OatExecResult(
+ OR_RETURN(ReadInt32Attribute(element, nodeName, "status", 0, kExecResultNotRun)),
+ OR_RETURN(ReadInt32Attribute(element, nodeName, "exit-code", -1, 255)),
+ OR_RETURN(ReadInt32Attribute(element, nodeName, "signal", 0, SIGRTMAX)));
+}
+
template <typename T>
void AddMetric(tinyxml2::XMLElement* parent, const char* name, const T& value) {
parent->InsertNewChildElement(name)->SetText(value);
}
+
+void AddResult(tinyxml2::XMLElement* parent,
+ const char* name,
+ const OdrMetricsRecord::Dex2OatExecResult& execResult) {
+ tinyxml2::XMLElement* result = parent->InsertNewChildElement(name);
+ result->SetAttribute("status", execResult.status);
+ result->SetAttribute("exit-code", execResult.exit_code);
+ result->SetAttribute("signal", execResult.signal);
+}
} // namespace
android::base::Result<void> OdrMetricsRecord::ReadFromFile(const std::string& filename) {
@@ -86,12 +133,15 @@ android::base::Result<void> OdrMetricsRecord::ReadFromFile(const std::string& fi
status = OR_RETURN(ReadInt32(metrics, "status"));
cache_space_free_start_mib = OR_RETURN(ReadInt32(metrics, "cache_space_free_start_mib"));
cache_space_free_end_mib = OR_RETURN(ReadInt32(metrics, "cache_space_free_end_mib"));
- primary_bcp_compilation_millis = OR_RETURN(
- ReadInt32(metrics, "primary_bcp_compilation_millis"));
- secondary_bcp_compilation_millis = OR_RETURN(
- ReadInt32(metrics, "secondary_bcp_compilation_millis"));
- system_server_compilation_millis = OR_RETURN(
- ReadInt32(metrics, "system_server_compilation_millis"));
+ primary_bcp_compilation_millis = OR_RETURN(ReadInt32(metrics, "primary_bcp_compilation_millis"));
+ secondary_bcp_compilation_millis =
+ OR_RETURN(ReadInt32(metrics, "secondary_bcp_compilation_millis"));
+ system_server_compilation_millis =
+ OR_RETURN(ReadInt32(metrics, "system_server_compilation_millis"));
+ primary_bcp_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "primary_bcp_dex2oat_result"));
+ secondary_bcp_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "secondary_bcp_dex2oat_result"));
+ system_server_dex2oat_result = OR_RETURN(ReadExecResult(metrics, "system_server_dex2oat_result"));
+
return {};
}
@@ -111,6 +161,9 @@ android::base::Result<void> OdrMetricsRecord::WriteToFile(const std::string& fil
AddMetric(metrics, "primary_bcp_compilation_millis", primary_bcp_compilation_millis);
AddMetric(metrics, "secondary_bcp_compilation_millis", secondary_bcp_compilation_millis);
AddMetric(metrics, "system_server_compilation_millis", system_server_compilation_millis);
+ AddResult(metrics, "primary_bcp_dex2oat_result", primary_bcp_dex2oat_result);
+ AddResult(metrics, "secondary_bcp_dex2oat_result", secondary_bcp_dex2oat_result);
+ AddResult(metrics, "system_server_dex2oat_result", system_server_dex2oat_result);
tinyxml2::XMLError result = xml_document.SaveFile(filename.data(), /*compact=*/true);
if (result == tinyxml2::XML_SUCCESS) {
diff --git a/odrefresh/odr_metrics_record.h b/odrefresh/odr_metrics_record.h
index fa953374e4..eb3ef9ee44 100644
--- a/odrefresh/odr_metrics_record.h
+++ b/odrefresh/odr_metrics_record.h
@@ -21,6 +21,7 @@
#include <iosfwd> // For forward-declaration of std::string.
#include "android-base/result.h"
+#include "exec_utils.h"
#include "tinyxml2.h"
namespace art {
@@ -30,12 +31,34 @@ namespace odrefresh {
constexpr const char* kOdrefreshMetricsFile = "/data/misc/odrefresh/odrefresh-metrics.xml";
// Initial OdrefreshMetrics version
-static constexpr int32_t kOdrefreshMetricsVersion = 2;
+static constexpr int32_t kOdrefreshMetricsVersion = 3;
+
+// Constant value used in ExecResult when the process was not run at all.
+// Mirrors EXEC_RESULT_STATUS_NOT_RUN contained in frameworks/proto_logging/atoms.proto.
+static constexpr int32_t kExecResultNotRun = 5;
+static_assert(kExecResultNotRun > ExecResult::Status::kLast,
+ "`art::odrefresh::kExecResultNotRun` value should not overlap with"
+ " values of enum `art::ExecResult::Status`");
+
// MetricsRecord is a simpler container for Odrefresh metric values reported to statsd. The order
// and types of fields here mirror definition of `OdrefreshReported` in
// frameworks/proto_logging/stats/atoms.proto.
struct OdrMetricsRecord {
+ struct Dex2OatExecResult {
+ int32_t status;
+ int32_t exit_code;
+ int32_t signal;
+
+ explicit Dex2OatExecResult(int32_t status, int32_t exit_code, int32_t signal)
+ : status(status), exit_code(exit_code), signal(signal) {}
+
+ explicit Dex2OatExecResult(const ExecResult& result)
+ : status(result.status), exit_code(result.exit_code), signal(result.signal) {}
+
+ Dex2OatExecResult() : status(kExecResultNotRun), exit_code(-1), signal(0) {}
+ };
+
int32_t odrefresh_metrics_version;
int64_t art_apex_version;
int32_t trigger;
@@ -46,6 +69,9 @@ struct OdrMetricsRecord {
int32_t primary_bcp_compilation_millis;
int32_t secondary_bcp_compilation_millis;
int32_t system_server_compilation_millis;
+ Dex2OatExecResult primary_bcp_dex2oat_result;
+ Dex2OatExecResult secondary_bcp_dex2oat_result;
+ Dex2OatExecResult system_server_dex2oat_result;
// Reads a `MetricsRecord` from an XML file.
// Returns an error if the XML document was not found or parsed correctly.
diff --git a/odrefresh/odr_metrics_record_test.cc b/odrefresh/odr_metrics_record_test.cc
index fbb5b99063..a6bfb8b431 100644
--- a/odrefresh/odr_metrics_record_test.cc
+++ b/odrefresh/odr_metrics_record_test.cc
@@ -27,32 +27,75 @@
namespace art {
namespace odrefresh {
-class OdrMetricsRecordTest : public CommonArtTest {};
+class OdrMetricsRecordTest : public CommonArtTest {
+ protected:
+ void WriteFile() {
+ std::ofstream ofs(file_path_);
+
+ ofs << "<odrefresh_metrics>";
+ ofs << metrics_version_;
+ ofs << "<art_apex_version>81966764218039518</art_apex_version>";
+ ofs << "<trigger>16909060</trigger>";
+ ofs << "<stage_reached>286397204</stage_reached>";
+ ofs << status_;
+ ofs << "<cache_space_free_start_mib>1633837924</cache_space_free_start_mib>";
+ ofs << "<cache_space_free_end_mib>1903326068</cache_space_free_end_mib>";
+ ofs << "<primary_bcp_compilation_millis>825373492</primary_bcp_compilation_millis>";
+ ofs << "<secondary_bcp_compilation_millis>1094861636</secondary_bcp_compilation_millis>";
+ ofs << "<system_server_compilation_millis>1364349780</system_server_compilation_millis>";
+ ofs << primary_bcp_dex2oat_result_;
+ ofs << secondary_bcp_dex2oat_result_;
+ ofs << system_server_dex2oat_result_;
+ ofs << "</odrefresh_metrics>";
+
+ ofs.close();
+ }
+
+ void SetUp() override {
+ CommonArtTest::SetUp();
+ scratch_dir_ = std::make_unique<ScratchDir>(/*keep_files=*/false);
+ file_path_ = scratch_dir_->GetPath() + "/metrics-record.xml";
+ }
+
+ void TearDown() override { scratch_dir_.reset(); }
+
+ std::unique_ptr<ScratchDir> scratch_dir_;
+ std::string file_path_;
+ std::string metrics_version_ = android::base::StringPrintf(
+ "<odrefresh_metrics_version>%d</odrefresh_metrics_version>", kOdrefreshMetricsVersion);
+ std::string status_ = "<status>30</status>";
+ std::string primary_bcp_dex2oat_result_ =
+ R"(<primary_bcp_dex2oat_result status="1" exit-code="-1" signal="0" />)";
+ std::string secondary_bcp_dex2oat_result_ =
+ R"(<secondary_bcp_dex2oat_result status="2" exit-code="15" signal="0" />)";
+ std::string system_server_dex2oat_result_ =
+ R"(<system_server_dex2oat_result status="3" exit-code="-1" signal="9" />)";
+};
-using android::base::testing::Ok;
using android::base::testing::HasError;
+using android::base::testing::Ok;
using android::base::testing::WithMessage;
TEST_F(OdrMetricsRecordTest, HappyPath) {
- const OdrMetricsRecord expected{
- .odrefresh_metrics_version = art::odrefresh::kOdrefreshMetricsVersion,
- .art_apex_version = 0x01233456'789abcde,
- .trigger = 0x01020304,
- .stage_reached = 0x11121314,
- .status = 0x21222324,
- .cache_space_free_start_mib = 0x61626364,
- .cache_space_free_end_mib = 0x71727374,
- .primary_bcp_compilation_millis = 0x31323334,
- .secondary_bcp_compilation_millis = 0x41424344,
- .system_server_compilation_millis = 0x51525354
- };
-
- ScratchDir dir(/*keep_files=*/false);
- std::string file_path = dir.GetPath() + "/metrics-record.xml";
- ASSERT_THAT(expected.WriteToFile(file_path), Ok());
-
- OdrMetricsRecord actual {};
- ASSERT_THAT(actual.ReadFromFile(file_path), Ok());
+ OdrMetricsRecord expected{};
+ expected.odrefresh_metrics_version = art::odrefresh::kOdrefreshMetricsVersion;
+ expected.art_apex_version = 0x01233456'789abcde;
+ expected.trigger = 0x01020304;
+ expected.stage_reached = 0x11121314;
+ expected.status = 0x21222324;
+ expected.cache_space_free_start_mib = 0x61626364;
+ expected.cache_space_free_end_mib = 0x71727374;
+ expected.primary_bcp_compilation_millis = 0x31323334;
+ expected.secondary_bcp_compilation_millis = 0x41424344;
+ expected.system_server_compilation_millis = 0x51525354;
+ expected.primary_bcp_dex2oat_result = OdrMetricsRecord::Dex2OatExecResult(1, -1, 0);
+ expected.secondary_bcp_dex2oat_result = OdrMetricsRecord::Dex2OatExecResult(2, 15, 0);
+ expected.system_server_dex2oat_result = OdrMetricsRecord::Dex2OatExecResult(3, -1, 9);
+
+ ASSERT_THAT(expected.WriteToFile(file_path_), Ok());
+
+ OdrMetricsRecord actual{};
+ ASSERT_THAT(actual.ReadFromFile(file_path_), Ok());
ASSERT_EQ(expected.odrefresh_metrics_version, actual.odrefresh_metrics_version);
ASSERT_EQ(expected.art_apex_version, actual.art_apex_version);
@@ -64,89 +107,146 @@ TEST_F(OdrMetricsRecordTest, HappyPath) {
ASSERT_EQ(expected.primary_bcp_compilation_millis, actual.primary_bcp_compilation_millis);
ASSERT_EQ(expected.secondary_bcp_compilation_millis, actual.secondary_bcp_compilation_millis);
ASSERT_EQ(expected.system_server_compilation_millis, actual.system_server_compilation_millis);
+ ASSERT_EQ(expected.primary_bcp_dex2oat_result.status, actual.primary_bcp_dex2oat_result.status);
+ ASSERT_EQ(expected.primary_bcp_dex2oat_result.exit_code,
+ actual.primary_bcp_dex2oat_result.exit_code);
+ ASSERT_EQ(expected.primary_bcp_dex2oat_result.signal, actual.primary_bcp_dex2oat_result.signal);
+ ASSERT_EQ(expected.secondary_bcp_dex2oat_result.status,
+ actual.secondary_bcp_dex2oat_result.status);
+ ASSERT_EQ(expected.secondary_bcp_dex2oat_result.exit_code,
+ actual.secondary_bcp_dex2oat_result.exit_code);
+ ASSERT_EQ(expected.secondary_bcp_dex2oat_result.signal,
+ actual.secondary_bcp_dex2oat_result.signal);
+ ASSERT_EQ(expected.system_server_dex2oat_result.status,
+ actual.system_server_dex2oat_result.status);
+ ASSERT_EQ(expected.system_server_dex2oat_result.exit_code,
+ actual.system_server_dex2oat_result.exit_code);
+ ASSERT_EQ(expected.system_server_dex2oat_result.signal,
+ actual.system_server_dex2oat_result.signal);
ASSERT_EQ(0, memcmp(&expected, &actual, sizeof(expected)));
}
TEST_F(OdrMetricsRecordTest, EmptyInput) {
- ScratchDir dir(/*keep_files=*/false);
- std::string file_path = dir.GetPath() + "/metrics-record.xml";
-
OdrMetricsRecord record{};
- ASSERT_THAT(record.ReadFromFile(file_path), testing::Not(Ok()));
+ ASSERT_THAT(record.ReadFromFile(file_path_), testing::Not(Ok()));
}
TEST_F(OdrMetricsRecordTest, UnexpectedInput) {
- ScratchDir dir(/*keep_files=*/false);
- std::string file_path = dir.GetPath() + "/metrics-record.xml";
-
- std::ofstream ofs(file_path);
+ std::ofstream ofs(file_path_);
ofs << "<not_odrefresh_metrics></not_odrefresh_metrics>";
ofs.close();
OdrMetricsRecord record{};
- ASSERT_THAT(
- record.ReadFromFile(file_path),
- HasError(WithMessage("odrefresh_metrics element not found in " + file_path)));
+ ASSERT_THAT(record.ReadFromFile(file_path_),
+ HasError(WithMessage("odrefresh_metrics element not found in " + file_path_)));
}
TEST_F(OdrMetricsRecordTest, ExpectedElementNotFound) {
- ScratchDir dir(/*keep_files=*/false);
- std::string file_path = dir.GetPath() + "/metrics-record.xml";
-
- std::ofstream ofs(file_path);
- ofs << "<odrefresh_metrics>";
- ofs << "<not_valid_metric>25</not_valid_metric>";
- ofs << "</odrefresh_metrics>";
- ofs.close();
+ metrics_version_ = "<not_valid_metric>25</not_valid_metric>";
+ WriteFile();
OdrMetricsRecord record{};
ASSERT_THAT(
- record.ReadFromFile(file_path),
+ record.ReadFromFile(file_path_),
HasError(WithMessage("Expected Odrefresh metric odrefresh_metrics_version not found")));
}
-TEST_F(OdrMetricsRecordTest, UnexpectedOdrefreshMetricsVersion) {
- ScratchDir dir(/*keep_files=*/false);
- std::string file_path = dir.GetPath() + "/metrics-record.xml";
+TEST_F(OdrMetricsRecordTest, ExpectedAttributeNotFound) {
+ // Missing "status".
+ primary_bcp_dex2oat_result_ = R"(<primary_bcp_dex2oat_result exit-code="17" signal="18" />)";
+ WriteFile();
- std::ofstream ofs(file_path);
- ofs << "<odrefresh_metrics>";
- ofs << "<odrefresh_metrics_version>0</odrefresh_metrics_version>";
- ofs << "</odrefresh_metrics>";
- ofs.close();
+ OdrMetricsRecord record{};
+ ASSERT_THAT(record.ReadFromFile(file_path_),
+ HasError(WithMessage(
+ "Expected Odrefresh metric primary_bcp_dex2oat_result.status is not an int32")));
+}
+
+TEST_F(OdrMetricsRecordTest, UnexpectedOdrefreshMetricsVersion) {
+ metrics_version_ = "<odrefresh_metrics_version>0</odrefresh_metrics_version>";
+ WriteFile();
OdrMetricsRecord record{};
std::string expected_error = android::base::StringPrintf(
- "odrefresh_metrics_version 0 is different than expected (%d)",
- kOdrefreshMetricsVersion);
- ASSERT_THAT(record.ReadFromFile(file_path),
- HasError(WithMessage(expected_error)));
+ "odrefresh_metrics_version 0 is different than expected (%d)", kOdrefreshMetricsVersion);
+ ASSERT_THAT(record.ReadFromFile(file_path_), HasError(WithMessage(expected_error)));
}
TEST_F(OdrMetricsRecordTest, UnexpectedType) {
- ScratchDir dir(/*keep_files=*/false);
- std::string file_path = dir.GetPath() + "/metrics-record.xml";
-
- std::ofstream ofs(file_path);
- ofs << "<odrefresh_metrics>";
- ofs << "<odrefresh_metrics_version>" << kOdrefreshMetricsVersion
- << "</odrefresh_metrics_version>";
- ofs << "<art_apex_version>81966764218039518</art_apex_version>";
- ofs << "<trigger>16909060</trigger>";
- ofs << "<stage_reached>286397204</stage_reached>";
- ofs << "<status>abcd</status>"; // It should be an int32.
- ofs << "<cache_space_free_start_mib>1633837924</cache_space_free_start_mib>";
- ofs << "<cache_space_free_end_mib>1903326068</cache_space_free_end_mib>";
- ofs << "<primary_bcp_compilation_millis>825373492</primary_bcp_compilation_millis>";
- ofs << "<secondary_bcp_compilation_millis>1094861636</secondary_bcp_compilation_millis>";
- ofs << "<system_server_compilation_millis>1364349780</system_server_compilation_millis>";
- ofs << "</odrefresh_metrics>";
- ofs.close();
+ status_ = "<status>abcd</status>"; // It should be an int32.
+ WriteFile();
+
+ OdrMetricsRecord record{};
+ ASSERT_THAT(record.ReadFromFile(file_path_),
+ HasError(WithMessage("Odrefresh metric status is not an int32")));
+}
+
+TEST_F(OdrMetricsRecordTest, ResultStatusOutsideOfRange) {
+ // Status is valid between 0 and 5 (5 being NOT_RUN)
+ primary_bcp_dex2oat_result_ =
+ R"(<primary_bcp_dex2oat_result status="-1" exit-code="-1" signal="0" />)";
+ WriteFile();
OdrMetricsRecord record{};
ASSERT_THAT(
- record.ReadFromFile(file_path),
- HasError(WithMessage("Odrefresh metric status is not an int32")));
+ record.ReadFromFile(file_path_),
+ HasError(WithMessage("Odrefresh metric primary_bcp_dex2oat_result.status has a value (-1) "
+ "outside of the expected range ([0, 5])")));
+
+ primary_bcp_dex2oat_result_ =
+ R"(<primary_bcp_dex2oat_result status="9" exit-code="-1" signal="0" />)";
+ WriteFile();
+
+ ASSERT_THAT(
+ record.ReadFromFile(file_path_),
+ HasError(WithMessage("Odrefresh metric primary_bcp_dex2oat_result.status has a value (9) "
+ "outside of the expected range ([0, 5])")));
+}
+
+TEST_F(OdrMetricsRecordTest, ResultExitCodeOutsideOfRange) {
+ // Exit Code is valid between -1 and 255
+ secondary_bcp_dex2oat_result_ =
+ R"(<secondary_bcp_dex2oat_result status="2" exit-code="-2" signal="0" />)";
+ WriteFile();
+
+ OdrMetricsRecord record{};
+ ASSERT_THAT(record.ReadFromFile(file_path_),
+ HasError(WithMessage(
+ "Odrefresh metric secondary_bcp_dex2oat_result.exit-code has a value (-2) "
+ "outside of the expected range ([-1, 255])")));
+
+ secondary_bcp_dex2oat_result_ =
+ R"(<secondary_bcp_dex2oat_result status="2" exit-code="258" signal="0" />)";
+ WriteFile();
+
+ ASSERT_THAT(record.ReadFromFile(file_path_),
+ HasError(WithMessage(
+ "Odrefresh metric secondary_bcp_dex2oat_result.exit-code has a value (258) "
+ "outside of the expected range ([-1, 255])")));
+}
+
+TEST_F(OdrMetricsRecordTest, ResultSignalOutsideOfRange) {
+ // Signal is valid between 0 and SIGRTMAX
+ system_server_dex2oat_result_ =
+ R"(<system_server_dex2oat_result status="3" exit-code="0" signal="-6" />)";
+ WriteFile();
+
+ OdrMetricsRecord record{};
+ ASSERT_THAT(record.ReadFromFile(file_path_),
+ HasError(WithMessage(android::base::StringPrintf(
+ "Odrefresh metric system_server_dex2oat_result.signal has a value (-6) "
+ "outside of the expected range ([0, %d])",
+ SIGRTMAX))));
+
+ system_server_dex2oat_result_ =
+ R"(<system_server_dex2oat_result status="3" exit-code="0" signal="65" />)";
+ WriteFile();
+
+ ASSERT_THAT(record.ReadFromFile(file_path_),
+ HasError(WithMessage(android::base::StringPrintf(
+ "Odrefresh metric system_server_dex2oat_result.signal has a value (65) "
+ "outside of the expected range ([0, %d])",
+ SIGRTMAX))));
}
} // namespace odrefresh
diff --git a/odrefresh/odr_metrics_test.cc b/odrefresh/odr_metrics_test.cc
index 7bc6f6becd..b8446df00b 100644
--- a/odrefresh/odr_metrics_test.cc
+++ b/odrefresh/odr_metrics_test.cc
@@ -145,5 +145,128 @@ TEST_F(OdrMetricsTest, CacheSpaceValuesAreUpdated) {
EXPECT_GT(record.cache_space_free_end_mib, 0);
}
+TEST_F(OdrMetricsTest, PrimaryBcpResultWithValue) {
+ OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
+ metrics.SetStage(OdrMetrics::Stage::kPrimaryBootClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kExited,
+ .exit_code = 0,
+ .signal = 0
+ });
+ OdrMetricsRecord record = metrics.ToRecord();
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.status, ExecResult::Status::kExited);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.exit_code, 0);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.signal, 0);
+}
+
+TEST_F(OdrMetricsTest, PrimaryBcpResultWithoutValue) {
+ OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
+
+ OdrMetricsRecord record = metrics.ToRecord();
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.status, kExecResultNotRun);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.exit_code, -1);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.signal, 0);
+}
+
+TEST_F(OdrMetricsTest, SecondaryBcpResultWithValue) {
+ OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
+ metrics.SetStage(OdrMetrics::Stage::kPrimaryBootClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kExited,
+ .exit_code = 0,
+ .signal = 0
+ });
+ metrics.SetStage(OdrMetrics::Stage::kSecondaryBootClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kTimedOut,
+ .exit_code = 3,
+ .signal = 0
+ });
+ OdrMetricsRecord record = metrics.ToRecord();
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.status, ExecResult::Status::kExited);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.exit_code, 0);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.signal, 0);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.status, ExecResult::Status::kTimedOut);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.exit_code, 3);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.signal, 0);
+}
+
+TEST_F(OdrMetricsTest, SecondaryBcpResultWithoutValue) {
+ OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
+ metrics.SetStage(OdrMetrics::Stage::kPrimaryBootClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kExited,
+ .exit_code = 0,
+ .signal = 0
+ });
+
+ OdrMetricsRecord record = metrics.ToRecord();
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.status, ExecResult::Status::kExited);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.exit_code, 0);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.signal, 0);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.status, kExecResultNotRun);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.exit_code, -1);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.signal, 0);
+}
+
+TEST_F(OdrMetricsTest, SystemServerResultWithValue) {
+ OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
+ metrics.SetStage(OdrMetrics::Stage::kPrimaryBootClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kExited,
+ .exit_code = 0,
+ .signal = 0
+ });
+ metrics.SetStage(OdrMetrics::Stage::kSecondaryBootClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kTimedOut,
+ .exit_code = 3,
+ .signal = 0
+ });
+ metrics.SetStage(OdrMetrics::Stage::kSystemServerClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kSignaled,
+ .exit_code = 2,
+ .signal = 9
+ });
+ OdrMetricsRecord record = metrics.ToRecord();
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.status, ExecResult::Status::kExited);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.exit_code, 0);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.signal, 0);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.status, ExecResult::Status::kTimedOut);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.exit_code, 3);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.signal, 0);
+ EXPECT_EQ(record.system_server_dex2oat_result.status, ExecResult::Status::kSignaled);
+ EXPECT_EQ(record.system_server_dex2oat_result.exit_code, 2);
+ EXPECT_EQ(record.system_server_dex2oat_result.signal, 9);
+}
+
+TEST_F(OdrMetricsTest, SystemServerResultWithoutValue) {
+ OdrMetrics metrics(GetCacheDirectory(), GetMetricsFilePath());
+ metrics.SetStage(OdrMetrics::Stage::kPrimaryBootClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kExited,
+ .exit_code = 0,
+ .signal = 0
+ });
+ metrics.SetStage(OdrMetrics::Stage::kSecondaryBootClasspath);
+ metrics.SetDex2OatResult({
+ .status = ExecResult::Status::kTimedOut,
+ .exit_code = 3,
+ .signal = 0
+ });
+
+ OdrMetricsRecord record = metrics.ToRecord();
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.status, ExecResult::Status::kExited);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.exit_code, 0);
+ EXPECT_EQ(record.primary_bcp_dex2oat_result.signal, 0);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.status, ExecResult::Status::kTimedOut);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.exit_code, 3);
+ EXPECT_EQ(record.secondary_bcp_dex2oat_result.signal, 0);
+ EXPECT_EQ(record.system_server_dex2oat_result.status, kExecResultNotRun);
+ EXPECT_EQ(record.system_server_dex2oat_result.exit_code, -1);
+ EXPECT_EQ(record.system_server_dex2oat_result.signal, 0);
+}
+
} // namespace odrefresh
} // namespace art
diff --git a/odrefresh/odr_statslog_android.cc b/odrefresh/odr_statslog_android.cc
index 90f769ff2c..29fcf493df 100644
--- a/odrefresh/odr_statslog_android.cc
+++ b/odrefresh/odr_statslog_android.cc
@@ -159,7 +159,16 @@ bool UploadStatsIfAvailable(/*out*/std::string* error_msg) {
record.cache_space_free_end_mib,
record.primary_bcp_compilation_millis,
record.secondary_bcp_compilation_millis,
- record.system_server_compilation_millis);
+ record.system_server_compilation_millis,
+ record.primary_bcp_dex2oat_result.status,
+ record.primary_bcp_dex2oat_result.exit_code,
+ record.primary_bcp_dex2oat_result.signal,
+ record.secondary_bcp_dex2oat_result.status,
+ record.secondary_bcp_dex2oat_result.exit_code,
+ record.secondary_bcp_dex2oat_result.signal,
+ record.system_server_dex2oat_result.status,
+ record.system_server_dex2oat_result.exit_code,
+ record.system_server_dex2oat_result.signal);
if (bytes_written <= 0) {
*error_msg = android::base::StringPrintf("stats_write returned %d", bytes_written);
return false;
diff --git a/runtime/exec_utils.h b/runtime/exec_utils.h
index c280e3e26f..11ab579b09 100644
--- a/runtime/exec_utils.h
+++ b/runtime/exec_utils.h
@@ -44,6 +44,8 @@ struct ExecCallbacks {
};
struct ExecResult {
+ // This struct needs to be in sync with the ExecResultStatus enum contained within
+ // the OdrefreshReported atom in frameworks/proto_logging/atoms.proto.
enum Status {
// Unable to get the status.
kUnknown = 0,
@@ -55,6 +57,7 @@ struct ExecResult {
kTimedOut = 3,
// Failed to start the process.
kStartFailed = 4,
+ kLast = kStartFailed
};
Status status = kUnknown;