| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include <nativehelper/JNIHelp.h> |
| #include "jni.h" |
| #include "core_jni_helpers.h" |
| |
| #include "android-base/logging.h" |
| #include "androidfw/PosixUtils.h" |
| |
| using ::android::util::ExecuteBinary; |
| |
| static jclass g_stringClass = nullptr; |
| |
| static jobjectArray createIdmap(JNIEnv* env, jclass /*clazz*/, jstring targetPath, |
| jobjectArray overlayPath, jobjectArray policies, |
| jboolean enforceOverlayable) { |
| if (access("/system/bin/idmap2", X_OK) == -1) { |
| PLOG(WARNING) << "unable to execute idmap2"; |
| return nullptr; |
| } |
| |
| const char* targetApkPath = env->GetStringUTFChars(targetPath, NULL /* isCopy */); |
| std::vector<std::string> argv{"/system/bin/idmap2", |
| "create-multiple", |
| "--target-apk-path", targetApkPath, |
| }; |
| env->ReleaseStringUTFChars(targetPath, targetApkPath); |
| |
| // Add the overlays for which to generate idmap files to the idmap arguments. |
| for (size_t i = 0, count = env->GetArrayLength(overlayPath); i < count; ++i) { |
| jstring element = (jstring) env->GetObjectArrayElement(overlayPath, i); |
| const char* overlayApkPath = env->GetStringUTFChars(element, NULL /* isCopy */); |
| argv.emplace_back("--overlay-apk-path"); |
| argv.emplace_back(overlayApkPath); |
| env->ReleaseStringUTFChars(element, overlayApkPath); |
| } |
| |
| // Add the policies the overlays fulfill to the idmap arguments. |
| for (size_t i = 0, count = env->GetArrayLength(policies); i < count; ++i) { |
| jstring element = (jstring)env->GetObjectArrayElement(policies, i); |
| const char* policy = env->GetStringUTFChars(element, NULL /* isCopy */); |
| argv.emplace_back("--policy"); |
| argv.emplace_back(policy); |
| env->ReleaseStringUTFChars(element, policy); |
| } |
| |
| if (!enforceOverlayable) { |
| argv.emplace_back("--ignore-overlayable"); |
| } |
| |
| const auto result = ExecuteBinary(argv); |
| if (!result) { |
| LOG(ERROR) << "failed to execute idmap2"; |
| return nullptr; |
| } |
| |
| if (result->status != 0) { |
| LOG(ERROR) << "idmap2: " << result->stderr; |
| return nullptr; |
| } |
| |
| // Return the paths of the idmaps created or updated during the idmap invocation. |
| std::vector<std::string> idmap_paths; |
| std::istringstream input(result->stdout); |
| std::string path; |
| while (std::getline(input, path)) { |
| idmap_paths.push_back(path); |
| } |
| |
| jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr); |
| if (array == nullptr) { |
| return nullptr; |
| } |
| for (size_t i = 0; i < idmap_paths.size(); i++) { |
| const std::string path = idmap_paths[i]; |
| jstring java_string = env->NewStringUTF(path.c_str()); |
| if (env->ExceptionCheck()) { |
| return nullptr; |
| } |
| env->SetObjectArrayElement(array, i, java_string); |
| env->DeleteLocalRef(java_string); |
| } |
| |
| return array; |
| } |
| |
| static const JNINativeMethod g_methods[] = { |
| { "createIdmap", |
| "(Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Z)[Ljava/lang/String;", |
| (void *)createIdmap }, |
| }; |
| |
| static const char* const kOverlayConfigPathName = "com/android/internal/content/om/OverlayConfig"; |
| |
| namespace android { |
| |
| int register_com_android_internal_content_om_OverlayConfig(JNIEnv* env) { |
| jclass stringClass = FindClassOrDie(env, "java/lang/String"); |
| g_stringClass = MakeGlobalRefOrDie(env, stringClass); |
| |
| return RegisterMethodsOrDie(env, kOverlayConfigPathName, g_methods, NELEM(g_methods)); |
| } |
| |
| } // namespace android |