Merge "Revert "Remove the implementation of libaapt2_jni in build file""
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index bd0a4bc..740b44e 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -170,6 +170,16 @@
 }
 
 // ==========================================================
+// Build the host shared library: aapt2_jni
+// ==========================================================
+cc_library_host_shared {
+    name: "libaapt2_jni",
+    srcs: toolSources + ["jni/aapt2_jni.cpp"],
+    static_libs: ["libaapt2"],
+    defaults: ["aapt2_defaults"],
+}
+
+// ==========================================================
 // Build the host tests: aapt2_tests
 // ==========================================================
 cc_test_host {
diff --git a/tools/aapt2/jni/ScopedUtfChars.h b/tools/aapt2/jni/ScopedUtfChars.h
new file mode 100644
index 0000000..a8c4b13
--- /dev/null
+++ b/tools/aapt2/jni/ScopedUtfChars.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef SCOPED_UTF_CHARS_H_included
+#define SCOPED_UTF_CHARS_H_included
+
+#include <string.h>
+#include <jni.h>
+
+#include "android-base/logging.h"
+
+// This file was copied with some minor modifications from libnativehelper.
+// As soon as libnativehelper can be compiled for Windows, this file should be
+// replaced with libnativehelper's implementation.
+class ScopedUtfChars {
+ public:
+  ScopedUtfChars(JNIEnv* env, jstring s) : env_(env), string_(s) {
+    CHECK(s != nullptr);
+    utf_chars_ = env->GetStringUTFChars(s, nullptr);
+  }
+
+  ScopedUtfChars(ScopedUtfChars&& rhs) :
+      env_(rhs.env_), string_(rhs.string_), utf_chars_(rhs.utf_chars_) {
+    rhs.env_ = nullptr;
+    rhs.string_ = nullptr;
+    rhs.utf_chars_ = nullptr;
+  }
+
+  ~ScopedUtfChars() {
+    if (utf_chars_) {
+      env_->ReleaseStringUTFChars(string_, utf_chars_);
+    }
+  }
+
+  ScopedUtfChars& operator=(ScopedUtfChars&& rhs) {
+    if (this != &rhs) {
+      // Delete the currently owned UTF chars.
+      this->~ScopedUtfChars();
+
+      // Move the rhs ScopedUtfChars and zero it out.
+      env_ = rhs.env_;
+      string_ = rhs.string_;
+      utf_chars_ = rhs.utf_chars_;
+      rhs.env_ = nullptr;
+      rhs.string_ = nullptr;
+      rhs.utf_chars_ = nullptr;
+    }
+    return *this;
+  }
+
+  const char* c_str() const {
+    return utf_chars_;
+  }
+
+  size_t size() const {
+    return strlen(utf_chars_);
+  }
+
+  const char& operator[](size_t n) const {
+    return utf_chars_[n];
+  }
+
+ private:
+  JNIEnv* env_;
+  jstring string_;
+  const char* utf_chars_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedUtfChars);
+};
+
+#endif  // SCOPED_UTF_CHARS_H_included
diff --git a/tools/aapt2/jni/aapt2_jni.cpp b/tools/aapt2/jni/aapt2_jni.cpp
new file mode 100644
index 0000000..ec3c543
--- /dev/null
+++ b/tools/aapt2/jni/aapt2_jni.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2015 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 "com_android_tools_aapt2_Aapt2Jni.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "android-base/logging.h"
+#include "ScopedUtfChars.h"
+
+#include "Diagnostics.h"
+#include "cmd/Compile.h"
+#include "cmd/Link.h"
+#include "util/Util.h"
+
+using android::StringPiece;
+
+/*
+ * Converts a java List<String> into C++ vector<ScopedUtfChars>.
+ */
+static std::vector<ScopedUtfChars> list_to_utfchars(JNIEnv *env, jobject obj) {
+  std::vector<ScopedUtfChars> converted;
+
+  // Call size() method on the list to know how many elements there are.
+  jclass list_cls = env->GetObjectClass(obj);
+  jmethodID size_method_id = env->GetMethodID(list_cls, "size", "()I");
+  CHECK(size_method_id != 0);
+  jint size = env->CallIntMethod(obj, size_method_id);
+  CHECK(size >= 0);
+
+  // Now, iterate all strings in the list
+  // (note: generic erasure means get() return an Object)
+  jmethodID get_method_id = env->GetMethodID(list_cls, "get", "(I)Ljava/lang/Object;");
+  CHECK(get_method_id != 0);
+  for (jint i = 0; i < size; i++) {
+    // Call get(i) to get the string in the ith position.
+    jobject string_obj_uncast = env->CallObjectMethod(obj, get_method_id, i);
+    CHECK(string_obj_uncast != nullptr);
+    jstring string_obj = static_cast<jstring>(string_obj_uncast);
+    converted.push_back(ScopedUtfChars(env, string_obj));
+  }
+
+  return converted;
+}
+
+/*
+ * Extracts all StringPiece from the ScopedUtfChars instances.
+ *
+ * The returned pieces can only be used while the original ones have not been
+ * destroyed.
+ */
+static std::vector<StringPiece> extract_pieces(const std::vector<ScopedUtfChars> &strings) {
+  std::vector<StringPiece> pieces;
+
+  std::for_each(
+      strings.begin(), strings.end(),
+      [&pieces](const ScopedUtfChars &p) { pieces.push_back(p.c_str()); });
+
+  return pieces;
+}
+
+class JniDiagnostics : public aapt::IDiagnostics {
+ public:
+  JniDiagnostics(JNIEnv* env, jobject diagnostics_obj)
+      : env_(env), diagnostics_obj_(diagnostics_obj) {
+    mid_ = NULL;
+  }
+
+  void Log(Level level, aapt::DiagMessageActual& actual_msg) override {
+    jint level_value;
+    switch (level) {
+      case Level::Error:
+        level_value = 3;
+        break;
+
+      case Level::Warn:
+        level_value = 2;
+        break;
+
+      case Level::Note:
+        level_value = 1;
+        break;
+    }
+    jstring message = env_->NewStringUTF(actual_msg.message.c_str());
+    jstring path = env_->NewStringUTF(actual_msg.source.path.c_str());
+    jlong line = -1;
+    if (actual_msg.source.line) {
+      line = actual_msg.source.line.value();
+    }
+    if (!mid_) {
+      jclass diagnostics_cls = env_->GetObjectClass(diagnostics_obj_);
+      mid_ = env_->GetMethodID(diagnostics_cls, "log", "(ILjava/lang/String;JLjava/lang/String;)V");
+    }
+    env_->CallVoidMethod(diagnostics_obj_, mid_, level_value, path, line, message);
+  }
+
+ private:
+  JNIEnv* env_;
+  jobject diagnostics_obj_;
+  jmethodID mid_;
+  DISALLOW_COPY_AND_ASSIGN(JniDiagnostics);
+};
+
+JNIEXPORT jint JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeCompile(
+    JNIEnv* env, jclass aapt_obj, jobject arguments_obj, jobject diagnostics_obj) {
+  std::vector<ScopedUtfChars> compile_args_jni =
+      list_to_utfchars(env, arguments_obj);
+  std::vector<StringPiece> compile_args = extract_pieces(compile_args_jni);
+  JniDiagnostics diagnostics(env, diagnostics_obj);
+  return aapt::CompileCommand(&diagnostics).Execute(compile_args, &std::cerr);
+}
+
+JNIEXPORT jint JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeLink(JNIEnv* env,
+                                                                        jclass aapt_obj,
+                                                                        jobject arguments_obj,
+                                                                        jobject diagnostics_obj) {
+  std::vector<ScopedUtfChars> link_args_jni =
+      list_to_utfchars(env, arguments_obj);
+  std::vector<StringPiece> link_args = extract_pieces(link_args_jni);
+  JniDiagnostics diagnostics(env, diagnostics_obj);
+  return aapt::LinkCommand(&diagnostics).Execute(link_args, &std::cerr);
+}
+
+JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_ping(
+        JNIEnv *env, jclass aapt_obj) {
+  // This is just a no-op method to see if the library has been loaded.
+}
diff --git a/tools/aapt2/jni/com_android_tools_aapt2_Aapt2Jni.h b/tools/aapt2/jni/com_android_tools_aapt2_Aapt2Jni.h
new file mode 100644
index 0000000..3cd9865
--- /dev/null
+++ b/tools/aapt2/jni/com_android_tools_aapt2_Aapt2Jni.h
@@ -0,0 +1,37 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_android_tools_aapt2_Aapt2Jni */
+
+#ifndef _Included_com_android_tools_aapt2_Aapt2Jni
+#define _Included_com_android_tools_aapt2_Aapt2Jni
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_android_tools_aapt2_Aapt2Jni
+ * Method:    ping
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_android_tools_aapt2_Aapt2Jni_ping
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     com_android_tools_aapt2_Aapt2Jni
+ * Method:    nativeCompile
+ * Signature: (Ljava/util/List;Lcom/android/tools/aapt2/Aapt2JniDiagnostics;)I
+ */
+JNIEXPORT jint JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeCompile(JNIEnv*, jclass, jobject,
+                                                                           jobject);
+
+/*
+ * Class:     com_android_tools_aapt2_Aapt2Jni
+ * Method:    nativeLink
+ * Signature: (Ljava/util/List;Lcom/android/tools/aapt2/Aapt2JniDiagnostics;)I
+ */
+JNIEXPORT jint JNICALL Java_com_android_tools_aapt2_Aapt2Jni_nativeLink(JNIEnv*, jclass, jobject,
+                                                                        jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif