Upgrade Kythe to v0.0.60.

Test: presubmit
Change-Id: I36006ef55385d0f4bf6544f9b7a0179aea90a2ff
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..6fea6b4
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,286 @@
+// Copyright 2018 Google Inc. All rights reserved
+//
+// 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.
+
+filegroup {
+    name: "kythe_protos",
+    srcs: [
+        "kythe/proto/analysis.proto",
+        "kythe/proto/buildinfo.proto",
+        "kythe/proto/common.proto",
+        "kythe/proto/cxx.proto",
+        "kythe/proto/filecontext.proto",
+        "kythe/proto/metadata.proto",
+        "kythe/proto/storage.proto",
+    ],
+}
+
+java_library_host {
+    name: "javac_extractor",
+    srcs: [
+        "kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java",
+        "kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java",
+        "kythe/java/com/google/devtools/kythe/extractors/java/*.java",
+        "kythe/java/com/google/devtools/kythe/extractors/shared/*.java",
+        "kythe/java/com/google/devtools/kythe/platform/kzip/*.java",
+        "kythe/java/com/google/devtools/kythe/platform/java/JavacOptionsUtils.java",
+        "kythe/java/com/google/devtools/kythe/platform/java/filemanager/ForwardingStandardJavaFileManager.java",
+        "kythe/java/com/google/devtools/kythe/platform/shared/CompilationUnits.java",
+        "kythe/java/com/google/devtools/kythe/util/DeleteRecursively.java",
+        "kythe/java/com/google/devtools/kythe/util/JsonUtil.java",
+        ":kythe_protos",
+        "kythe/proto/java.proto",
+    ],
+    javacflags: [
+        "-target 1.9",
+        "--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
+        "--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+        "--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
+        "--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+        "--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+        "--add-modules java.compiler",
+    ],
+    manifest: "javac_extractor_manifest.txt",
+    proto: {
+        include_dirs: [
+            "external/kythe",
+            "external/protobuf/src",
+        ],
+        type: "full",
+        canonical_path_from_root: false,
+    },
+    static_libs: [
+        "gson",
+        "libprotobuf-java-full",
+        "libprotobuf-java-util-full",
+        "guava",
+        "jsr305",
+    ],
+    java_version: "1.9",
+}
+
+cc_defaults {
+    name: "kythe_common_defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wno-deprecated",
+        "-Wno-missing-field-initializers",
+        "-Wno-unused-parameter",
+        "-Wno-unused-private-field",
+        "-Wno-sign-compare",
+        "-Wno-unused-variable",
+        "-fno-exceptions",
+        "-fno-rtti",
+    ],
+}
+
+cc_defaults {
+    name: "kythe_proto_defaults",
+    srcs: [":kythe_protos"],
+    proto: {
+        include_dirs: [
+            "external/kythe",
+            "external/protobuf/src",
+        ],
+        type: "full",
+        canonical_path_from_root: false,
+    },
+    shared_libs: [
+        "libprotobuf-cpp-full",
+    ],
+}
+
+cc_library_host_static {
+    name: "kythe_cxx_glog",
+    defaults: ["kythe_common_defaults"],
+    srcs: ["kythe/cxx/glog/logging.cc"],
+    export_include_dirs: ["kythe/cxx"],
+    shared_libs: ["libbase"],
+}
+
+cc_library_host_static {
+    name: "kythe_cxx_common",
+    defaults: [
+        "kythe_common_defaults",
+        "kythe_proto_defaults",
+    ],
+    srcs: [
+        "kythe/cxx/common/file_utils.cc",
+        "kythe/cxx/common/file_vname_generator.cc",
+        "kythe/cxx/common/init.cc",
+        "kythe/cxx/common/json_proto.cc",
+        "kythe/cxx/common/kythe_metadata_file.cc",
+        "kythe/cxx/common/kzip_writer_aosp.cc",
+        "kythe/cxx/common/path_utils.cc",
+        "kythe/cxx/common/status.cc",
+    ],
+    header_libs: [
+        "libabsl_headers",
+        "rapidjson_headers",
+    ],
+    static_libs: [
+        "kythe_cxx_glog",
+        "libabsl_strings",
+        "libgflags",
+        "libcrypto",
+        "regex-re2",
+    ],
+    shared_libs: [
+        "libbase",
+        "libziparchive",
+    ],
+}
+
+cc_binary_host {
+    name: "cxx_extractor",
+    defaults: [
+        "kythe_common_defaults",
+        "kythe_proto_defaults",
+    ],
+    srcs: [
+        "kythe/cxx/common/index_writer.cc",
+        "kythe/cxx/common/schema/edges.cc",
+        "kythe/cxx/extractor/CommandLineUtils.cc",
+        "kythe/cxx/extractor/cxx_details.cc",
+        "kythe/cxx/extractor/cxx_extractor.cc",
+        "kythe/cxx/extractor/cxx_extractor_main.cc",
+        "kythe/cxx/extractor/language.cc",
+        "kythe/cxx/extractor/path_utils.cc",
+        "kythe/cxx/indexer/cxx/clang_utils.cc",
+        "kythe/cxx/indexer/cxx/indexed_parent_map.cc",
+        "third_party/llvm/src/cxx_extractor_preprocessor_utils.cc",
+        "third_party/llvm/src/clang_builtin_headers.cc",
+    ],
+    shared_libs: [
+        "libbase",
+        "libclang-cpp_host",
+        "libziparchive",
+    ],
+    header_libs: [
+        "libabsl_headers",
+    ],
+    static_libs: [
+        "kythe_cxx_glog",
+        "kythe_cxx_common",
+        "regex-re2",
+        "libabsl_base",
+        "libabsl_container",
+        "libabsl_debugging",
+        "libabsl_hash",
+        "libabsl_numeric",
+        "libabsl_profiling",
+        "libabsl_status",
+        "libabsl_strings",
+        "libabsl_synchronization",
+        "libabsl_time",
+        "libcrypto",
+    ],
+    generated_headers: ["clang_builtin_headers_resources"],
+    target: {
+        darwin: {
+            host_ldlibs: [
+                "-framework CoreFoundation",
+            ],
+        },
+    },
+}
+
+cc_binary_host {
+    name: "protoc_extractor",
+    defaults: [
+        "kythe_common_defaults",
+        "kythe_proto_defaults",
+    ],
+    srcs: [
+        "kythe/cxx/extractor/proto/proto_extractor.cc",
+        "kythe/cxx/extractor/proto/proto_extractor_main.cc",
+        "kythe/cxx/indexer/proto/search_path.cc",
+    ],
+    header_libs: [
+        "libabsl_headers",
+    ],
+    static_libs: [
+        "kythe_cxx_glog",
+        "kythe_cxx_common",
+        "regex-re2",
+        "libabsl_base",
+        "libabsl_container",
+        "libabsl_debugging",
+        "libabsl_flags",
+        "libabsl_hash",
+        "libabsl_numeric",
+        "libabsl_profiling",
+        "libabsl_status",
+        "libabsl_strings",
+        "libabsl_synchronization",
+        "libabsl_time",
+        "libcrypto",
+    ],
+    shared_libs: [
+        "libbase",
+        "libziparchive",
+    ],
+    target: {
+        darwin: {
+            host_ldlibs: [
+                "-framework CoreFoundation",
+            ],
+        },
+    },
+}
+
+// A plugin for protobuffers compiler (aprotoc) to include metadata descriptor
+// into the generated header. Extractors and indexers use it to trace the entities in
+// the generated files back to the protobuffer dec
+cc_binary_host {
+    name: "proto_metadata_plugin",
+    defaults: [
+        "kythe_common_defaults",
+        "kythe_proto_defaults",
+    ],
+    srcs: [
+        "kythe/cxx/tools/proto_metadata_plugin.cc",
+    ],
+    header_libs: [
+        "libabsl_headers",
+    ],
+    static_libs: [
+        "kythe_cxx_glog",
+        "kythe_cxx_common",
+        "libabsl_base",
+        "libabsl_container",
+        "libabsl_debugging",
+        "libabsl_hash",
+        "libabsl_numeric",
+        "libabsl_strings",
+        "libabsl_synchronization",
+        "libabsl_time",
+        "libprotoc",
+    ],
+    shared_libs: [
+        "libbase",
+        "libz",
+        "libziparchive",
+    ],
+    target: {
+        darwin: {
+            host_ldlibs: [
+                "-framework CoreFoundation",
+            ],
+        },
+    },
+}
+
+// Go extractor
+build = ["Android.gen.bp"]
diff --git a/Android.gen.bp b/Android.gen.bp
new file mode 100644
index 0000000..4f30e42
--- /dev/null
+++ b/Android.gen.bp
@@ -0,0 +1,421 @@
+// Automatically generated with:
+// go2bp -rewrite github.com/google/go-cmp/cmp=go-cmp -rewrite google.golang.org/protobuf=golang-protobuf -rewrite github.com/beevik/etree=go-etree -rewrite bitbucket.org/creachadair=creachadair -rewrite github.com/google/subcommands=go-subcommands -rewrite golang.org/x=golang-x -rewrite kythe.io/kythe=kythe -rewrite gotool=go_extractor -limit kythe.io/kythe/go/extractors/config/runextractor -limit kythe.io/kythe/go/extractors/cmd/gotool -limit kythe.io/kythe/go/extractors/cmd/rust_extractor -skip-tests
+
+blueprint_go_binary {
+    name: "go_extractor",
+    deps: [
+        "kythe-go-extractors-golang",
+        "kythe-go-platform-analysis",
+        "kythe-go-platform-kzip",
+        "kythe-go-platform-vfs",
+        "kythe-go-util-flagutil",
+        "kythe-go-util-vnameutil",
+        "kythe-proto-analysis_go_proto",
+    ],
+    srcs: [
+        "kythe/go/extractors/cmd/gotool/gotool.go",
+    ],
+}
+
+blueprint_go_binary {
+    name: "rust_extractor",
+    deps: [
+        "kythe-go-platform-kzip",
+        "kythe-go-util-vnameutil",
+        "kythe-proto-analysis_go_proto",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/go/extractors/cmd/rust_extractor/rust_extractor.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-config-preprocessor-modifier",
+    pkgPath: "kythe.io/kythe/go/extractors/config/preprocessor/modifier",
+    deps: [
+        "go-etree",
+    ],
+    srcs: [
+        "kythe/go/extractors/config/preprocessor/modifier/build_gradle_modifier.go",
+        "kythe/go/extractors/config/preprocessor/modifier/pom_xml_modifier.go",
+    ],
+}
+
+blueprint_go_binary {
+    name: "runextractor",
+    deps: [
+        "go-subcommands",
+        "kythe-go-extractors-config-runextractor-cmakecmd",
+        "kythe-go-extractors-config-runextractor-compdbcmd",
+        "kythe-go-extractors-config-runextractor-gradlecmd",
+        "kythe-go-extractors-config-runextractor-mavencmd",
+    ],
+    srcs: [
+        "kythe/go/extractors/config/runextractor/runextractor.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-config-runextractor-backup",
+    pkgPath: "kythe.io/kythe/go/extractors/config/runextractor/backup",
+    deps: [
+        "go-cmp",
+    ],
+    srcs: [
+        "kythe/go/extractors/config/runextractor/backup/backup.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-config-runextractor-cmakecmd",
+    pkgPath: "kythe.io/kythe/go/extractors/config/runextractor/cmakecmd",
+    deps: [
+        "go-subcommands",
+        "kythe-go-extractors-config-runextractor-compdb",
+        "kythe-go-util-cmdutil",
+        "kythe-go-util-flagutil",
+    ],
+    srcs: [
+        "kythe/go/extractors/config/runextractor/cmakecmd/cmakecmd.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-config-runextractor-compdb",
+    pkgPath: "kythe.io/kythe/go/extractors/config/runextractor/compdb",
+    deps: [
+        "creachadair-shell",
+        "golang-x-sync-semaphore",
+    ],
+    srcs: [
+        "kythe/go/extractors/config/runextractor/compdb/compdb.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-config-runextractor-compdbcmd",
+    pkgPath: "kythe.io/kythe/go/extractors/config/runextractor/compdbcmd",
+    deps: [
+        "go-subcommands",
+        "kythe-go-extractors-config-runextractor-compdb",
+        "kythe-go-util-cmdutil",
+    ],
+    srcs: [
+        "kythe/go/extractors/config/runextractor/compdbcmd/compdbcmd.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-config-runextractor-gradlecmd",
+    pkgPath: "kythe.io/kythe/go/extractors/config/runextractor/gradlecmd",
+    deps: [
+        "go-subcommands",
+        "kythe-go-extractors-config-preprocessor-modifier",
+        "kythe-go-extractors-config-runextractor-backup",
+        "kythe-go-extractors-constants",
+        "kythe-go-util-cmdutil",
+    ],
+    srcs: [
+        "kythe/go/extractors/config/runextractor/gradlecmd/gradlecmd.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-config-runextractor-mavencmd",
+    pkgPath: "kythe.io/kythe/go/extractors/config/runextractor/mavencmd",
+    deps: [
+        "go-subcommands",
+        "kythe-go-extractors-config-preprocessor-modifier",
+        "kythe-go-extractors-config-runextractor-backup",
+        "kythe-go-extractors-constants",
+        "kythe-go-util-cmdutil",
+    ],
+    srcs: [
+        "kythe/go/extractors/config/runextractor/mavencmd/mavencmd.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-constants",
+    pkgPath: "kythe.io/kythe/go/extractors/constants",
+    srcs: [
+        "kythe/go/extractors/constants/constants.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-golang",
+    pkgPath: "kythe.io/kythe/go/extractors/golang",
+    deps: [
+        "creachadair-stringset",
+        "golang-protobuf-types-known-anypb",
+        "kythe-go-extractors-govname",
+        "kythe-go-platform-analysis",
+        "kythe-go-platform-kindex",
+        "kythe-go-platform-vfs",
+        "kythe-go-util-ptypes",
+        "kythe-proto-analysis_go_proto",
+        "kythe-proto-go_go_proto",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/go/extractors/golang/golang.go",
+        "kythe/go/extractors/golang/packages.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-extractors-govname",
+    pkgPath: "kythe.io/kythe/go/extractors/govname",
+    deps: [
+        "golang-x-tools-go-vcs",
+        "kythe-go-util-vnameutil",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/go/extractors/govname/govname.go",
+        "kythe/go/extractors/govname/types.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-platform-analysis",
+    pkgPath: "kythe.io/kythe/go/platform/analysis",
+    deps: [
+        "golang-protobuf-proto",
+        "kythe-proto-analysis_go_proto",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/go/platform/analysis/analysis.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-platform-delimited",
+    pkgPath: "kythe.io/kythe/go/platform/delimited",
+    deps: [
+        "golang-protobuf-proto",
+    ],
+    srcs: [
+        "kythe/go/platform/delimited/copy.go",
+        "kythe/go/platform/delimited/delimited.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-platform-kcd",
+    pkgPath: "kythe.io/kythe/go/platform/kcd",
+    srcs: [
+        "kythe/go/platform/kcd/kcd.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-platform-kcd-kythe",
+    pkgPath: "kythe.io/kythe/go/platform/kcd/kythe",
+    deps: [
+        "golang-protobuf-encoding-protojson",
+        "golang-protobuf-proto",
+        "kythe-go-platform-kcd",
+        "kythe-go-util-ptypes",
+        "kythe-proto-analysis_go_proto",
+        "kythe-proto-buildinfo_go_proto",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/go/platform/kcd/kythe/units.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-platform-kindex",
+    pkgPath: "kythe.io/kythe/go/platform/kindex",
+    deps: [
+        "golang-protobuf-proto",
+        "kythe-go-platform-analysis",
+        "kythe-go-platform-delimited",
+        "kythe-go-platform-vfs",
+        "kythe-go-util-ptypes",
+        "kythe-proto-analysis_go_proto",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/go/platform/kindex/kindex.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-platform-kzip",
+    pkgPath: "kythe.io/kythe/go/platform/kzip",
+    deps: [
+        "creachadair-stringset",
+        "golang-x-sync-errgroup",
+        "golang-protobuf-encoding-protojson",
+        "golang-protobuf-proto",
+        "kythe-go-platform-kcd-kythe",
+        "kythe-proto-analysis_go_proto",
+        "kythe-proto-buildinfo_go_proto",
+        "kythe-proto-cxx_go_proto",
+        "kythe-proto-filecontext_go_proto",
+        "kythe-proto-go_go_proto",
+        "kythe-proto-java_go_proto",
+    ],
+    srcs: [
+        "kythe/go/platform/kzip/kzip.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-platform-vfs",
+    pkgPath: "kythe.io/kythe/go/platform/vfs",
+    srcs: [
+        "kythe/go/platform/vfs/vfs.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-util-build",
+    pkgPath: "kythe.io/kythe/go/util/build",
+    srcs: [
+        "kythe/go/util/build/build.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-util-cmdutil",
+    pkgPath: "kythe.io/kythe/go/util/cmdutil",
+    deps: [
+        "go-subcommands",
+    ],
+    srcs: [
+        "kythe/go/util/cmdutil/cmdutil.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-util-flagutil",
+    pkgPath: "kythe.io/kythe/go/util/flagutil",
+    deps: [
+        "creachadair-stringset",
+        "kythe-go-util-build",
+    ],
+    srcs: [
+        "kythe/go/util/flagutil/flagutil.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-util-ptypes",
+    pkgPath: "kythe.io/kythe/go/util/ptypes",
+    deps: [
+        "golang-protobuf-proto",
+        "golang-protobuf-types-known-anypb",
+    ],
+    srcs: [
+        "kythe/go/util/ptypes/ptypes.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-go-util-vnameutil",
+    pkgPath: "kythe.io/kythe/go/util/vnameutil",
+    deps: [
+        "golang-protobuf-encoding-protojson",
+        "golang-protobuf-proto",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/go/util/vnameutil/order.go",
+        "kythe/go/util/vnameutil/rewrite.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-proto-analysis_go_proto",
+    pkgPath: "kythe.io/kythe/proto/analysis_go_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "golang-protobuf-types-known-anypb",
+        "golang-protobuf-types-known-timestamppb",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/proto/analysis_go_proto/analysis.pb.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-proto-buildinfo_go_proto",
+    pkgPath: "kythe.io/kythe/proto/buildinfo_go_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "kythe/proto/buildinfo_go_proto/buildinfo.pb.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-proto-cxx_go_proto",
+    pkgPath: "kythe.io/kythe/proto/cxx_go_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "kythe/proto/cxx_go_proto/cxx.pb.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-proto-filecontext_go_proto",
+    pkgPath: "kythe.io/kythe/proto/filecontext_go_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "kythe/proto/filecontext_go_proto/filecontext.pb.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-proto-go_go_proto",
+    pkgPath: "kythe.io/kythe/proto/go_go_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "kythe/proto/go_go_proto/go.pb.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-proto-java_go_proto",
+    pkgPath: "kythe.io/kythe/proto/java_go_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+        "kythe-proto-storage_go_proto",
+    ],
+    srcs: [
+        "kythe/proto/java_go_proto/java.pb.go",
+    ],
+}
+
+bootstrap_go_package {
+    name: "kythe-proto-storage_go_proto",
+    pkgPath: "kythe.io/kythe/proto/storage_go_proto",
+    deps: [
+        "golang-protobuf-reflect-protoreflect",
+        "golang-protobuf-runtime-protoimpl",
+    ],
+    srcs: [
+        "kythe/proto/storage_go_proto/storage.pb.go",
+    ],
+}
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..135ce26
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,18 @@
+name: "kythe"
+description:
+    "A pluggable, (mostly) language-agnostic ecosystem for building tools that "
+    "work with code"
+
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://kythe.io/"
+  }
+  url {
+    type: GIT
+    value: "https://github.com/kythe/kythe"
+  }
+  version: "v0.0.60"
+  last_upgrade_date { year: 2022 month: 11 day: 8 }
+  license_type: NOTICE
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1 @@
+LICENSE
\ No newline at end of file
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..627c36d
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1,7 @@
+asmundak@google.com
+ccross@google.com
+dwillemsen@google.com
+jungjw@google.com
+patricearruda@google.com
+
+include toolchain/llvm_android:master:/OWNERS
diff --git a/go.mod b/go.mod
index 0b5bc97..4914274 100644
--- a/go.mod
+++ b/go.mod
@@ -19,6 +19,7 @@
 	github.com/google/uuid v1.3.0 // indirect
 	github.com/hanwen/go-fuse v1.0.0
 	github.com/jmhodges/levigo v1.0.0
+	github.com/jstemmer/go-junit-report v0.9.1 // indirect
 	github.com/minio/highwayhash v1.0.2
 	github.com/onsi/ginkgo v1.8.0 // indirect
 	github.com/onsi/gomega v1.5.0 // indirect
@@ -30,9 +31,10 @@
 	golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
 	golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
-	golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c
-	golang.org/x/text v0.3.6
+	golang.org/x/sys v0.0.0-20211019181941-9d821ace8654
+	golang.org/x/text v0.3.7
 	golang.org/x/tools v0.1.5
+	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
 	google.golang.org/api v0.52.0
 	google.golang.org/genproto v0.0.0-20210803142424-70bd63adacf2 // indirect
 	google.golang.org/grpc v1.39.0
@@ -41,4 +43,15 @@
 	sigs.k8s.io/yaml v1.2.0
 )
 
-go 1.13
+replace (
+	bitbucket.org/creachadair/shell v0.0.6 => ../go-creachadair-shell
+	bitbucket.org/creachadair/stringset v0.0.9 => ../go-creachadair-stringset
+	github.com/beevik/etree => ../go-etree
+	github.com/google/go-cmp => ../go-cmp
+	github.com/google/subcommands => ../go-subcommands
+	golang.org/x/sync => ../golang-x-sync
+	golang.org/x/sys => ../golang-x-sys
+	golang.org/x/tools => ../golang-x-tools
+)
+
+go 1.18
diff --git a/go.sum b/go.sum
index 03c4e7b..71e4580 100644
--- a/go.sum
+++ b/go.sum
@@ -167,8 +167,6 @@
 github.com/google/subcommands v1.2.0 h1:vWQspBTo2nEqTUFita5/KeEWlUL8kQObDFbub/EN9oE=
 github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
 github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
@@ -228,6 +226,7 @@
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -242,6 +241,7 @@
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -277,8 +277,9 @@
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o=
+golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -303,7 +304,6 @@
 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
-golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
@@ -313,10 +313,9 @@
 golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985 h1:4CSI6oo7cOjJKajidEljs9h+uP0rRZBPPPhcCbj5mw8=
-golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -397,8 +396,9 @@
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/javac_extractor_manifest.txt b/javac_extractor_manifest.txt
new file mode 100644
index 0000000..7e039cc
--- /dev/null
+++ b/javac_extractor_manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.google.devtools.kythe.extractors.java.standalone.Javac9Wrapper
diff --git a/kythe/cxx/common/kythe_metadata_file.cc b/kythe/cxx/common/kythe_metadata_file.cc
index f446296..fc3b66f 100644
--- a/kythe/cxx/common/kythe_metadata_file.cc
+++ b/kythe/cxx/common/kythe_metadata_file.cc
@@ -46,7 +46,7 @@
 absl::optional<std::string> LoadCommentMetadata(absl::string_view buf_string,
                                                 size_t comment_slash_pos,
                                                 size_t data_start_pos) {
-  google::protobuf::string raw_data;
+  std::string raw_data;
   // Over-reserves--though we expect the comment to be the only thing in the
   // file or the last thing in the file, so this approximation is reasonable.
   raw_data.reserve(buf_string.size() - comment_slash_pos);
@@ -74,9 +74,9 @@
     }
     break;
   }
-  google::protobuf::string decoded;
+  std::string decoded;
   return absl::Base64Unescape(raw_data, &decoded)
-             ? absl::optional<std::string>(std::string(decoded))
+             ? absl::optional<std::string>(decoded)
              : absl::nullopt;
 }
 
diff --git a/kythe/cxx/common/kzip_writer_aosp.cc b/kythe/cxx/common/kzip_writer_aosp.cc
new file mode 100644
index 0000000..c7f619c
--- /dev/null
+++ b/kythe/cxx/common/kzip_writer_aosp.cc
@@ -0,0 +1,172 @@
+#include "kythe/cxx/common/kzip_writer_aosp.h"
+
+#include <openssl/sha.h>
+
+#include <array>
+#include <string>
+
+#include "absl/memory/memory.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/escaping.h"
+#include "glog/logging.h"
+#include "kythe/cxx/common/json_proto.h"
+#include "kythe/proto/analysis.pb.h"
+
+namespace kythe {
+namespace {
+
+constexpr absl::string_view kRoot = "root/";
+constexpr absl::string_view kJsonUnitRoot = "root/units/";
+constexpr absl::string_view kProtoUnitRoot = "root/pbunits/";
+constexpr absl::string_view kFileRoot = "root/files/";
+// Set all file modified times to 0 so zip file diffs only show content diffs,
+// not zip creation time diffs.
+constexpr time_t kModTime = 0;
+
+std::string SHA256Digest(absl::string_view content) {
+  std::array<unsigned char, SHA256_DIGEST_LENGTH> buf;
+  ::SHA256(reinterpret_cast<const unsigned char*>(content.data()),
+           content.size(), buf.data());
+  return absl::BytesToHexString(
+      absl::string_view(reinterpret_cast<const char*>(buf.data()), buf.size()));
+}
+
+}  // namespace
+
+bool KzipWriter::HasEncoding(KzipEncoding encoding) {
+  return encoding_ == encoding || encoding_ == KzipEncoding::kAll;
+}
+
+absl::Status KzipWriter::WriteTextFile(absl::string_view path,
+                                 absl::string_view content) {
+  int32_t rc = zip_writer_.StartEntryWithTime(path.data(), ZipWriter::kCompress,
+                                              kModTime);
+  if (rc == 0) {
+    rc = zip_writer_.WriteBytes(content.data(), content.size());
+  }
+  if (rc == 0) {
+    rc = zip_writer_.FinishEntry();
+  }
+  return rc ? absl::InternalError(ZipWriter::ErrorCodeString(rc)) : absl::OkStatus();
+}
+
+int32_t KzipWriter::CreateDirEntry(absl::string_view path) {
+  auto rc = zip_writer_.StartEntryWithTime(path.data(), 0, kModTime);
+  if (rc == 0) {
+    rc = zip_writer_.FinishEntry();
+  }
+  return rc;
+}
+
+// Creates entries for the directories if not already present.
+int32_t KzipWriter::InitializeArchive() {
+  if (initialized_) {
+    return 0;
+  }
+  initialized_ = true;
+  auto rc = CreateDirEntry(kRoot);
+  if (rc == 0) {
+    rc = CreateDirEntry(kFileRoot);
+  }
+  if (rc == 0 && HasEncoding(KzipEncoding::kJson)) {
+    rc = CreateDirEntry(kJsonUnitRoot);
+  }
+  if (rc == 0 && HasEncoding(KzipEncoding::kProto)) {
+    rc = CreateDirEntry(kProtoUnitRoot);
+  }
+  return rc;
+}
+
+/* static */
+absl::StatusOr<IndexWriter> KzipWriter::Create(absl::string_view path,
+                                               KzipEncoding encoding) {
+  FILE* fp = fopen(path.data(), "wb");
+  if (!fp) {
+    return absl::UnimplementedError(strerror(errno));
+  }
+  return IndexWriter(absl::WrapUnique(new KzipWriter(fp, encoding)));
+}
+
+KzipWriter::KzipWriter(FILE* fp, KzipEncoding encoding)
+    : fp_(fp), zip_writer_(fp), initialized_(false), encoding_(encoding) {}
+
+KzipWriter::~KzipWriter() {
+  DCHECK(fp_ == nullptr) << "KzipWriterAosp::Close was not called!";
+}
+
+absl::StatusOr<std::string> KzipWriter::WriteUnit(
+    const kythe::proto::IndexedCompilation& unit) {
+  int32_t rc = InitializeArchive();
+  if (rc) {
+    return absl::InternalError(ZipWriter::ErrorCodeString(rc));
+  }
+  auto json = WriteMessageAsJsonToString(unit);
+  if (!json.ok()) {
+    return json.status();
+  }
+
+  auto digest = SHA256Digest(*json);
+  absl::StatusOr<std::string> result = absl::InternalError("unsupported encoding");
+  if (HasEncoding(KzipEncoding::kJson)) {
+    if (!(result = InsertFile(kJsonUnitRoot, digest, *json)).ok()) {
+      return result;
+    }
+  }
+  if (HasEncoding(KzipEncoding::kProto)) {
+    std::string contents;
+    if (!unit.SerializeToString(&contents)) {
+      return absl::InternalError("Failure serializing compilation unit");
+    }
+    result = InsertFile(kProtoUnitRoot, digest, contents);
+  }
+  return result;
+}
+
+absl::StatusOr<std::string> KzipWriter::WriteFile(absl::string_view content) {
+  int32_t rc = InitializeArchive();
+  if (rc) {
+    return absl::InternalError(ZipWriter::ErrorCodeString(rc));
+  }
+  return InsertFile(kFileRoot, SHA256Digest(content), content);
+}
+
+absl::Status KzipWriter::Close() {
+  int32_t rc = zip_writer_.Finish();
+  fclose(fp_);
+  fp_ = nullptr;
+  return rc ? absl::InternalError(ZipWriter::ErrorCodeString(rc)) : absl::OkStatus();
+}
+
+absl::StatusOr<std::string> KzipWriter::InsertFile(absl::string_view dir,
+                                                   absl::string_view content_digest,
+                                                   absl::string_view content) {
+  auto kzip_entry = absl::StrCat(dir, content_digest);
+  // Keep track of the inserted entries, reject duplicates
+  auto insertion = contents_.insert(kzip_entry);
+  if (insertion.second) {
+    auto status = WriteTextFile(kzip_entry, std::string(content));
+    if (!status.ok()) {
+      contents_.erase(insertion.first);
+      return status;
+    }
+  }
+  return std::string(content_digest);
+}
+
+KzipEncoding KzipWriter::DefaultEncoding() {
+  const char* env_encoding = getenv("KYTHE_KZIP_ENCODING");
+  if (env_encoding != nullptr && *env_encoding) {
+    if (strcasecmp(env_encoding, "json") == 0) {
+      return KzipEncoding::kJson;
+    } else if (strcasecmp(env_encoding, "proto") == 0) {
+      return KzipEncoding::kProto;
+    } else if (strcasecmp(env_encoding, "all") == 0) {
+      return KzipEncoding::kAll;
+    } else {
+      LOG(ERROR) << "Unknown encoding '" << env_encoding << "', using JSON";
+    }
+  }
+  return KzipEncoding::kJson;
+}
+
+}  // namespace kythe
diff --git a/kythe/cxx/common/kzip_writer_aosp.h b/kythe/cxx/common/kzip_writer_aosp.h
new file mode 100644
index 0000000..8415ad5
--- /dev/null
+++ b/kythe/cxx/common/kzip_writer_aosp.h
@@ -0,0 +1,61 @@
+#ifndef KYTHE_CXX_COMMON_KZIP_WRITER_AOSP_H_
+#define KYTHE_CXX_COMMON_KZIP_WRITER_AOSP_H_
+
+#include <unordered_set>
+
+#include "absl/status/status.h"
+#include "absl/status/statusor.h"
+#include "absl/strings/string_view.h"
+#include "kythe/cxx/common/index_writer.h"
+#include "kythe/cxx/common/kzip_encoding.h"
+#include "kythe/proto/analysis.pb.h"
+#include "ziparchive/zip_writer.h"
+
+namespace kythe {
+
+/// \brief Kzip implementation of IndexWriter for AOSP.
+/// see https://www.kythe.io/docs/kythe-kzip.html for format description.
+class KzipWriter : public IndexWriterInterface {
+ public:
+  /// \brief Constructs a Kzip IndexWriter which will create and write to
+  /// \param path Path to the file to create. Must not currently exist.
+  static absl::StatusOr<IndexWriter> Create(
+      absl::string_view path, KzipEncoding encoding = DefaultEncoding());
+
+  /// \brief Destroys the KzipWriter.
+  ~KzipWriter() override;
+
+  /// \brief Writes the unit to the kzip file, returning its digest.
+  absl::StatusOr<std::string> WriteUnit(
+      const kythe::proto::IndexedCompilation& unit) override;
+
+  /// \brief Writes the file contents to the kzip file, returning their digest.
+  absl::StatusOr<std::string> WriteFile(absl::string_view content) override;
+
+  /// \brief Flushes accumulated writes and closes the kzip file.
+  /// Close must be called before the KzipWriter is destroyed!
+  absl::Status Close() override;
+
+ private:
+  explicit KzipWriter(FILE* fp, KzipEncoding encoding);
+
+  // Adds an entry <dir_name>/<content_digest> to the kzip file unless it
+  // already exists. Returns <content_digest> on success.
+  absl::StatusOr<std::string> InsertFile(absl::string_view dir_name,
+                                         absl::string_view content_digest,
+                                         absl::string_view content);
+  absl::Status WriteTextFile(absl::string_view name, absl::string_view content);
+  int32_t InitializeArchive();
+  int32_t CreateDirEntry(absl::string_view dir_name);
+  bool HasEncoding(KzipEncoding encoding);
+  static KzipEncoding DefaultEncoding();
+
+  FILE* fp_;
+  ZipWriter zip_writer_;
+  bool initialized_;  // Whether or not the `root` entry exists.
+  KzipEncoding encoding_;
+  std::unordered_set<std::string> contents_;
+};
+
+}  // namespace kythe
+#endif  // KYTHE_CXX_COMMON_KZIP_WRITER_AOSP_H_
diff --git a/kythe/cxx/common/protobuf_metadata_file.h b/kythe/cxx/common/protobuf_metadata_file.h
index 471d054..3dd4b5f 100644
--- a/kythe/cxx/common/protobuf_metadata_file.h
+++ b/kythe/cxx/common/protobuf_metadata_file.h
@@ -18,6 +18,8 @@
 #define KYTHE_CXX_COMMON_PROTOBUF_METADATA_FILE_H_
 
 #include <memory>
+// ANDROID_BUILD: need <sstream> for std::stringstream
+#include <sstream>
 
 #include "glog/logging.h"
 #include "google/protobuf/descriptor.pb.h"
diff --git a/kythe/cxx/extractor/cxx_extractor.cc b/kythe/cxx/extractor/cxx_extractor.cc
index aff6837..c244aca 100644
--- a/kythe/cxx/extractor/cxx_extractor.cc
+++ b/kythe/cxx/extractor/cxx_extractor.cc
@@ -38,6 +38,8 @@
 #include "absl/types/optional.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendAction.h"
+// ANDROID_BUILD
+#include "clang/Lex/LexDiagnostic.h"
 #include "clang/Lex/MacroArgs.h"
 #include "clang/Lex/PPCallbacks.h"
 #include "clang/Lex/Preprocessor.h"
@@ -45,7 +47,8 @@
 #include "glog/logging.h"
 #include "kythe/cxx/common/file_utils.h"
 #include "kythe/cxx/common/json_proto.h"
-#include "kythe/cxx/common/kzip_writer.h"
+// ANDROID_BUILD
+#include "kythe/cxx/common/kzip_writer_aosp.h"
 #include "kythe/cxx/common/path_utils.h"
 #include "kythe/cxx/extractor/CommandLineUtils.h"
 #include "kythe/cxx/extractor/language.h"
@@ -957,6 +960,11 @@
         << "Expected to see only one TU; instead saw " << inputs.size() << ".";
     main_source_file_ = std::string(inputs[0].getFile());
     auto* preprocessor = &getCompilerInstance().getPreprocessor();
+    // ANDROID_BUILD:
+    // TODO: find a better way to ignore unknown pragmas
+    preprocessor->getDiagnostics().setSeverity(
+        clang::diag::warn_pragma_ignored, clang::diag::Severity::Ignored,
+        clang::SourceLocation());
     preprocessor->addPPCallbacks(
         absl::make_unique<ExtractorPPCallbacks>(ExtractorState{
             index_writer_, &getCompilerInstance().getSourceManager(),
diff --git a/kythe/cxx/extractor/proto/proto_extractor_main.cc b/kythe/cxx/extractor/proto/proto_extractor_main.cc
index fcdc53a..402b84e 100644
--- a/kythe/cxx/extractor/proto/proto_extractor_main.cc
+++ b/kythe/cxx/extractor/proto/proto_extractor_main.cc
@@ -29,8 +29,11 @@
 #include "absl/flags/usage.h"
 #include "absl/strings/match.h"
 #include "glog/logging.h"
+
 #include "kythe/cxx/common/init.h"
-#include "kythe/cxx/common/kzip_writer.h"
+// (ANDROID_BUILD
+#include "kythe/cxx/common/kzip_writer_aosp.h"
+// )
 #include "kythe/cxx/extractor/proto/proto_extractor.h"
 #include "kythe/cxx/indexer/proto/search_path.h"
 #include "kythe/proto/analysis.pb.h"
diff --git a/kythe/cxx/extractor/testdata/claim_pragma_test.cc b/kythe/cxx/extractor/testdata/claim_pragma_test.cc
index 077ec4f..97dc9f8 100644
--- a/kythe/cxx/extractor/testdata/claim_pragma_test.cc
+++ b/kythe/cxx/extractor/testdata/claim_pragma_test.cc
@@ -22,8 +22,6 @@
 using ::google::protobuf::util::MessageDifferencer;
 using ::testing::ElementsAre;
 
-using pbstring = ::google::protobuf::string;
-
 constexpr char kExpectedContents[] = R"(
 v_name {
   language: "c++"
@@ -113,7 +111,7 @@
 //                                {"message", "inner", "field"});
 const FieldDescriptor* FindNestedFieldByLowercasePath(
     const google::protobuf::Descriptor* descriptor,
-    const std::vector<pbstring>& field_names) {
+    const std::vector<std::string>& field_names) {
   const FieldDescriptor* field = nullptr;
   for (const auto& name : field_names) {
     if (descriptor == nullptr) return nullptr;
@@ -147,7 +145,7 @@
   }
 
  private:
-  using HashMap = std::unordered_map<pbstring, size_t>;
+  using HashMap = std::unordered_map<std::string, size_t>;
 
   ComparisonResult Compare(
       const Message& message_1, const Message& message_2,
@@ -163,8 +161,8 @@
     if (field->is_repeated()) {
       // Allocate scratch strings to store the result if a conversion is
       // needed.
-      pbstring scratch1;
-      pbstring scratch2;
+      std::string scratch1;
+      std::string scratch2;
       return CompareCanonicalHash(reflection_1->GetRepeatedStringReference(
                                       message_1, field, index_1, &scratch1),
                                   reflection_2->GetRepeatedStringReference(
@@ -172,23 +170,23 @@
     } else {
       // Allocate scratch strings to store the result if a conversion is
       // needed.
-      pbstring scratch1;
-      pbstring scratch2;
+      std::string scratch1;
+      std::string scratch2;
       return CompareCanonicalHash(
           reflection_1->GetStringReference(message_1, field, &scratch1),
           reflection_2->GetStringReference(message_2, field, &scratch2));
     }
   }
 
-  ComparisonResult CompareCanonicalHash(const pbstring& string_1,
-                                        const pbstring& string_2) {
+  ComparisonResult CompareCanonicalHash(const std::string& string_1,
+                                        const std::string& string_2) {
     return HashIndex(&left_message_hashes_, string_1) ==
                    HashIndex(&right_message_hashes_, string_2)
                ? SAME
                : DIFFERENT;
   }
 
-  static size_t HashIndex(HashMap* canonical_map, const pbstring& hash) {
+  static size_t HashIndex(HashMap* canonical_map, const std::string& hash) {
     size_t index = canonical_map->size();
     // We use an index equivalent to the visitation order of the hashes.
     // This is potentially fragile as we really only care if a protocol buffer
@@ -231,7 +229,7 @@
 
     kythe::proto::CompilationUnit expected;
     ASSERT_TRUE(TextFormat::ParseFromString(kExpectedContents, &expected));
-    google::protobuf::string diffs;
+    std::string diffs;
     diff.ReportDifferencesToString(&diffs);
     EXPECT_TRUE(diff.Compare(expected, unit)) << diffs;
 
diff --git a/kythe/cxx/glog/logging.cc b/kythe/cxx/glog/logging.cc
new file mode 100644
index 0000000..8b85c6a
--- /dev/null
+++ b/kythe/cxx/glog/logging.cc
@@ -0,0 +1,5 @@
+#include "glog/logging.h"
+namespace google {
+void InitGoogleLogging(const char *) {
+}
+}
diff --git a/kythe/cxx/glog/logging.h b/kythe/cxx/glog/logging.h
new file mode 100644
index 0000000..3aca935
--- /dev/null
+++ b/kythe/cxx/glog/logging.h
@@ -0,0 +1,15 @@
+/*
+ * Android-compatible logging.h to avoid pulling in Google logging package.
+ */
+
+#if !defined(GLOG_LOGGING_H_)
+#define GLOG_LOGGING_H_
+#include "android-base/logging.h"
+#define DFATAL FATAL
+#define VLOG(verbose_level) LOG(VERBOSE)
+
+namespace google {
+void InitGoogleLogging(const char *argv0);
+}
+
+#endif // GLOG_LOGGING_H
diff --git a/kythe/cxx/indexer/cxx/IndexerASTHooks.cc b/kythe/cxx/indexer/cxx/IndexerASTHooks.cc
index 50df814..38aebef 100644
--- a/kythe/cxx/indexer/cxx/IndexerASTHooks.cc
+++ b/kythe/cxx/indexer/cxx/IndexerASTHooks.cc
@@ -4210,6 +4210,9 @@
     case TemplateName::UsingTemplate:
       CHECK(options_.IgnoreUnimplemented) << "TN.UsingTemplate";
       return absl::nullopt;
+    case TemplateName::UsingTemplate:
+      CHECK(options_.IgnoreUnimplemented) << "TN.UsingTemplate";
+      return absl::nullopt;
   }
   CHECK(options_.IgnoreUnimplemented)
       << "Unexpected TemplateName kind: " << Name.getKind();
diff --git a/kythe/cxx/indexer/cxx/KytheIndexerUnitTest.cc b/kythe/cxx/indexer/cxx/KytheIndexerUnitTest.cc
index de6ef18..d23f08a 100644
--- a/kythe/cxx/indexer/cxx/KytheIndexerUnitTest.cc
+++ b/kythe/cxx/indexer/cxx/KytheIndexerUnitTest.cc
@@ -277,9 +277,9 @@
   EXPECT_EQ(vname_target.DebugString(), entry.target().DebugString());
 }
 
-static void WriteStringToStackAndBuffer(const google::protobuf::string& value,
+static void WriteStringToStackAndBuffer(const std::string& value,
                                         kythe::BufferStack* stack,
-                                        google::protobuf::string* buffer) {
+                                        std::string* buffer) {
   unsigned char* bytes = stack->WriteToTop(value.size());
   memcpy(bytes, value.data(), value.size());
   if (buffer) {
@@ -289,7 +289,7 @@
 
 TEST(KytheIndexerUnitTest, BufferStackWrite) {
   kythe::BufferStack stack;
-  google::protobuf::string expected, actual;
+  std::string expected, actual;
   {
     google::protobuf::io::StringOutputStream stream(&actual);
     stack.Push(0);
@@ -305,7 +305,7 @@
 
 TEST(KytheIndexerUnitTest, BufferStackMergeDown) {
   kythe::BufferStack stack;
-  google::protobuf::string actual;
+  std::string actual;
   {
     google::protobuf::io::StringOutputStream stream(&actual);
     stack.Push(0);
@@ -344,7 +344,7 @@
 
 TEST(KytheIndexerUnitTest, BufferStackMergeFailures) {
   kythe::BufferStack stack;
-  google::protobuf::string actual;
+  std::string actual;
   {
     google::protobuf::io::StringOutputStream stream(&actual);
     ASSERT_FALSE(stack.MergeDownIfTooSmall(0, 2048));  // too few on the stack
diff --git a/kythe/cxx/indexer/cxx/proto_conversions.h b/kythe/cxx/indexer/cxx/proto_conversions.h
index 59e0ab1..7167093 100644
--- a/kythe/cxx/indexer/cxx/proto_conversions.h
+++ b/kythe/cxx/indexer/cxx/proto_conversions.h
@@ -25,7 +25,7 @@
 /// \brief Wrap a protobuf string in a StringRef.
 /// \param string The string to wrap.
 /// \return The wrapped string (which should not outlive `string`).
-inline llvm::StringRef ToStringRef(const google::protobuf::string& string) {
+inline llvm::StringRef ToStringRef(const std::string& string) {
   return llvm::StringRef(string.c_str(), string.size());
 }
 }  // namespace kythe
diff --git a/kythe/cxx/verifier/verifier.cc b/kythe/cxx/verifier/verifier.cc
index e006c47..a8cac9b 100644
--- a/kythe/cxx/verifier/verifier.cc
+++ b/kythe/cxx/verifier/verifier.cc
@@ -1331,7 +1331,7 @@
 }
 
 AstNode* Verifier::ConvertCodeFact(const yy::location& loc,
-                                   const google::protobuf::string& code_data) {
+                                   const std::string& code_data) {
   proto::common::MarkedSource marked_source;
   if (!marked_source.ParseFromString(code_data)) {
     std::cerr << loc << ": can't parse code protobuf" << std::endl;
diff --git a/kythe/cxx/verifier/verifier.h b/kythe/cxx/verifier/verifier.h
index b8a9600..226ed43 100644
--- a/kythe/cxx/verifier/verifier.h
+++ b/kythe/cxx/verifier/verifier.h
@@ -223,7 +223,7 @@
   /// \return null if something went wrong; otherwise, an AstNode corresponding
   /// to a VName of a synthetic node for `code_data`.
   AstNode* ConvertCodeFact(const yy::location& loc,
-                           const google::protobuf::string& code_data);
+                           const std::string& code_data);
 
   /// \brief Converts a MarkedSource message to a form that's useful
   /// to the verifier.
diff --git a/kythe/cxx/verifier/verifier_unit_test.cc b/kythe/cxx/verifier/verifier_unit_test.cc
index c530008..20c7f3f 100644
--- a/kythe/cxx/verifier/verifier_unit_test.cc
+++ b/kythe/cxx/verifier/verifier_unit_test.cc
@@ -2652,10 +2652,10 @@
 TEST(VerifierUnitTest, DontConvertMarkedSource) {
   Verifier v;
   MarkedSource source;
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_TRUE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2673,10 +2673,10 @@
   Verifier v;
   v.ConvertMarkedSource();
   MarkedSource source;
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_TRUE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2708,10 +2708,10 @@
     v.ConvertMarkedSource();
     MarkedSource source;
     source.set_kind(kind_enum);
-    google::protobuf::string source_string;
+    std::string source_string;
     ASSERT_TRUE(source.SerializeToString(&source_string));
     google::protobuf::TextFormat::FieldValuePrinter printer;
-    google::protobuf::string enc_source = printer.PrintBytes(source_string);
+    std::string enc_source = printer.PrintBytes(source_string);
     ASSERT_TRUE(v.LoadInlineProtoFile(R"(
     entries {
       source { signature:"test" }
@@ -2732,10 +2732,10 @@
   v.ConvertMarkedSource();
   MarkedSource source;
   source.add_link()->add_definition("kythe://corpus#sig");
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_TRUE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2754,10 +2754,10 @@
   v.ConvertMarkedSource();
   MarkedSource source;
   source.add_link()->add_definition("kythe:/&bad");
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_FALSE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2772,10 +2772,10 @@
   v.ConvertMarkedSource();
   MarkedSource source;
   source.add_link();
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_FALSE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2792,10 +2792,10 @@
   auto* link = source.add_link();
   link->add_definition("kythe://corpus#sig");
   link->add_definition("kythe://corpus#sig2");
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_FALSE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2813,10 +2813,10 @@
   child->set_kind(MarkedSource::IDENTIFIER);
   child = source.add_child();
   child->set_kind(MarkedSource::CONTEXT);
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_TRUE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2841,10 +2841,10 @@
   auto* link = child->add_link();
   link->add_definition("kythe://corpus#sig");
   link->add_definition("kythe://corpus#sig2");
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(parent.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_FALSE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2864,10 +2864,10 @@
   source.set_lookup_index(42);
   source.set_default_children_count(43);
   source.set_add_final_list_token(true);
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_TRUE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2890,10 +2890,10 @@
   Verifier v;
   MarkedSource source;
   v.IgnoreDuplicateFacts();
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_TRUE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
@@ -2914,10 +2914,10 @@
   Verifier v;
   v.ConvertMarkedSource();
   MarkedSource source;
-  google::protobuf::string source_string;
+  std::string source_string;
   ASSERT_TRUE(source.SerializeToString(&source_string));
   google::protobuf::TextFormat::FieldValuePrinter printer;
-  google::protobuf::string enc_source = printer.PrintBytes(source_string);
+  std::string enc_source = printer.PrintBytes(source_string);
   ASSERT_TRUE(v.LoadInlineProtoFile(R"(
   entries {
     source { signature:"test" }
diff --git a/kythe/go/extractors/cmd/rust_extractor/rust_extractor.go b/kythe/go/extractors/cmd/rust_extractor/rust_extractor.go
new file mode 100644
index 0000000..a7a7f7b
--- /dev/null
+++ b/kythe/go/extractors/cmd/rust_extractor/rust_extractor.go
@@ -0,0 +1,307 @@
+// rust_extractor prepares kzip for a given Rust compilation.
+// It is a "prefix tool", i.e. if Rust compiler is invoked with
+//   rustc --emit link foo.rs ...
+// then running
+//   KYTHE_OUTPUT_FILE=foo.kzip rust_extractor rustc --emit foo.rs
+// creates foo.kzip
+// Kythe corpus is picked from KYTHE_CORPUS environment variable.
+// KYTHE_VNAMES environment variable points the JSON file with path rewrite rules.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"kythe.io/kythe/go/platform/kzip"
+	"kythe.io/kythe/go/util/vnameutil"
+	apb "kythe.io/kythe/proto/analysis_go_proto"
+	spb "kythe.io/kythe/proto/storage_go_proto"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strings"
+)
+
+func maybeFatal(err error) {
+	if err == nil {
+		return
+	}
+	_, _ = fmt.Fprintln(os.Stderr, err)
+	os.Exit(2)
+}
+
+// Context maintains extraction state and and implements extraction.
+type Context struct {
+	cu           *apb.CompilationUnit
+	kzipPath     string
+	kzipFile     *kzip.Writer
+	rustCompiler string
+	inputs       []string
+	rewriteRules vnameutil.Rules
+}
+
+// Construct
+func newContext(args []string, kzipPath string) *Context {
+	ctx := &Context{
+		kzipPath: kzipPath,
+		cu: &apb.CompilationUnit{
+			VName: &spb.VName{
+				Corpus:   os.Getenv("KYTHE_CORPUS"),
+				Language: "rust",
+			},
+		},
+	}
+	// Process command line arguments.
+	envRex := regexp.MustCompile("^([A-Za-z_]\\w*)=(.*)$")
+	for i, arg := range args {
+		if m := envRex.FindStringSubmatch(arg); m != nil {
+			ctx.cu.Environment = append(ctx.cu.Environment, &apb.CompilationUnit_Env{Name: m[1], Value: m[2]})
+			continue
+		}
+		ctx.rustCompiler = arg
+		ctx.cu.Argument = args[i+1:]
+		break
+	}
+	return ctx
+}
+
+// Transforms command line arguments into our arguments.
+func (ctx *Context) actualCompilerArgs() []string {
+	// Drop -o and -emit arguments, prepend -emit dep-info=...,metadata=...
+	args := []string{
+		"--emit", fmt.Sprintf("dep-info=%s,metadata=%s", ctx.depsPath(), ctx.metadataPath()),
+		"-Z", "save-analysis"}
+
+	rdr := newArgReader(ctx.cu.Argument)
+	for ; !rdr.atEnd(); rdr.read() {
+		switch rdr.key() {
+		case "--emit", "-o":
+		default:
+			args = append(args, rdr.currentArg()...)
+		}
+	}
+	return args
+}
+
+// Runs Rust compiler, saving compilation analysis, extracts input files list
+func (ctx *Context) runCompiler() {
+	// Remove old files, ensure the output directory exists
+	_ = os.Remove(ctx.savedAnalysisPath())
+	_ = os.Remove(ctx.depsPath())
+	_ = os.Remove(ctx.metadataPath())
+	_ = os.Remove(ctx.kzipPath)
+	err := os.MkdirAll(filepath.Dir(ctx.kzipPath), 0755)
+	maybeFatal(err)
+
+	// In addition to the actual parameters, instruct the compiler to
+	// generate the dependencies file, the metadata file, and save the
+	// compiler analysis as JSON file.
+	cmd := exec.Command(ctx.rustCompiler, ctx.actualCompilerArgs()...)
+	// Append command line environment variables
+	cmd.Env = os.Environ()
+	for _, x := range ctx.cu.Environment {
+		cmd.Env = append(cmd.Env, x.Name+"="+x.Value)
+	}
+	// Append save analysis configuration, including saved analysis path
+	cmd.Env = append(cmd.Env,
+		fmt.Sprintf(`RUST_SAVE_ANALYSIS_CONFIG={`+
+			`"output_file": %q,`+
+			`"full_docs":true,`+
+			`"pub_only":false,`+
+			`"reachable_only":false,`+
+			`"distro_crate":false,`+
+			`"signatures":false,`+
+			`"borrow_data":false}`, ctx.savedAnalysisPath()))
+
+	output, err := cmd.CombinedOutput()
+	if len(output) > 0 {
+		fmt.Printf("%s\n", output)
+	}
+	maybeFatal(err)
+
+	// Build the list of the source files
+	f, err := os.Open(ctx.depsPath())
+	maybeFatal(err)
+	ctx.getInputFiles(f, ctx.depsPath())
+	_ = f.Close()
+}
+
+// Obtains the list of the Rust source being compiled.
+func (ctx *Context) getInputFiles(f io.Reader, dependentsOf string) {
+	s := bufio.NewScanner(f)
+	n := len(dependentsOf)
+	for s.Scan() {
+		ln := s.Text()
+		// Look for the line:
+		//  <dependentsOf>: file ...
+		// Ignore not .rs files.
+		if strings.HasPrefix(ln, dependentsOf) && ln[n] == ':' {
+			deps := strings.Split(strings.Trim(ln[n+1:], " "), " ")
+			for _, dep := range deps {
+				if strings.HasSuffix(dep, ".rs") {
+					ctx.inputs = append(ctx.inputs, dep)
+				}
+			}
+		}
+	}
+}
+
+// Reads vname rewriting rules
+func (ctx *Context) loadRules(r io.Reader) {
+	var err error
+	ctx.rewriteRules, err = vnameutil.ReadRules(r)
+	maybeFatal(err)
+}
+
+func (ctx *Context) makeVname(path string) *spb.VName {
+	var vname *spb.VName
+	var ok bool
+	if vname, ok = ctx.rewriteRules.Apply(path); !ok {
+		vname = &spb.VName{Path: path, Corpus: ctx.cu.VName.Corpus}
+	}
+	// By default, the corpus is the same as compilation unit's.
+	if vname.Corpus == "" {
+		vname.Corpus = ctx.cu.VName.Corpus
+	}
+	return vname
+}
+
+// Saves kzip file.
+func (ctx *Context) saveKzip() {
+	kzf, err := os.Create(ctx.kzipPath)
+	maybeFatal(err)
+	ctx.kzipFile, err = kzip.NewWriteCloser(kzf)
+	maybeFatal(err)
+
+	// The output archive contains an entry with save analysis
+	// contents, and entry for each input file, and a proto/JSON
+	// message for the compilation unit.
+
+	// First, save analysis
+	saPath := ctx.savedAnalysisPath()
+	f, err := os.Open(saPath)
+	maybeFatal(err)
+	digest, err := ctx.kzipFile.AddFile(f)
+	err = f.Close()
+	maybeFatal(err)
+
+	ctx.cu.RequiredInput = append(ctx.cu.RequiredInput, &apb.CompilationUnit_FileInput{
+		VName: ctx.makeVname(saPath),
+		Info:  &apb.FileInfo{Path: saPath, Digest: digest},
+	})
+
+	// Input files
+	for _, input := range ctx.inputs {
+		f, err = os.Open(input)
+		maybeFatal(err)
+		digest, err = ctx.kzipFile.AddFile(f)
+		maybeFatal(err)
+		err = f.Close()
+		maybeFatal(err)
+		vname := ctx.makeVname(input)
+		vname.Language = "rust"
+		ctx.cu.RequiredInput = append(ctx.cu.RequiredInput, &apb.CompilationUnit_FileInput{
+			VName: vname,
+			Info: &apb.FileInfo{
+				Path:   input,
+				Digest: digest,
+			},
+		})
+		ctx.cu.SourceFile = append(ctx.cu.SourceFile, input)
+	}
+
+	// Finally, compilation unit
+	_, err = ctx.kzipFile.AddUnit(ctx.cu, nil)
+	maybeFatal(err)
+	err = ctx.kzipFile.Close()
+	maybeFatal(err)
+}
+
+func (ctx Context) savedAnalysisPath() string {
+	return ctx.kzipPath + ".sa.json"
+}
+
+func (ctx Context) depsPath() string {
+	return ctx.kzipPath + ".deps"
+}
+
+func (ctx Context) metadataPath() string {
+	return ctx.kzipPath + ".metadummy"
+}
+
+// Utility stuff to iterate over rustc command-line "items"
+// An item can be:
+//   --foo val
+//   --foo=val
+//   -C val
+//   -Cval
+//   arg
+type argReader struct {
+	inArgs       []string
+	currentIndex int
+	nextIndex    int
+	argKey       string
+}
+
+func newArgReader(args []string) *argReader {
+	ret := &argReader{inArgs: args, nextIndex: 0, currentIndex: 0}
+	ret.read()
+	return ret
+}
+
+func (ar argReader) atEnd() bool {
+	return ar.currentIndex >= len(ar.inArgs)
+}
+
+func (ar *argReader) read() {
+	ar.currentIndex = ar.nextIndex
+	if ar.atEnd() {
+		return
+	}
+	ar.nextIndex++
+	ar.argKey = ar.inArgs[ar.currentIndex]
+	if ar.argKey[0] != '-' {
+		return
+	}
+	n := -1
+	if strings.HasPrefix(ar.argKey, "--") {
+		n = strings.Index(ar.argKey, "=")
+	} else if len(ar.argKey) > 2 {
+		n = 2
+	}
+	if n >= 0 {
+		ar.argKey = ar.argKey[0:n]
+	} else if !ar.atEnd() {
+		ar.nextIndex++
+	}
+}
+
+func (ar *argReader) currentArg() []string {
+	return ar.inArgs[ar.currentIndex:ar.nextIndex]
+}
+
+func (ar argReader) key() string {
+	return ar.argKey
+}
+
+func main() {
+	if len(os.Args) < 2 {
+		maybeFatal(fmt.Errorf("at least the rust compiler path should be present"))
+	}
+	const KzipEnv = "KYTHE_OUTPUT_FILE"
+	kzipPath := os.Getenv(KzipEnv)
+	if kzipPath == "" {
+		maybeFatal(fmt.Errorf("%s is  not set", KzipEnv))
+	}
+	ctx := newContext(os.Args[1:], kzipPath)
+	vnamesPath := os.Getenv("KYTHE_VNAMES")
+	if vnamesPath != "" {
+		vf, err := os.Open(vnamesPath)
+		maybeFatal(err)
+		ctx.loadRules(vf)
+	}
+	ctx.runCompiler()
+	ctx.saveKzip()
+}
diff --git a/kythe/go/extractors/cmd/rust_extractor/rust_extractor_test.go b/kythe/go/extractors/cmd/rust_extractor/rust_extractor_test.go
new file mode 100644
index 0000000..ef6c6c5
--- /dev/null
+++ b/kythe/go/extractors/cmd/rust_extractor/rust_extractor_test.go
@@ -0,0 +1,97 @@
+package main
+
+import (
+	"kythe.io/kythe/go/test/testutil"
+	apb "kythe.io/kythe/proto/analysis_go_proto"
+	spb "kythe.io/kythe/proto/storage_go_proto"
+	"os"
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func TestNewContext(t *testing.T) {
+	t.Run("processCommandLine", func(t *testing.T) {
+		line := "FOO=x RUST_VERSION=1.59 compiler arg"
+		ctx := newContext(strings.Split(line, " "), "foo.kzip")
+		if err := testutil.DeepEqual(
+			[]*apb.CompilationUnit_Env{
+				{Name: "FOO", Value: "x"},
+				{Name: "RUST_VERSION", Value: "1.59"}},
+			ctx.cu.Environment); err != nil {
+			t.Errorf("wrong environment: %s", err)
+		}
+		if err := testutil.DeepEqual("compiler", ctx.rustCompiler); err != nil {
+			t.Errorf("wrong compiler: %s", err)
+		}
+		if err := testutil.DeepEqual([]string{"arg1"}, ctx.cu.Argument); err == nil {
+			t.Errorf("wrong arguments: %s", err)
+		}
+
+	})
+}
+
+func TestContext_compilerArgs(t *testing.T) {
+	cmdLine := "rustc -C linker=lld --emit link -o foo lib.rs --extern std=bar.so -Zremap-cwd-prefix= --crate-type=rlib"
+	expected := "--emit dep-info=foo.kzip.deps,metadata=foo.kzip.metadummy -Z save-analysis " +
+		"-C linker=lld lib.rs --extern std=bar.so -Zremap-cwd-prefix= --crate-type=rlib"
+
+	t.Run("parseArgs1", func(t *testing.T) {
+		ctx := newContext(strings.Split(cmdLine, " "), "foo.kzip")
+		if err := testutil.DeepEqual(strings.Split(expected, " "), ctx.actualCompilerArgs()); err != nil {
+			t.Errorf("wrong compiler arguments: %s", err)
+		}
+	})
+}
+
+func TestContext_getInputFiles(t *testing.T) {
+	t.Run("input files", func(t *testing.T) {
+		ctx := newContext(strings.Split("rustc foo.rs", " '"), "foo.kzip")
+		deps := `
+foo.rmeta: x.rs x.der
+foo.deps: foo.rs y.der
+`
+		ctx.getInputFiles(strings.NewReader(deps), "foo.deps")
+		if err := testutil.DeepEqual([]string{"foo.rs"}, ctx.inputs); err != nil {
+			t.Errorf("wrong input files: %s", err)
+		}
+	})
+}
+
+func TestContext_makeVname(t *testing.T) {
+	t.Run("name rewriting", func(t *testing.T) {
+		vnameJson := `[
+  {
+    "pattern": "out/(.*)",
+    "vname": {
+      "root": "out",
+      "path": "@1@"
+    }
+  },
+  {
+    "pattern": "(.*)",
+    "vname": {
+      "path": "@1@"
+    }
+  }
+]
+`
+		tests := []struct {
+			path string
+			want *spb.VName
+		}{
+			// static
+			{"foo/bar.rs", &spb.VName{Path: "foo/bar.rs", Corpus: "aosp"}},
+			{"out/path.json", &spb.VName{Root: "out", Path: "path.json", Corpus: "aosp"}},
+		}
+
+		_ = os.Setenv("KYTHE_CORPUS", "aosp")
+		ctx := newContext(strings.Split("rustc foo.rs", " '"), "foo.kzip")
+		ctx.loadRules(strings.NewReader(vnameJson))
+		for _, test := range tests {
+			if got := ctx.makeVname(test.path); !reflect.DeepEqual(got, test.want) {
+				t.Errorf("makeVname() = %v, want %v", got, test.want)
+			}
+		}
+	})
+}
diff --git a/kythe/go/extractors/golang/golang.go b/kythe/go/extractors/golang/golang.go
index 66666ab..50874b5 100644
--- a/kythe/go/extractors/golang/golang.go
+++ b/kythe/go/extractors/golang/golang.go
@@ -51,7 +51,7 @@
 
 	"bitbucket.org/creachadair/stringset"
 
-	anypb "github.com/golang/protobuf/ptypes/any"
+	"google.golang.org/protobuf/types/known/anypb"
 
 	apb "kythe.io/kythe/proto/analysis_go_proto"
 	gopb "kythe.io/kythe/proto/go_go_proto"
diff --git a/kythe/go/platform/kindex/kindex.go b/kythe/go/platform/kindex/kindex.go
index 23519f9..4b55a30 100644
--- a/kythe/go/platform/kindex/kindex.go
+++ b/kythe/go/platform/kindex/kindex.go
@@ -53,7 +53,7 @@
 	"kythe.io/kythe/go/platform/vfs"
 	"kythe.io/kythe/go/util/ptypes"
 
-	"github.com/golang/protobuf/proto"
+	"google.golang.org/protobuf/proto"
 
 	apb "kythe.io/kythe/proto/analysis_go_proto"
 	spb "kythe.io/kythe/proto/storage_go_proto"
@@ -146,15 +146,15 @@
 	}
 	dw := delimited.NewWriter(gz)
 
-	buf := proto.NewBuffer(nil)
-	if err := buf.Marshal(c.Proto); err != nil {
+	buf, err := proto.Marshal(c.Proto)
+	if err != nil {
 		gz.Close()
 		return 0, fmt.Errorf("marshalling compilation: %v", err)
 	}
 
 	var total int64
 
-	nw, err := dw.WriteRecord(buf.Bytes())
+	nw, err := dw.WriteRecord(buf)
 	total += int64(nw)
 	if err != nil {
 		gz.Close()
@@ -162,12 +162,12 @@
 	}
 
 	for _, file := range c.Files {
-		buf.Reset()
-		if err := buf.Marshal(file); err != nil {
+		buf, err := proto.Marshal(file)
+		if err != nil {
 			gz.Close()
 			return total, fmt.Errorf("marshaling file data: %v", err)
 		}
-		nw, err := dw.WriteRecord(buf.Bytes())
+		nw, err := dw.WriteRecord(buf)
 		total += int64(nw)
 		if err != nil {
 			gz.Close()
diff --git a/kythe/go/util/ptypes/ptypes.go b/kythe/go/util/ptypes/ptypes.go
index 52c7ef7..8e9b5c4 100644
--- a/kythe/go/util/ptypes/ptypes.go
+++ b/kythe/go/util/ptypes/ptypes.go
@@ -23,10 +23,9 @@
 	"sort"
 	"strings"
 
-	"github.com/golang/protobuf/proto"
-	"github.com/golang/protobuf/ptypes"
+	"google.golang.org/protobuf/proto"
 
-	anypb "github.com/golang/protobuf/ptypes/any"
+	"google.golang.org/protobuf/types/known/anypb"
 )
 
 // Any is an alias for the protocol buffer Any message type.
@@ -38,14 +37,14 @@
 	// The ptypes package vendors generated code for the Any type, so we have
 	// to convert the type. The pointers are convertible, but since we need to
 	// do surgery on the URL anyway, we just construct the output separately.
-	internalAny, err := ptypes.MarshalAny(pb)
+	internalAny, err := anypb.New(pb)
 	if err != nil {
 		return nil, err
 	}
 
 	// Fix up messages in the Kythe namespace.
 	url := internalAny.TypeUrl
-	if name, _ := ptypes.AnyMessageName(internalAny); strings.HasPrefix(name, "kythe.") {
+	if name := string(internalAny.MessageName()); strings.HasPrefix(name, "kythe.") {
 		url = "kythe.io/proto/" + name
 	}
 	return &anypb.Any{
@@ -57,7 +56,7 @@
 // UnmarshalAny unmarshals a google.protobuf.Any message into pb.
 // This is an alias for ptypes.UnmarshalAny to save an import.
 func UnmarshalAny(any *anypb.Any, pb proto.Message) error {
-	return ptypes.UnmarshalAny(any, pb)
+	return any.UnmarshalTo(pb)
 }
 
 // SortByTypeURL orders a slice of Any messages by their type URL, modifying
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/JavaCompilationUnitExtractor.java b/kythe/java/com/google/devtools/kythe/extractors/java/JavaCompilationUnitExtractor.java
index e214935..676b8b1 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/java/JavaCompilationUnitExtractor.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/JavaCompilationUnitExtractor.java
@@ -30,7 +30,6 @@
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Multimap;
 import com.google.common.collect.Streams;
-import com.google.common.flogger.FluentLogger;
 import com.google.common.io.ByteStreams;
 import com.google.devtools.kythe.extractors.shared.CompilationDescription;
 import com.google.devtools.kythe.extractors.shared.ExtractionException;
@@ -87,6 +86,8 @@
 import java.util.Optional;
 import java.util.ServiceLoader;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.regex.Pattern;
 import javax.annotation.processing.Processor;
 import javax.tools.Diagnostic;
@@ -111,7 +112,8 @@
   public static final String JAVA_DETAILS_URL = "kythe.io/proto/kythe.proto.JavaDetails";
   public static final String BUILD_DETAILS_URL = "kythe.io/proto/kythe.proto.BuildDetails";
 
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+  private static final Logger logger =
+      Logger.getLogger(JavaCompilationUnitExtractor.class.getName());
 
   private static final Pattern JDK_MODULE_PATTERN = Pattern.compile("^/modules/(java|jdk)[.].*");
   private static final String MODULE_INFO_NAME = "module-info";
@@ -219,7 +221,7 @@
       try {
         fileManager.close();
       } catch (IOException err) {
-        logger.atWarning().withCause(err).log("Unable to close file manager");
+        logger.log(Level.WARNING, "Unable to close file manager", err);
       }
     }
   }
@@ -536,8 +538,8 @@
           // because we pick up this source jar and the classpath/sourcepath usage with our other
           // compiler hooks.
           if ("jar".equals(uri.getScheme())) {
-            logger.atWarning().log(
-                "Detected a source in a jar file: %s - %s", uri, compilationUnit);
+            logger.warning(
+                String.format("Detected a source in a jar file: %s - %s", uri, compilationUnit));
             continue;
           }
           String path = uri.getPath();
@@ -736,7 +738,7 @@
         }
         byte[] data = ByteStreams.toByteArray(stream);
         if (data.length == 0) {
-          logger.atWarning().log("Empty java source file: %s", strippedPath);
+          logger.warning(String.format("Empty java source file: %s", strippedPath));
         }
         results.fileContents.put(strippedPath, data);
         results.relativePaths.put(strippedPath, relativePath);
@@ -993,7 +995,7 @@
       try {
         DeleteRecursively.delete(path);
       } catch (IOException ioe) {
-        logger.atSevere().withCause(ioe).log("Failed to delete temporary directory %s", path);
+        logger.log(Level.SEVERE, String.format("Failed to delete temporary directory %s", path), ioe);
       }
     }
   }
@@ -1008,6 +1010,9 @@
     return ModifiableOptions.of(rawOptions)
         .removeUnsupportedOptions()
         .ensureEncodingSet(StandardCharsets.UTF_8)
+        // Android always uses this option.
+        // TODO(asmundak): needs more work before contributing upstream.
+        .add("-XDstringConcat=inline")
         .replaceOptionValue(Option.D, tempDestinationDir.toString())
         .build();
   }
@@ -1020,7 +1025,7 @@
       // Notably, when using modules the system compiler is inhibited and the actual compiler
       // resides in jdk.compiler.iterim.  Rather than hard-code this, just fall back to the first
       // JavaCompiler we can find.
-      logger.atWarning().log("Unable to find system compiler, using first available.");
+      logger.warning("Unable to find system compiler, using first available.");
       for (JavaCompiler found : ServiceLoader.load(JavaCompiler.class, moduleClassLoader)) {
         return Optional.ofNullable(found);
       }
@@ -1052,8 +1057,8 @@
         String path = sym.sourcefile.toUri().getPath();
         if (path != null) {
           String basename = Paths.get(path).getFileName().toString();
-          if (!basename.endsWith(".java")) {
-            logger.atWarning().log("Invalid sourcefile name: '%s'", basename);
+          if (!basename.endsWith(".java") && !basename.endsWith(".kt")) {
+            logger.warning(String.format("Invalid sourcefile name: '%s'", basename));
           }
           sourceBaseNames.put(sym.classfile.toUri(), basename);
         }
@@ -1098,13 +1103,13 @@
             .peek(
                 diag -> {
                   if (diag.getSource() != null) {
-                    logger.atSevere().log(
+                    logger.severe(String.format(
                         "compiler error: %s(%d): %s",
                         diag.getSource().getName(),
                         diag.getLineNumber(),
-                        diag.getMessage(Locale.ENGLISH));
+                        diag.getMessage(Locale.ENGLISH)));
                   } else {
-                    logger.atSevere().log("compiler error: %s", diag.getMessage(Locale.ENGLISH));
+                    logger.severe(String.format("compiler error: %s", diag.getMessage(Locale.ENGLISH)));
                   }
                 })
             .count()
@@ -1117,7 +1122,7 @@
         .filter(d -> d.getKind() == Diagnostic.Kind.ERROR)
         .forEach(
             d ->
-                logger.atSevere().log("Fatal error in compiler: %s", d.getMessage(Locale.ENGLISH)));
+                logger.severe(String.format("Fatal error in compiler: %s", d.getMessage(Locale.ENGLISH))));
   }
 
   private static Symtab getSymbolTable(JavacTask javacTask) {
@@ -1135,8 +1140,8 @@
   private static String stableRoot(
       String rootDirectory, Iterable<String> options, Iterable<FileInput> requiredInput) {
     if (Iterables.any(options, o -> o.contains(rootDirectory))) {
-      logger.atInfo().log(
-          "Using real working directory (%s) due to its inclusion in %s", rootDirectory, options);
+      logger.info(String.format(
+          "Using real working directory (%s) due to its inclusion in %s", rootDirectory, options));
       return rootDirectory;
     }
     ImmutableSet<String> requiredRoots =
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/ProcessAnnotation.java b/kythe/java/com/google/devtools/kythe/extractors/java/ProcessAnnotation.java
index 5408b7d..9a9651b 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/java/ProcessAnnotation.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/ProcessAnnotation.java
@@ -16,24 +16,25 @@
 
 package com.google.devtools.kythe.extractors.java;
 
-import static com.google.auto.common.AnnotationMirrors.getAnnotationValue;
-import static com.google.auto.common.MoreElements.asType;
-
 import com.google.common.collect.ImmutableSet;
-import com.google.common.flogger.FluentLogger;
-import com.google.devtools.kythe.platform.shared.Metadata;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.TypeSymbol;
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Map;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import javax.annotation.processing.AbstractProcessor;
 import javax.annotation.processing.RoundEnvironment;
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.AnnotationValue;
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
 import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.Elements;
 import javax.tools.JavaFileObject;
 import javax.tools.JavaFileObject.Kind;
 import javax.tools.StandardLocation;
@@ -47,7 +48,11 @@
 @SupportedAnnotationTypes(value = {"*"})
 public class ProcessAnnotation extends AbstractProcessor {
 
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+  private static final Logger logger = Logger.getLogger(ProcessAnnotation.class.getName());
+
+  // ANDROID_BUILD: This line has been copied from ../../platform/shared/Metadata.java to avoid
+  // compiling that file and all its dependencies when building javac_extractor for Android.
+  private static final String ANNOTATION_COMMENT_PREFIX = "annotations:";
 
   private static final ImmutableSet<String> GENERATED_ANNOTATIONS =
       ImmutableSet.of("javax.annotation.Generated", "javax.annotation.processing.Generated");
@@ -85,17 +90,36 @@
       } catch (IOException ex) {
         // We only log any IO exception here and do not cancel the whole processing because of an
         // exception in this stage.
-        logger.atSevere().withCause(ex).log("Error in annotation processing");
+        logger.log(Level.SEVERE, "Error in annotation processing", ex);
       }
     }
 
+    Elements elementUtils = processingEnv.getElementUtils();
     for (String annotationName : GENERATED_ANNOTATIONS) {
-      TypeElement generatedType = processingEnv.getElementUtils().getTypeElement(annotationName);
-      if (generatedType == null) {
+      TypeElement annotationType = elementUtils.getTypeElement(annotationName);
+      if (annotationType == null) {
         // javax.annotation.processing.Generated isn't available until Java 9
         continue;
       }
-      visitGeneratedElements(roundEnv, generatedType);
+      for (Element ae : roundEnv.getElementsAnnotatedWith(annotationType)) {
+        String comments = getGeneratedComments(elementUtils, ae, annotationType);
+        if (comments == null || !comments.startsWith(ANNOTATION_COMMENT_PREFIX)) {
+          continue;
+        }
+        String annotationFile = comments.substring(ANNOTATION_COMMENT_PREFIX.length());
+        if (ae instanceof ClassSymbol) {
+          ClassSymbol cs = (ClassSymbol) ae;
+          try {
+            String annotationPath = cs.sourcefile.toUri().resolve(annotationFile).getPath();
+            for (JavaFileObject file :
+                fileManager.getJavaFileForSources(Arrays.asList(annotationPath))) {
+              ((UsageAsInputReportingJavaFileObject) file).markUsed();
+            }
+          } catch (IllegalArgumentException ex) {
+            logger.log(Level.WARNING, "Bad annotationFile: " + annotationFile, ex);
+          }
+        }
+      }
     }
 
     // We must return false so normal processors run after us.
@@ -107,46 +131,28 @@
     return SourceVersion.latest();
   }
 
-  private void visitGeneratedElements(RoundEnvironment roundEnv, TypeElement generatedElement) {
-    for (Element ae : roundEnv.getElementsAnnotatedWith(generatedElement)) {
-      String comments = getGeneratedComments(ae, generatedElement);
-      if (comments == null || !comments.startsWith(Metadata.ANNOTATION_COMMENT_PREFIX)) {
+  private static String getGeneratedComments(
+      Elements elementUtils, Element element, TypeElement annotationType) {
+    AnnotationMirror mirror;
+    for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
+      Element el = annotationMirror.getAnnotationType().asElement();
+      if (!annotationType.equals(el)) {
         continue;
       }
-      String annotationFile = comments.substring(Metadata.ANNOTATION_COMMENT_PREFIX.length());
-      if (ae instanceof ClassSymbol) {
-        ClassSymbol cs = (ClassSymbol) ae;
-        try {
-          String annotationPath = cs.sourcefile.toUri().resolve(annotationFile).getPath();
-          for (JavaFileObject file :
-              fileManager.getJavaFileForSources(Arrays.asList(annotationPath))) {
-            ((UsageAsInputReportingJavaFileObject) file).markUsed();
-          }
-        } catch (IllegalArgumentException ex) {
-          logger.atWarning().withCause(ex).log("Bad annotationFile: %s", annotationFile);
+      Object value = null;
+      for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry :
+          elementUtils.getElementValuesWithDefaults(annotationMirror).entrySet()) {
+        if (entry.getKey().getSimpleName().contentEquals("comments")) {
+          value = entry.getValue();
+          break;
         }
       }
-    }
-  }
-
-  private static String getGeneratedComments(
-      Element annotatedElement, TypeElement generatedElement) {
-    AnnotationMirror mirror = getAnnotationMirror(annotatedElement, generatedElement);
-    if (mirror == null) {
-      return null;
-    }
-    Object value = getAnnotationValue(mirror, "comments").getValue();
-    if (value instanceof String) {
-      return (String) value;
-    }
-    return null;
-  }
-
-  private static AnnotationMirror getAnnotationMirror(Element element, TypeElement annotationType) {
-    for (AnnotationMirror annotationMirror : element.getAnnotationMirrors()) {
-      TypeElement annotationTypeElement = asType(annotationMirror.getAnnotationType().asElement());
-      if (annotationTypeElement.equals(annotationType)) {
-        return annotationMirror;
+      if (value == null) {
+        throw new IllegalArgumentException(
+            String.format("@%s does not define an element comments()", element));
+      }
+      if (value instanceof String) {
+        return (String) value;
       }
     }
     return null;
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/UsageAsInputReportingFileManager.java b/kythe/java/com/google/devtools/kythe/extractors/java/UsageAsInputReportingFileManager.java
index b73f3bf..2256c5d 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/java/UsageAsInputReportingFileManager.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/UsageAsInputReportingFileManager.java
@@ -18,7 +18,6 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
-import com.google.common.flogger.FluentLogger;
 import com.google.devtools.kythe.platform.java.filemanager.ForwardingStandardJavaFileManager;
 import java.io.File;
 import java.io.IOException;
@@ -42,7 +41,6 @@
  */
 @com.sun.tools.javac.api.ClientCodeWrapper.Trusted
 class UsageAsInputReportingFileManager extends ForwardingStandardJavaFileManager {
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
 
   private final Map<URI, InputUsageRecord> inputUsageRecords = new HashMap<>();
 
@@ -176,8 +174,7 @@
     } catch (UnsupportedOperationException err) {
       try {
         return Paths.get(fo.toUri());
-      } catch (Throwable suppressed) {
-        logger.atWarning().withCause(suppressed).log("asPath unsupported due underlying error");
+      } catch (Throwable unused) {
         throw err; // Re-throw the original error.
       }
     }
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java
index 3e0323b..0c883ac 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java
@@ -22,7 +22,6 @@
 import com.google.common.base.Throwables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Ordering;
-import com.google.common.flogger.FluentLogger;
 import com.google.common.hash.Hashing;
 import com.google.devtools.kythe.extractors.java.JavaCompilationUnitExtractor;
 import com.google.devtools.kythe.extractors.shared.CompilationDescription;
@@ -35,10 +34,14 @@
 import com.sun.tools.javac.main.CommandLine;
 import java.io.File;
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.Optional;
 
 /**
@@ -62,7 +65,7 @@
  * is not set
  */
 public abstract class AbstractJavacWrapper {
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+  private static final Logger logger = Logger.getLogger(AbstractJavacWrapper.class.getName());
 
   protected abstract Collection<CompilationDescription> processCompilation(
       String[] arguments, JavaCompilationUnitExtractor javaCompilationUnitExtractor)
@@ -147,7 +150,26 @@
 
   private static String[] getCleanedUpArguments(String[] args) throws IOException {
     // Expand all @file arguments
-    List<String> expandedArgs = Lists.newArrayList(CommandLine.parse(args));
+    // JDK changed the signature of the CommandLine.parse method in JDK15,
+    // support both versions
+    List<String> expandedArgs = null;
+    try {
+      try {
+        // JDK15+: the signature is
+        //     List<String> parse(List<String> args);
+        expandedArgs = (List<String>)CommandLine.class.getMethod("parse", List.class).invoke(null, (Object)Arrays.asList(args));
+      } catch (NoSuchMethodException nsme) {
+        // pre-JDK15:
+        //     String[] parse(String[]);
+        expandedArgs = Arrays.asList((String[])CommandLine.class.getMethod("parse", String[].class).invoke(null, (Object)args));
+      }
+    } catch (NoSuchMethodException ns2) {
+      System.err.printf("Cannot locate com.sun.tools.javac.main.CommandLine.parse method, JDK version %s\n", System.getProperty("java.version"));
+      System.exit(2);
+    } catch (InvocationTargetException|IllegalAccessException ex) {
+      System.err.printf("Cannot call com.sun.tools.javac.main.CommandLine.parse (JDK version %s):\n%s\n", System.getProperty("java.version"), ex);
+      System.exit(2);
+    }
 
     // We skip some arguments that would normally be passed to javac:
     // -J, these are flags to the java environment running javac.
@@ -215,7 +237,7 @@
               try {
                 return Integer.parseInt(s);
               } catch (NumberFormatException err) {
-                logger.atWarning().withCause(err).log("Invalid KYTHE_JAVA_SOURCE_BATCH_SIZE");
+                logger.log(Level.WARNING, "Invalid KYTHE_JAVA_SOURCE_BATCH_SIZE", err);
                 return null;
               }
             });
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java
index 534bd12..31bc66a 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java
@@ -28,6 +28,8 @@
 import com.sun.tools.javac.util.Context;
 import com.sun.tools.javac.util.Options;
 import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.EnumSet;
@@ -46,7 +48,27 @@
 
     JavacFileManager fileManager = new JavacFileManager(context, true, null);
     Arguments args = Arguments.instance(context);
-    args.init("kythe_javac", arguments);
+    // JDK changed the signature of Arguments.init method, support both
+    try {
+      try {
+        // JDK15+: the signature is
+        //     init(String, Iterable<String> args);
+        Arguments.class.getMethod("init", String.class, Iterable.class)
+          .invoke(args, "kythe_javac", (Object) Arrays.asList(arguments));
+      } catch (NoSuchMethodException nsme) {
+        // pre-JDK15:
+        //     init(String, String...);
+        Arguments.class.getMethod("init", String.class,String[].class)
+          .invoke(args, "kythe_javac", (Object)arguments);
+      }
+    } catch (NoSuchMethodException ns2) {
+      System.err.printf("Cannot locate com.sun.tools.javac.main.Arguments.init method, JDK version %s\n", System.getProperty("java.version"));
+      System.exit(2);
+    } catch (InvocationTargetException|IllegalAccessException ex) {
+      System.err.printf("Cannot call com.sun.tools.javac.main.Arguments.init (JDK version %s):\n%s\n", System.getProperty("java.version"), ex);
+      System.exit(2);
+    }
+
     fileManager.handleOptions(args.getDeferredFileManagerOptions());
     Options options = Options.instance(context);
 
@@ -101,6 +123,17 @@
       }
     }
 
+    /* Special processing for -Ax=y options. Arguments.init immediately processes them
+     * into x=>y pairs that cannot be easily retrieved. This may be an indication that
+     * we are processing the command line arguments in a wrong way (that is, after parsing
+     * them we reconstruct the strings and pass them as completeOptions).
+     */
+    for (String arg : arguments) {
+      if (arg.startsWith("-A")) {
+        completeOptions.add(arg);
+      }
+    }
+
     List<String> bootclasspath = new ArrayList<>();
     for (File bcp : fileManager.getLocation(StandardLocation.PLATFORM_CLASS_PATH)) {
       bootclasspath.add(bcp.toString());
diff --git a/kythe/java/com/google/devtools/kythe/extractors/shared/EnvironmentUtils.java b/kythe/java/com/google/devtools/kythe/extractors/shared/EnvironmentUtils.java
index ca2a818..ad9c142 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/shared/EnvironmentUtils.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/shared/EnvironmentUtils.java
@@ -17,15 +17,15 @@
 package com.google.devtools.kythe.extractors.shared;
 
 import com.google.common.base.Strings;
-import com.google.common.flogger.FluentLogger;
 import java.util.Optional;
+import java.util.logging.Logger;
 
 /**
  * A class containing common utilities for uniform access to system properties and environment
  * variables.
  */
 public class EnvironmentUtils {
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+  private static final Logger logger = Logger.getLogger(EnvironmentUtils.class.getName());
 
   private EnvironmentUtils() {}
 
@@ -69,7 +69,7 @@
     return tryReadEnvironmentVariable("KYTHE_CORPUS")
         .orElseGet(
             () -> {
-              logger.atWarning().log("KYTHE_CORPUS not set, using suboptimal default of 'kythe'");
+              logger.warning("KYTHE_CORPUS not set, using suboptimal default of 'kythe'");
               return DEFAULT_CORPUS;
             });
   }
diff --git a/kythe/java/com/google/devtools/kythe/extractors/shared/FileVNames.java b/kythe/java/com/google/devtools/kythe/extractors/shared/FileVNames.java
index 9212314..d9a0591 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/shared/FileVNames.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/shared/FileVNames.java
@@ -31,8 +31,6 @@
 import com.google.gson.JsonDeserializer;
 import com.google.gson.JsonElement;
 import com.google.gson.reflect.TypeToken;
-import com.google.re2j.Matcher;
-import com.google.re2j.Pattern;
 import java.io.IOException;
 import java.lang.reflect.Type;
 import java.nio.file.Files;
@@ -43,6 +41,8 @@
 import java.util.Deque;
 import java.util.List;
 import java.util.function.Supplier;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 /**
diff --git a/kythe/java/com/google/devtools/kythe/platform/java/JavacOptionsUtils.java b/kythe/java/com/google/devtools/kythe/platform/java/JavacOptionsUtils.java
index 31a5e0b..935e6c2 100644
--- a/kythe/java/com/google/devtools/kythe/platform/java/JavacOptionsUtils.java
+++ b/kythe/java/com/google/devtools/kythe/platform/java/JavacOptionsUtils.java
@@ -49,7 +49,6 @@
 import javax.tools.OptionChecker;
 import javax.tools.StandardJavaFileManager;
 import javax.tools.StandardLocation;
-import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * A utility class for dealing with javac command-line options.
@@ -378,7 +377,6 @@
    * once, returns the last copy, which matches javac's behavior. If the flag is not specified,
    * returns null.
    */
-  @Nullable
   public static Charset getEncodingOption(List<String> options) {
     int i = options.lastIndexOf("-encoding");
     return (i >= 0) ? Charset.forName(options.get(i + 1)) : null;
diff --git a/kythe/java/com/google/devtools/kythe/platform/java/filemanager/ForwardingStandardJavaFileManager.java b/kythe/java/com/google/devtools/kythe/platform/java/filemanager/ForwardingStandardJavaFileManager.java
index 2efdec8..bdb9b0c 100644
--- a/kythe/java/com/google/devtools/kythe/platform/java/filemanager/ForwardingStandardJavaFileManager.java
+++ b/kythe/java/com/google/devtools/kythe/platform/java/filemanager/ForwardingStandardJavaFileManager.java
@@ -21,6 +21,8 @@
 import java.util.Collection;
 import java.util.ServiceLoader;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import javax.tools.FileObject;
 import javax.tools.ForwardingJavaFileManager;
 import javax.tools.JavaFileObject;
diff --git a/kythe/java/com/google/devtools/kythe/platform/kzip/KZip.java b/kythe/java/com/google/devtools/kythe/platform/kzip/KZip.java
index 5fa7686..cf8c9cd 100644
--- a/kythe/java/com/google/devtools/kythe/platform/kzip/KZip.java
+++ b/kythe/java/com/google/devtools/kythe/platform/kzip/KZip.java
@@ -15,7 +15,6 @@
  */
 package com.google.devtools.kythe.platform.kzip;
 
-import com.google.auto.value.AutoValue;
 import com.google.common.hash.HashFunction;
 import com.google.common.hash.Hashing;
 import com.google.devtools.kythe.proto.Analysis;
@@ -133,26 +132,36 @@
     private final String subdirectory;
   }
 
-  @AutoValue
-  abstract static class Descriptor {
-    abstract String root();
-
-    abstract Encoding encoding();
+  static class Descriptor {
+    private String root;
+    private Encoding encoding;
+    private Descriptor(String root, Encoding encoding) {
+        this.root = root;
+        this.encoding = encoding;
+    }
 
     static Descriptor create(String root, Encoding encoding) {
-      return new AutoValue_KZip_Descriptor(root, encoding);
+      return new Descriptor(root, encoding);
     }
 
     String getUnitsPath(String digest) {
-      return getUnitsPath(digest, encoding());
+      return getUnitsPath(digest, encoding);
     }
 
     String getUnitsPath(String digest, Encoding encoding) {
-      return Paths.get(root(), encoding.getSubdirectory(), digest).toString();
+      return Paths.get(root, encoding.getSubdirectory(), digest).toString();
     }
 
     String getFilesPath(String digest) {
-      return Paths.get(root(), FILES_SUBDIRECTORY, digest).toString();
+      return Paths.get(root, FILES_SUBDIRECTORY, digest).toString();
+    }
+
+    Encoding encoding() {
+      return this.encoding;
+    }
+
+    String root() {
+      return this.root;
     }
   }
 }
diff --git a/kythe/java/com/google/devtools/kythe/platform/kzip/KZipWriter.java b/kythe/java/com/google/devtools/kythe/platform/kzip/KZipWriter.java
index 01fe8bb..b495a21 100644
--- a/kythe/java/com/google/devtools/kythe/platform/kzip/KZipWriter.java
+++ b/kythe/java/com/google/devtools/kythe/platform/kzip/KZipWriter.java
@@ -15,7 +15,6 @@
  */
 package com.google.devtools.kythe.platform.kzip;
 
-import com.google.common.flogger.FluentLogger;
 import com.google.devtools.kythe.platform.shared.CompilationUnits;
 import com.google.devtools.kythe.proto.Analysis;
 import com.google.gson.Gson;
@@ -25,12 +24,14 @@
 import java.io.IOException;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
 /** Write a kzip file. */
 public final class KZipWriter implements KZip.Writer {
-  private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+  private static final Logger logger = Logger.getLogger(KZipWriter.class.getName());
 
   // Constant time used so time information is not stored in the kzip. This way files can be diff'd
   // and they will only be different if the contents are different.
@@ -44,7 +45,7 @@
       try {
         encoding = KZip.Encoding.valueOf(encodingStr.toUpperCase());
       } catch (IllegalArgumentException e) {
-        logger.atWarning().log("Unknown kzip encoding '%s', using %s", encodingStr, encoding);
+        logger.log(Level.WARNING, String.format("Unknown kzip encoding '%s', using %s", encodingStr, encoding));
       }
     }
     DEFAULT_ENCODING = encoding;
@@ -128,8 +129,6 @@
       output.putNextEntry(entry);
       output.write(data);
       output.closeEntry();
-    } else {
-      logger.atInfo().log("Already wrote %s to kzip.", path);
     }
   }
 
diff --git a/kythe/java/com/google/devtools/kythe/util/JsonUtil.java b/kythe/java/com/google/devtools/kythe/util/JsonUtil.java
index bd75fb2..142a88a 100644
--- a/kythe/java/com/google/devtools/kythe/util/JsonUtil.java
+++ b/kythe/java/com/google/devtools/kythe/util/JsonUtil.java
@@ -96,7 +96,7 @@
     @Override
     public JsonElement serialize(GeneratedMessageV3 msg, Type t, JsonSerializationContext ctx) {
       try {
-        return JsonParser.parseString(printer.print(msg));
+        return new JsonParser().parse(printer.print(msg));
       } catch (InvalidProtocolBufferException e) {
         throw new RuntimeException(e);
       }
diff --git a/third_party/llvm/src/clang_builtin_headers.cc b/third_party/llvm/src/clang_builtin_headers.cc
index eb5c564..cd26e8c 100644
--- a/third_party/llvm/src/clang_builtin_headers.cc
+++ b/third_party/llvm/src/clang_builtin_headers.cc
@@ -1,4 +1,6 @@
 #include "third_party/llvm/src/clang_builtin_headers.h"
-#include "third_party/llvm/src/clang_builtin_headers_resources.inc"
+// ANDROID_BUILD {
+#include "clang_builtin_headers_resources.inc"
+// }
 
 const struct FileToc *builtin_headers_create() { return kPackedFiles; }