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,