1 /* 2 * Copyright (C) 2015 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 #include "com_android_tools_aapt2_Aapt2Jni.h" 18 19 #include <algorithm> 20 #include <memory> 21 #include <utility> 22 #include <vector> 23 24 #include "android-base/logging.h" 25 #include "ScopedUtfChars.h" 26 27 #include "Diagnostics.h" 28 #include "cmd/Compile.h" 29 #include "cmd/Link.h" 30 #include "util/Util.h" 31 32 using android::StringPiece; 33 34 /* 35 * Converts a java List<String> into C++ vector<ScopedUtfChars>. 36 */ 37 static std::vector<ScopedUtfChars> list_to_utfchars(JNIEnv *env, jobject obj) { 38 std::vector<ScopedUtfChars> converted; 39 40 // Call size() method on the list to know how many elements there are. 41 jclass list_cls = env->GetObjectClass(obj); 42 jmethodID size_method_id = env->GetMethodID(list_cls, "size", "()I"); 43 CHECK(size_method_id != 0); 44 jint size = env->CallIntMethod(obj, size_method_id); 45 CHECK(size >= 0); 46 47 // Now, iterate all strings in the list 48 // (note: generic erasure means get() return an Object) 49 jmethodID get_method_id = env->GetMethodID(list_cls, "get", "(I)Ljava/lang/Object;"); 50 CHECK(get_method_id != 0); 51 for (jint i = 0; i < size; i++) { 52 // Call get(i) to get the string in the ith position. 53 jobject string_obj_uncast = env->CallObjectMethod(obj, get_method_id, i); 54 CHECK(string_obj_uncast != nullptr); 55 jstring string_obj = static_cast<jstring>(string_obj_uncast); 56 converted.push_back(ScopedUtfChars(env, string_obj)); 57 } 58 59 return converted; 60 } 61 62 /* 63 * Extracts all StringPiece from the ScopedUtfChars instances. 64 * 65 * The returned pieces can only be used while the original ones have not been 66 * destroyed. 67 */ 68 static std::vector<StringPiece> extract_pieces(const std::vector<ScopedUtfChars> &strings) { 69 std::vector<StringPiece> pieces; 70 71 std::for_each( 72 strings.begin(), strings.end(), 73 [&pieces](const ScopedUtfChars &p) { pieces.push_back(p.c_str()); }); 74 75 return pieces; 76 } 77 78 class JniDiagnostics : public aapt::IDiagnostics { 79 public: 80 JniDiagnostics(JNIEnv* env, jobject diagnostics_obj) 81 : env_(env), diagnostics_obj_(diagnostics_obj) { 82 mid_ = NULL; 83 } 84 85 void Log(Level level, aapt::DiagMessageActual& actual_msg) override { 86 jint level_value; 87 switch (level) { 88 case Level::Error: 89 level_value = 3; 90 break; 91 92 case Level::Warn: 93 level_value = 2; 94 break; 95 96 case Level::Note: 97 level_value = 1; 98 break; 99 } 100 jstring message = env_->NewStringUTF(actual_msg.message.c_str()); 101 jstring path = env_->NewStringUTF(actual_msg.source.path.c_str()); 102 jlong line = -1; 103 if (actual_msg.source.line) { 104 line = actual_msg.source.line.value(); 105 } 106 if (!mid_) { 107 jclass diagnostics_cls = env_->GetObjectClass(diagnostics_obj_); 108 mid_ = env_->GetMethodID(diagnostics_cls, "log", "(ILjava/lang/String;JLjava/lang/String;)V"); 109 } 110 env_->CallVoidMethod(diagnostics_obj_, mid_, level_value, path, line, message); 111 } 112 113 private: 114 JNIEnv* env_; 115 jobject diagnostics_obj_; 116 jmethodID mid_; 117 DISALLOW_COPY_AND_ASSIGN(JniDiagnostics); 118 }; 119 120 JNIEXPORT jint JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeCompile( 121 JNIEnv* env, jclass aapt_obj, jobject arguments_obj, jobject diagnostics_obj) { 122 std::vector<ScopedUtfChars> compile_args_jni = 123 list_to_utfchars(env, arguments_obj); 124 std::vector<StringPiece> compile_args = extract_pieces(compile_args_jni); 125 JniDiagnostics diagnostics(env, diagnostics_obj); 126 return aapt::CompileCommand(&diagnostics).Execute(compile_args, &std::cerr); 127 } 128 129 JNIEXPORT jint JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeLink(JNIEnv* env, 130 jclass aapt_obj, 131 jobject arguments_obj, 132 jobject diagnostics_obj) { 133 std::vector<ScopedUtfChars> link_args_jni = 134 list_to_utfchars(env, arguments_obj); 135 std::vector<StringPiece> link_args = extract_pieces(link_args_jni); 136 JniDiagnostics diagnostics(env, diagnostics_obj); 137 return aapt::LinkCommand(&diagnostics).Execute(link_args, &std::cerr); 138 } 139 140 JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_ping( 141 JNIEnv *env, jclass aapt_obj) { 142 // This is just a dummy method to see if the library has been loaded. 143 } 144