From c322256ed02e1b19668bed85af1ee6086ef94de8 Mon Sep 17 00:00:00 2001 From: "A. Cody Schuffelen" Date: Thu, 4 Jun 2026 17:18:46 -0700 Subject: [PATCH] Request higher SafeLevel builds when requesting Android build by branch In cvd fetch, when requesting a build by branch and target, prefer requesting higher SafeLevel builds (PLATINUM, SAFE_2, SAFE_1) when possible before falling back to any complete successful build (SAFE_0 / unspecified). If users want a specific build id, that is already possible to request through command line arguments. When a user requests a branch by name, they probably do not care as much how recent the build is. In the case of our presubmit, this will hopefully reduce flakes that come from the device side. The main failure mode here is if a build target / branch combination has previously reported a higher safe level and no longer does, it will get stuck on the older build from the higher safe level indefinitely. Assisted-by: Jetski:Gemini Next Bug: b/518049553 --- .../host/libs/web/android_build_api.cpp | 42 +++++++++++-------- .../host/libs/web/android_build_url.cpp | 24 ++++++++++- .../host/libs/web/android_build_url.h | 31 +++++++++++++- 3 files changed, 77 insertions(+), 20 deletions(-) diff --git a/base/cvd/cuttlefish/host/libs/web/android_build_api.cpp b/base/cvd/cuttlefish/host/libs/web/android_build_api.cpp index abfdf575d16..573010e92ae 100644 --- a/base/cvd/cuttlefish/host/libs/web/android_build_api.cpp +++ b/base/cvd/cuttlefish/host/libs/web/android_build_api.cpp @@ -275,25 +275,33 @@ Result> AndroidBuildApi::Headers() { Result> AndroidBuildApi::LatestBuildId( const std::string& branch, const std::string& target) { - const std::string url = - android_build_url_.GetLatestBuildIdUrl(branch, target); - auto response = - CF_EXPECT(HttpGetToJson(http_client_, url, CF_EXPECT(Headers()))); + for (const SafeLevel safe_level : kAllSafeLevels) { + VLOG(0) << "Attempting to download build at safe level '" << safe_level + << "' for branch '" << branch << "' and target '" << target << "'"; + const std::string url = + android_build_url_.GetLatestBuildIdUrl(branch, target, safe_level); + const std::vector headers = CF_EXPECT(Headers()); + const HttpResponse response = + CF_EXPECT(HttpGetToJson(http_client_, url, headers)); + + Result json_res = GetResponseJson(response); + if (!json_res.ok()) { + continue; + } + const Json::Value json = *json_res; - const Json::Value json = CF_EXPECTF(GetResponseJson(response), - "Error fetching last known good build " - "id for:\nbranch \"{}\", target \"{}\"", - branch, target); - if (!json.isMember("builds")) { - return std::nullopt; - } + if (!json.isMember("builds")) { + continue; + } - CF_EXPECTF(json["builds"].isArray() && json["builds"].size() == 1, - "Expected to find a single latest build for branch \"{}\" and " - "target \"{}\" in the response array, " - "but found {}", - branch, target, json["builds"].size()); - return CF_EXPECT(GetValue(json["builds"][0], { "buildId" })); + CF_EXPECTF(json["builds"].isArray() && json["builds"].size() == 1, + "Expected to find a single latest build for branch \"{}\" and " + "target \"{}\" in the response array, " + "but found {}", + branch, target, json["builds"].size()); + return CF_EXPECT(GetValue(json["builds"][0], {"buildId"})); + } + return std::nullopt; } Result> AndroidBuildApi::Artifacts( diff --git a/base/cvd/cuttlefish/host/libs/web/android_build_url.cpp b/base/cvd/cuttlefish/host/libs/web/android_build_url.cpp index 628ba47bf21..56df3c6c1a8 100644 --- a/base/cvd/cuttlefish/host/libs/web/android_build_url.cpp +++ b/base/cvd/cuttlefish/host/libs/web/android_build_url.cpp @@ -15,6 +15,7 @@ #include "cuttlefish/host/libs/web/android_build_url.h" +#include #include #include #include @@ -109,6 +110,25 @@ std::string BuildNameRegexp( } // namespace +std::string_view format_as(SafeLevel level) { + switch (level) { + case SafeLevel::kPlatinum: + return "PLATINUM"; + case SafeLevel::kSafe2: + return "SAFE_2"; + case SafeLevel::kSafe1: + return "SAFE_1"; + case SafeLevel::kSafe0: + return "SAFE_0"; + case SafeLevel::kSafeLevelUnspecified: + return ""; + } +} + +std::ostream& operator<<(std::ostream& os, SafeLevel level) { + return os << format_as(level); +} + AndroidBuildUrl::AndroidBuildUrl(std::string api_base_url, std::string api_key, std::string project_id) : api_base_url_(std::move(api_base_url)), @@ -116,12 +136,14 @@ AndroidBuildUrl::AndroidBuildUrl(std::string api_base_url, std::string api_key, project_id_(std::move(project_id)) {} std::string AndroidBuildUrl::GetLatestBuildIdUrl(std::string_view branch, - std::string_view target) { + std::string_view target, + SafeLevel safe_level) { UrlBuilder builder = UrlBuilder::GetLatestBuildIdBaseUrl(api_base_url_); builder.AddQueryParameter("buildAttemptStatus", "complete"); builder.AddQueryParameter("buildType", "submitted"); builder.AddQueryParameter("pageSize", "1"); builder.AddQueryParameter("successful", "true"); + builder.AddQueryParameter("safeLevel", format_as(safe_level)); builder.AddQueryParameter("branches", branch); builder.AddQueryParameter("targets", target); builder.AddApiKeyAndProjectId(api_key_, project_id_); diff --git a/base/cvd/cuttlefish/host/libs/web/android_build_url.h b/base/cvd/cuttlefish/host/libs/web/android_build_url.h index 21098fbf7fa..1ba55f0fea2 100644 --- a/base/cvd/cuttlefish/host/libs/web/android_build_url.h +++ b/base/cvd/cuttlefish/host/libs/web/android_build_url.h @@ -15,12 +15,38 @@ #pragma once +#include #include #include #include namespace cuttlefish { +enum class SafeLevel { + kSafeLevelUnspecified = 0, + kSafe0, + kSafe1, + kSafe2, + kPlatinum, +}; + +std::string_view format_as(SafeLevel level); + +template +void AbslStringify(Sink& sink, SafeLevel level) { + sink.Append(format_as(level)); +} + +std::ostream& operator<<(std::ostream& os, SafeLevel level); + +inline constexpr SafeLevel kAllSafeLevels[] = { + SafeLevel::kPlatinum, + SafeLevel::kSafe2, + SafeLevel::kSafe1, + SafeLevel::kSafe0, + SafeLevel::kSafeLevelUnspecified, +}; + inline constexpr char kAndroidBuildServiceUrl[] = "https://androidbuild-pa.googleapis.com/v4"; @@ -29,8 +55,9 @@ class AndroidBuildUrl { AndroidBuildUrl(std::string api_base_url, std::string api_key, std::string project_id); - std::string GetLatestBuildIdUrl(std::string_view branch, - std::string_view target); + std::string GetLatestBuildIdUrl( + std::string_view branch, std::string_view target, + SafeLevel safe_level = SafeLevel::kSafeLevelUnspecified); std::string GetBuildUrl(std::string_view id, std::string_view target); std::string GetArtifactUrl(std::string_view id, std::string_view target, const std::vector& artifact_filenames,