diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java index 505655775239d06d4152f32e61213b7a765ec05a..bb89e0791053c94fbddc2f4d816c2298065eba6b 100644 --- a/core/java/android/os/VintfObject.java +++ b/core/java/android/os/VintfObject.java @@ -17,8 +17,11 @@ package android.os; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.TestApi; +import android.app.ActivityThread; +import java.io.IOException; import java.util.Map; /** @@ -113,5 +116,20 @@ public class VintfObject { @TestApi public static native Long getTargetFrameworkCompatibilityMatrixVersion(); + /** + * Executes a shell command using shell user identity, and return the standard output in string. + * + * @hide + */ + private static @Nullable String runShellCommand(@NonNull String command) throws IOException { + var activityThread = ActivityThread.currentActivityThread(); + var instrumentation = activityThread.getInstrumentation(); + var automation = instrumentation.getUiAutomation(); + var pfd = automation.executeShellCommand(command); + try (var is = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { + return new String(is.readAllBytes()); + } + } + private VintfObject() {} } diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index 8dc9d0aa578e8051c0be3cf54802727508676665..7a4854bbd260405f0192545d77ae92d882ba3cd6 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -32,6 +32,8 @@ static jmethodID gHashMapInit; static jmethodID gHashMapPut; static jclass gLongClazz; static jmethodID gLongValueOf; +static jclass gVintfObjectClazz; +static jmethodID gRunCommand; namespace android { @@ -47,6 +49,56 @@ using vintf::VintfObject; using vintf::Vndk; using vintf::CheckFlags::ENABLE_ALL_CHECKS; +// Instead of VintfObject::GetXxx(), we construct +// HalManifest/CompatibilityMatrix objects by calling `vintf` through +// UiAutomation.executeShellCommand() so that the commands are executed +// using shell identity. Otherwise, we would need to allow "apps" to access +// files like apex-info-list.xml which we don't want to open to apps. +// This is okay because VintfObject is @TestApi and only used in CTS tests. + +static std::string runCmd(JNIEnv* env, const char* cmd) { + jstring jstr = (jstring)env->CallStaticObjectMethod(gVintfObjectClazz, gRunCommand, + env->NewStringUTF(cmd)); + std::string output; + if (jstr) { + auto cstr = env->GetStringUTFChars(jstr, nullptr); + output = std::string(cstr); + env->ReleaseStringUTFChars(jstr, cstr); + } else { + LOG(WARNING) << "Failed to run " << cmd; + env->ExceptionDescribe(); + env->ExceptionClear(); + } + return output; +} + +template <typename T> +static std::shared_ptr<const T> fromXml(const std::string& content) { + std::shared_ptr<T> object = std::make_unique<T>(); + std::string error; + if (fromXml(object.get(), content, &error)) { + return object; + } + LOG(WARNING) << "Unabled to parse: " << error; + return nullptr; +} + +static std::shared_ptr<const HalManifest> getDeviceHalManifest(JNIEnv* env) { + return fromXml<HalManifest>(runCmd(env, "vintf dm")); +} + +static std::shared_ptr<const HalManifest> getFrameworkHalManifest(JNIEnv* env) { + return fromXml<HalManifest>(runCmd(env, "vintf fm")); +} + +static std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix(JNIEnv* env) { + return fromXml<CompatibilityMatrix>(runCmd(env, "vintf dcm")); +} + +static std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix(JNIEnv* env) { + return fromXml<CompatibilityMatrix>(runCmd(env, "vintf fcm")); +} + template<typename V> static inline jobjectArray toJavaStringArray(JNIEnv* env, const V& v) { size_t i; @@ -83,12 +135,10 @@ static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass) { std::vector<std::string> cStrings; - tryAddSchema(VintfObject::GetDeviceHalManifest(), "device manifest", &cStrings); - tryAddSchema(VintfObject::GetFrameworkHalManifest(), "framework manifest", &cStrings); - tryAddSchema(VintfObject::GetDeviceCompatibilityMatrix(), "device compatibility matrix", - &cStrings); - tryAddSchema(VintfObject::GetFrameworkCompatibilityMatrix(), "framework compatibility matrix", - &cStrings); + tryAddSchema(getDeviceHalManifest(env), "device manifest", &cStrings); + tryAddSchema(getFrameworkHalManifest(env), "framework manifest", &cStrings); + tryAddSchema(getDeviceCompatibilityMatrix(env), "device compatibility matrix", &cStrings); + tryAddSchema(getFrameworkCompatibilityMatrix(env), "framework compatibility matrix", &cStrings); return toJavaStringArray(env, cStrings); } @@ -108,15 +158,13 @@ static jint android_os_VintfObject_verifyBuildAtBoot(JNIEnv*, jclass) { static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) { std::set<std::string> halNames; - tryAddHalNamesAndVersions(VintfObject::GetDeviceHalManifest(), - "device manifest", &halNames); - tryAddHalNamesAndVersions(VintfObject::GetFrameworkHalManifest(), - "framework manifest", &halNames); + tryAddHalNamesAndVersions(getDeviceHalManifest(env), "device manifest", &halNames); + tryAddHalNamesAndVersions(getFrameworkHalManifest(env), "framework manifest", &halNames); return toJavaStringArray(env, halNames); } static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) { - std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest(); + std::shared_ptr<const HalManifest> manifest = getDeviceHalManifest(env); if (manifest == nullptr || manifest->type() != SchemaType::DEVICE) { LOG(WARNING) << __FUNCTION__ << "Cannot get device manifest"; return nullptr; @@ -126,8 +174,7 @@ static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) { } static jstring android_os_VintfObject_getPlatformSepolicyVersion(JNIEnv* env, jclass) { - std::shared_ptr<const CompatibilityMatrix> matrix = - VintfObject::GetFrameworkCompatibilityMatrix(); + std::shared_ptr<const CompatibilityMatrix> matrix = getFrameworkCompatibilityMatrix(env); if (matrix == nullptr || matrix->type() != SchemaType::FRAMEWORK) { jniThrowRuntimeException(env, "Cannot get framework compatibility matrix"); return nullptr; @@ -148,7 +195,7 @@ static jstring android_os_VintfObject_getPlatformSepolicyVersion(JNIEnv* env, jc } static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) { - std::shared_ptr<const HalManifest> manifest = VintfObject::GetFrameworkHalManifest(); + std::shared_ptr<const HalManifest> manifest = getFrameworkHalManifest(env); if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) { LOG(WARNING) << __FUNCTION__ << "Cannot get framework manifest"; return nullptr; @@ -163,7 +210,7 @@ static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) { } static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion(JNIEnv* env, jclass) { - std::shared_ptr<const HalManifest> manifest = VintfObject::GetDeviceHalManifest(); + std::shared_ptr<const HalManifest> manifest = getDeviceHalManifest(env); if (manifest == nullptr || manifest->level() == Level::UNSPECIFIED) { return nullptr; } @@ -188,19 +235,20 @@ static const JNINativeMethod gVintfObjectMethods[] = { const char* const kVintfObjectPathName = "android/os/VintfObject"; -int register_android_os_VintfObject(JNIEnv* env) -{ - +int register_android_os_VintfObject(JNIEnv* env) { gString = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/String")); gHashMapClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/HashMap")); gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V"); - gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz, - "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz, "put", + "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); gLongClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Long")); gLongValueOf = GetStaticMethodIDOrDie(env, gLongClazz, "valueOf", "(J)Ljava/lang/Long;"); + gVintfObjectClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, kVintfObjectPathName)); + gRunCommand = GetStaticMethodIDOrDie(env, gVintfObjectClazz, "runShellCommand", + "(Ljava/lang/String;)Ljava/lang/String;"); return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods, - NELEM(gVintfObjectMethods)); + NELEM(gVintfObjectMethods)); } extern int register_android_os_VintfRuntimeInfo(JNIEnv* env);