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 */
list_to_utfchars(JNIEnv * env,jobject obj)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 */
extract_pieces(const std::vector<ScopedUtfChars> & strings)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:
JniDiagnostics(JNIEnv * env,jobject diagnostics_obj)83 JniDiagnostics(JNIEnv* env, jobject diagnostics_obj)
84 : env_(env), diagnostics_obj_(diagnostics_obj) {
85 mid_ = NULL;
86 }
87
Log(Level level,aapt::DiagMessageActual & actual_msg)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
Java_com_android_tools_aapt2_Aapt2Jni_nativeCompile(JNIEnv * env,jclass aapt_obj,jobject arguments_obj,jobject diagnostics_obj)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
Java_com_android_tools_aapt2_Aapt2Jni_nativeLink(JNIEnv * env,jclass aapt_obj,jobject arguments_obj,jobject diagnostics_obj)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
Java_com_android_tools_aapt2_Aapt2Jni_ping(JNIEnv * env,jclass aapt_obj)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