0

Make all char* in android's build_info std::strings

There used to be a comment about needing to use char* instead of
std::string, but I think that's obsolete, since I couldn't find any uses
of these build_info fields during crash time. They all seem to be set
beforehand.

Bug: 414609682
Change-Id: I5fb795b2701e25c74cf604adf14f8f0c73a4c486
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6526386
Commit-Queue: Sam Maier <smaier@chromium.org>
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Owners-Override: Sam Maier <smaier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1459610}
This commit is contained in:
Sam Maier
2025-05-13 11:51:38 -07:00
committed by Chromium LUCI CQ
parent 4feb0cc824
commit 05ccd44feb
19 changed files with 262 additions and 278 deletions

@ -15,6 +15,7 @@
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/check.h" #include "base/check.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
@ -25,126 +26,118 @@ namespace base::android::android_info {
namespace { namespace {
struct AndroidInfo { struct AndroidInfo {
// Const char* is used instead of std::strings because these values must be const std::string device;
// available even if the process is in a crash state. Sadly
// std::string.c_str() doesn't guarantee that memory won't be allocated when
// it is called.
const char* device;
const char* manufacturer; const std::string manufacturer;
const char* model; const std::string model;
const char* brand; const std::string brand;
const char* android_build_id; const std::string android_build_id;
const char* build_type; const std::string build_type;
const char* board; const std::string board;
const char* android_build_fp; const std::string android_build_fp;
int sdk_int; int sdk_int;
bool is_debug_android; bool is_debug_android;
const char* version_incremental; const std::string version_incremental;
const char* hardware; const std::string hardware;
const char* codename; const std::string codename;
// Available only on android S+. For S-, this method returns empty string. // Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer; const std::string soc_manufacturer;
const char* abi_name; const std::string abi_name;
}; };
std::optional<AndroidInfo> holder; static std::optional<AndroidInfo>& get_holder() {
static base::NoDestructor<std::optional<AndroidInfo>> holder;
return *holder;
}
const AndroidInfo& get_android_info() { const AndroidInfo& get_android_info() {
[[maybe_unused]] static auto once = [] { const std::optional<AndroidInfo>& holder = get_holder();
if (!holder.has_value()) {
Java_AndroidInfo_nativeReadyForFields(AttachCurrentThread()); Java_AndroidInfo_nativeReadyForFields(AttachCurrentThread());
return std::monostate(); }
}();
// holder should be initialized as the java is supposed to call the native
// method FillFields which will initialize the fields within the holder.
DCHECK(holder.has_value());
return *holder; return *holder;
} }
} // namespace } // namespace
static void JNI_AndroidInfo_FillFields( static void JNI_AndroidInfo_FillFields(JNIEnv* env,
JNIEnv* env, std::string& brand,
const jni_zero::JavaParamRef<jstring>& brand, std::string& device,
const jni_zero::JavaParamRef<jstring>& device, std::string& buildId,
const jni_zero::JavaParamRef<jstring>& buildId, std::string& manufacturer,
const jni_zero::JavaParamRef<jstring>& manufacturer, std::string& model,
const jni_zero::JavaParamRef<jstring>& model, std::string& type,
const jni_zero::JavaParamRef<jstring>& type, std::string& board,
const jni_zero::JavaParamRef<jstring>& board, std::string& androidBuildFingerprint,
const jni_zero::JavaParamRef<jstring>& androidBuildFingerprint, std::string& versionIncremental,
const jni_zero::JavaParamRef<jstring>& versionIncremental, std::string& hardware,
const jni_zero::JavaParamRef<jstring>& hardware, std::string& codeName,
const jni_zero::JavaParamRef<jstring>& codeName, std::string& socManufacturer,
const jni_zero::JavaParamRef<jstring>& socManufacturer, std::string& supportedAbis,
const jni_zero::JavaParamRef<jstring>& supportedAbis, jint sdkInt,
jint sdkInt, jboolean isDebugAndroid) {
jboolean isDebugAndroid) { std::optional<AndroidInfo>& holder = get_holder();
DCHECK(!holder.has_value()); DCHECK(!holder.has_value());
auto java_string_to_const_char = holder.emplace(
[](const jni_zero::JavaParamRef<jstring>& str) { AndroidInfo{.device = device,
return UNSAFE_TODO(strdup(ConvertJavaStringToUTF8(str).c_str())); .manufacturer = manufacturer,
}; .model = model,
holder = AndroidInfo{ .brand = brand,
.device = java_string_to_const_char(device), .android_build_id = buildId,
.manufacturer = java_string_to_const_char(manufacturer), .build_type = type,
.model = java_string_to_const_char(model), .board = board,
.brand = java_string_to_const_char(brand), .android_build_fp = androidBuildFingerprint,
.android_build_id = java_string_to_const_char(buildId), .sdk_int = sdkInt,
.build_type = java_string_to_const_char(type), .is_debug_android = static_cast<bool>(isDebugAndroid),
.board = java_string_to_const_char(board), .version_incremental = versionIncremental,
.android_build_fp = java_string_to_const_char(androidBuildFingerprint), .hardware = hardware,
.sdk_int = sdkInt, .codename = codeName,
.is_debug_android = static_cast<bool>(isDebugAndroid), .soc_manufacturer = socManufacturer,
.version_incremental = java_string_to_const_char(versionIncremental), .abi_name = supportedAbis});
.hardware = java_string_to_const_char(hardware),
.codename = java_string_to_const_char(codeName),
.soc_manufacturer = java_string_to_const_char(socManufacturer),
.abi_name = java_string_to_const_char(supportedAbis)};
} }
const char* device() { const std::string& device() {
return get_android_info().device; return get_android_info().device;
} }
const char* manufacturer() { const std::string& manufacturer() {
return get_android_info().manufacturer; return get_android_info().manufacturer;
} }
const char* model() { const std::string& model() {
return get_android_info().model; return get_android_info().model;
} }
const char* brand() { const std::string& brand() {
return get_android_info().brand; return get_android_info().brand;
} }
const char* android_build_id() { const std::string& android_build_id() {
return get_android_info().android_build_id; return get_android_info().android_build_id;
} }
const char* build_type() { const std::string& build_type() {
return get_android_info().build_type; return get_android_info().build_type;
} }
const char* board() { const std::string& board() {
return get_android_info().board; return get_android_info().board;
} }
const char* android_build_fp() { const std::string& android_build_fp() {
return get_android_info().android_build_fp; return get_android_info().android_build_fp;
} }
@ -156,24 +149,24 @@ bool is_debug_android() {
return get_android_info().is_debug_android; return get_android_info().is_debug_android;
} }
const char* version_incremental() { const std::string& version_incremental() {
return get_android_info().version_incremental; return get_android_info().version_incremental;
} }
const char* hardware() { const std::string& hardware() {
return get_android_info().hardware; return get_android_info().hardware;
} }
const char* codename() { const std::string& codename() {
return get_android_info().codename; return get_android_info().codename;
} }
// Available only on android S+. For S-, this method returns empty string. // Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer() { const std::string& soc_manufacturer() {
return get_android_info().soc_manufacturer; return get_android_info().soc_manufacturer;
} }
const char* abi_name() { const std::string& abi_name() {
return get_android_info().abi_name; return get_android_info().abi_name;
} }

@ -5,6 +5,8 @@
#ifndef BASE_ANDROID_ANDROID_INFO_H_ #ifndef BASE_ANDROID_ANDROID_INFO_H_
#define BASE_ANDROID_ANDROID_INFO_H_ #define BASE_ANDROID_ANDROID_INFO_H_
#include <string>
#include "base/base_export.h" #include "base/base_export.h"
namespace base::android::android_info { namespace base::android::android_info {
@ -35,36 +37,36 @@ enum SdkVersion {
SDK_VERSION_BAKLAVA = 36, SDK_VERSION_BAKLAVA = 36,
}; };
const char* device(); const std::string& device();
const char* manufacturer(); const std::string& manufacturer();
const char* model(); const std::string& model();
BASE_EXPORT const char* brand(); BASE_EXPORT const std::string& brand();
const char* android_build_id(); const std::string& android_build_id();
const char* build_type(); const std::string& build_type();
const char* board(); const std::string& board();
const char* android_build_fp(); const std::string& android_build_fp();
BASE_EXPORT int sdk_int(); BASE_EXPORT int sdk_int();
bool is_debug_android(); bool is_debug_android();
const char* version_incremental(); const std::string& version_incremental();
BASE_EXPORT const char* hardware(); BASE_EXPORT const std::string& hardware();
const char* codename(); const std::string& codename();
// Available only on android S+. For S-, this method returns empty string. // Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer(); const std::string& soc_manufacturer();
const char* abi_name(); const std::string& abi_name();
} // namespace base::android::android_info } // namespace base::android::android_info

@ -12,6 +12,7 @@
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
@ -22,96 +23,87 @@ namespace base::android::apk_info {
namespace { namespace {
struct ApkInfo { struct ApkInfo {
// Const char* is used instead of std::strings because these values must be const std::string host_package_name;
// available even if the process is in a crash state. Sadly const std::string host_version_code;
// std::string.c_str() doesn't guarantee that memory won't be allocated when const std::string host_package_label;
// it is called. const std::string package_version_code;
const char* host_package_name; const std::string package_version_name;
const char* host_version_code; const std::string package_name;
const char* host_package_label; const std::string resources_version;
const char* package_version_code; const std::string installer_package_name;
const char* package_version_name;
const char* package_name;
const char* resources_version;
const char* installer_package_name;
bool is_debug_app; bool is_debug_app;
int target_sdk_version; int target_sdk_version;
}; };
std::optional<ApkInfo> holder; static std::optional<ApkInfo>& get_holder() {
static base::NoDestructor<std::optional<ApkInfo>> holder;
return *holder;
}
ApkInfo& get_apk_info() { const ApkInfo& get_apk_info() {
[[maybe_unused]] static auto once = [] { const std::optional<ApkInfo>& holder = get_holder();
if (!holder.has_value()) {
Java_ApkInfo_nativeReadyForFields(AttachCurrentThread()); Java_ApkInfo_nativeReadyForFields(AttachCurrentThread());
return std::monostate(); }
}();
// holder should be initialized as the java is supposed to call the native
// method FillFields which will initialize the fields within the holder.
DCHECK(holder.has_value());
return *holder; return *holder;
} }
} // namespace } // namespace
static void JNI_ApkInfo_FillFields( static void JNI_ApkInfo_FillFields(JNIEnv* env,
JNIEnv* env, std::string& hostPackageName,
const jni_zero::JavaParamRef<jstring>& hostPackageName, std::string& hostVersionCode,
const jni_zero::JavaParamRef<jstring>& hostVersionCode, std::string& hostPackageLabel,
const jni_zero::JavaParamRef<jstring>& hostPackageLabel, std::string& packageVersionCode,
const jni_zero::JavaParamRef<jstring>& packageVersionCode, std::string& packageVersionName,
const jni_zero::JavaParamRef<jstring>& packageVersionName, std::string& packageName,
const jni_zero::JavaParamRef<jstring>& packageName, std::string& resourcesVersion,
const jni_zero::JavaParamRef<jstring>& resourcesVersion, std::string& installerPackageName,
const jni_zero::JavaParamRef<jstring>& installerPackageName, jboolean isDebugApp,
jboolean isDebugApp, jint targetSdkVersion) {
jint targetSdkVersion) { std::optional<ApkInfo>& holder = get_holder();
DCHECK(!holder.has_value()); DCHECK(!holder.has_value());
auto java_string_to_const_char = holder.emplace(ApkInfo{.host_package_name = hostPackageName,
[](const jni_zero::JavaParamRef<jstring>& str) { .host_version_code = hostVersionCode,
return UNSAFE_TODO(strdup(ConvertJavaStringToUTF8(str).c_str())); .host_package_label = hostPackageLabel,
}; .package_version_code = packageVersionCode,
holder = ApkInfo{ .package_version_name = packageVersionName,
.host_package_name = java_string_to_const_char(hostPackageName), .package_name = packageName,
.host_version_code = java_string_to_const_char(hostVersionCode), .resources_version = resourcesVersion,
.host_package_label = java_string_to_const_char(hostPackageLabel), .installer_package_name = installerPackageName,
.package_version_code = java_string_to_const_char(packageVersionCode), .is_debug_app = static_cast<bool>(isDebugApp),
.package_version_name = java_string_to_const_char(packageVersionName), .target_sdk_version = targetSdkVersion});
.package_name = java_string_to_const_char(packageName),
.resources_version = java_string_to_const_char(resourcesVersion),
.installer_package_name = java_string_to_const_char(installerPackageName),
.is_debug_app = static_cast<bool>(isDebugApp),
.target_sdk_version = targetSdkVersion};
} }
const char* host_package_name() { const std::string& host_package_name() {
return get_apk_info().host_package_name; return get_apk_info().host_package_name;
} }
const char* host_version_code() { const std::string& host_version_code() {
return get_apk_info().host_version_code; return get_apk_info().host_version_code;
} }
const char* host_package_label() { const std::string& host_package_label() {
return get_apk_info().host_package_label; return get_apk_info().host_package_label;
} }
const char* package_version_code() { const std::string& package_version_code() {
return get_apk_info().package_version_code; return get_apk_info().package_version_code;
} }
const char* package_version_name() { const std::string& package_version_name() {
return get_apk_info().package_version_name; return get_apk_info().package_version_name;
} }
const char* package_name() { const std::string& package_name() {
return get_apk_info().package_name; return get_apk_info().package_name;
} }
const char* resources_version() { const std::string& resources_version() {
return get_apk_info().resources_version; return get_apk_info().resources_version;
} }
const char* installer_package_name() { const std::string& installer_package_name() {
return get_apk_info().installer_package_name; return get_apk_info().installer_package_name;
} }

@ -5,33 +5,35 @@
#ifndef BASE_ANDROID_APK_INFO_H_ #ifndef BASE_ANDROID_APK_INFO_H_
#define BASE_ANDROID_APK_INFO_H_ #define BASE_ANDROID_APK_INFO_H_
#include <string>
namespace base::android::apk_info { namespace base::android::apk_info {
// The package name of the host app which has loaded WebView, retrieved from // The package name of the host app which has loaded WebView, retrieved from
// the application context. In the context of the SDK Runtime, the package // the application context. In the context of the SDK Runtime, the package
// name of the app that owns this particular instance of the SDK Runtime will // name of the app that owns this particular instance of the SDK Runtime will
// also be included. e.g. // also be included. e.g.
// com.google.android.sdksandbox:com:com.example.myappwithads // com.google.android.sdksandbox:com:com.example.myappwithads
const char* host_package_name(); const std::string& host_package_name();
// The application name (e.g. "Chrome"). For WebView, this is name of the // The application name (e.g. "Chrome"). For WebView, this is name of the
// embedding app. In the context of the SDK Runtime, this is the name of the // embedding app. In the context of the SDK Runtime, this is the name of the
// app that owns this particular instance of the SDK Runtime. // app that owns this particular instance of the SDK Runtime.
const char* host_version_code(); const std::string& host_version_code();
// By default: same as versionCode. For WebView: versionCode of the embedding // By default: same as versionCode. For WebView: versionCode of the embedding
// app. In the context of the SDK Runtime, this is the versionCode of the app // app. In the context of the SDK Runtime, this is the versionCode of the app
// that owns this particular instance of the SDK Runtime. // that owns this particular instance of the SDK Runtime.
const char* host_package_label(); const std::string& host_package_label();
const char* package_version_code(); const std::string& package_version_code();
const char* package_version_name(); const std::string& package_version_name();
const char* package_name(); const std::string& package_name();
const char* resources_version(); const std::string& resources_version();
const char* installer_package_name(); const std::string& installer_package_name();
bool is_debug_app(); bool is_debug_app();

@ -72,7 +72,7 @@ BuildInfo::BuildInfo()
BuildInfo::~BuildInfo() = default; BuildInfo::~BuildInfo() = default;
const char* BuildInfo::gms_version_code() const { const std::string& BuildInfo::gms_version_code() const {
return device_info::gms_version_code(); return device_info::gms_version_code();
} }
@ -81,7 +81,7 @@ void BuildInfo::set_gms_version_code_for_test(
device_info::set_gms_version_code_for_test(gms_version_code); device_info::set_gms_version_code_for_test(gms_version_code);
} }
std::string BuildInfo::host_signing_cert_sha256() { const std::string BuildInfo::host_signing_cert_sha256() {
JNIEnv* env = AttachCurrentThread(); JNIEnv* env = AttachCurrentThread();
return Java_BuildInfo_lazyGetHostSigningCertSha256(env); return Java_BuildInfo_lazyGetHostSigningCertSha256(env);
} }

@ -62,23 +62,19 @@ class BASE_EXPORT BuildInfo {
// should only be one instance of BuildInfo ever created. // should only be one instance of BuildInfo ever created.
static BuildInfo* GetInstance(); static BuildInfo* GetInstance();
// Const char* is used instead of std::strings because these values must be const std::string& device() const { return device_; }
// available even if the process is in a crash state. Sadly
// std::string.c_str() doesn't guarantee that memory won't be allocated when
// it is called.
const char* device() const { return device_; }
const char* manufacturer() const { return manufacturer_; } const std::string& manufacturer() const { return manufacturer_; }
const char* model() const { return model_; } const std::string& model() const { return model_; }
const char* brand() const { return brand_; } const std::string& brand() const { return brand_; }
const char* android_build_id() const { return android_build_id_; } const std::string& android_build_id() const { return android_build_id_; }
const char* android_build_fp() const { return android_build_fp_; } const std::string& android_build_fp() const { return android_build_fp_; }
const char* gms_version_code() const; const std::string& gms_version_code() const;
void set_gms_version_code_for_test(const std::string& gms_version_code); void set_gms_version_code_for_test(const std::string& gms_version_code);
@ -87,37 +83,43 @@ class BASE_EXPORT BuildInfo {
// name of the app that owns this particular instance of the SDK Runtime will // name of the app that owns this particular instance of the SDK Runtime will
// also be included. e.g. // also be included. e.g.
// com.google.android.sdksandbox:com:com.example.myappwithads // com.google.android.sdksandbox:com:com.example.myappwithads
const char* host_package_name() const { return host_package_name_; } const std::string& host_package_name() const { return host_package_name_; }
// The application name (e.g. "Chrome"). For WebView, this is name of the // The application name (e.g. "Chrome"). For WebView, this is name of the
// embedding app. In the context of the SDK Runtime, this is the name of the // embedding app. In the context of the SDK Runtime, this is the name of the
// app that owns this particular instance of the SDK Runtime. // app that owns this particular instance of the SDK Runtime.
const char* host_version_code() const { return host_version_code_; } const std::string& host_version_code() const { return host_version_code_; }
// By default: same as versionCode. For WebView: versionCode of the embedding // By default: same as versionCode. For WebView: versionCode of the embedding
// app. In the context of the SDK Runtime, this is the versionCode of the app // app. In the context of the SDK Runtime, this is the versionCode of the app
// that owns this particular instance of the SDK Runtime. // that owns this particular instance of the SDK Runtime.
const char* host_package_label() const { return host_package_label_; } const std::string& host_package_label() const { return host_package_label_; }
// The SHA256 of the public certificate used to sign the host application. // The SHA256 of the public certificate used to sign the host application.
// This will default to an empty string if we were unable to retrieve it. // This will default to an empty string if we were unable to retrieve it.
std::string host_signing_cert_sha256(); const std::string host_signing_cert_sha256();
const char* package_version_code() const { return package_version_code_; } const std::string& package_version_code() const {
return package_version_code_;
}
const char* package_version_name() const { return package_version_name_; } const std::string& package_version_name() const {
return package_version_name_;
}
const char* package_name() const { return package_name_; } const std::string& package_name() const { return package_name_; }
const char* resources_version() const { return resources_version_; } const std::string& resources_version() const { return resources_version_; }
const char* build_type() const { return build_type_; } const std::string& build_type() const { return build_type_; }
const char* board() const { return board_; } const std::string& board() const { return board_; }
const char* installer_package_name() const { return installer_package_name_; } const std::string& installer_package_name() const {
return installer_package_name_;
}
const char* abi_name() const { return abi_name_; } const std::string& abi_name() const { return abi_name_; }
int sdk_int() const { return sdk_int_; } int sdk_int() const { return sdk_int_; }
@ -133,13 +135,15 @@ class BASE_EXPORT BuildInfo {
bool is_tv() const { return is_tv_; } bool is_tv() const { return is_tv_; }
const char* version_incremental() const { return version_incremental_; } const std::string& version_incremental() const {
return version_incremental_;
}
const char* hardware() const { return hardware_; } const std::string& hardware() const { return hardware_; }
bool is_automotive() const { return is_automotive_; } bool is_automotive() const { return is_automotive_; }
const char* codename() const { return codename_; } const std::string& codename() const { return codename_; }
bool is_foldable() const { return is_foldable_; } bool is_foldable() const { return is_foldable_; }
@ -149,7 +153,7 @@ class BASE_EXPORT BuildInfo {
int32_t vulkan_deqp_level() const { return vulkan_deqp_level_; } int32_t vulkan_deqp_level() const { return vulkan_deqp_level_; }
// Available only on android S+. For S-, this method returns empty string. // Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer() const { return soc_manufacturer_; } const std::string& soc_manufacturer() const { return soc_manufacturer_; }
bool is_debug_app() const { return is_debug_app_; } bool is_debug_app() const { return is_debug_app_; }
@ -158,39 +162,34 @@ class BASE_EXPORT BuildInfo {
explicit BuildInfo(); explicit BuildInfo();
// Const char* is used instead of std::strings because these values must be const std::string brand_;
// available even if the process is in a crash state. Sadly const std::string device_;
// std::string.c_str() doesn't guarantee that memory won't be allocated when const std::string android_build_id_;
// it is called. const std::string manufacturer_;
const char* const brand_; const std::string model_;
const char* const device_;
const char* const android_build_id_;
const char* const manufacturer_;
const char* const model_;
const int sdk_int_; const int sdk_int_;
const char* const build_type_; const std::string build_type_;
const char* const board_; const std::string board_;
const char* const host_package_name_; const std::string host_package_name_;
const char* const host_version_code_; const std::string host_version_code_;
const char* const host_package_label_; const std::string host_package_label_;
const char* const package_name_; const std::string package_name_;
const char* const package_version_code_; const std::string package_version_code_;
const char* const package_version_name_; const std::string package_version_name_;
const char* const android_build_fp_; const std::string android_build_fp_;
const char* const installer_package_name_; const std::string installer_package_name_;
const char* const abi_name_; const std::string abi_name_;
const char* const resources_version_; const std::string resources_version_;
// Not needed by breakpad.
const int target_sdk_version_; const int target_sdk_version_;
const bool is_debug_android_; const bool is_debug_android_;
const bool is_tv_; const bool is_tv_;
const char* const version_incremental_; const std::string version_incremental_;
const char* const hardware_; const std::string hardware_;
const bool is_automotive_; const bool is_automotive_;
const char* const codename_; const std::string codename_;
const int32_t vulkan_deqp_level_; const int32_t vulkan_deqp_level_;
const bool is_foldable_; const bool is_foldable_;
const char* const soc_manufacturer_; const std::string soc_manufacturer_;
const bool is_debug_app_; const bool is_debug_app_;
const bool is_desktop_; const bool is_desktop_;
}; };

@ -11,6 +11,7 @@
#include "base/android/jni_string.h" #include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h" #include "base/android/scoped_java_ref.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType(). // Must come after all headers that specialize FromJniType() / ToJniType().
@ -20,11 +21,7 @@
namespace base::android::device_info { namespace base::android::device_info {
namespace { namespace {
struct DeviceInfo { struct DeviceInfo {
// Const char* is used instead of std::strings because these values must be std::string gms_version_code;
// available even if the process is in a crash state. Sadly
// std::string.c_str() doesn't guarantee that memory won't be allocated when
// it is called.
const char* gms_version_code;
bool is_tv; bool is_tv;
bool is_automotive; bool is_automotive;
bool is_foldable; bool is_foldable;
@ -33,50 +30,44 @@ struct DeviceInfo {
int32_t vulkan_deqp_level; int32_t vulkan_deqp_level;
}; };
std::optional<DeviceInfo> holder; static std::optional<DeviceInfo>& get_holder() {
static base::NoDestructor<std::optional<DeviceInfo>> holder;
return *holder;
}
DeviceInfo& get_device_info() { DeviceInfo& get_device_info() {
[[maybe_unused]] static auto once = [] { std::optional<DeviceInfo>& holder = get_holder();
if (!holder.has_value()) {
Java_DeviceInfo_nativeReadyForFields(AttachCurrentThread()); Java_DeviceInfo_nativeReadyForFields(AttachCurrentThread());
return std::monostate(); }
}();
// holder should be initialized as the java is supposed to call the native
// method FillFields which will initialize the fields within the holder.
DCHECK(holder.has_value());
return *holder; return *holder;
} }
} // namespace } // namespace
static void JNI_DeviceInfo_FillFields( static void JNI_DeviceInfo_FillFields(JNIEnv* env,
JNIEnv* env, std::string& gmsVersionCode,
const jni_zero::JavaParamRef<jstring>& gmsVersionCode, jboolean isTV,
jboolean isTV, jboolean isAutomotive,
jboolean isAutomotive, jboolean isFoldable,
jboolean isFoldable, jboolean isDesktop,
jboolean isDesktop, jint vulkanDeqpLevel) {
jint vulkanDeqpLevel) { std::optional<DeviceInfo>& holder = get_holder();
DCHECK(!holder.has_value()); DCHECK(!holder.has_value());
auto java_string_to_const_char = holder.emplace(DeviceInfo{.gms_version_code = gmsVersionCode,
[](const jni_zero::JavaParamRef<jstring>& str) { .is_tv = static_cast<bool>(isTV),
return UNSAFE_TODO(strdup(ConvertJavaStringToUTF8(str).c_str())); .is_automotive = static_cast<bool>(isAutomotive),
}; .is_foldable = static_cast<bool>(isFoldable),
holder = .is_desktop = static_cast<bool>(isDesktop),
DeviceInfo{.gms_version_code = java_string_to_const_char(gmsVersionCode), .vulkan_deqp_level = vulkanDeqpLevel});
.is_tv = static_cast<bool>(isTV),
.is_automotive = static_cast<bool>(isAutomotive),
.is_foldable = static_cast<bool>(isFoldable),
.is_desktop = static_cast<bool>(isDesktop),
.vulkan_deqp_level = vulkanDeqpLevel};
} }
const char* gms_version_code() { const std::string& gms_version_code() {
return get_device_info().gms_version_code; return get_device_info().gms_version_code;
} }
void set_gms_version_code_for_test(const std::string& gms_version_code) { void set_gms_version_code_for_test(const std::string& gms_version_code) {
get_device_info().gms_version_code = get_device_info().gms_version_code = gms_version_code;
UNSAFE_TODO(strdup(gms_version_code.c_str()));
Java_DeviceInfo_setGmsVersionCodeForTest(AttachCurrentThread(), Java_DeviceInfo_setGmsVersionCodeForTest(AttachCurrentThread(),
gms_version_code); gms_version_code);
} }

@ -8,7 +8,7 @@
#include <string> #include <string>
namespace base::android::device_info { namespace base::android::device_info {
const char* gms_version_code(); const std::string& gms_version_code();
void set_gms_version_code_for_test(const std::string& gms_version_code); void set_gms_version_code_for_test(const std::string& gms_version_code);

@ -9,6 +9,7 @@ import android.text.TextUtils;
import org.jni_zero.CalledByNative; import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.JniType;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.build.annotations.NullMarked; import org.chromium.build.annotations.NullMarked;
@ -69,19 +70,19 @@ public final class AndroidInfo {
@NativeMethods @NativeMethods
interface Natives { interface Natives {
void fillFields( void fillFields(
String brand, @JniType("std::string") String brand,
String device, @JniType("std::string") String device,
String buildId, @JniType("std::string") String buildId,
String manufacturer, @JniType("std::string") String manufacturer,
String model, @JniType("std::string") String model,
String type, @JniType("std::string") String type,
String board, @JniType("std::string") String board,
String androidBuildFingerprint, @JniType("std::string") String androidBuildFingerprint,
String versionIncremental, @JniType("std::string") String versionIncremental,
String hardware, @JniType("std::string") String hardware,
String codeName, @JniType("std::string") String codeName,
String socManufacturer, @JniType("std::string") String socManufacturer,
String supportedAbis, @JniType("std::string") String supportedAbis,
int sdkInt, int sdkInt,
boolean isDebugAndroid); boolean isDebugAndroid);
} }

@ -14,6 +14,7 @@ import android.os.Process;
import org.jni_zero.CalledByNative; import org.jni_zero.CalledByNative;
import org.jni_zero.JNINamespace; import org.jni_zero.JNINamespace;
import org.jni_zero.JniType;
import org.jni_zero.NativeMethods; import org.jni_zero.NativeMethods;
import org.chromium.base.version_info.VersionInfo; import org.chromium.base.version_info.VersionInfo;
@ -322,14 +323,14 @@ public final class ApkInfo {
@NativeMethods @NativeMethods
interface Natives { interface Natives {
void fillFields( void fillFields(
String hostPackageName, @JniType("std::string") String hostPackageName,
String hostVersionCode, @JniType("std::string") String hostVersionCode,
String hostPackageLabel, @JniType("std::string") String hostPackageLabel,
String packageVersionCode, @JniType("std::string") String packageVersionCode,
String packageVersionName, @JniType("std::string") String packageVersionName,
String packageName, @JniType("std::string") String packageName,
String resourcesVersion, @JniType("std::string") String resourcesVersion,
String installerPackageName, @JniType("std::string") String installerPackageName,
boolean isDebugApp, boolean isDebugApp,
int targetSdkVersion); int targetSdkVersion);
} }

@ -196,7 +196,7 @@ public final class DeviceInfo {
@NativeMethods @NativeMethods
interface Natives { interface Natives {
void fillFields( void fillFields(
String gmsVersionCode, @JniType("std::string") String gmsVersionCode,
boolean isTV, boolean isTV,
boolean isAutomotive, boolean isAutomotive,
boolean isFoldable, boolean isFoldable,

@ -67,16 +67,17 @@ void PerfettoPlatform::ResetTaskRunner(
// Note that we override the producer name for the mojo backend in ProducerHost, // Note that we override the producer name for the mojo backend in ProducerHost,
// and thus this only affects the producer name for the system backend. // and thus this only affects the producer name for the system backend.
std::string PerfettoPlatform::GetCurrentProcessName() { std::string PerfettoPlatform::GetCurrentProcessName() {
const char* host_package_name = nullptr;
#if BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID)
host_package_name = android::apk_info::host_package_name(); const std::string& host_package_name = android::apk_info::host_package_name();
#else
std::string host_package_name;
#endif // BUILDFLAG(IS_ANDROID) #endif // BUILDFLAG(IS_ANDROID)
// On Android we want to include if this is webview inside of an app or // On Android we want to include if this is webview inside of an app or
// Android Chrome. To aid this we add the host_package_name to differentiate // Android Chrome. To aid this we add the host_package_name to differentiate
// the various apps and sources. // the various apps and sources.
std::string process_name; std::string process_name;
if (host_package_name) { if (!host_package_name.empty()) {
process_name = StrCat( process_name = StrCat(
{process_name_prefix_, host_package_name, "-", {process_name_prefix_, host_package_name, "-",
NumberToString(trace_event::TraceLog::GetInstance()->process_id())}); NumberToString(trace_event::TraceLog::GetInstance()->process_id())});

@ -165,8 +165,8 @@ class SandboxedHandler {
restore_previous_handler_ = restore_previous_handler_ =
build_info->sdk_int() < base::android::SDK_VERSION_JELLY_BEAN_MR2 || build_info->sdk_int() < base::android::SDK_VERSION_JELLY_BEAN_MR2 ||
build_info->sdk_int() >= base::android::SDK_VERSION_OREO || build_info->sdk_int() >= base::android::SDK_VERSION_OREO ||
strcmp(build_info->build_type(), "eng") == 0 || build_info->build_type() == "eng" ||
strcmp(build_info->build_type(), "userdebug") == 0; build_info->build_type() == "userdebug";
bool signal_stack_initialized = bool signal_stack_initialized =
CrashpadClient::InitializeSignalStackForThread(); CrashpadClient::InitializeSignalStackForThread();

@ -51,13 +51,14 @@ bool AlwaysUseWideColorGamut() {
// As it takes some work to compute this, cache the result. // As it takes some work to compute this, cache the result.
static bool is_always_use_wide_color_gamut_enabled = [] { static bool is_always_use_wide_color_gamut_enabled = [] {
const char* current_model = const std::string& current_model =
base::android::BuildInfo::GetInstance()->model(); base::android::BuildInfo::GetInstance()->model();
const std::array<std::string, 2> enabled_models = { const std::array<std::string, 2> enabled_models = {
std::string{"Pixel 4"}, std::string{"Pixel 4 XL"}}; std::string{"Pixel 4"}, std::string{"Pixel 4 XL"}};
for (const std::string& model : enabled_models) { for (const std::string& model : enabled_models) {
if (model == current_model) if (model == current_model) {
return true; return true;
}
} }
return false; return false;

@ -33,7 +33,7 @@ namespace features {
namespace { namespace {
#if BUILDFLAG(IS_ANDROID) #if BUILDFLAG(IS_ANDROID)
bool IsDeviceBlocked(const char* field, const std::string& block_list) { bool IsDeviceBlocked(const std::string& field, const std::string& block_list) {
auto disable_patterns = base::SplitString( auto disable_patterns = base::SplitString(
block_list, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); block_list, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
for (const auto& disable_pattern : disable_patterns) { for (const auto& disable_pattern : disable_patterns) {

@ -66,17 +66,18 @@ bool IsDeviceBlocked(std::string_view field, std::string_view block_list) {
int GetEMUIVersion() { int GetEMUIVersion() {
const auto* build_info = base::android::BuildInfo::GetInstance(); const auto* build_info = base::android::BuildInfo::GetInstance();
std::string_view manufacturer(build_info->manufacturer());
// TODO(crbug.com/40136096): check Honor devices as well. // TODO(crbug.com/40136096): check Honor devices as well.
if (manufacturer != "HUAWEI") if (build_info->manufacturer() != "HUAWEI") {
return -1; return -1;
}
// Huawei puts EMUI version in the build version incremental. // Huawei puts EMUI version in the build version incremental.
// Example: 11.0.0.130C00 // Example: 11.0.0.130C00
int version = 0; int version = 0;
if (sscanf(build_info->version_incremental(), "%d.", &version) != 1) if (sscanf(build_info->version_incremental().c_str(), "%d.", &version) != 1) {
return -1; return -1;
}
return version; return version;
} }

@ -42,9 +42,9 @@ void MetadataDataSource::WriteMetadata() {
#if BUILDFLAG(IS_ANDROID) && defined(OFFICIAL_BUILD) #if BUILDFLAG(IS_ANDROID) && defined(OFFICIAL_BUILD)
// Version code is only set for official builds on Android. // Version code is only set for official builds on Android.
const char* version_code_str = const std::string& version_code_str =
base::android::BuildInfo::GetInstance()->package_version_code(); base::android::BuildInfo::GetInstance()->package_version_code();
if (version_code_str) { if (!version_code_str.empty()) {
int version_code = 0; int version_code = 0;
bool res = base::StringToInt(version_code_str, &version_code); bool res = base::StringToInt(version_code_str, &version_code);
DCHECK(res); DCHECK(res);

@ -127,9 +127,9 @@ void TraceEventMetadataSource::WriteMetadataPacket(
bool privacy_filtering_enabled) { bool privacy_filtering_enabled) {
#if BUILDFLAG(IS_ANDROID) && defined(OFFICIAL_BUILD) #if BUILDFLAG(IS_ANDROID) && defined(OFFICIAL_BUILD)
// Version code is only set for official builds on Android. // Version code is only set for official builds on Android.
const char* version_code_str = const std::string& version_code_str =
base::android::BuildInfo::GetInstance()->package_version_code(); base::android::BuildInfo::GetInstance()->package_version_code();
if (version_code_str) { if (!version_code_str.empty()) {
int version_code = 0; int version_code = 0;
bool res = base::StringToInt(version_code_str, &version_code); bool res = base::StringToInt(version_code_str, &version_code);
DCHECK(res); DCHECK(res);

@ -65,7 +65,7 @@ const base::FeatureParam<std::string>
kPassthroughCommandDecoderBlockListByGPUVendorId{ kPassthroughCommandDecoderBlockListByGPUVendorId{
&kDefaultPassthroughCommandDecoder, "BlockListByGPUVendorId", ""}; &kDefaultPassthroughCommandDecoder, "BlockListByGPUVendorId", ""};
bool IsDeviceBlocked(const char* field, const std::string& block_list) { bool IsDeviceBlocked(const std::string& field, const std::string& block_list) {
auto disable_patterns = base::SplitString( auto disable_patterns = base::SplitString(
block_list, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); block_list, "|", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
for (const auto& disable_pattern : disable_patterns) { for (const auto& disable_pattern : disable_patterns) {