blob: 99d736db1c048b42310f69e3ce84190aee4e39fb [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/android/android_info.h"
#include <cstring>
#include <mutex>
#include <string>
#include <variant>
#include "base/android/jni_android.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/check.h"
#include "base/compiler_specific.h"
#include "base/strings/string_number_conversions.h"
// Must come after all headers that specialize FromJniType() / ToJniType().
#include "base/android_info_jni/AndroidInfo_jni.h"
namespace base::android::android_info {
namespace {
struct AndroidInfo {
// Const char* is used instead of std::strings because these values must be
// 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 char* model;
const char* brand;
const char* android_build_id;
const char* build_type;
const char* board;
const char* android_build_fp;
int sdk_int;
bool is_debug_android;
const char* version_incremental;
const char* hardware;
bool is_at_least_u;
const char* codename;
// Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer;
bool is_at_least_t;
const char* abi_name;
};
std::optional<AndroidInfo> holder;
const AndroidInfo& get_android_info() {
[[maybe_unused]] static auto once = [] {
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;
}
} // namespace
static void JNI_AndroidInfo_FillFields(
JNIEnv* env,
const jni_zero::JavaParamRef<jstring>& brand,
const jni_zero::JavaParamRef<jstring>& device,
const jni_zero::JavaParamRef<jstring>& buildId,
const jni_zero::JavaParamRef<jstring>& manufacturer,
const jni_zero::JavaParamRef<jstring>& model,
const jni_zero::JavaParamRef<jstring>& type,
const jni_zero::JavaParamRef<jstring>& board,
const jni_zero::JavaParamRef<jstring>& androidBuildFingerprint,
const jni_zero::JavaParamRef<jstring>& versionIncremental,
const jni_zero::JavaParamRef<jstring>& hardware,
const jni_zero::JavaParamRef<jstring>& codeName,
const jni_zero::JavaParamRef<jstring>& socManufacturer,
const jni_zero::JavaParamRef<jstring>& supportedAbis,
jint sdkInt,
jboolean isDebugAndroid,
jboolean isAtleastU,
jboolean isAtleastT) {
DCHECK(!holder.has_value());
auto java_string_to_const_char =
[](const jni_zero::JavaParamRef<jstring>& str) {
return UNSAFE_TODO(strdup(ConvertJavaStringToUTF8(str).c_str()));
};
holder = AndroidInfo{
.device = java_string_to_const_char(device),
.manufacturer = java_string_to_const_char(manufacturer),
.model = java_string_to_const_char(model),
.brand = java_string_to_const_char(brand),
.android_build_id = java_string_to_const_char(buildId),
.build_type = java_string_to_const_char(type),
.board = java_string_to_const_char(board),
.android_build_fp = java_string_to_const_char(androidBuildFingerprint),
.sdk_int = sdkInt,
.is_debug_android = static_cast<bool>(isDebugAndroid),
.version_incremental = java_string_to_const_char(versionIncremental),
.hardware = java_string_to_const_char(hardware),
.is_at_least_u = static_cast<bool>(isAtleastU),
.codename = java_string_to_const_char(codeName),
.soc_manufacturer = java_string_to_const_char(socManufacturer),
.is_at_least_t = static_cast<bool>(isAtleastT),
.abi_name = java_string_to_const_char(supportedAbis),
};
}
const char* device() {
return get_android_info().device;
}
const char* manufacturer() {
return get_android_info().manufacturer;
}
const char* model() {
return get_android_info().model;
}
const char* brand() {
return get_android_info().brand;
}
const char* android_build_id() {
return get_android_info().android_build_id;
}
const char* build_type() {
return get_android_info().build_type;
}
const char* board() {
return get_android_info().board;
}
const char* android_build_fp() {
return get_android_info().android_build_fp;
}
int sdk_int() {
return get_android_info().sdk_int;
}
bool is_debug_android() {
return get_android_info().is_debug_android;
}
const char* version_incremental() {
return get_android_info().version_incremental;
}
const char* hardware() {
return get_android_info().hardware;
}
bool is_at_least_u() {
return get_android_info().is_at_least_u;
}
const char* codename() {
return get_android_info().codename;
}
// Available only on android S+. For S-, this method returns empty string.
const char* soc_manufacturer() {
return get_android_info().soc_manufacturer;
}
bool is_at_least_t() {
return get_android_info().is_at_least_t;
}
const char* abi_name() {
return get_android_info().abi_name;
}
} // namespace base::android::android_info