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