1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "VintfObject"
18 //#define LOG_NDEBUG 0
19 #include <android-base/logging.h>
20 #include <vintf/VintfObject.h>
21 #include <vintf/parse_string.h>
22 #include <vintf/parse_xml.h>
23
24 #include <vector>
25 #include <string>
26
27 #include "jni_wrappers.h"
28
29 static jclass gString;
30 static jclass gHashMapClazz;
31 static jmethodID gHashMapInit;
32 static jmethodID gHashMapPut;
33 static jclass gLongClazz;
34 static jmethodID gLongValueOf;
35 static jclass gVintfObjectClazz;
36 static jmethodID gRunCommand;
37
38 namespace android {
39
40 using vintf::CompatibilityMatrix;
41 using vintf::HalManifest;
42 using vintf::Level;
43 using vintf::SchemaType;
44 using vintf::SepolicyVersion;
45 using vintf::to_string;
46 using vintf::toXml;
47 using vintf::Version;
48 using vintf::VintfObject;
49 using vintf::Vndk;
50 using vintf::CheckFlags::ENABLE_ALL_CHECKS;
51
52 // Instead of VintfObject::GetXxx(), we construct
53 // HalManifest/CompatibilityMatrix objects by calling `vintf` through
54 // UiAutomation.executeShellCommand() so that the commands are executed
55 // using shell identity. Otherwise, we would need to allow "apps" to access
56 // files like apex-info-list.xml which we don't want to open to apps.
57 // This is okay because VintfObject is @TestApi and only used in CTS tests.
58
runCmd(JNIEnv * env,const char * cmd)59 static std::string runCmd(JNIEnv* env, const char* cmd) {
60 jstring jstr = (jstring)env->CallStaticObjectMethod(gVintfObjectClazz, gRunCommand,
61 env->NewStringUTF(cmd));
62 std::string output;
63 if (jstr) {
64 auto cstr = env->GetStringUTFChars(jstr, nullptr);
65 output = std::string(cstr);
66 env->ReleaseStringUTFChars(jstr, cstr);
67 } else {
68 LOG(WARNING) << "Failed to run " << cmd;
69 env->ExceptionDescribe();
70 env->ExceptionClear();
71 }
72 return output;
73 }
74
75 template <typename T>
fromXml(const std::string & content)76 static std::shared_ptr<const T> fromXml(const std::string& content) {
77 std::shared_ptr<T> object = std::make_unique<T>();
78 std::string error;
79 if (fromXml(object.get(), content, &error)) {
80 return object;
81 }
82 LOG(WARNING) << "Unabled to parse: " << error;
83 return nullptr;
84 }
85
getDeviceHalManifest(JNIEnv * env)86 static std::shared_ptr<const HalManifest> getDeviceHalManifest(JNIEnv* env) {
87 return fromXml<HalManifest>(runCmd(env, "vintf dm"));
88 }
89
getFrameworkHalManifest(JNIEnv * env)90 static std::shared_ptr<const HalManifest> getFrameworkHalManifest(JNIEnv* env) {
91 return fromXml<HalManifest>(runCmd(env, "vintf fm"));
92 }
93
getDeviceCompatibilityMatrix(JNIEnv * env)94 static std::shared_ptr<const CompatibilityMatrix> getDeviceCompatibilityMatrix(JNIEnv* env) {
95 return fromXml<CompatibilityMatrix>(runCmd(env, "vintf dcm"));
96 }
97
getFrameworkCompatibilityMatrix(JNIEnv * env)98 static std::shared_ptr<const CompatibilityMatrix> getFrameworkCompatibilityMatrix(JNIEnv* env) {
99 return fromXml<CompatibilityMatrix>(runCmd(env, "vintf fcm"));
100 }
101
102 template<typename V>
toJavaStringArray(JNIEnv * env,const V & v)103 static inline jobjectArray toJavaStringArray(JNIEnv* env, const V& v) {
104 size_t i;
105 typename V::const_iterator it;
106 jobjectArray ret = env->NewObjectArray(v.size(), gString, NULL /* init element */);
107 for (i = 0, it = v.begin(); it != v.end(); ++i, ++it) {
108 env->SetObjectArrayElement(ret, i, env->NewStringUTF(it->c_str()));
109 }
110 return ret;
111 }
112
113 template <typename T>
tryAddSchema(const std::shared_ptr<const T> & object,const std::string & description,std::vector<std::string> * cStrings)114 static void tryAddSchema(const std::shared_ptr<const T>& object, const std::string& description,
115 std::vector<std::string>* cStrings) {
116 if (object == nullptr) {
117 LOG(WARNING) << __FUNCTION__ << "Cannot get " << description;
118 } else {
119 cStrings->push_back(toXml(*object));
120 }
121 }
122
tryAddHalNamesAndVersions(const std::shared_ptr<const HalManifest> & manifest,const std::string & description,std::set<std::string> * output)123 static void tryAddHalNamesAndVersions(const std::shared_ptr<const HalManifest>& manifest,
124 const std::string& description,
125 std::set<std::string> *output) {
126 if (manifest == nullptr) {
127 LOG(WARNING) << __FUNCTION__ << "Cannot get " << description;
128 } else {
129 auto names = manifest->getHalNamesAndVersions();
130 output->insert(names.begin(), names.end());
131 }
132 }
133
android_os_VintfObject_report(JNIEnv * env,jclass)134 static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass)
135 {
136 std::vector<std::string> cStrings;
137
138 tryAddSchema(getDeviceHalManifest(env), "device manifest", &cStrings);
139 tryAddSchema(getFrameworkHalManifest(env), "framework manifest", &cStrings);
140 tryAddSchema(getDeviceCompatibilityMatrix(env), "device compatibility matrix", &cStrings);
141 tryAddSchema(getFrameworkCompatibilityMatrix(env), "framework compatibility matrix", &cStrings);
142
143 return toJavaStringArray(env, cStrings);
144 }
145
android_os_VintfObject_verifyBuildAtBoot(JNIEnv *,jclass)146 static jint android_os_VintfObject_verifyBuildAtBoot(JNIEnv*, jclass) {
147 std::string error;
148 // Use temporary VintfObject, not the shared instance, to release memory
149 // after check.
150 int32_t status =
151 VintfObject::Builder()
152 .build()
153 ->checkCompatibility(&error, ENABLE_ALL_CHECKS.disableAvb().disableKernel());
154 if (status)
155 LOG(WARNING) << "VintfObject.verifyBuildAtBoot() returns " << status << ": " << error;
156 return status;
157 }
158
android_os_VintfObject_getHalNamesAndVersions(JNIEnv * env,jclass)159 static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
160 std::set<std::string> halNames;
161 tryAddHalNamesAndVersions(getDeviceHalManifest(env), "device manifest", &halNames);
162 tryAddHalNamesAndVersions(getFrameworkHalManifest(env), "framework manifest", &halNames);
163 return toJavaStringArray(env, halNames);
164 }
165
android_os_VintfObject_getSepolicyVersion(JNIEnv * env,jclass)166 static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) {
167 std::shared_ptr<const HalManifest> manifest = getDeviceHalManifest(env);
168 if (manifest == nullptr || manifest->type() != SchemaType::DEVICE) {
169 LOG(WARNING) << __FUNCTION__ << "Cannot get device manifest";
170 return nullptr;
171 }
172 std::string cString = to_string(manifest->sepolicyVersion());
173 return env->NewStringUTF(cString.c_str());
174 }
175
android_os_VintfObject_getPlatformSepolicyVersion(JNIEnv * env,jclass)176 static jstring android_os_VintfObject_getPlatformSepolicyVersion(JNIEnv* env, jclass) {
177 std::shared_ptr<const CompatibilityMatrix> matrix = getFrameworkCompatibilityMatrix(env);
178 if (matrix == nullptr || matrix->type() != SchemaType::FRAMEWORK) {
179 jniThrowRuntimeException(env, "Cannot get framework compatibility matrix");
180 return nullptr;
181 }
182
183 auto versions = matrix->getSepolicyVersions();
184 if (versions.empty()) {
185 jniThrowRuntimeException(env,
186 "sepolicy_version in framework compatibility matrix is empty");
187 return nullptr;
188 }
189
190 SepolicyVersion latest;
191 for (const auto& range : versions) {
192 latest = std::max(latest, range.maxVer());
193 }
194 return env->NewStringUTF(to_string(latest).c_str());
195 }
196
android_os_VintfObject_getVndkSnapshots(JNIEnv * env,jclass)197 static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) {
198 std::shared_ptr<const HalManifest> manifest = getFrameworkHalManifest(env);
199 if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) {
200 LOG(WARNING) << __FUNCTION__ << "Cannot get framework manifest";
201 return nullptr;
202 }
203 jobject jMap = env->NewObject(gHashMapClazz, gHashMapInit);
204 for (const auto &vndk : manifest->vendorNdks()) {
205 const std::string& key = vndk.version();
206 env->CallObjectMethod(jMap, gHashMapPut,
207 env->NewStringUTF(key.c_str()), toJavaStringArray(env, vndk.libraries()));
208 }
209 return jMap;
210 }
211
android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion(JNIEnv * env,jclass)212 static jobject android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion(JNIEnv* env, jclass) {
213 std::shared_ptr<const HalManifest> manifest = getDeviceHalManifest(env);
214 if (manifest == nullptr || manifest->level() == Level::UNSPECIFIED) {
215 return nullptr;
216 }
217 return env->CallStaticObjectMethod(gLongClazz, gLongValueOf, static_cast<jlong>(manifest->level()));
218 }
219
220 // ----------------------------------------------------------------------------
221
222 static const JNINativeMethod gVintfObjectMethods[] = {
223 {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report},
224 {"verifyBuildAtBoot", "()I", (void*)android_os_VintfObject_verifyBuildAtBoot},
225 {"getHalNamesAndVersions", "()[Ljava/lang/String;",
226 (void*)android_os_VintfObject_getHalNamesAndVersions},
227 {"getSepolicyVersion", "()Ljava/lang/String;",
228 (void*)android_os_VintfObject_getSepolicyVersion},
229 {"getPlatformSepolicyVersion", "()Ljava/lang/String;",
230 (void*)android_os_VintfObject_getPlatformSepolicyVersion},
231 {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots},
232 {"getTargetFrameworkCompatibilityMatrixVersion", "()Ljava/lang/Long;",
233 (void*)android_os_VintfObject_getTargetFrameworkCompatibilityMatrixVersion},
234 };
235
236 const char* const kVintfObjectPathName = "android/os/VintfObject";
237
register_android_os_VintfObject(JNIEnv * env)238 int register_android_os_VintfObject(JNIEnv* env) {
239 gString = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/String"));
240 gHashMapClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/HashMap"));
241 gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V");
242 gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz, "put",
243 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
244 gLongClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/Long"));
245 gLongValueOf = GetStaticMethodIDOrDie(env, gLongClazz, "valueOf", "(J)Ljava/lang/Long;");
246 gVintfObjectClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, kVintfObjectPathName));
247 gRunCommand = GetStaticMethodIDOrDie(env, gVintfObjectClazz, "runShellCommand",
248 "(Ljava/lang/String;)Ljava/lang/String;");
249
250 return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods,
251 NELEM(gVintfObjectMethods));
252 }
253
254 extern int register_android_os_VintfRuntimeInfo(JNIEnv* env);
255
256 } // namespace android
257
JNI_OnLoad(JavaVM * vm,void *)258 jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
259 JNIEnv* env = NULL;
260 if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
261 return JNI_ERR;
262 }
263
264 if (android::register_android_os_VintfObject(env) < 0) {
265 return JNI_ERR;
266 }
267
268 if (android::register_android_os_VintfRuntimeInfo(env) < 0) {
269 return JNI_ERR;
270 }
271
272 return JNI_VERSION_1_6;
273 }
274