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