Loading core/java/android/os/VintfObject.java +18 −0 Original line number Diff line number Diff line Loading @@ -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; /** Loading Loading @@ -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() {} } core/jni/android_os_VintfObject.cpp +69 −21 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ static jmethodID gHashMapInit; static jmethodID gHashMapPut; static jclass gLongClazz; static jmethodID gLongValueOf; static jclass gVintfObjectClazz; static jmethodID gRunCommand; namespace android { Loading @@ -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; Loading Loading @@ -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); } Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; } Loading @@ -188,16 +235,17 @@ 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)); Loading Loading
core/java/android/os/VintfObject.java +18 −0 Original line number Diff line number Diff line Loading @@ -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; /** Loading Loading @@ -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() {} }
core/jni/android_os_VintfObject.cpp +69 −21 Original line number Diff line number Diff line Loading @@ -32,6 +32,8 @@ static jmethodID gHashMapInit; static jmethodID gHashMapPut; static jclass gLongClazz; static jmethodID gLongValueOf; static jclass gVintfObjectClazz; static jmethodID gRunCommand; namespace android { Loading @@ -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; Loading Loading @@ -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); } Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading @@ -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; } Loading @@ -188,16 +235,17 @@ 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)); Loading