Merge "AStatsEvent_overwriteTimestamp"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d6945e3..0ec505d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -4,6 +4,12 @@
       "name": "adbd_test"
     },
     {
+      "name": "adb_crypto_test"
+    },
+    {
+      "name": "adb_tls_connection_test"
+    },
+    {
       "name": "CtsInitTestCases"
     },
     {
diff --git a/adb/Android.bp b/adb/Android.bp
index 675525c..c71138a 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -255,6 +255,8 @@
     },
 
     static_libs: [
+        "libadb_crypto",
+        "libadb_protos",
         "libbase",
         "libcrypto_utils",
         "libcrypto",
@@ -272,6 +274,7 @@
     defaults: ["adb_defaults"],
     srcs: libadb_test_srcs,
     static_libs: [
+        "libadb_crypto",
         "libadb_host",
         "libbase",
         "libcutils",
@@ -347,6 +350,7 @@
     ],
 
     static_libs: [
+        "libadb_crypto",
         "libadb_host",
         "libandroidfw",
         "libbase",
@@ -422,6 +426,7 @@
     ],
 
     shared_libs: [
+        "libadb_crypto",
         "libadbd_auth",
         "libasyncio",
         "libbase",
@@ -765,6 +770,7 @@
         "fastdeploy/deploypatchgenerator/patch_utils_test.cpp",
     ],
     static_libs: [
+        "libadb_crypto",
         "libadb_host",
         "libandroidfw",
         "libbase",
diff --git a/adb/client/auth.cpp b/adb/client/auth.cpp
index e8be784..dcf4bc0 100644
--- a/adb/client/auth.cpp
+++ b/adb/client/auth.cpp
@@ -29,6 +29,7 @@
 #include <set>
 #include <string>
 
+#include <adb/crypto/rsa_2048_key.h>
 #include <android-base/errors.h>
 #include <android-base/file.h>
 #include <android-base/stringprintf.h>
@@ -53,100 +54,50 @@
     *new std::map<std::string, std::shared_ptr<RSA>>;
 static std::map<int, std::string>& g_monitored_paths = *new std::map<int, std::string>;
 
-static std::string get_user_info() {
-    std::string hostname;
-    if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
-#if !defined(_WIN32)
-    char buf[64];
-    if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
-#endif
-    if (hostname.empty()) hostname = "unknown";
+using namespace adb::crypto;
 
-    std::string username;
-    if (getenv("LOGNAME")) username = getenv("LOGNAME");
-#if !defined(_WIN32)
-    if (username.empty() && getlogin()) username = getlogin();
-#endif
-    if (username.empty()) hostname = "unknown";
-
-    return " " + username + "@" + hostname;
-}
-
-static bool calculate_public_key(std::string* out, RSA* private_key) {
-    uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
-    if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
-        LOG(ERROR) << "Failed to convert to public key";
-        return false;
-    }
-
-    size_t expected_length;
-    if (!EVP_EncodedLength(&expected_length, sizeof(binary_key_data))) {
-        LOG(ERROR) << "Public key too large to base64 encode";
-        return false;
-    }
-
-    out->resize(expected_length);
-    size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
-                                           sizeof(binary_key_data));
-    out->resize(actual_length);
-    out->append(get_user_info());
-    return true;
-}
-
-static int generate_key(const std::string& file) {
+static bool generate_key(const std::string& file) {
     LOG(INFO) << "generate_key(" << file << ")...";
 
-    mode_t old_mask;
-    FILE *f = nullptr;
-    int ret = 0;
+    auto rsa_2048 = CreateRSA2048Key();
+    if (!rsa_2048) {
+        LOG(ERROR) << "Unable to create key";
+        return false;
+    }
     std::string pubkey;
 
-    EVP_PKEY* pkey = EVP_PKEY_new();
-    BIGNUM* exponent = BN_new();
-    RSA* rsa = RSA_new();
-    if (!pkey || !exponent || !rsa) {
-        LOG(ERROR) << "Failed to allocate key";
-        goto out;
-    }
+    RSA* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey());
+    CHECK(rsa);
 
-    BN_set_word(exponent, RSA_F4);
-    RSA_generate_key_ex(rsa, 2048, exponent, nullptr);
-    EVP_PKEY_set1_RSA(pkey, rsa);
-
-    if (!calculate_public_key(&pubkey, rsa)) {
+    if (!CalculatePublicKey(&pubkey, rsa)) {
         LOG(ERROR) << "failed to calculate public key";
-        goto out;
+        return false;
     }
 
-    old_mask = umask(077);
+    mode_t old_mask = umask(077);
 
-    f = fopen(file.c_str(), "w");
+    std::unique_ptr<FILE, decltype(&fclose)> f(nullptr, &fclose);
+    f.reset(fopen(file.c_str(), "w"));
     if (!f) {
         PLOG(ERROR) << "Failed to open " << file;
         umask(old_mask);
-        goto out;
+        return false;
     }
 
     umask(old_mask);
 
-    if (!PEM_write_PrivateKey(f, pkey, nullptr, nullptr, 0, nullptr, nullptr)) {
+    if (!PEM_write_PrivateKey(f.get(), rsa_2048->GetEvpPkey(), nullptr, nullptr, 0, nullptr,
+                              nullptr)) {
         LOG(ERROR) << "Failed to write key";
-        goto out;
+        return false;
     }
 
     if (!android::base::WriteStringToFile(pubkey, file + ".pub")) {
         PLOG(ERROR) << "failed to write public key";
-        goto out;
+        return false;
     }
 
-    ret = 1;
-
-out:
-    if (f) fclose(f);
-    EVP_PKEY_free(pkey);
-    RSA_free(rsa);
-    BN_free(exponent);
-    return ret;
+    return true;
 }
 
 static std::string hash_key(RSA* key) {
@@ -325,7 +276,7 @@
     if (!privkey) {
         return false;
     }
-    return calculate_public_key(out, privkey.get());
+    return CalculatePublicKey(out, privkey.get());
 }
 
 std::string adb_auth_get_userkey() {
@@ -343,7 +294,7 @@
 }
 
 int adb_auth_keygen(const char* filename) {
-    return (generate_key(filename) == 0);
+    return !generate_key(filename);
 }
 
 int adb_auth_pubkey(const char* filename) {
diff --git a/adb/crypto/Android.bp b/adb/crypto/Android.bp
new file mode 100644
index 0000000..da4869a
--- /dev/null
+++ b/adb/crypto/Android.bp
@@ -0,0 +1,85 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "libadb_crypto_defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wthread-safety",
+        "-Werror",
+    ],
+
+    compile_multilib: "both",
+
+    srcs: [
+        "key.cpp",
+        "rsa_2048_key.cpp",
+        "x509_generator.cpp",
+    ],
+
+    target: {
+        windows: {
+            compile_multilib: "first",
+            enabled: true,
+        },
+    },
+
+    export_include_dirs: ["include"],
+
+    visibility: [
+        "//system/core/adb:__subpackages__",
+    ],
+
+    host_supported: true,
+    recovery_available: true,
+
+    stl: "libc++_static",
+
+    shared_libs: [
+        "libadb_protos",
+        "libbase",
+        "liblog",
+        "libcrypto",
+        "libcrypto_utils",
+    ],
+}
+
+cc_library {
+    name: "libadb_crypto",
+    defaults: ["libadb_crypto_defaults"],
+
+    apex_available: [
+        "com.android.adbd",
+        "test_com.android.adbd",
+    ],
+
+    static_libs: [
+        "libadb_protos",
+    ],
+}
+
+// For running atest (b/147158681)
+cc_library_static {
+    name: "libadb_crypto_static",
+    defaults: ["libadb_crypto_defaults"],
+
+    apex_available: [
+        "//apex_available:platform",
+    ],
+
+    static_libs: [
+        "libadb_protos_static",
+    ],
+}
diff --git a/adb/crypto/include/adb/crypto/key.h b/adb/crypto/include/adb/crypto/key.h
new file mode 100644
index 0000000..d9ce69e
--- /dev/null
+++ b/adb/crypto/include/adb/crypto/key.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <openssl/evp.h>
+
+#include "key_type.pb.h"
+
+namespace adb {
+namespace crypto {
+
+// Class that represents a public/private key pair.
+class Key {
+  public:
+    explicit Key(bssl::UniquePtr<EVP_PKEY>&& pkey, adb::proto::KeyType type)
+        : pkey_(std::move(pkey)), key_type_(type) {}
+    Key(Key&&) = default;
+    Key& operator=(Key&&) = default;
+
+    EVP_PKEY* GetEvpPkey() const { return pkey_.get(); }
+    adb::proto::KeyType GetKeyType() const { return key_type_; }
+    static std::string ToPEMString(EVP_PKEY* pkey);
+
+  private:
+    bssl::UniquePtr<EVP_PKEY> pkey_;
+    adb::proto::KeyType key_type_;
+};  // Key
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/crypto/include/adb/crypto/rsa_2048_key.h b/adb/crypto/include/adb/crypto/rsa_2048_key.h
new file mode 100644
index 0000000..2983a84
--- /dev/null
+++ b/adb/crypto/include/adb/crypto/rsa_2048_key.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <optional>
+
+#include "adb/crypto/key.h"
+
+namespace adb {
+namespace crypto {
+
+// Create a new RSA2048 key pair.
+std::optional<Key> CreateRSA2048Key();
+
+// Generates the public key from the RSA private key.
+bool CalculatePublicKey(std::string* out, RSA* private_key);
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/crypto/include/adb/crypto/x509_generator.h b/adb/crypto/include/adb/crypto/x509_generator.h
new file mode 100644
index 0000000..a269243
--- /dev/null
+++ b/adb/crypto/include/adb/crypto/x509_generator.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <openssl/x509v3.h>
+
+namespace adb {
+namespace crypto {
+
+// Generate a X.509 certificate based on the key |pkey|.
+bssl::UniquePtr<X509> GenerateX509Certificate(EVP_PKEY* pkey);
+
+// Convert X509* to PEM string format
+std::string X509ToPEMString(X509* x509);
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/crypto/key.cpp b/adb/crypto/key.cpp
new file mode 100644
index 0000000..4d87006
--- /dev/null
+++ b/adb/crypto/key.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb/crypto/key.h"
+
+#include <android-base/logging.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+namespace adb {
+namespace crypto {
+
+// static
+std::string Key::ToPEMString(EVP_PKEY* pkey) {
+    bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+    int rc = PEM_write_bio_PKCS8PrivateKey(bio.get(), pkey, nullptr, nullptr, 0, nullptr, nullptr);
+    if (rc != 1) {
+        LOG(ERROR) << "PEM_write_bio_PKCS8PrivateKey failed";
+        return "";
+    }
+
+    BUF_MEM* mem = nullptr;
+    BIO_get_mem_ptr(bio.get(), &mem);
+    if (!mem || !mem->data || !mem->length) {
+        LOG(ERROR) << "BIO_get_mem_ptr failed";
+        return "";
+    }
+
+    return std::string(mem->data, mem->length);
+}
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/crypto/rsa_2048_key.cpp b/adb/crypto/rsa_2048_key.cpp
new file mode 100644
index 0000000..7911af9
--- /dev/null
+++ b/adb/crypto/rsa_2048_key.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb/crypto/rsa_2048_key.h"
+
+#include <android-base/logging.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+namespace adb {
+namespace crypto {
+
+namespace {
+std::string get_user_info() {
+    std::string hostname;
+    if (getenv("HOSTNAME")) hostname = getenv("HOSTNAME");
+#if !defined(_WIN32)
+    char buf[64];
+    if (hostname.empty() && gethostname(buf, sizeof(buf)) != -1) hostname = buf;
+#endif
+    if (hostname.empty()) hostname = "unknown";
+
+    std::string username;
+    if (getenv("LOGNAME")) username = getenv("LOGNAME");
+#if !defined(_WIN32)
+    if (username.empty() && getlogin()) username = getlogin();
+#endif
+    if (username.empty()) hostname = "unknown";
+
+    return " " + username + "@" + hostname;
+}
+
+}  // namespace
+
+bool CalculatePublicKey(std::string* out, RSA* private_key) {
+    uint8_t binary_key_data[ANDROID_PUBKEY_ENCODED_SIZE];
+    if (!android_pubkey_encode(private_key, binary_key_data, sizeof(binary_key_data))) {
+        LOG(ERROR) << "Failed to convert to public key";
+        return false;
+    }
+
+    size_t expected_length;
+    if (!EVP_EncodedLength(&expected_length, sizeof(binary_key_data))) {
+        LOG(ERROR) << "Public key too large to base64 encode";
+        return false;
+    }
+
+    out->resize(expected_length);
+    size_t actual_length = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(out->data()), binary_key_data,
+                                           sizeof(binary_key_data));
+    out->resize(actual_length);
+    out->append(get_user_info());
+    return true;
+}
+
+std::optional<Key> CreateRSA2048Key() {
+    bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+    bssl::UniquePtr<BIGNUM> exponent(BN_new());
+    bssl::UniquePtr<RSA> rsa(RSA_new());
+    if (!pkey || !exponent || !rsa) {
+        LOG(ERROR) << "Failed to allocate key";
+        return std::nullopt;
+    }
+
+    BN_set_word(exponent.get(), RSA_F4);
+    RSA_generate_key_ex(rsa.get(), 2048, exponent.get(), nullptr);
+    EVP_PKEY_set1_RSA(pkey.get(), rsa.get());
+
+    return std::optional<Key>{Key(std::move(pkey), adb::proto::KeyType::RSA_2048)};
+}
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/crypto/tests/Android.bp b/adb/crypto/tests/Android.bp
new file mode 100644
index 0000000..b32dcf7
--- /dev/null
+++ b/adb/crypto/tests/Android.bp
@@ -0,0 +1,41 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "adb_crypto_test",
+    srcs: [
+        "rsa_2048_key_test.cpp",
+        "x509_generator_test.cpp",
+    ],
+
+    compile_multilib: "first",
+
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libcrypto_utils",
+        "libprotobuf-cpp-lite",
+    ],
+
+    // Let's statically link them so we don't have to install it onto the
+    // system image for testing.
+    static_libs: [
+        "libadb_crypto_static",
+        "libadb_protos_static",
+    ],
+
+    test_suites: ["device-tests"],
+}
diff --git a/adb/crypto/tests/key_test.cpp b/adb/crypto/tests/key_test.cpp
new file mode 100644
index 0000000..1feb6e8
--- /dev/null
+++ b/adb/crypto/tests/key_test.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <resolv.h>
+
+#include <adb/crypto/rsa_2048_key.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+namespace adb {
+namespace crypto {
+
+TEST(RSA2048Key, Smoke) {
+    auto rsa_2048 = CreateRSA2048Key();
+    EXPECT_NE(rsa_2048, std::nullopt);
+    EXPECT_EQ(rsa_2048->GetKeyType(), adb::proto::KeyType::RSA_2048);
+    ASSERT_NE(rsa_2048->GetEvpPkey(), nullptr);
+
+    // The public key string format is expected to be: "<pub_key> <host_name>"
+    std::string pub_key_plus_name;
+    auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey());
+    ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa));
+    std::vector<std::string> split = android::base::Split(std::string(pub_key_plus_name), " \t");
+    EXPECT_EQ(split.size(), 2);
+
+    LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]";
+
+    // Try to sign something and decode it.
+    const char token[SHA_DIGEST_LENGTH] = "abcdefghij123456789";
+    std::vector<uint8_t> sig(RSA_size(rsa));
+    unsigned sig_len;
+    EXPECT_EQ(RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(token), sizeof(token), sig.data(),
+                       &sig_len, rsa),
+              1);
+    sig.resize(sig_len);
+
+    {
+        uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+        const std::string& pubkey = split[0];
+        ASSERT_EQ(b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)), ANDROID_PUBKEY_ENCODED_SIZE);
+        RSA* key = nullptr;
+        ASSERT_TRUE(android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key));
+        EXPECT_EQ(RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), sizeof(token),
+                             sig.data(), sig.size(), key),
+                  1);
+        RSA_free(key);
+    }
+}
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/crypto/tests/rsa_2048_key_test.cpp b/adb/crypto/tests/rsa_2048_key_test.cpp
new file mode 100644
index 0000000..1d8880e
--- /dev/null
+++ b/adb/crypto/tests/rsa_2048_key_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <resolv.h>
+
+#include <adb/crypto/rsa_2048_key.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/err.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+
+namespace adb {
+namespace crypto {
+
+TEST(RSA2048Key, Smoke) {
+    auto rsa_2048 = CreateRSA2048Key();
+    EXPECT_NE(rsa_2048, std::nullopt);
+    EXPECT_EQ(rsa_2048->GetKeyType(), adb::proto::KeyType::RSA_2048);
+    ASSERT_NE(rsa_2048->GetEvpPkey(), nullptr);
+
+    // The public key string format is expected to be: "<pub_key> <host_name>"
+    std::string pub_key_plus_name;
+    auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey());
+    ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa));
+    std::vector<std::string> split = android::base::Split(std::string(pub_key_plus_name), " \t");
+    EXPECT_EQ(split.size(), 2);
+
+    LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]";
+
+    std::string pemString = Key::ToPEMString(rsa_2048->GetEvpPkey());
+    ASSERT_FALSE(pemString.empty());
+
+    // Try to sign something and decode it.
+    const char token[SHA_DIGEST_LENGTH] = "abcdefghij123456789";
+    std::vector<uint8_t> sig(RSA_size(rsa));
+    unsigned sig_len;
+    EXPECT_EQ(RSA_sign(NID_sha1, reinterpret_cast<const uint8_t*>(token), sizeof(token), sig.data(),
+                       &sig_len, rsa),
+              1);
+    sig.resize(sig_len);
+
+    {
+        uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+        const std::string& pubkey = split[0];
+        ASSERT_EQ(b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)), ANDROID_PUBKEY_ENCODED_SIZE);
+        RSA* key = nullptr;
+        ASSERT_TRUE(android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key));
+        EXPECT_EQ(RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), sizeof(token),
+                             sig.data(), sig.size(), key),
+                  1);
+        RSA_free(key);
+    }
+}
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/crypto/tests/x509_generator_test.cpp b/adb/crypto/tests/x509_generator_test.cpp
new file mode 100644
index 0000000..281776b
--- /dev/null
+++ b/adb/crypto/tests/x509_generator_test.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <adb/crypto/rsa_2048_key.h>
+#include <adb/crypto/x509_generator.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+
+namespace adb {
+namespace crypto {
+
+TEST(X509Generator, Smoke) {
+    auto rsa_2048 = CreateRSA2048Key();
+
+    std::string pub_key_plus_name;
+    auto* rsa = EVP_PKEY_get0_RSA(rsa_2048->GetEvpPkey());
+    ASSERT_TRUE(CalculatePublicKey(&pub_key_plus_name, rsa));
+    std::vector<std::string> split = android::base::Split(std::string(pub_key_plus_name), " \t");
+    EXPECT_EQ(split.size(), 2);
+
+    LOG(INFO) << "pub_key=[" << pub_key_plus_name << "]";
+    auto x509_cert = GenerateX509Certificate(rsa_2048->GetEvpPkey());
+    ASSERT_NE(x509_cert.get(), nullptr);
+
+    std::string x509_str = X509ToPEMString(x509_cert.get());
+    ASSERT_FALSE(x509_str.empty());
+}
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/crypto/x509_generator.cpp b/adb/crypto/x509_generator.cpp
new file mode 100644
index 0000000..43b8153
--- /dev/null
+++ b/adb/crypto/x509_generator.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb/crypto/x509_generator.h"
+
+#include <vector>
+
+#include <android-base/logging.h>
+#include <crypto_utils/android_pubkey.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+namespace adb {
+namespace crypto {
+
+namespace {
+
+const char kBasicConstraints[] = "critical,CA:TRUE";
+const char kKeyUsage[] = "critical,keyCertSign,cRLSign,digitalSignature";
+const char kSubjectKeyIdentifier[] = "hash";
+constexpr int kCertLifetimeSeconds = 10 * 365 * 24 * 60 * 60;
+
+bool add_ext(X509* cert, int nid, const char* value) {
+    size_t len = strlen(value) + 1;
+    std::vector<char> mutableValue(value, value + len);
+    X509V3_CTX context;
+
+    X509V3_set_ctx_nodb(&context);
+
+    X509V3_set_ctx(&context, cert, cert, nullptr, nullptr, 0);
+    X509_EXTENSION* ex = X509V3_EXT_nconf_nid(nullptr, &context, nid, mutableValue.data());
+    if (!ex) {
+        return false;
+    }
+
+    X509_add_ext(cert, ex, -1);
+    X509_EXTENSION_free(ex);
+    return true;
+}
+
+}  // namespace
+
+bssl::UniquePtr<X509> GenerateX509Certificate(EVP_PKEY* pkey) {
+    CHECK(pkey);
+    bssl::UniquePtr<X509> x509(X509_new());
+    if (!x509) {
+        LOG(ERROR) << "Unable to allocate x509 container";
+        return nullptr;
+    }
+    X509_set_version(x509.get(), 2);
+
+    ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), 1);
+    X509_gmtime_adj(X509_get_notBefore(x509.get()), 0);
+    X509_gmtime_adj(X509_get_notAfter(x509.get()), kCertLifetimeSeconds);
+
+    if (!X509_set_pubkey(x509.get(), pkey)) {
+        LOG(ERROR) << "Unable to set x509 public key";
+        return nullptr;
+    }
+
+    X509_NAME* name = X509_get_subject_name(x509.get());
+    if (!name) {
+        LOG(ERROR) << "Unable to get x509 subject name";
+        return nullptr;
+    }
+    X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
+                               reinterpret_cast<const unsigned char*>("US"), -1, -1, 0);
+    X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC,
+                               reinterpret_cast<const unsigned char*>("Android"), -1, -1, 0);
+    X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
+                               reinterpret_cast<const unsigned char*>("Adb"), -1, -1, 0);
+    if (!X509_set_issuer_name(x509.get(), name)) {
+        LOG(ERROR) << "Unable to set x509 issuer name";
+        return nullptr;
+    }
+
+    add_ext(x509.get(), NID_basic_constraints, kBasicConstraints);
+    add_ext(x509.get(), NID_key_usage, kKeyUsage);
+    add_ext(x509.get(), NID_subject_key_identifier, kSubjectKeyIdentifier);
+
+    int bytes = X509_sign(x509.get(), pkey, EVP_sha256());
+    if (bytes <= 0) {
+        LOG(ERROR) << "Unable to sign x509 certificate";
+        return nullptr;
+    }
+
+    return x509;
+}
+
+std::string X509ToPEMString(X509* x509) {
+    bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+    int rc = PEM_write_bio_X509(bio.get(), x509);
+    if (rc != 1) {
+        LOG(ERROR) << "PEM_write_bio_X509 failed";
+        return "";
+    }
+
+    BUF_MEM* mem = nullptr;
+    BIO_get_mem_ptr(bio.get(), &mem);
+    if (!mem || !mem->data || !mem->length) {
+        LOG(ERROR) << "BIO_get_mem_ptr failed";
+        return "";
+    }
+
+    return std::string(mem->data, mem->length);
+}
+
+}  // namespace crypto
+}  // namespace adb
diff --git a/adb/proto/Android.bp b/adb/proto/Android.bp
new file mode 100644
index 0000000..a7e5d9c
--- /dev/null
+++ b/adb/proto/Android.bp
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "libadb_protos_defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wthread-safety",
+        "-Werror",
+    ],
+
+    compile_multilib: "both",
+
+    proto: {
+        export_proto_headers: true,
+        type: "lite",
+    },
+    srcs: [
+        "adb_known_hosts.proto",
+        "key_type.proto",
+        "pairing.proto",
+    ],
+    target: {
+        windows: {
+            compile_multilib: "first",
+            enabled: true,
+        },
+    },
+
+    visibility: [
+        "//system/core/adb:__subpackages__",
+    ],
+
+    stl: "libc++_static",
+
+    host_supported: true,
+    recovery_available: true,
+}
+
+cc_library {
+    name: "libadb_protos",
+    defaults: ["libadb_protos_defaults"],
+
+    apex_available: [
+        "com.android.adbd",
+        "test_com.android.adbd",
+    ],
+}
+
+// For running atest (b/147158681)
+cc_library_static {
+    name: "libadb_protos_static",
+    defaults: ["libadb_protos_defaults"],
+
+    apex_available: [
+        "//apex_available:platform",
+    ],
+}
diff --git a/adb/proto/adb_known_hosts.proto b/adb/proto/adb_known_hosts.proto
new file mode 100644
index 0000000..85d1489
--- /dev/null
+++ b/adb/proto/adb_known_hosts.proto
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "AdbKnownHostsProto";
+
+package adb.proto;
+
+// Each known host
+message HostInfo {
+    string guid = 1;
+}
+
+// Protobuf definition for the adb_known_hosts.
+message AdbKnownHosts {
+    repeated HostInfo host_infos = 1;
+}
diff --git a/adb/proto/jarjar-rules.txt b/adb/proto/jarjar-rules.txt
new file mode 100644
index 0000000..4e40637
--- /dev/null
+++ b/adb/proto/jarjar-rules.txt
@@ -0,0 +1 @@
+rule com.google.protobuf.** com.android.framework.protobuf.@1
diff --git a/adb/proto/key_type.proto b/adb/proto/key_type.proto
new file mode 100644
index 0000000..ed451c5
--- /dev/null
+++ b/adb/proto/key_type.proto
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "KeyTypeProto";
+
+package adb.proto;
+
+enum KeyType {
+    RSA_2048 = 0;
+}
diff --git a/adb/proto/pairing.proto b/adb/proto/pairing.proto
new file mode 100644
index 0000000..b0be20e
--- /dev/null
+++ b/adb/proto/pairing.proto
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+syntax = "proto3";
+
+option java_package = "com.android.server.adb.protos";
+option java_outer_classname = "PairingProto";
+
+package adb.proto;
+
+// The type of packets used in the pairing protocol
+message PairingPacket {
+    enum Type {
+        SPAKE2_MSG = 0;
+        PEER_INFO = 1;
+    }
+}
diff --git a/adb/tls/Android.bp b/adb/tls/Android.bp
new file mode 100644
index 0000000..49833ff
--- /dev/null
+++ b/adb/tls/Android.bp
@@ -0,0 +1,75 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "libadb_tls_connection_defaults",
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Wthread-safety",
+        "-Werror",
+    ],
+
+    compile_multilib: "both",
+
+    srcs: [
+        "adb_ca_list.cpp",
+        "tls_connection.cpp",
+    ],
+    target: {
+        windows: {
+            compile_multilib: "first",
+            enabled: true,
+        },
+    },
+    export_include_dirs: ["include"],
+
+    host_supported: true,
+    recovery_available: true,
+
+    visibility: [
+        "//system/core/adb:__subpackages__",
+    ],
+
+    stl: "libc++_static",
+
+    static_libs: [
+        "libbase",
+    ],
+    shared_libs: [
+        "libcrypto",
+        "liblog",
+        "libssl",
+    ],
+}
+
+cc_library {
+    name: "libadb_tls_connection",
+    defaults: ["libadb_tls_connection_defaults"],
+
+    apex_available: [
+        "com.android.adbd",
+        "test_com.android.adbd",
+    ],
+}
+
+// For running atest (b/147158681)
+cc_library_static {
+    name: "libadb_tls_connection_static",
+    defaults: ["libadb_tls_connection_defaults"],
+
+    apex_available: [
+        "//apex_available:platform",
+    ],
+}
diff --git a/adb/tls/adb_ca_list.cpp b/adb/tls/adb_ca_list.cpp
new file mode 100644
index 0000000..8d37bbe
--- /dev/null
+++ b/adb/tls/adb_ca_list.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb/tls/adb_ca_list.h"
+
+#include <iomanip>
+#include <sstream>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <openssl/ssl.h>
+
+namespace adb {
+namespace tls {
+
+namespace {
+
+// CA issuer identifier to distinguished embedded keys. Also has version
+// information appended to the end of the string (e.g. "AdbKey-0").
+static constexpr int kAdbKeyIdentifierNid = NID_organizationName;
+static constexpr char kAdbKeyIdentifierPrefix[] = "AdbKey-";
+static constexpr int kAdbKeyVersion = 0;
+
+// Where we store the actual data
+static constexpr int kAdbKeyValueNid = NID_commonName;
+
+// TODO: Remove this once X509_NAME_add_entry_by_NID is fixed to use const unsigned char*
+int X509_NAME_add_entry_by_NID_const(X509_NAME* name, int nid, int type, const unsigned char* bytes,
+                                     int len, int loc, int set) {
+    return X509_NAME_add_entry_by_NID(name, nid, type, const_cast<unsigned char*>(bytes), len, loc,
+                                      set);
+}
+
+bool IsHexDigit(char c) {
+    return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
+}
+
+// Wrapper around X509_NAME_get_text_by_NID that first calculates the size
+// of the string. Returns empty string on failure.
+std::optional<std::string> GetX509NameTextByNid(X509_NAME* name, int nid) {
+    // |len| is the len of the text excluding the final null
+    int len = X509_NAME_get_text_by_NID(name, nid, nullptr, -1);
+    if (len <= 0) {
+        return {};
+    }
+
+    // Include the space for the final null byte
+    std::vector<char> buf(len + 1, '\0');
+    CHECK(X509_NAME_get_text_by_NID(name, nid, buf.data(), buf.size()));
+    return buf.data();
+}
+
+}  // namespace
+
+// Takes an encoded public key and generates a X509_NAME that can be used in
+// TlsConnection::SetClientCAList(), to allow the client to figure out which of
+// its keys it should try to use in the TLS handshake.
+bssl::UniquePtr<X509_NAME> CreateCAIssuerFromEncodedKey(std::string_view key) {
+    // "O=AdbKey-0;CN=<key>;"
+    CHECK(!key.empty());
+
+    std::string identifier = kAdbKeyIdentifierPrefix;
+    identifier += std::to_string(kAdbKeyVersion);
+    bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
+    CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyIdentifierNid, MBSTRING_ASC,
+                                           reinterpret_cast<const uint8_t*>(identifier.data()),
+                                           identifier.size(), -1, 0));
+
+    CHECK(X509_NAME_add_entry_by_NID_const(name.get(), kAdbKeyValueNid, MBSTRING_ASC,
+                                           reinterpret_cast<const uint8_t*>(key.data()), key.size(),
+                                           -1, 0));
+    return name;
+}
+
+// Parses a CA issuer and returns the encoded key, if any.
+std::optional<std::string> ParseEncodedKeyFromCAIssuer(X509_NAME* issuer) {
+    CHECK(issuer);
+
+    auto buf = GetX509NameTextByNid(issuer, kAdbKeyIdentifierNid);
+    if (!buf || !android::base::StartsWith(*buf, kAdbKeyIdentifierPrefix)) {
+        return {};
+    }
+
+    return GetX509NameTextByNid(issuer, kAdbKeyValueNid);
+}
+
+std::string SHA256BitsToHexString(std::string_view sha256) {
+    CHECK_EQ(sha256.size(), static_cast<size_t>(SHA256_DIGEST_LENGTH));
+    std::stringstream ss;
+    ss << std::uppercase << std::setfill('0') << std::hex;
+    // Convert to hex-string representation
+    for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+        ss << std::setw(2) << (0x00FF & sha256[i]);
+    }
+    return ss.str();
+}
+
+std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str) {
+    if (sha256_str.size() != SHA256_DIGEST_LENGTH * 2) {
+        return {};
+    }
+
+    std::string result;
+    for (size_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+        auto bytestr = std::string(sha256_str.substr(i * 2, 2));
+        if (!IsHexDigit(bytestr[0]) || !IsHexDigit(bytestr[1])) {
+            LOG(ERROR) << "SHA256 string has invalid non-hex chars";
+            return {};
+        }
+        result += static_cast<char>(std::stol(bytestr, nullptr, 16));
+    }
+    return result;
+}
+
+}  // namespace tls
+}  // namespace adb
diff --git a/adb/tls/include/adb/tls/adb_ca_list.h b/adb/tls/include/adb/tls/adb_ca_list.h
new file mode 100644
index 0000000..a1ab9a7
--- /dev/null
+++ b/adb/tls/include/adb/tls/adb_ca_list.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <openssl/base.h>
+#include <optional>
+#include <string>
+
+// These APIs is used to embed adbd's known public keys into client-allowed CA
+// issuer list that can indicate to the client which key to use.
+namespace adb {
+namespace tls {
+
+// Takes an encoded public key and generates a X509_NAME that can be used in
+// TlsConnection::SetClientCAList(), to allow the client to figure out which of
+// its keys it should try to use in the TLS handshake. This is guaranteed to
+// return a valid X509_NAME, given a non-empty key.
+bssl::UniquePtr<X509_NAME> CreateCAIssuerFromEncodedKey(std::string_view key);
+
+// Parses a CA issuer and returns the encoded key, if any. On failure, returns
+// nullopt.
+std::optional<std::string> ParseEncodedKeyFromCAIssuer(X509_NAME* issuer);
+
+// Converts SHA256 bits to a hex string representation. |sha256| must be exactly
+// |SHA256_DIGEST_LENGTH| in size.
+std::string SHA256BitsToHexString(std::string_view sha256);
+
+// Converts a valid SHA256 hex string to the actual bits. Returns nullopt on
+// failure.
+std::optional<std::string> SHA256HexStringToBits(std::string_view sha256_str);
+
+}  // namespace tls
+}  // namespace adb
diff --git a/adb/tls/include/adb/tls/tls_connection.h b/adb/tls/include/adb/tls/tls_connection.h
new file mode 100644
index 0000000..ae70857
--- /dev/null
+++ b/adb/tls/include/adb/tls/tls_connection.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string_view>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+
+namespace adb {
+namespace tls {
+
+class TlsConnection {
+  public:
+    // This class will require both client and server to exchange valid
+    // certificates.
+    enum class Role {
+        Server,
+        Client,
+    };
+
+    enum class TlsError : uint8_t {
+        Success = 0,
+        // An error indicating that we rejected the peer's certificate.
+        CertificateRejected,
+        // An error indicating that the peer rejected our certificate.
+        PeerRejectedCertificate,
+        // Add more if needed
+        UnknownFailure,
+    };
+
+    using CertVerifyCb = std::function<int(X509_STORE_CTX*)>;
+    using SetCertCb = std::function<int(SSL*)>;
+
+    virtual ~TlsConnection() = default;
+
+    // Adds a trusted certificate to the list for the SSL connection.
+    // During the handshake phase, it will check the list of trusted certificates.
+    // The connection will fail if the peer's certificate is not in the list. Use
+    // |EnableCertificateVerification(false)| to disable certificate
+    // verification.
+    //
+    // Returns true if |cert| was successfully added, false otherwise.
+    virtual bool AddTrustedCertificate(std::string_view cert) = 0;
+
+    // Sets a custom certificate verify callback. |cb| must return 1 if the
+    // certificate is trusted. Otherwise, return 0 if not. Note that |cb| is
+    // only used if EnableCertificateVerification(false).
+    virtual void SetCertVerifyCallback(CertVerifyCb cb) = 0;
+
+    // Configures a client |ca_list| that the server sends to the client in the
+    // CertificateRequest message.
+    virtual void SetClientCAList(STACK_OF(X509_NAME) * ca_list) = 0;
+
+    // Sets a callback that will be called to select a certificate. See
+    // https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_cert_cb
+    // for more details.
+    virtual void SetCertificateCallback(SetCertCb cb) = 0;
+
+    // Exports a value derived from the master secret used in the TLS
+    // connection. This value should be used alongside any PAKE to ensure the
+    // peer is the intended peer. |length| is the requested length for the
+    // keying material. This is only valid after |DoHandshake| succeeds.
+    virtual std::vector<uint8_t> ExportKeyingMaterial(size_t length) = 0;
+
+    // Enable client-side check on whether server accepted the handshake. In TLS
+    // 1.3, client will not know the server rejected the handshake until after
+    // performing a read operation. Basically, this will perform an
+    // SSL_peek right after the handshake and see whether that succeeds.
+    //
+    // IMPORTANT: this will only work if the protocol is a server-speaks-first
+    // type. Enabling this for the server is a no-op. This is disabled by
+    // default.
+    virtual void EnableClientPostHandshakeCheck(bool enable) = 0;
+
+    // Starts the handshake process. Returns TlsError::Success if handshake
+    // succeeded.
+    virtual TlsError DoHandshake() = 0;
+
+    // Reads |size| bytes and returns the data. The returned data has either
+    // size |size| or zero, in which case the read failed.
+    virtual std::vector<uint8_t> ReadFully(size_t size) = 0;
+
+    // Overloaded ReadFully method, which accepts a buffer for writing in.
+    // Returns true iff exactly |size| amount of data was written into |buf|,
+    // false otherwise.
+    virtual bool ReadFully(void* buf, size_t size) = 0;
+
+    // Writes |size| bytes. Returns true if all |size| bytes were read.
+    // Returns false otherwise.
+    virtual bool WriteFully(std::string_view data) = 0;
+
+    // Create a new TlsConnection instance. |cert| and |priv_key| cannot be
+    // empty.
+    static std::unique_ptr<TlsConnection> Create(Role role, std::string_view cert,
+                                                 std::string_view priv_key,
+                                                 android::base::borrowed_fd fd);
+
+    // Helper to set the certificate and key strings to a SSL client/server.
+    // Useful when in the set-certificate callback.
+    static bool SetCertAndKey(SSL* ssl, std::string_view cert_chain, std::string_view priv_key);
+
+  protected:
+    TlsConnection() = default;
+};  // TlsConnection
+
+}  // namespace tls
+}  // namespace adb
diff --git a/adb/tls/tests/Android.bp b/adb/tls/tests/Android.bp
new file mode 100644
index 0000000..198de58
--- /dev/null
+++ b/adb/tls/tests/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "adb_tls_connection_test",
+    srcs: [
+        "adb_ca_list_test.cpp",
+        "tls_connection_test.cpp",
+    ],
+
+    compile_multilib: "first",
+
+    shared_libs: [
+        "libbase",
+        "libcrypto",
+        "libcrypto_utils",
+        "libssl",
+    ],
+
+    // Let's statically link them so we don't have to install it onto the
+    // system image for testing.
+    static_libs: [
+        "libadb_crypto_static",
+        "libadb_protos_static",
+        "libadb_tls_connection_static",
+    ],
+
+    test_suites: ["device-tests"],
+}
diff --git a/adb/tls/tests/adb_ca_list_test.cpp b/adb/tls/tests/adb_ca_list_test.cpp
new file mode 100644
index 0000000..c727e5f
--- /dev/null
+++ b/adb/tls/tests/adb_ca_list_test.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AdbCAListTest"
+
+#include <gtest/gtest.h>
+
+#include <adb/tls/adb_ca_list.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <openssl/ssl.h>
+
+namespace adb {
+namespace tls {
+
+class AdbCAListTest : public testing::Test {
+  protected:
+    virtual void SetUp() override {}
+
+    virtual void TearDown() override {}
+};
+
+TEST_F(AdbCAListTest, SHA256BitsToHexString_BadParam) {
+    // Should crash if not exactly SHA256_DIGEST_LENGTH size
+    ASSERT_DEATH(
+            {
+                // empty
+                std::string sha;
+                SHA256BitsToHexString(sha);
+            },
+            "");
+    ASSERT_DEATH(
+            {
+                std::string sha(1, 0x80);
+                SHA256BitsToHexString(sha);
+            },
+            "");
+    ASSERT_DEATH(
+            {
+                std::string sha(SHA256_DIGEST_LENGTH - 1, 0x80);
+                SHA256BitsToHexString(sha);
+            },
+            "");
+    ASSERT_DEATH(
+            {
+                std::string sha(SHA256_DIGEST_LENGTH + 1, 0x80);
+                SHA256BitsToHexString(sha);
+            },
+            "");
+}
+
+TEST_F(AdbCAListTest, SHA256HexStringToBits_BadParam) {
+    {
+        // empty
+        std::string sha_str;
+        auto res = SHA256HexStringToBits(sha_str);
+        EXPECT_FALSE(res.has_value());
+    }
+    {
+        std::string sha_str(1, 'a');
+        auto res = SHA256HexStringToBits(sha_str);
+        EXPECT_FALSE(res.has_value());
+    }
+    {
+        std::string sha_str(SHA256_DIGEST_LENGTH * 2 - 1, 'a');
+        auto res = SHA256HexStringToBits(sha_str);
+        EXPECT_FALSE(res.has_value());
+    }
+    {
+        std::string sha_str(SHA256_DIGEST_LENGTH * 2 + 1, 'a');
+        auto res = SHA256HexStringToBits(sha_str);
+        EXPECT_FALSE(res.has_value());
+    }
+    {
+        // Non-hex chars
+        std::string sha_str(SHA256_DIGEST_LENGTH * 2, 'a');
+        sha_str[32] = 'x';
+        auto res = SHA256HexStringToBits(sha_str);
+        EXPECT_FALSE(res.has_value());
+    }
+}
+
+TEST_F(AdbCAListTest, SHA256BitsToHexString_ValidParam) {
+    uint8_t ct = 0;
+    // Test every possible byte
+    std::vector<std::string> expectedStr = {
+            "000102030405060708090A0B0C0D0E0F"
+            "101112131415161718191A1B1C1D1E1F",
+
+            "202122232425262728292A2B2C2D2E2F"
+            "303132333435363738393A3B3C3D3E3F",
+
+            "404142434445464748494A4B4C4D4E4F"
+            "505152535455565758595A5B5C5D5E5F",
+
+            "606162636465666768696A6B6C6D6E6F"
+            "707172737475767778797A7B7C7D7E7F",
+
+            "808182838485868788898A8B8C8D8E8F"
+            "909192939495969798999A9B9C9D9E9F",
+
+            "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
+            "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF",
+
+            "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
+            "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF",
+
+            "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
+            "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF",
+    };
+
+    for (auto& expected : expectedStr) {
+        std::string sha;
+        while (sha.size() < SHA256_DIGEST_LENGTH) {
+            sha += ct++;
+        }
+
+        auto sha_str = SHA256BitsToHexString(sha);
+        EXPECT_EQ(expected, sha_str);
+
+        // try to convert back to bits
+        auto out_sha = SHA256HexStringToBits(sha_str);
+        ASSERT_TRUE(out_sha.has_value());
+        EXPECT_EQ(*out_sha, sha);
+    }
+}
+
+TEST_F(AdbCAListTest, CreateCAIssuerFromEncodedKey_EmptyKey) {
+    ASSERT_DEATH({ auto issuer = CreateCAIssuerFromEncodedKey(""); }, "");
+}
+
+TEST_F(AdbCAListTest, Smoke) {
+    {
+        std::string key =
+                "A45BC1FF6C89BF0E"
+                "65F9BA153FBC9876"
+                "4969B4113F1CF878"
+                "EEF9BF1C3F9C9227";
+        auto issuer = CreateCAIssuerFromEncodedKey(key);
+        ASSERT_NE(issuer, nullptr);
+
+        // Try to parse the encoded key out of the X509_NAME
+        auto out_key = ParseEncodedKeyFromCAIssuer(issuer.get());
+        ASSERT_TRUE(out_key.has_value());
+        EXPECT_EQ(key, *out_key);
+    }
+}
+
+}  // namespace tls
+}  // namespace adb
diff --git a/adb/tls/tests/tls_connection_test.cpp b/adb/tls/tests/tls_connection_test.cpp
new file mode 100644
index 0000000..880904b
--- /dev/null
+++ b/adb/tls/tests/tls_connection_test.cpp
@@ -0,0 +1,616 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AdbWifiTlsConnectionTest"
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include <adb/crypto/rsa_2048_key.h>
+#include <adb/crypto/x509_generator.h>
+#include <adb/tls/adb_ca_list.h>
+#include <adb/tls/tls_connection.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <openssl/ssl.h>
+
+using namespace adb::crypto;
+
+namespace adb {
+namespace tls {
+
+using android::base::unique_fd;
+using TlsError = TlsConnection::TlsError;
+
+// Test X.509 certificates (RSA 2048)
+static const std::string kTestRsa2048ServerCert =
+        "-----BEGIN CERTIFICATE-----\n"
+        "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n"
+        "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyMTIyMjU1NVoX\n"
+        "DTMwMDExODIyMjU1NVowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n"
+        "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK8E\n"
+        "2Ck9TfuKlz7wqWdMfknjZ1luFDp2IHxAUZzh/F6jeI2dOFGAjpeloSnGOE86FIaT\n"
+        "d1EvpyTh7nBwbrLZAA6XFZTo7Bl6BdNOQdqb2d2+cLEN0inFxqUIycevRtohUE1Y\n"
+        "FHM9fg442X1jOTWXjDZWeiqFWo95paAPhzm6pWqfJK1+YKfT1LsWZpYqJGGQE5pi\n"
+        "C3qOBYYgFpoXMxTYJNoZo3uOYEdM6upc8/vh15nMgIxX/ymJxEY5BHPpZPPWjXLg\n"
+        "BfzVaV9fUfv0JT4HQ4t2WvxC3cD/UsjWp2a6p454uUp2ENrANa+jRdRJepepg9D2\n"
+        "DKsx9L8zjc5Obqexrt0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
+        "Af8EBAMCAYYwHQYDVR0OBBYEFDFW+8GTErwoZN5Uu9KyY4QdGYKpMA0GCSqGSIb3\n"
+        "DQEBCwUAA4IBAQBCDEn6SHXGlq5TU7J8cg1kRPd9bsJW+0hDuKSq0REXDkl0PcBf\n"
+        "fy282Agg9enKPPKmnpeQjM1dmnxdM8tT8LIUbMl779i3fn6v9HJVB+yG4gmRFThW\n"
+        "c+AGlBnrIT820cX/gU3h3R3FTahfsq+1rrSJkEgHyuC0HYeRyveSckBdaEOLvx0S\n"
+        "toun+32JJl5hWydpUUZhE9Mbb3KHBRM2YYZZU9JeJ08Apjl+3lRUeMAUwI5fkAAu\n"
+        "z/1SqnuGL96bd8P5ixdkA1+rF8FPhodGcq9mQOuUGP9g5HOXjaNoJYvwVRUdLeGh\n"
+        "cP/ReOTwQIzM1K5a83p8cX8AGGYmM7dQp7ec\n"
+        "-----END CERTIFICATE-----\n";
+
+static const std::string kTestRsa2048ServerPrivKey =
+        "-----BEGIN PRIVATE KEY-----\n"
+        "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCvBNgpPU37ipc+\n"
+        "8KlnTH5J42dZbhQ6diB8QFGc4fxeo3iNnThRgI6XpaEpxjhPOhSGk3dRL6ck4e5w\n"
+        "cG6y2QAOlxWU6OwZegXTTkHam9ndvnCxDdIpxcalCMnHr0baIVBNWBRzPX4OONl9\n"
+        "Yzk1l4w2VnoqhVqPeaWgD4c5uqVqnyStfmCn09S7FmaWKiRhkBOaYgt6jgWGIBaa\n"
+        "FzMU2CTaGaN7jmBHTOrqXPP74deZzICMV/8picRGOQRz6WTz1o1y4AX81WlfX1H7\n"
+        "9CU+B0OLdlr8Qt3A/1LI1qdmuqeOeLlKdhDawDWvo0XUSXqXqYPQ9gyrMfS/M43O\n"
+        "Tm6nsa7dAgMBAAECggEAFCS2bPdUKIgjbzLgtHW+hT+J2hD20rcHdyAp+dNH/2vI\n"
+        "yLfDJHJA4chGMRondKA704oDw2bSJxxlG9t83326lB35yxPhye7cM8fqgWrK8PVl\n"
+        "tU22FhO1ZgeJvb9OeXWNxKZyDW9oOOJ8eazNXVMuEo+dFj7B6l3MXQyHJPL2mJDm\n"
+        "u9ofFLdypX+gJncVO0oW0FNJnEUn2MMwHDNlo7gc4WdQuidPkuZItKRGcB8TTGF3\n"
+        "Ka1/2taYdTQ4Aq//Z84LlFvE0zD3T4c8LwYYzOzD4gGGTXvft7vSHzIun1S8YLRS\n"
+        "dEKXdVjtaFhgH3uUe4j+1b/vMvSHeoGBNX/G88GD+wKBgQDWUYVlMVqc9HD2IeYi\n"
+        "EfBcNwAJFJkh51yAl5QbUBgFYgFJVkkS/EDxEGFPvEmI3/pAeQFHFY13BI466EPs\n"
+        "o8Z8UUwWDp+Z1MFHHKQKnFakbsZbZlbqjJ9VJsqpezbpWhMHTOmcG0dmE7rf0lyM\n"
+        "eQv9slBB8qp2NEUs5Of7f2C2bwKBgQDRDq4nUuMQF1hbjM05tGKSIwkobmGsLspv\n"
+        "TMhkM7fq4RpbFHmbNgsFqMhcqYZ8gY6/scv5KCuAZ4yHUkbqwf5h+QCwrJ4uJeUJ\n"
+        "ZgJfHus2mmcNSo8FwSkNoojIQtzcbJav7bs2K9VTuertk/i7IJLApU4FOZZ5pghN\n"
+        "EXu0CZF1cwKBgDWFGhjRIF29tU/h20R60llU6s9Zs3wB+NmsALJpZ/ZAKS4VPB5f\n"
+        "nCAXBRYSYRKrTCU5kpYbzb4BBzuysPOxWmnFK4j+keCqfrGxd02nCQP7HdHJVr8v\n"
+        "6sIq88UrHeVcNxBFprjzHvtgxfQK5k22FMZ/9wbhAKyQFQ5HA5+MiaxFAoGAIcZZ\n"
+        "ZIkDninnYIMS9OursShv5lRO+15j3i9tgKLKZ+wOMgDQ1L6acUOfezj4PU1BHr8+\n"
+        "0PYocQpJreMhCfRlgLaV4fVBaPs+UZJld7CrF5tCYudUy/01ALrtlk0XGZWBktK5\n"
+        "mDrksC4tQkzRtonAq9cJD9cJ9IVaefkFH0UcdvkCgYBpZj50VLeGhnHHBnkJRlV1\n"
+        "fV+/P6PAq6RtqjA6O9Qdaoj5V3w2d63aQcQXQLJjH2BBmtCIy47r04rFvZpbCxP7\n"
+        "NH/OnK9NHpk2ucRTe8TAnVbvF/TZzPJoIxAO/D3OWaW6df4R8en8u6GYzWFglAyT\n"
+        "sydGT8yfWD1FYUWgfrVRbg==\n"
+        "-----END PRIVATE KEY-----\n";
+
+static const std::string kTestRsa2048ClientCert =
+        "-----BEGIN CERTIFICATE-----\n"
+        "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n"
+        "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyMTIyMjU1NloX\n"
+        "DTMwMDExODIyMjU1NlowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n"
+        "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAI3a\n"
+        "EXh1S5FTbet7JVONswffRPaekdIK53cb8SnAbSO9X5OLA4zGwdkrBvDTsd96SKrp\n"
+        "JxmoNOE1DhbZh05KPlWAPkGKacjGWaz+S7biDOL0I6aaLbTlU/il1Ub9olPSBVUx\n"
+        "0nhdtEFgIOzddnP6/1KmyIIeRxS5lTKeg4avqUkZNXkz/wL1dHBFL7FNFf0SCcbo\n"
+        "tsub/deFbjZ27LTDN+SIBgFttTNqC5NTvoBAoMdyCOAgNYwaHO+fKiK3edfJieaw\n"
+        "7HD8qqmQxcpCtRlA8CUPj7GfR+WHiCJmlevhnkFXCo56R1BS0F4wuD4KPdSWt8gc\n"
+        "27ejH/9/z2cKo/6SLJMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
+        "Af8EBAMCAYYwHQYDVR0OBBYEFO/Mr5ygqqpyU/EHM9v7RDvcqaOkMA0GCSqGSIb3\n"
+        "DQEBCwUAA4IBAQAH33KMouzF2DYbjg90KDrDQr4rq3WfNb6P743knxdUFuvb+40U\n"
+        "QjC2OJZHkSexH7wfG/y6ic7vfCfF4clNs3QvU1lEjOZC57St8Fk7mdNdsWLwxEMD\n"
+        "uePFz0dvclSxNUHyCVMqNxddzQYzxiDWQRmXWrUBliMduQqEQelcxW2yDtg8bj+s\n"
+        "aMpR1ra9scaD4jzIZIIxLoOS9zBMuNRbgP217sZrniyGMhzoI1pZ/izN4oXpyH7O\n"
+        "THuaCzzRT3ph2f8EgmHSodz3ttgSf2DHzi/Ez1xUkk7NOlgNtmsxEdrM47+cC5ae\n"
+        "fIf2V+1o1JW8J7D11RmRbNPh3vfisueB4f88\n"
+        "-----END CERTIFICATE-----\n";
+
+static const std::string kTestRsa2048ClientPrivKey =
+        "-----BEGIN PRIVATE KEY-----\n"
+        "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCN2hF4dUuRU23r\n"
+        "eyVTjbMH30T2npHSCud3G/EpwG0jvV+TiwOMxsHZKwbw07Hfekiq6ScZqDThNQ4W\n"
+        "2YdOSj5VgD5BimnIxlms/ku24gzi9COmmi205VP4pdVG/aJT0gVVMdJ4XbRBYCDs\n"
+        "3XZz+v9SpsiCHkcUuZUynoOGr6lJGTV5M/8C9XRwRS+xTRX9EgnG6LbLm/3XhW42\n"
+        "duy0wzfkiAYBbbUzaguTU76AQKDHcgjgIDWMGhzvnyoit3nXyYnmsOxw/KqpkMXK\n"
+        "QrUZQPAlD4+xn0flh4giZpXr4Z5BVwqOekdQUtBeMLg+Cj3UlrfIHNu3ox//f89n\n"
+        "CqP+kiyTAgMBAAECggEAAa64eP6ggCob1P3c73oayYPIbvRqiQdAFOrr7Vwu7zbr\n"
+        "z0rde+n6RU0mrpc+4NuzyPMtrOGQiatLbidJB5Cx3z8U00ovqbCl7PtcgorOhFKe\n"
+        "VEzihebCcYyQqbWQcKtpDMhOgBxRwFoXieJb6VGXfa96FAZalCWvXgOrTl7/BF2X\n"
+        "qMqIm9nJi+yS5tIO8VdOsOmrMWRH/b/ENUcef4WpLoxTXr0EEgyKWraeZ/hhXo1e\n"
+        "z29dZKqdr9wMsq11NPsRddwS94jnDkXTo+EQyWVTfB7gb6yyp07s8jysaDb21tVv\n"
+        "UXB9MRhDV1mOv0ncXfXZ4/+4A2UahmZaLDAVLaat4QKBgQDAVRredhGRGl2Nkic3\n"
+        "KvZCAfyxug788CgasBdEiouz19iCCwcgMIDwnq0s3/WM7h/laCamT2x38riYDnpq\n"
+        "rkYMfuVtU9CjEL9pTrdfwbIRhTwYNqADaPz2mXwQUhRXutE5TIdgxxC/a+ZTh0qN\n"
+        "S+vhTj/4hf0IZhMh5Nqj7IPExQKBgQC8zxEzhmSGjys0GuE6Wl6Doo2TpiR6vwvi\n"
+        "xPLU9lmIz5eca/Rd/eERioFQqeoIWDLzx52DXuz6rUoQhbJWz9hP3yqCwXD+pbNP\n"
+        "oDJqDDbCC4IMYEb0IK/PEPH+gIpnTjoFcW+ecKDFG7W5Lt05J8WsJsfOaJvMrOU+\n"
+        "dLXq3IgxdwKBgQC5RAFq0v6e8G+3hFaEHL0z3igkpt3zJf7rnj37hx2FMmDa+3Z0\n"
+        "umQp5B9af61PgL12xLmeMBmC/Wp1BlVDV/Yf6Uhk5Hyv5t0KuomHEtTNbbLyfAPs\n"
+        "5P/vJu/L5NS1oT4S3LX3MineyjgGs+bLbpub3z1dzutrYLADUSiPCK/xJQKBgBQt\n"
+        "nQ0Ao+Wtj1R2OvPdjJRM3wyUiPmFSWPm4HzaBx+T8AQLlYYmB9O0FbXlMtnJc0iS\n"
+        "YMcVcgYoVu4FG9YjSF7g3s4yljzgwJUV7c1fmMqMKE3iTDLy+1cJ3JLycdgwiArk\n"
+        "4KTyLHxkRbuQwpvFIF8RlfD9RQlOwQE3v+llwDhpAoGBAL6XG6Rp6mBoD2Ds5c9R\n"
+        "943yYgSUes3ji1SI9zFqeJtj8Ml/enuK1xu+8E/BxB0//+vgZsH6i3i8GFwygKey\n"
+        "CGJF8CbiHc3EJc3NQIIRXcni/CGacf0HwC6m+PGFDBIpA4H2iDpVvCSofxttQiq0\n"
+        "/Z7HXmXUvZHVyYi/QzX2Gahj\n"
+        "-----END PRIVATE KEY-----\n";
+
+static const std::string kTestRsa2048UnknownPrivKey =
+        "-----BEGIN PRIVATE KEY-----\n"
+        "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCrIhr+CS+6UI0w\n"
+        "CTaVzQAicKBe6X531LeQAGYx7j5RLHR1QIoJ0WCc5msmXKe2VzcWuLbVdTGAIP1H\n"
+        "mwbPqlbO4ioxeJhiDv+WPuLG8+j4Iw1Yqxt8cfohxjfvNmIQM8aF5hGyyaaTetDF\n"
+        "EYWONoYCBC4WnFWgYCPb8mzWXlhHE3F66GnHpc32zydPTg3ZurGvSsFf7fNY9yRw\n"
+        "8WtwPiI6mpRxt+n2bQUp+LZ+g/3rXLFPg8uWDGYG7IvLluWc9gR9lxjL64t6ryLU\n"
+        "2cm7eTfDgLw/B1F/wEgCJDnby1JgQ4rq6klJO3BR2ooUr/7T343y5njG5hQJreV7\n"
+        "5ZnSmRLZAgMBAAECggEABPrfeHZFuWkj7KqN+DbAmt/2aMCodZ3+7/20+528WkIe\n"
+        "CvXzdmTth+9UHagLWNzpnVuHdYd9JuZ+3F00aelh8JAIDIu++naHhUSj9ohtRoBF\n"
+        "oIeNK5ZJAj/Zi5hkauaIz8dxyyc/VdIYfm2bundXd7pNqYqH2tyFWp6PwH67GKlZ\n"
+        "1lC7o8gKAK8sz9g0Ctdoe+hDqAsvYFCW4EWDM2qboucSgn8g3E/Gux/KrpXVv7d0\n"
+        "PMQ60m+dyTOCMGqXIoDR3TAvQR7ex5sQ/QZSREdxKy878s/2FY4ktxtCUWlhrmcI\n"
+        "VKtrDOGEKwNoiMluf2635rsVq2e01XhQlmdxbRFU0QKBgQDjOhhD1m9duFTQ2b+J\n"
+        "Xfn6m8Rs7sZqO4Az7gLOWmD/vYWlK4n2nZsh6u5/cB1N+PA+ncvvV4yKJAlLHxbT\n"
+        "pVvfzJ/jbUsj/NJg/w7+KYC9gXgRmBonuG2gRZF/5Otdlza4vMcoSkqGjlGxJyzL\n"
+        "+9umEziN3tEYMRwipYvt7BgbUQKBgQDAzaXryJ3YD3jpecy/+fSnQvFjpyeDRqU1\n"
+        "KDA9nxN5tJN6bnKhUlMhy64SsgvVX9jUuN7cK+qYV0uzdBn6kIAJNLWTdbtH93+e\n"
+        "vNVgluR3jmixW4QfY9vfZKdXZbVGNc0DFMi1vJqgxTgQ5Mq5PxxxRL4FsAF840V1\n"
+        "Wu9uhU0NCQKBgBfjga2QG8E0oeYbHmHouWE5gxsYt09v1fifqzfalJwOZsCIpUaC\n"
+        "J08Xjd9kABC0fT14BXqyL5pOU5PMPvAdUF1k++JDGUU9TTjZV9AsuNYziFYBMa6/\n"
+        "WvcgmT1i6cO7JAuj/SQlO1SOHdSME8+WOO9q0eVIaZ8repPB58YprhchAoGBAJyR\n"
+        "Y8AJdkTSq7nNszvi245IioYGY8vzPo3gSOyBlesrfOfbcTMYC3JSWNXNyFZKM2br\n"
+        "ie75qtRzb4IXMlGLrq3LI/jPjnpuvjBF4HFDl9yOxO3iB3UGPrM2pb4PVhnh7s4l\n"
+        "vqf2tQsBnPn7EbVFTu+ch0NPHqYwWWNnqS/zCBMhAoGBAIkYjOE0iD9W2FXee6VL\n"
+        "iN8wDqlqsGEEtLvykIDmTmM+ZX5ftQuPo18khpE9wQKmJ5OpoVTYIP1UsJFBakgo\n"
+        "+dGaf6xVuPvmydNFqixlW3z227n4Px6GX7CXlCaAleTeItezli+dWf/9astwTA3x\n"
+        "IazYzsxUUpZFC4dJ1GhBn3y1\n"
+        "-----END PRIVATE KEY-----\n";
+
+static const std::string kTestRsa2048UnknownCert =
+        "-----BEGIN CERTIFICATE-----\n"
+        "MIIDFzCCAf+gAwIBAgIBATANBgkqhkiG9w0BAQsFADAtMQswCQYDVQQGEwJVUzEQ\n"
+        "MA4GA1UECgwHQW5kcm9pZDEMMAoGA1UEAwwDQWRiMB4XDTIwMDEyNDE4MzMwNVoX\n"
+        "DTMwMDEyMTE4MzMwNVowLTELMAkGA1UEBhMCVVMxEDAOBgNVBAoMB0FuZHJvaWQx\n"
+        "DDAKBgNVBAMMA0FkYjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKsi\n"
+        "Gv4JL7pQjTAJNpXNACJwoF7pfnfUt5AAZjHuPlEsdHVAignRYJzmayZcp7ZXNxa4\n"
+        "ttV1MYAg/UebBs+qVs7iKjF4mGIO/5Y+4sbz6PgjDVirG3xx+iHGN+82YhAzxoXm\n"
+        "EbLJppN60MURhY42hgIELhacVaBgI9vybNZeWEcTcXroacelzfbPJ09ODdm6sa9K\n"
+        "wV/t81j3JHDxa3A+IjqalHG36fZtBSn4tn6D/etcsU+Dy5YMZgbsi8uW5Zz2BH2X\n"
+        "GMvri3qvItTZybt5N8OAvD8HUX/ASAIkOdvLUmBDiurqSUk7cFHaihSv/tPfjfLm\n"
+        "eMbmFAmt5XvlmdKZEtkCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
+        "Af8EBAMCAYYwHQYDVR0OBBYEFDtRSOm1ilhnq6bKN4qJ1ekK/PAkMA0GCSqGSIb3\n"
+        "DQEBCwUAA4IBAQAP6Q8/OxnBA3BO8oxKer0tjI4rZMefUhbAKUWXYjTTNEBm5//b\n"
+        "lVGP2RptO7bxj8w1L3rxsjmVcv2TqBOhrbJqvGVPE2ntoYlFhBBkRvmxuu1y5W9V\n"
+        "uJU7SF9lNmDXShTURULu3P8GdeT1HGeXzWQ4x7VhY9a3VIbmN5VxjB+3C6hYZxSs\n"
+        "DCpmidu/sR+n5Azlh6oqrhOxmv17PuF/ioTUsHd4y2Z41IvvO47oghxNDtboUUsg\n"
+        "LfsM1MOxVC9PqOfQphFU4i8owNIYzBMadDLw+1TSQj0ALqZVyc9Dq+WDFdz+JAE+\n"
+        "k7TkVU06UPGVSnLVzJeYwGCXQp3apBszY9vO\n"
+        "-----END CERTIFICATE-----\n";
+
+struct CAIssuerField {
+    int nid;
+    std::vector<uint8_t> val;
+};
+using CAIssuer = std::vector<CAIssuerField>;
+static std::vector<CAIssuer> kCAIssuers = {
+        {
+                {NID_commonName, {'a', 'b', 'c', 'd', 'e'}},
+                {NID_organizationName,
+                 {
+                         'd',
+                         'e',
+                         'f',
+                         'g',
+                 }},
+        },
+        {
+                {NID_commonName,
+                 {
+                         'h',
+                         'i',
+                         'j',
+                         'k',
+                         'l',
+                         'm',
+                 }},
+                {NID_countryName, {'n', 'o'}},
+        },
+};
+
+class AdbWifiTlsConnectionTest : public testing::Test {
+  protected:
+    virtual void SetUp() override {
+        // TODO: move client code in each test into its own thread, as the
+        // socket pair buffer is limited.
+        android::base::Socketpair(SOCK_STREAM, &server_fd_, &client_fd_);
+        server_ = TlsConnection::Create(TlsConnection::Role::Server, kTestRsa2048ServerCert,
+                                        kTestRsa2048ServerPrivKey, server_fd_);
+        client_ = TlsConnection::Create(TlsConnection::Role::Client, kTestRsa2048ClientCert,
+                                        kTestRsa2048ClientPrivKey, client_fd_);
+        ASSERT_NE(nullptr, server_);
+        ASSERT_NE(nullptr, client_);
+    }
+
+    virtual void TearDown() override {
+        WaitForClientConnection();
+        // Shutdown the SSL connection first.
+        server_.reset();
+        client_.reset();
+    }
+
+    bssl::UniquePtr<STACK_OF(X509_NAME)> GetCAIssuerList() {
+        bssl::UniquePtr<STACK_OF(X509_NAME)> ret(sk_X509_NAME_new_null());
+        for (auto& issuer : kCAIssuers) {
+            bssl::UniquePtr<X509_NAME> name(X509_NAME_new());
+            for (auto& attr : issuer) {
+                CHECK(X509_NAME_add_entry_by_NID(name.get(), attr.nid, MBSTRING_ASC,
+                                                 attr.val.data(), attr.val.size(), -1, 0));
+            }
+
+            CHECK(bssl::PushToStack(ret.get(), std::move(name)));
+        }
+
+        return ret;
+    }
+
+    void StartClientHandshakeAsync(bool expect_success) {
+        client_thread_ = std::thread([=]() {
+            if (expect_success) {
+                EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
+            } else {
+                EXPECT_NE(client_->DoHandshake(), TlsError::Success);
+            }
+        });
+    }
+
+    void WaitForClientConnection() {
+        if (client_thread_.joinable()) {
+            client_thread_.join();
+        }
+    }
+
+    unique_fd server_fd_;
+    unique_fd client_fd_;
+    const std::vector<uint8_t> msg_{0xff, 0xab, 0x32, 0xf6, 0x12, 0x56};
+    std::unique_ptr<TlsConnection> server_;
+    std::unique_ptr<TlsConnection> client_;
+    std::thread client_thread_;
+};
+
+TEST_F(AdbWifiTlsConnectionTest, InvalidCreationParams) {
+    // Verify that passing empty certificate/private key results in a crash.
+    ASSERT_DEATH(
+            {
+                server_ = TlsConnection::Create(TlsConnection::Role::Server, "",
+                                                kTestRsa2048ServerPrivKey, server_fd_);
+            },
+            "");
+    ASSERT_DEATH(
+            {
+                server_ = TlsConnection::Create(TlsConnection::Role::Server, kTestRsa2048ServerCert,
+                                                "", server_fd_);
+            },
+            "");
+    ASSERT_DEATH(
+            {
+                client_ = TlsConnection::Create(TlsConnection::Role::Client, "",
+                                                kTestRsa2048ClientPrivKey, client_fd_);
+            },
+            "");
+    ASSERT_DEATH(
+            {
+                client_ = TlsConnection::Create(TlsConnection::Role::Client, kTestRsa2048ClientCert,
+                                                "", client_fd_);
+            },
+            "");
+}
+
+TEST_F(AdbWifiTlsConnectionTest, NoCertificateVerification) {
+    // Allow any certificate
+    server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+    StartClientHandshakeAsync(true);
+
+    // Handshake should succeed
+    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    WaitForClientConnection();
+
+    // Client write, server read
+    EXPECT_TRUE(client_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    auto data = server_->ReadFully(msg_.size());
+    EXPECT_EQ(data, msg_);
+
+    // Client read, server write
+    EXPECT_TRUE(server_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    // Try with overloaded ReadFully
+    std::vector<uint8_t> buf(msg_.size());
+    ASSERT_TRUE(client_->ReadFully(buf.data(), msg_.size()));
+    EXPECT_EQ(buf, msg_);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, NoTrustedCertificates) {
+    StartClientHandshakeAsync(false);
+
+    // Handshake should not succeed
+    EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+    WaitForClientConnection();
+
+    // Client write, server read should fail
+    EXPECT_FALSE(client_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    auto data = server_->ReadFully(msg_.size());
+    EXPECT_EQ(data.size(), 0);
+
+    // Client read, server write should fail
+    EXPECT_FALSE(server_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    data = client_->ReadFully(msg_.size());
+    EXPECT_EQ(data.size(), 0);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates) {
+    // Add peer certificates
+    EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert));
+    EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert));
+
+    StartClientHandshakeAsync(true);
+
+    // Handshake should succeed
+    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    WaitForClientConnection();
+
+    // Client write, server read
+    EXPECT_TRUE(client_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    auto data = server_->ReadFully(msg_.size());
+    EXPECT_EQ(data, msg_);
+
+    // Client read, server write
+    EXPECT_TRUE(server_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    data = client_->ReadFully(msg_.size());
+    EXPECT_EQ(data, msg_);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, AddTrustedCertificates_ClientWrongCert) {
+    // Server trusts a certificate, client has the wrong certificate
+    EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
+    // Client accepts any certificate
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+    // Without enabling EnableClientPostHandshakeCheck(), DoHandshake() will
+    // succeed, because in TLS 1.3, the client doesn't get notified if the
+    // server rejected the certificate until a read operation is called.
+    StartClientHandshakeAsync(true);
+
+    // Handshake should fail for server, succeed for client
+    EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+    WaitForClientConnection();
+
+    // Client write succeeds, server read should fail
+    EXPECT_TRUE(client_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    auto data = server_->ReadFully(msg_.size());
+    EXPECT_EQ(data.size(), 0);
+
+    // Client read, server write should fail
+    EXPECT_FALSE(server_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    data = client_->ReadFully(msg_.size());
+    EXPECT_EQ(data.size(), 0);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, ExportKeyingMaterial) {
+    // Allow any certificate
+    server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+    // Add peer certificates
+    EXPECT_TRUE(client_->AddTrustedCertificate(kTestRsa2048ServerCert));
+    EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048ClientCert));
+
+    StartClientHandshakeAsync(true);
+
+    // Handshake should succeed
+    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    WaitForClientConnection();
+
+    // Verify the client and server's exported key material match.
+    const size_t key_size = 64;
+    auto client_key_material = client_->ExportKeyingMaterial(key_size);
+    ASSERT_FALSE(client_key_material.empty());
+    auto server_key_material = server_->ExportKeyingMaterial(key_size);
+    ASSERT_TRUE(!server_key_material.empty());
+    ASSERT_EQ(client_key_material.size(), key_size);
+    ASSERT_EQ(client_key_material, server_key_material);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientAcceptsServerRejects) {
+    // Client accepts all
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+    // Server rejects all
+    server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
+    // Client handshake should succeed, because in TLS 1.3, client does not
+    // realize that the peer rejected the certificate until after a read
+    // operation.
+    client_thread_ = std::thread([&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::Success); });
+
+    // Server handshake should fail
+    EXPECT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
+    WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientAcceptsServerRejects_PostHSCheck) {
+    // Client accepts all
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+    // Client should now get a failure in the handshake
+    client_->EnableClientPostHandshakeCheck(true);
+    // Server rejects all
+    server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
+
+    // Client handshake should fail because server rejects everything
+    client_thread_ = std::thread(
+            [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::PeerRejectedCertificate); });
+
+    // Server handshake should fail
+    EXPECT_EQ(server_->DoHandshake(), TlsError::CertificateRejected);
+    WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientRejectsServerAccepts) {
+    // Client rejects all
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
+    // Server accepts all
+    server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+    // Client handshake should fail
+    client_thread_ = std::thread(
+            [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::CertificateRejected); });
+
+    // Server handshake should fail
+    EXPECT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
+    WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetCertVerifyCallback_ClientRejectsServerAccepts_PostHSCheck) {
+    // Client rejects all
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 0; });
+    // This shouldn't affect the error types returned in the
+    // #SetCertVerifyCallback_ClientRejectsServerAccepts test, since
+    // the failure is still within the TLS 1.3 handshake.
+    client_->EnableClientPostHandshakeCheck(true);
+    // Server accepts all
+    server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+    // Client handshake should fail
+    client_thread_ = std::thread(
+            [&]() { EXPECT_EQ(client_->DoHandshake(), TlsError::CertificateRejected); });
+
+    // Server handshake should fail
+    EXPECT_EQ(server_->DoHandshake(), TlsError::PeerRejectedCertificate);
+    WaitForClientConnection();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, EnableClientPostHandshakeCheck_ClientWrongCert) {
+    // client's DoHandshake() will fail if the server rejected the certificate
+    client_->EnableClientPostHandshakeCheck(true);
+
+    // Add peer certificates
+    EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
+
+    // Handshake should fail for client
+    StartClientHandshakeAsync(false);
+
+    // Handshake should fail for server
+    EXPECT_NE(server_->DoHandshake(), TlsError::Success);
+    WaitForClientConnection();
+
+    // Client write fails, server read should fail
+    EXPECT_FALSE(client_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    auto data = server_->ReadFully(msg_.size());
+    EXPECT_EQ(data.size(), 0);
+
+    // Client read, server write should fail
+    EXPECT_FALSE(server_->WriteFully(
+            std::string_view(reinterpret_cast<const char*>(msg_.data()), msg_.size())));
+    data = client_->ReadFully(msg_.size());
+    EXPECT_EQ(data.size(), 0);
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_Empty) {
+    // Setting an empty CA list should not crash
+    server_->SetClientCAList(nullptr);
+    ASSERT_DEATH(
+            {
+                // Client cannot use this API
+                client_->SetClientCAList(nullptr);
+            },
+            "");
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_Smoke) {
+    auto bsslIssuerList = GetCAIssuerList();
+    server_->SetClientCAList(bsslIssuerList.get());
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+    client_thread_ = std::thread([&]() {
+        client_->SetCertificateCallback([&](SSL* ssl) -> int {
+            const STACK_OF(X509_NAME)* received = SSL_get_client_CA_list(ssl);
+            EXPECT_NE(received, nullptr);
+            const size_t num_names = sk_X509_NAME_num(received);
+            EXPECT_EQ(kCAIssuers.size(), num_names);
+
+            // Client initially registered with the wrong key. Let's change it
+            // here to verify this callback actually changes the client
+            // certificate to the right one.
+            EXPECT_TRUE(TlsConnection::SetCertAndKey(ssl, kTestRsa2048UnknownCert,
+                                                     kTestRsa2048UnknownPrivKey));
+
+            const size_t buf_size = 256;
+            uint8_t buf[buf_size];
+            size_t idx = 0;
+            for (auto& issuer : kCAIssuers) {
+                auto* name = sk_X509_NAME_value(received, idx++);
+                for (auto& attr : issuer) {
+                    EXPECT_EQ(X509_NAME_get_text_by_NID(name, attr.nid,
+                                                        reinterpret_cast<char*>(buf), buf_size),
+                              attr.val.size());
+                    std::vector<uint8_t> out(buf, buf + attr.val.size());
+                    EXPECT_EQ(out, attr.val);
+                }
+            }
+
+            return 1;
+        });
+        // Client handshake should succeed
+        EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
+    });
+
+    EXPECT_TRUE(server_->AddTrustedCertificate(kTestRsa2048UnknownCert));
+    // Server handshake should succeed
+    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    client_thread_.join();
+}
+
+TEST_F(AdbWifiTlsConnectionTest, SetClientCAList_AdbCAList) {
+    bssl::UniquePtr<STACK_OF(X509_NAME)> ca_list(sk_X509_NAME_new_null());
+    std::string keyhash = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+    auto issuer = CreateCAIssuerFromEncodedKey(keyhash);
+    ASSERT_TRUE(bssl::PushToStack(ca_list.get(), std::move(issuer)));
+    server_->SetClientCAList(ca_list.get());
+    client_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+
+    client_thread_ = std::thread([&]() {
+        client_->SetCertificateCallback([&](SSL* ssl) -> int {
+            // Client initially registered with a certificate that is not trusted by
+            // the server. Let's test that we can change the certificate to the
+            // trusted one here.
+            const STACK_OF(X509_NAME)* received = SSL_get_client_CA_list(ssl);
+            EXPECT_NE(received, nullptr);
+            const size_t num_names = sk_X509_NAME_num(received);
+            EXPECT_EQ(1, num_names);
+
+            auto* name = sk_X509_NAME_value(received, 0);
+            EXPECT_NE(name, nullptr);
+            auto enc_key = ParseEncodedKeyFromCAIssuer(name);
+            EXPECT_EQ(keyhash, enc_key);
+
+            return 1;
+        });
+        // Client handshake should succeed
+        EXPECT_EQ(client_->DoHandshake(), TlsError::Success);
+    });
+
+    server_->SetCertVerifyCallback([](X509_STORE_CTX*) { return 1; });
+    // Server handshake should succeed
+    EXPECT_EQ(server_->DoHandshake(), TlsError::Success);
+    client_thread_.join();
+}
+}  // namespace tls
+}  // namespace adb
diff --git a/adb/tls/tls_connection.cpp b/adb/tls/tls_connection.cpp
new file mode 100644
index 0000000..7df6ef4
--- /dev/null
+++ b/adb/tls/tls_connection.cpp
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "adb/tls/tls_connection.h"
+
+#include <algorithm>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/strings.h>
+#include <openssl/err.h>
+#include <openssl/ssl.h>
+
+using android::base::borrowed_fd;
+
+namespace adb {
+namespace tls {
+
+namespace {
+
+static constexpr char kExportedKeyLabel[] = "adb-label";
+
+class TlsConnectionImpl : public TlsConnection {
+  public:
+    explicit TlsConnectionImpl(Role role, std::string_view cert, std::string_view priv_key,
+                               borrowed_fd fd);
+    ~TlsConnectionImpl() override;
+
+    bool AddTrustedCertificate(std::string_view cert) override;
+    void SetCertVerifyCallback(CertVerifyCb cb) override;
+    void SetCertificateCallback(SetCertCb cb) override;
+    void SetClientCAList(STACK_OF(X509_NAME) * ca_list) override;
+    std::vector<uint8_t> ExportKeyingMaterial(size_t length) override;
+    void EnableClientPostHandshakeCheck(bool enable) override;
+    TlsError DoHandshake() override;
+    std::vector<uint8_t> ReadFully(size_t size) override;
+    bool ReadFully(void* buf, size_t size) override;
+    bool WriteFully(std::string_view data) override;
+
+    static bssl::UniquePtr<EVP_PKEY> EvpPkeyFromPEM(std::string_view pem);
+    static bssl::UniquePtr<CRYPTO_BUFFER> BufferFromPEM(std::string_view pem);
+
+  private:
+    static int SSLSetCertVerifyCb(X509_STORE_CTX* ctx, void* opaque);
+    static int SSLSetCertCb(SSL* ssl, void* opaque);
+
+    static bssl::UniquePtr<X509> X509FromBuffer(bssl::UniquePtr<CRYPTO_BUFFER> buffer);
+    static const char* SSLErrorString();
+    void Invalidate();
+    TlsError GetFailureReason(int err);
+
+    Role role_;
+    bssl::UniquePtr<EVP_PKEY> priv_key_;
+    bssl::UniquePtr<CRYPTO_BUFFER> cert_;
+
+    bssl::UniquePtr<STACK_OF(X509_NAME)> ca_list_;
+    bssl::UniquePtr<SSL_CTX> ssl_ctx_;
+    bssl::UniquePtr<SSL> ssl_;
+    std::vector<bssl::UniquePtr<X509>> known_certificates_;
+    bool client_verify_post_handshake_ = false;
+
+    CertVerifyCb cert_verify_cb_;
+    SetCertCb set_cert_cb_;
+    borrowed_fd fd_;
+};  // TlsConnectionImpl
+
+TlsConnectionImpl::TlsConnectionImpl(Role role, std::string_view cert, std::string_view priv_key,
+                                     borrowed_fd fd)
+    : role_(role), fd_(fd) {
+    CHECK(!cert.empty() && !priv_key.empty());
+    LOG(INFO) << "Initializing adbwifi TlsConnection";
+    cert_ = BufferFromPEM(cert);
+    priv_key_ = EvpPkeyFromPEM(priv_key);
+}
+
+TlsConnectionImpl::~TlsConnectionImpl() {
+    // shutdown the SSL connection
+    if (ssl_ != nullptr) {
+        SSL_shutdown(ssl_.get());
+    }
+}
+
+// static
+const char* TlsConnectionImpl::SSLErrorString() {
+    auto sslerr = ERR_peek_last_error();
+    return ERR_reason_error_string(sslerr);
+}
+
+// static
+bssl::UniquePtr<EVP_PKEY> TlsConnectionImpl::EvpPkeyFromPEM(std::string_view pem) {
+    bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem.data(), pem.size()));
+    return bssl::UniquePtr<EVP_PKEY>(PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
+}
+
+// static
+bssl::UniquePtr<CRYPTO_BUFFER> TlsConnectionImpl::BufferFromPEM(std::string_view pem) {
+    bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem.data(), pem.size()));
+    char* name = nullptr;
+    char* header = nullptr;
+    uint8_t* data = nullptr;
+    long data_len = 0;
+
+    if (!PEM_read_bio(bio.get(), &name, &header, &data, &data_len)) {
+        LOG(ERROR) << "Failed to read certificate";
+        return nullptr;
+    }
+    OPENSSL_free(name);
+    OPENSSL_free(header);
+
+    auto ret = bssl::UniquePtr<CRYPTO_BUFFER>(CRYPTO_BUFFER_new(data, data_len, nullptr));
+    OPENSSL_free(data);
+    return ret;
+}
+
+// static
+bssl::UniquePtr<X509> TlsConnectionImpl::X509FromBuffer(bssl::UniquePtr<CRYPTO_BUFFER> buffer) {
+    if (!buffer) {
+        return nullptr;
+    }
+    return bssl::UniquePtr<X509>(X509_parse_from_buffer(buffer.get()));
+}
+
+// static
+int TlsConnectionImpl::SSLSetCertVerifyCb(X509_STORE_CTX* ctx, void* opaque) {
+    auto* p = reinterpret_cast<TlsConnectionImpl*>(opaque);
+    return p->cert_verify_cb_(ctx);
+}
+
+// static
+int TlsConnectionImpl::SSLSetCertCb(SSL* ssl, void* opaque) {
+    auto* p = reinterpret_cast<TlsConnectionImpl*>(opaque);
+    return p->set_cert_cb_(ssl);
+}
+
+bool TlsConnectionImpl::AddTrustedCertificate(std::string_view cert) {
+    // Create X509 buffer from the certificate string
+    auto buf = X509FromBuffer(BufferFromPEM(cert));
+    if (buf == nullptr) {
+        LOG(ERROR) << "Failed to create a X509 buffer for the certificate.";
+        return false;
+    }
+    known_certificates_.push_back(std::move(buf));
+    return true;
+}
+
+void TlsConnectionImpl::SetCertVerifyCallback(CertVerifyCb cb) {
+    cert_verify_cb_ = cb;
+}
+
+void TlsConnectionImpl::SetCertificateCallback(SetCertCb cb) {
+    set_cert_cb_ = cb;
+}
+
+void TlsConnectionImpl::SetClientCAList(STACK_OF(X509_NAME) * ca_list) {
+    CHECK(role_ == Role::Server);
+    ca_list_.reset(ca_list != nullptr ? SSL_dup_CA_list(ca_list) : nullptr);
+}
+
+std::vector<uint8_t> TlsConnectionImpl::ExportKeyingMaterial(size_t length) {
+    if (ssl_.get() == nullptr) {
+        return {};
+    }
+
+    std::vector<uint8_t> out(length);
+    if (SSL_export_keying_material(ssl_.get(), out.data(), out.size(), kExportedKeyLabel,
+                                   sizeof(kExportedKeyLabel), nullptr, 0, false) == 0) {
+        return {};
+    }
+    return out;
+}
+
+void TlsConnectionImpl::EnableClientPostHandshakeCheck(bool enable) {
+    client_verify_post_handshake_ = enable;
+}
+
+TlsConnection::TlsError TlsConnectionImpl::GetFailureReason(int err) {
+    switch (ERR_GET_REASON(err)) {
+        case SSL_R_SSLV3_ALERT_BAD_CERTIFICATE:
+        case SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE:
+        case SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED:
+        case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED:
+        case SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN:
+        case SSL_R_TLSV1_ALERT_ACCESS_DENIED:
+        case SSL_R_TLSV1_ALERT_UNKNOWN_CA:
+        case SSL_R_TLSV1_CERTIFICATE_REQUIRED:
+            return TlsError::PeerRejectedCertificate;
+        case SSL_R_CERTIFICATE_VERIFY_FAILED:
+            return TlsError::CertificateRejected;
+        default:
+            return TlsError::UnknownFailure;
+    }
+}
+
+TlsConnection::TlsError TlsConnectionImpl::DoHandshake() {
+    int err = -1;
+    LOG(INFO) << "Starting adbwifi tls handshake";
+    ssl_ctx_.reset(SSL_CTX_new(TLS_method()));
+    // TODO: Remove set_max_proto_version() once external/boringssl is updated
+    // past
+    // https://boringssl.googlesource.com/boringssl/+/58d56f4c59969a23e5f52014e2651c76fea2f877
+    if (ssl_ctx_.get() == nullptr ||
+        !SSL_CTX_set_min_proto_version(ssl_ctx_.get(), TLS1_3_VERSION) ||
+        !SSL_CTX_set_max_proto_version(ssl_ctx_.get(), TLS1_3_VERSION)) {
+        LOG(ERROR) << "Failed to create SSL context";
+        return TlsError::UnknownFailure;
+    }
+
+    // Register user-supplied known certificates
+    for (auto const& cert : known_certificates_) {
+        if (X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx_.get()), cert.get()) == 0) {
+            LOG(ERROR) << "Unable to add certificates into the X509_STORE";
+            return TlsError::UnknownFailure;
+        }
+    }
+
+    // Custom certificate verification
+    if (cert_verify_cb_) {
+        SSL_CTX_set_cert_verify_callback(ssl_ctx_.get(), SSLSetCertVerifyCb, this);
+    }
+
+    // set select certificate callback, if any.
+    if (set_cert_cb_) {
+        SSL_CTX_set_cert_cb(ssl_ctx_.get(), SSLSetCertCb, this);
+    }
+
+    // Server-allowed client CA list
+    if (ca_list_ != nullptr) {
+        bssl::UniquePtr<STACK_OF(X509_NAME)> names(SSL_dup_CA_list(ca_list_.get()));
+        SSL_CTX_set_client_CA_list(ssl_ctx_.get(), names.release());
+    }
+
+    // Register our certificate and private key.
+    std::vector<CRYPTO_BUFFER*> cert_chain = {
+            cert_.get(),
+    };
+    if (!SSL_CTX_set_chain_and_key(ssl_ctx_.get(), cert_chain.data(), cert_chain.size(),
+                                   priv_key_.get(), nullptr)) {
+        LOG(ERROR) << "Unable to register the certificate chain file and private key ["
+                   << SSLErrorString() << "]";
+        Invalidate();
+        return TlsError::UnknownFailure;
+    }
+
+    SSL_CTX_set_verify(ssl_ctx_.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+
+    // Okay! Let's try to do the handshake!
+    ssl_.reset(SSL_new(ssl_ctx_.get()));
+    if (!SSL_set_fd(ssl_.get(), fd_.get())) {
+        LOG(ERROR) << "SSL_set_fd failed. [" << SSLErrorString() << "]";
+        return TlsError::UnknownFailure;
+    }
+    switch (role_) {
+        case Role::Server:
+            err = SSL_accept(ssl_.get());
+            break;
+        case Role::Client:
+            err = SSL_connect(ssl_.get());
+            break;
+    }
+    if (err != 1) {
+        LOG(ERROR) << "Handshake failed in SSL_accept/SSL_connect [" << SSLErrorString() << "]";
+        auto sslerr = ERR_get_error();
+        Invalidate();
+        return GetFailureReason(sslerr);
+    }
+
+    if (client_verify_post_handshake_ && role_ == Role::Client) {
+        uint8_t check;
+        // Try to peek one byte for any failures. This assumes on success that
+        // the server actually sends something.
+        err = SSL_peek(ssl_.get(), &check, 1);
+        if (err <= 0) {
+            LOG(ERROR) << "Post-handshake SSL_peek failed [" << SSLErrorString() << "]";
+            auto sslerr = ERR_get_error();
+            Invalidate();
+            return GetFailureReason(sslerr);
+        }
+    }
+
+    LOG(INFO) << "Handshake succeeded.";
+    return TlsError::Success;
+}
+
+void TlsConnectionImpl::Invalidate() {
+    ssl_.reset();
+    ssl_ctx_.reset();
+}
+
+std::vector<uint8_t> TlsConnectionImpl::ReadFully(size_t size) {
+    std::vector<uint8_t> buf(size);
+    if (!ReadFully(buf.data(), buf.size())) {
+        return {};
+    }
+
+    return buf;
+}
+
+bool TlsConnectionImpl::ReadFully(void* buf, size_t size) {
+    CHECK_GT(size, 0U);
+    if (!ssl_) {
+        LOG(ERROR) << "Tried to read on a null SSL connection";
+        return false;
+    }
+
+    size_t offset = 0;
+    uint8_t* p8 = reinterpret_cast<uint8_t*>(buf);
+    while (size > 0) {
+        int bytes_read =
+                SSL_read(ssl_.get(), p8 + offset, std::min(static_cast<size_t>(INT_MAX), size));
+        if (bytes_read <= 0) {
+            LOG(WARNING) << "SSL_read failed [" << SSLErrorString() << "]";
+            return false;
+        }
+        size -= bytes_read;
+        offset += bytes_read;
+    }
+    return true;
+}
+
+bool TlsConnectionImpl::WriteFully(std::string_view data) {
+    CHECK(!data.empty());
+    if (!ssl_) {
+        LOG(ERROR) << "Tried to read on a null SSL connection";
+        return false;
+    }
+
+    while (!data.empty()) {
+        int bytes_out = SSL_write(ssl_.get(), data.data(),
+                                  std::min(static_cast<size_t>(INT_MAX), data.size()));
+        if (bytes_out <= 0) {
+            LOG(WARNING) << "SSL_write failed [" << SSLErrorString() << "]";
+            return false;
+        }
+        data = data.substr(bytes_out);
+    }
+    return true;
+}
+}  // namespace
+
+// static
+std::unique_ptr<TlsConnection> TlsConnection::Create(TlsConnection::Role role,
+                                                     std::string_view cert,
+                                                     std::string_view priv_key, borrowed_fd fd) {
+    CHECK(!cert.empty());
+    CHECK(!priv_key.empty());
+
+    return std::make_unique<TlsConnectionImpl>(role, cert, priv_key, fd);
+}
+
+// static
+bool TlsConnection::SetCertAndKey(SSL* ssl, std::string_view cert, std::string_view priv_key) {
+    CHECK(ssl);
+    // Note: declaring these in local scope is okay because
+    // SSL_set_chain_and_key will increase the refcount (bssl::UpRef).
+    auto x509_cert = TlsConnectionImpl::BufferFromPEM(cert);
+    auto evp_pkey = TlsConnectionImpl::EvpPkeyFromPEM(priv_key);
+    if (x509_cert == nullptr || evp_pkey == nullptr) {
+        return false;
+    }
+
+    std::vector<CRYPTO_BUFFER*> cert_chain = {
+            x509_cert.get(),
+    };
+    if (!SSL_set_chain_and_key(ssl, cert_chain.data(), cert_chain.size(), evp_pkey.get(),
+                               nullptr)) {
+        LOG(ERROR) << "SSL_set_chain_and_key failed";
+        return false;
+    }
+
+    return true;
+}
+
+}  // namespace tls
+}  // namespace adb
diff --git a/code_coverage/Android.bp b/code_coverage/Android.bp
new file mode 100644
index 0000000..b51c802
--- /dev/null
+++ b/code_coverage/Android.bp
@@ -0,0 +1,83 @@
+
+prebuilt_etc {
+    name: "code_coverage.policy",
+    sub_dir: "seccomp_policy",
+    filename_from_src: true,
+    arch: {
+        arm: {
+            src: "empty_policy/code_coverage.arm.policy",
+            product_variables: {
+                native_coverage: {
+                    src: "seccomp_policy/code_coverage.arm.policy",
+                },
+            },
+        },
+        arm64: {
+            src: "empty_policy/code_coverage.arm64.policy",
+            product_variables: {
+                native_coverage: {
+                    src: "seccomp_policy/code_coverage.arm64.policy",
+                },
+            },
+        },
+        x86: {
+            src: "empty_policy/code_coverage.x86.policy",
+            product_variables: {
+                native_coverage: {
+                    src: "seccomp_policy/code_coverage.x86.policy",
+                },
+            },
+        },
+        x86_64: {
+            src: "empty_policy/code_coverage.x86_64.policy",
+            product_variables: {
+                native_coverage: {
+                    src: "seccomp_policy/code_coverage.x86_64.policy",
+                },
+            },
+        },
+    },
+    required: [
+        "code_coverage.policy.other",
+    ],
+}
+
+prebuilt_etc {
+    name: "code_coverage.policy.other",
+    sub_dir: "seccomp_policy",
+    filename_from_src: true,
+    arch: {
+        arm: {
+            src: "empty_policy/code_coverage.arm64.policy",
+            product_variables: {
+                native_coverage: {
+                    src: "seccomp_policy/code_coverage.arm64.policy",
+                },
+            },
+        },
+        arm64: {
+            src: "empty_policy/code_coverage.arm.policy",
+            product_variables: {
+                native_coverage: {
+                    src: "seccomp_policy/code_coverage.arm.policy",
+                },
+            },
+        },
+        x86: {
+            src: "empty_policy/code_coverage.x86_64.policy",
+            product_variables: {
+                native_coverage: {
+                    src: "seccomp_policy/code_coverage.x86_64.policy",
+                },
+            },
+        },
+        x86_64: {
+            src: "empty_policy/code_coverage.x86.policy",
+            product_variables: {
+                native_coverage: {
+                    src: "seccomp_policy/code_coverage.x86.policy",
+                },
+            },
+        },
+    },
+}
diff --git a/code_coverage/Android.mk b/code_coverage/Android.mk
deleted file mode 100644
index 80ab36b..0000000
--- a/code_coverage/Android.mk
+++ /dev/null
@@ -1,37 +0,0 @@
-# policies to allow processes inside minijail to dump code coverage information
-#
-
-LOCAL_PATH := $(call my-dir)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := code_coverage.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MULTILIB := both
-
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
-LOCAL_MODULE_STEM_32 := code_coverage.arm.policy
-LOCAL_MODULE_STEM_64 := code_coverage.arm64.policy
-endif
-
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64))
-LOCAL_MODULE_STEM_32 := code_coverage.x86.policy
-LOCAL_MODULE_STEM_64 := code_coverage.x86_64.policy
-endif
-
-# different files for different configurations
-ifeq ($(NATIVE_COVERAGE),true)
-LOCAL_SRC_FILES_arm := seccomp_policy/code_coverage.arm.policy
-LOCAL_SRC_FILES_arm64 := seccomp_policy/code_coverage.arm64.policy
-LOCAL_SRC_FILES_x86 := seccomp_policy/code_coverage.x86.policy
-LOCAL_SRC_FILES_x86_64 := seccomp_policy/code_coverage.x86_64.policy
-else
-LOCAL_SRC_FILES_arm := empty_policy/code_coverage.arm.policy
-LOCAL_SRC_FILES_arm64 := empty_policy/code_coverage.arm64.policy
-LOCAL_SRC_FILES_x86 := empty_policy/code_coverage.x86.policy
-LOCAL_SRC_FILES_x86_64 := empty_policy/code_coverage.x86_64.policy
-endif
-
-LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-include $(BUILD_PREBUILT)
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index c8df3e3..e3ce531 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -355,3 +355,49 @@
 
     init_rc: ["tombstoned/tombstoned.rc"],
 }
+
+prebuilt_etc {
+    name: "crash_dump.policy",
+    sub_dir: "seccomp_policy",
+    filename_from_src: true,
+    arch: {
+        arm: {
+            src: "seccomp_policy/crash_dump.arm.policy",
+        },
+        arm64: {
+            src: "seccomp_policy/crash_dump.arm64.policy",
+        },
+        x86: {
+            src: "seccomp_policy/crash_dump.x86.policy",
+        },
+        x86_64: {
+            src: "seccomp_policy/crash_dump.x86_64.policy",
+        },
+    },
+    required: [
+        "crash_dump.policy_other",
+    ],
+}
+
+
+// NB -- this installs "the other" architecture. (puts 32 bit config in on 64 bit device)
+// or at least that is the intention so that we get both of them populated
+prebuilt_etc {
+    name: "crash_dump.policy_other",
+    sub_dir: "seccomp_policy",
+    filename_from_src: true,
+    arch: {
+        arm: {
+            src: "seccomp_policy/crash_dump.arm64.policy",
+        },
+        arm64: {
+            src: "seccomp_policy/crash_dump.arm.policy",
+        },
+        x86: {
+            src: "seccomp_policy/crash_dump.x86_64.policy",
+        },
+        x86_64: {
+            src: "seccomp_policy/crash_dump.x86.policy",
+        },
+    },
+}
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk
deleted file mode 100644
index c03b41d..0000000
--- a/debuggerd/Android.mk
+++ /dev/null
@@ -1,24 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := crash_dump.policy
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MULTILIB := both
-
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
-LOCAL_MODULE_STEM_32 := crash_dump.arm.policy
-LOCAL_MODULE_STEM_64 := crash_dump.arm64.policy
-endif
-
-ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), x86 x86_64))
-LOCAL_MODULE_STEM_32 := crash_dump.x86.policy
-LOCAL_MODULE_STEM_64 := crash_dump.x86_64.policy
-endif
-
-LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
-LOCAL_SRC_FILES_arm := seccomp_policy/crash_dump.arm.policy
-LOCAL_SRC_FILES_arm64 := seccomp_policy/crash_dump.arm64.policy
-LOCAL_SRC_FILES_x86 := seccomp_policy/crash_dump.x86.policy
-LOCAL_SRC_FILES_x86_64 := seccomp_policy/crash_dump.x86_64.policy
-LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
-include $(BUILD_PREBUILT)
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index 42dda90..2099170 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -211,7 +211,7 @@
             }
         } else if (StartsWith(flag, "swapprio=")) {
             if (!ParseInt(arg, &entry->swap_prio)) {
-                LWARNING << "Warning: length= flag malformed: " << arg;
+                LWARNING << "Warning: swapprio= flag malformed: " << arg;
             }
         } else if (StartsWith(flag, "zramsize=")) {
             if (!arg.empty() && arg.back() == '%') {
diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp
index 2bc53d3..1fa1aa1 100644
--- a/fs_mgr/fs_mgr_overlayfs.cpp
+++ b/fs_mgr/fs_mgr_overlayfs.cpp
@@ -1026,6 +1026,8 @@
         }
 
         if (change) *change = true;
+    } else if (scratch_device->empty()) {
+        *scratch_device = GetBootScratchDevice();
     }
     return true;
 }
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 93bba68..24cbad7 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -80,9 +80,13 @@
     return &(*it);
 }
 
+auto verbose = false;
+
 void MyLogger(android::base::LogId id, android::base::LogSeverity severity, const char* tag,
               const char* file, unsigned int line, const char* message) {
-    fprintf(stderr, "%s\n", message);
+    if (verbose || severity == android::base::ERROR || message[0] != '[') {
+        fprintf(stderr, "%s\n", message);
+    }
     static auto logd = android::base::LogdLogger();
     logd(id, severity, tag, file, line, message);
 }
@@ -131,10 +135,14 @@
             {"fstab", required_argument, nullptr, 'T'},
             {"help", no_argument, nullptr, 'h'},
             {"reboot", no_argument, nullptr, 'R'},
+            {"verbose", no_argument, nullptr, 'v'},
             {0, 0, nullptr, 0},
     };
-    for (int opt; (opt = ::getopt_long(argc, argv, "hRT:", longopts, nullptr)) != -1;) {
+    for (int opt; (opt = ::getopt_long(argc, argv, "hRT:v", longopts, nullptr)) != -1;) {
         switch (opt) {
+            case 'h':
+                usage(SUCCESS);
+                break;
             case 'R':
                 can_reboot = true;
                 break;
@@ -145,13 +153,13 @@
                 }
                 fstab_file = optarg;
                 break;
+            case 'v':
+                verbose = true;
+                break;
             default:
                 LOG(ERROR) << "Bad Argument -" << char(opt);
                 usage(BADARG);
                 break;
-            case 'h':
-                usage(SUCCESS);
-                break;
         }
     }
 
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index a937b43..ba53615 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -232,7 +232,12 @@
     LOG(WARNING) << callstack_str.c_str();
     std::stringstream path;
     path << "/data/misc/snapshotctl_log/libsnapshot." << Now() << ".log";
-    android::base::WriteStringToFile(callstack_str.c_str(), path.str());
+    std::string path_str = path.str();
+    android::base::WriteStringToFile(callstack_str.c_str(), path_str);
+    if (chmod(path_str.c_str(), 0644) == -1) {
+        PLOG(WARNING) << "Unable to chmod 0644 "
+                      << ", file maybe dropped from bugreport:" << path_str;
+    }
 #endif
 
     if (!RemoveAllSnapshots(lock)) {
diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp
index d724be3..e35ad4b 100644
--- a/fs_mgr/libsnapshot/snapshotctl.cpp
+++ b/fs_mgr/libsnapshot/snapshotctl.cpp
@@ -61,7 +61,16 @@
         ss << kLogFilePath << "snapshotctl." << Now() << ".log";
         fd_.reset(TEMP_FAILURE_RETRY(
                 open(ss.str().c_str(),
-                     O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0660)));
+                     O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW | O_SYNC, 0644)));
+        if (fd_ == -1) {
+            PLOG(ERROR) << "Cannot open persistent log " << ss.str();
+            return;
+        }
+        // Explicitly chmod again because mode in open() may be masked by umask.
+        if (fchmod(fd_.get(), 0644) == -1) {
+            PLOG(ERROR) << "Cannot chmod 0644 persistent log " << ss.str();
+            return;
+        }
     }
     // Copy-contuctor needed to be converted to std::function.
     FileLogger(const FileLogger& other) { fd_.reset(dup(other.fd_)); }
@@ -108,7 +117,8 @@
 
     // 'snapshotctl merge' is stripped away from arguments to
     // Logger.
-    android::base::InitLogging(argv, MergeCmdLogger(argc - 2, argv + 2));
+    android::base::InitLogging(argv);
+    android::base::SetLogger(MergeCmdLogger(argc - 2, argv + 2));
 
     auto state = SnapshotManager::New()->InitiateMergeAndWait();
 
diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh
index e364436..cf324fe 100755
--- a/fs_mgr/tests/adb-remount-test.sh
+++ b/fs_mgr/tests/adb-remount-test.sh
@@ -902,7 +902,11 @@
   done
 
 # If reboot too soon after fresh flash, could trip device update failure logic
-wait_for_screen
+if ! wait_for_screen && ${screen_wait}; then
+  screen_wait=false
+  echo "${ORANGE}[  WARNING ]${NORMAL} not healthy, no launcher, skipping wait for screen" >&2
+fi
+
 # Can we test remount -R command?
 OVERLAYFS_BACKING="cache mnt/scratch"
 overlayfs_supported=true
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 7caf468..b85f23f 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -265,7 +265,9 @@
         mHealthInfo->batteryChargeTimeToFullNowSeconds =
                 getIntField(mHealthdConfig->batteryChargeTimeToFullNowPath);
 
-    mHealthInfo->batteryFullCapacityUah = props.batteryFullCharge;
+    if (!mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
+        mHealthInfo->batteryFullChargeDesignCapacityUah =
+                getIntField(mHealthdConfig->batteryFullChargeDesignCapacityUahPath);
 
     props.batteryTemperature = mBatteryFixedTemperature ?
         mBatteryFixedTemperature :
@@ -622,6 +624,13 @@
                         mHealthdConfig->batteryChargeTimeToFullNowPath = path;
                 }
 
+                if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty()) {
+                    path.clear();
+                    path.appendFormat("%s/%s/charge_full_design", POWER_SUPPLY_SYSFS_PATH, name);
+                    if (access(path, R_OK) == 0)
+                        mHealthdConfig->batteryFullChargeDesignCapacityUahPath = path;
+                }
+
                 if (mHealthdConfig->batteryCurrentAvgPath.isEmpty()) {
                     path.clear();
                     path.appendFormat("%s/%s/current_avg",
@@ -694,6 +703,8 @@
             KLOG_WARNING(LOG_TAG, "batteryCapacityLevelPath not found\n");
         if (mHealthdConfig->batteryChargeTimeToFullNowPath.isEmpty())
             KLOG_WARNING(LOG_TAG, "batteryChargeTimeToFullNowPath. not found\n");
+        if (mHealthdConfig->batteryFullChargeDesignCapacityUahPath.isEmpty())
+            KLOG_WARNING(LOG_TAG, "batteryFullChargeDesignCapacityUahPath. not found\n");
     }
 
     if (property_get("ro.boot.fake_battery", pval, NULL) > 0
diff --git a/healthd/include/healthd/healthd.h b/healthd/include/healthd/healthd.h
index 8ffb114..706c332 100644
--- a/healthd/include/healthd/healthd.h
+++ b/healthd/include/healthd/healthd.h
@@ -71,6 +71,7 @@
     android::String8 batteryCycleCountPath;
     android::String8 batteryCapacityLevelPath;
     android::String8 batteryChargeTimeToFullNowPath;
+    android::String8 batteryFullChargeDesignCapacityUahPath;
 
     int (*energyCounter)(int64_t *);
     int boot_min_cap;
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 21663e6..622e457 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -21,6 +21,7 @@
 #include <unistd.h>
 
 #include <chrono>
+#include <filesystem>
 #include <map>
 #include <memory>
 #include <set>
@@ -99,7 +100,11 @@
     void GetDmLinearMetadataDevice(std::set<std::string>* devices);
     bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata);
     void UseDsuIfPresent();
+    // Reads all fstab.avb_keys from the ramdisk for first-stage mount.
     void PreloadAvbKeys();
+    // Copies /avb/*.avbpubkey used for DSU from the ramdisk to /metadata for key
+    // revocation check by DSU installation service.
+    void CopyDsuAvbKeys();
 
     ListenerAction UeventCallback(const Uevent& uevent, std::set<std::string>* required_devices);
 
@@ -595,7 +600,12 @@
         return entry.mount_point == "/metadata";
     });
     if (metadata_partition != fstab_.end()) {
-        MountPartition(metadata_partition, true /* erase_same_mounts */);
+        if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
+            // Copies DSU AVB keys from the ramdisk to /metadata.
+            // Must be done before the following TrySwitchSystemAsRoot().
+            // Otherwise, ramdisk will be inaccessible after switching root.
+            CopyDsuAvbKeys();
+        }
     }
 
     if (!CreateLogicalPartitions()) return false;
@@ -663,6 +673,27 @@
     return true;
 }
 
+// Preserves /avb/*.avbpubkey to /metadata/gsi/dsu/avb/, so they can be used for
+// key revocation check by DSU installation service.  Note that failing to
+// copy files to /metadata is NOT fatal, because it is auxiliary to perform
+// public key matching before booting into DSU images on next boot. The actual
+// public key matching will still be done on next boot to DSU.
+void FirstStageMount::CopyDsuAvbKeys() {
+    std::error_code ec;
+    // Removing existing keys in gsi::kDsuAvbKeyDir as they might be stale.
+    std::filesystem::remove_all(gsi::kDsuAvbKeyDir, ec);
+    if (ec) {
+        LOG(ERROR) << "Failed to remove directory " << gsi::kDsuAvbKeyDir << ": " << ec.message();
+    }
+    // Copy keys from the ramdisk /avb/* to gsi::kDsuAvbKeyDir.
+    static constexpr char kRamdiskAvbKeyDir[] = "/avb";
+    std::filesystem::copy(kRamdiskAvbKeyDir, gsi::kDsuAvbKeyDir, ec);
+    if (ec) {
+        LOG(ERROR) << "Failed to copy " << kRamdiskAvbKeyDir << " into " << gsi::kDsuAvbKeyDir
+                   << ": " << ec.message();
+    }
+}
+
 void FirstStageMount::UseDsuIfPresent() {
     std::string error;
 
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 41007c1..c5b7576 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -65,6 +65,7 @@
 #include <android-base/parseint.h>
 #include <android-base/unique_fd.h>
 #include <fs_avb/fs_avb.h>
+#include <libgsi/libgsi.h>
 #include <selinux/android.h>
 
 #include "debug_ramdisk.h"
@@ -533,6 +534,8 @@
     selinux_android_restorecon("/apex", 0);
 
     selinux_android_restorecon("/linkerconfig", 0);
+
+    selinux_android_restorecon(gsi::kDsuAvbKeyDir, SELINUX_ANDROID_RESTORECON_RECURSE);
 }
 
 int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 2cf60e0..7f183c2 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -121,6 +121,10 @@
     ],
     logtags: ["event.logtags"],
     compile_multilib: "both",
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 ndk_headers {
diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h
index 0b38b6b..4aa439a 100644
--- a/libprocessgroup/include/processgroup/processgroup.h
+++ b/libprocessgroup/include/processgroup/processgroup.h
@@ -30,8 +30,7 @@
 bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path);
 
 bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache = false);
-bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
-                        bool use_fd_cache = false);
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
 
 #ifndef __ANDROID_VNDK__
 
diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp
index 6272664..d669ebe 100644
--- a/libprocessgroup/processgroup.cpp
+++ b/libprocessgroup/processgroup.cpp
@@ -115,9 +115,8 @@
     TaskProfiles::GetInstance().DropResourceCaching();
 }
 
-bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
-                        bool use_fd_cache) {
-    return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles, use_fd_cache);
+bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles) {
+    return TaskProfiles::GetInstance().SetProcessProfiles(uid, pid, profiles);
 }
 
 bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache) {
diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp
index 72f01af..4af4589 100644
--- a/libprocessgroup/task_profiles.cpp
+++ b/libprocessgroup/task_profiles.cpp
@@ -201,22 +201,6 @@
 }
 
 bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
-    std::lock_guard<std::mutex> lock(fd_mutex_);
-    if (IsFdValid()) {
-        // fd is cached, reuse it
-        if (!AddTidToCgroup(pid, fd_)) {
-            LOG(ERROR) << "Failed to add task into cgroup";
-            return false;
-        }
-        return true;
-    }
-
-    if (fd_ == FDS_INACCESSIBLE) {
-        // no permissions to access the file, ignore
-        return true;
-    }
-
-    // this is app-dependent path and fd is not cached or cached fd can't be used
     std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid);
     unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC)));
     if (tmp_fd < 0) {
@@ -270,7 +254,6 @@
 
 bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const {
     for (const auto& profile : profiles_) {
-        profile->EnableResourceCaching();
         if (!profile->ExecuteForProcess(uid, pid)) {
             PLOG(WARNING) << "ExecuteForProcess failed for aggregate profile";
         }
@@ -280,7 +263,6 @@
 
 bool ApplyProfileAction::ExecuteForTask(int tid) const {
     for (const auto& profile : profiles_) {
-        profile->EnableResourceCaching();
         if (!profile->ExecuteForTask(tid)) {
             PLOG(WARNING) << "ExecuteForTask failed for aggregate profile";
         }
@@ -288,6 +270,18 @@
     return true;
 }
 
+void ApplyProfileAction::EnableResourceCaching() {
+    for (const auto& profile : profiles_) {
+        profile->EnableResourceCaching();
+    }
+}
+
+void ApplyProfileAction::DropResourceCaching() {
+    for (const auto& profile : profiles_) {
+        profile->DropResourceCaching();
+    }
+}
+
 void TaskProfile::MoveTo(TaskProfile* profile) {
     profile->elements_ = std::move(elements_);
     profile->res_cached_ = res_cached_;
@@ -527,13 +521,10 @@
 }
 
 bool TaskProfiles::SetProcessProfiles(uid_t uid, pid_t pid,
-                                      const std::vector<std::string>& profiles, bool use_fd_cache) {
+                                      const std::vector<std::string>& profiles) {
     for (const auto& name : profiles) {
         TaskProfile* profile = GetProfile(name);
         if (profile != nullptr) {
-            if (use_fd_cache) {
-                profile->EnableResourceCaching();
-            }
             if (!profile->ExecuteForProcess(uid, pid)) {
                 PLOG(WARNING) << "Failed to apply " << name << " process profile";
             }
diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h
index a64ca50..28bc00c 100644
--- a/libprocessgroup/task_profiles.h
+++ b/libprocessgroup/task_profiles.h
@@ -163,6 +163,8 @@
 
     virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const;
     virtual bool ExecuteForTask(int tid) const;
+    virtual void EnableResourceCaching();
+    virtual void DropResourceCaching();
 
   private:
     std::vector<std::shared_ptr<TaskProfile>> profiles_;
@@ -176,8 +178,7 @@
     TaskProfile* GetProfile(const std::string& name) const;
     const ProfileAttribute* GetAttribute(const std::string& name) const;
     void DropResourceCaching() const;
-    bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles,
-                            bool use_fd_cache);
+    bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector<std::string>& profiles);
     bool SetTaskProfiles(int tid, const std::vector<std::string>& profiles, bool use_fd_cache);
 
   private:
diff --git a/libstats/pull/Android.bp b/libstats/pull/Android.bp
index 827e992..d74a36b 100644
--- a/libstats/pull/Android.bp
+++ b/libstats/pull/Android.bp
@@ -29,12 +29,14 @@
     export_include_dirs: ["include"],
     shared_libs: [
         "libbinder_ndk",
-        "libstatssocket",
+        "liblog",
         "statsd-aidl-ndk_platform",
     ],
     static_libs: [
-        "liblog",
         "libutils",
+        // TODO(b/149340100): Clean this up when libstatssocket is moved to the apex.
+        "libstatssocket",
+        "libcutils",
     ],
     // enumerate stable entry points for APEX use
     stubs: {
@@ -43,4 +45,8 @@
             "30",
         ],
     },
+    apex_available: [
+        "com.android.os.statsd",
+        "test_com.android.os.statsd",
+    ],
 }
diff --git a/libstats/socket/Android.bp b/libstats/socket/Android.bp
index f36b214..893ef28 100644
--- a/libstats/socket/Android.bp
+++ b/libstats/socket/Android.bp
@@ -25,6 +25,7 @@
         // TODO(b/145573568): Remove stats_event_list once stats_event
         // migration is complete.
         "stats_event_list.c",
+        "stats_socket.c",
         "statsd_writer.c",
     ],
     host_supported: true,
@@ -47,7 +48,13 @@
         versions: [
             "30",
         ],
-    }
+    },
+    apex_available: [
+        "com.android.os.statsd",
+        "test_com.android.os.statsd",
+        //TODO(b/149340100): Remove this once libstatssocket is only linked as shared.
+        "//apex_available:platform",
+    ],
 }
 
 cc_library_headers {
diff --git a/libstats/socket/include/stats_socket.h b/libstats/socket/include/stats_socket.h
new file mode 100644
index 0000000..5a75fc0
--- /dev/null
+++ b/libstats/socket/include/stats_socket.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/**
+ * Helpers to manage the statsd socket.
+ **/
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __CPLUSPLUS
+
+/**
+ * Closes the statsd socket file descriptor.
+ **/
+void AStatsSocket_close();
+#ifdef __cplusplus
+}
+#endif  // __CPLUSPLUS
diff --git a/libstats/socket/libstatssocket.map.txt b/libstats/socket/libstatssocket.map.txt
index e2e7ae3..5c13904 100644
--- a/libstats/socket/libstatssocket.map.txt
+++ b/libstats/socket/libstatssocket.map.txt
@@ -14,6 +14,7 @@
         AStatsEvent_writeAttributionChain; # apex # introduced=30
         AStatsEvent_addBoolAnnotation; # apex # introduced=30
         AStatsEvent_addInt32Annotation; # apex # introduced=30
+        AStatsSocket_close; # apex # introduced=30
     local:
         *;
 };
diff --git a/libstats/socket/stats_socket.c b/libstats/socket/stats_socket.c
new file mode 100644
index 0000000..09f8967
--- /dev/null
+++ b/libstats/socket/stats_socket.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "include/stats_socket.h"
+#include "stats_buffer_writer.h"
+
+void AStatsSocket_close() {
+    stats_log_close();
+}
diff --git a/libutils/Android.bp b/libutils/Android.bp
index efa4c41..3311793 100644
--- a/libutils/Android.bp
+++ b/libutils/Android.bp
@@ -159,6 +159,11 @@
             ],
         },
     },
+
+    apex_available: [
+        "//apex_available:anyapex",
+        "//apex_available:platform",
+    ],
 }
 
 cc_library {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 050f8a8..6dd2dc5 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -611,7 +611,7 @@
     mkdir /data/misc/installd 0700 root root
     mkdir /data/misc/apexdata 0711 root root
     mkdir /data/misc/apexrollback 0700 root root
-    mkdir /data/misc/snapshotctl_log 0770 root root
+    mkdir /data/misc/snapshotctl_log 0755 root root
     # create location to store pre-reboot information
     mkdir /data/misc/prereboot 0700 system system
 
@@ -764,13 +764,13 @@
     # IOCTLs on ashmem fds any more.
     setprop sys.use_memfd false
 
-    # Explicitly disable FUSE
-    setprop persist.sys.fuse false
-
     # Set fscklog permission
     chown root system /dev/fscklogs/log
     chmod 0770 /dev/fscklogs/log
 
+    # Enable FUSE by default
+    setprop persist.sys.fuse true
+
 # Switch between sdcardfs and FUSE depending on persist property
 # TODO: Move this to ro property before launch because FDE devices
 # interact with persistent properties differently during boot