Snap for 6001391 from 109adaa9660a1a330d9762f4e0e904abbc22e5e0 to qt-aml-networking-release

Change-Id: I2afaf47f4f028f44efa917ed45c128c9d3eaebab
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 73379cd..c84bd24 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -89,3 +89,4 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/recovery/root/product_services)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/debug_ramdisk/product_services)
 $(call add-clean-step, find $(PRODUCT_OUT) -type l -name "charger" -print0 | xargs -0 rm -f)
+$(call add-clean-step, rm -f $(PRODUCT_OUT)/system/bin/adbd)
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 375207b..51d5755 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -22,6 +22,9 @@
       "name": "libpackagelistparser_test"
     },
     {
+      "name": "libcutils_test"
+    },
+    {
       "name": "libprocinfo_test"
     },
     {
diff --git a/adb/Android.bp b/adb/Android.bp
index d14fe56..d605907 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -356,11 +356,12 @@
     generated_headers: ["platform_tools_version"],
 
     static_libs: [
-        "libadbconnection_server",
         "libdiagnose_usb",
     ],
 
     shared_libs: [
+        "libadbconnection_server",
+        "libadbd_auth",
         "libasyncio",
         "libbase",
         "libcrypto",
@@ -408,12 +409,13 @@
     ],
 
     static_libs: [
-        "libadbconnection_server",
         "libadbd_core",
         "libdiagnose_usb",
     ],
 
     shared_libs: [
+        "libadbconnection_server",
+        "libadbd_auth",
         "libasyncio",
         "libbase",
         "libcrypto",
@@ -460,6 +462,8 @@
     ],
 
     shared_libs: [
+        "libadbconnection_server",
+        "libadbd_auth",
         "libadbd_services",
         "libasyncio",
         "libbase",
@@ -492,23 +496,34 @@
         keep_symbols: true,
     },
 
-    shared_libs: [
+    stl: "libc++_static",
+    static_libs: [
         "libadbd",
+        "libadbd_auth",
         "libadbd_services",
+        "libasyncio",
         "libbase",
         "libcap",
-        "libcrypto",
+        "libcrypto_utils",
         "libcutils",
+        "libdiagnose_usb",
         "liblog",
+        "libmdnssd",
         "libminijail",
         "libselinux",
     ],
+
+    shared_libs: [
+        "libadbconnection_server",
+        "libcrypto",
+    ],
 }
 
 phony {
     name: "adbd_system_binaries",
     required: [
         "abb",
+        "libadbd_auth",
         "reboot",
         "set-verity-state",
     ]
@@ -522,53 +537,6 @@
 }
 
 cc_binary {
-    name: "static_adbd",
-    defaults: ["adbd_defaults", "host_adbd_supported"],
-
-    recovery_available: false,
-    static_executable: true,
-    host_supported: false,
-
-    srcs: [
-        "daemon/main.cpp",
-    ],
-
-    cflags: [
-        "-D_GNU_SOURCE",
-        "-Wno-deprecated-declarations",
-    ],
-
-    strip: {
-        keep_symbols: true,
-    },
-
-    static_libs: [
-        "libadbconnection_server",
-        "libadbd",
-        "libadbd_services",
-        "libasyncio",
-        "libavb_user",
-        "libbase",
-        "libbootloader_message",
-        "libcap",
-        "libcrypto_static",
-        "libcrypto_utils",
-        "libcutils",
-        "libdiagnose_usb",
-        "libext4_utils",
-        "libfec",
-        "libfec_rs",
-        "libfs_mgr",
-        "liblog",
-        "liblp",
-        "libmdnssd",
-        "libminijail",
-        "libselinux",
-        "libsquashfs_utils",
-    ],
-}
-
-cc_binary {
     name: "abb",
 
     defaults: ["adbd_defaults"],
@@ -615,6 +583,7 @@
 
     static_libs: [
         "libadbd",
+        "libadbd_auth",
         "libbase",
         "libcutils",
         "libcrypto_utils",
@@ -759,3 +728,39 @@
         "fastdeploy/testdata/sample.cd",
     ],
 }
+
+prebuilt_etc {
+    name: "com.android.adbd.ld.config.txt",
+    src: "apex/ld.config.txt",
+    filename: "ld.config.txt",
+    installable: false,
+}
+
+apex {
+    name: "com.android.adbd",
+    manifest: "apex/apex_manifest.json",
+
+    binaries: ["adbd"],
+    prebuilts: ["com.android.adbd.init.rc", "com.android.adbd.ld.config.txt"],
+
+    key: "com.android.adbd.key",
+    certificate: ":com.android.adbd.certificate",
+}
+
+apex_key {
+    name: "com.android.adbd.key",
+    public_key: "apex/com.android.adbd.avbpubkey",
+    private_key: "apex/com.android.adbd.pem",
+}
+
+android_app_certificate {
+    name: "com.android.adbd.certificate",
+    certificate: "apex/com.android.adbd",
+}
+
+prebuilt_etc {
+    name: "com.android.adbd.init.rc",
+    src: "apex/adbd.rc",
+    filename: "init.rc",
+    installable: false,
+}
diff --git a/adb/adb.cpp b/adb/adb.cpp
index 1ec145b..9b663be 100644
--- a/adb/adb.cpp
+++ b/adb/adb.cpp
@@ -300,6 +300,7 @@
     handle_online(t);
 #else
     if (!auth_required) {
+        LOG(INFO) << "authentication not required";
         handle_online(t);
         send_connect(t);
     } else {
diff --git a/adb/apex/adbd.rc b/adb/apex/adbd.rc
new file mode 100644
index 0000000..9cb072b
--- /dev/null
+++ b/adb/apex/adbd.rc
@@ -0,0 +1,6 @@
+service adbd /apex/com.android.adbd/bin/adbd --root_seclabel=u:r:su:s0
+    class core
+    socket adbd seqpacket 660 system system
+    disabled
+    override
+    seclabel u:r:adbd:s0
diff --git a/adb/apex/apex_manifest.json b/adb/apex/apex_manifest.json
new file mode 100644
index 0000000..ff2df12
--- /dev/null
+++ b/adb/apex/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+  "name": "com.android.adbd",
+  "version": 1
+}
diff --git a/adb/apex/com.android.adbd.avbpubkey b/adb/apex/com.android.adbd.avbpubkey
new file mode 100644
index 0000000..06235bd
--- /dev/null
+++ b/adb/apex/com.android.adbd.avbpubkey
Binary files differ
diff --git a/adb/apex/com.android.adbd.pem b/adb/apex/com.android.adbd.pem
new file mode 100644
index 0000000..2c9a860
--- /dev/null
+++ b/adb/apex/com.android.adbd.pem
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEAwUmO4l/ZdLhmBcBtpwDjih6z6bC7iZDPAVgnFVnYuYDRlVDA
+9OCDwv02Wwc/YCNzON7vt7JBk3o9wyJZpqY9HR1PUjk2DJa/wHtxbskmLcqsvcoh
+wZxmMkgx1mFyni/vQ0tCjjxYmDcnpoVmSntoPG4LBTZRwbgE2roYSuEi7q88Z9+t
+cFiQ5x7MqVTzUFsi1E+rpsxRaTt6Ly9DO71yR1gMTqONsSgmFm8f2HhUCiQzRh7H
+qLwk8eN5ZLPLVc1JBqo8swuH5pR9whR8HaYyQtK1VANRR9oVj3JpRXmyFUk8QjEn
+91I3sFV1lErdP1uh6xi6ewMBp+mQ+ccNFiNJs8PHVprzbEgX2ah45Tnge95ZwnkR
+V/5G/EwGBsggk/BcZjQyj0PExG6LmygR7lq8q4m9ODJj3cmNLZsZu8ukMBxf4Fim
+4/Y7lyaelW0FL+x3CR27wlIxLyIf/JfUNv/cFO/O2MHrDHYdHtCbvg8vpq1MZtDN
++gJIkYQNUfBEtGS4SkH3WWfNet3bcL5yFx5IVdwCY+n635jPA1fvr1vcIiKnyGUm
+zNE+jMOZkgk6lPPuDwllAX0D8nYTm1eBMCTAWCePO0QlcFHCT9j1/xKbFbjt/xYI
+0pXuOc8/1n61F5ybzH/91cS66gqmYUAekUiP0osTIZ7idVFJMoqpc9m7+rECAwEA
+AQKCAgEAkjg9WU89SCk/NNavnQj1GUXEwOKr3JOppdC0MFi5tQuYgSaH8jfuNZIs
+joxbCzWGMt2j5wl4xkJRes7/lyxnSyEjIoaZNsjL4qb/1tlggn+yUhkZlEfmn98x
+pIYvmS+WBwhmHwfT1cLTwgtkqK/W2PA+cgD3tF6rfXQOcIcEUCBMyB/UKws1A0Kv
+fOIA9ycaoBZtOk+SvtL5ybwtVoIoc4ROOydLR1uiBJKoOrA8kzdzenZKgIFkSYDW
+ErJY/l3AAsTCCoiMlIh84ldw1VUm7JpOBnJECOEYMl5Q+PfpGmU+qqxZGaYe7syX
+mElSOl3tjdY1LF3H4Oi2fd5xLfAgDgQjXcawKRYpImEgbqNfEUHW4BE/uVp0hHn+
+W0tCq9hvWoizhjxVq7oEfpdCXJBH0bTg9h3Ho2nuJMHTrUVbSWPTqNJn1xOi4Oxl
+vWsD5qjOOVw1e0P1dtxQ+6a8+rCL8LDvIthQC9Wpt0yXduEi/vUWiMFx2VbcSpNn
+5PB9HK7vvCpR/k0IocaTKt80D3m2svJCnfrekRx/7n//x8imrvtvaYNpoToTSN0q
+hPOpTNc77R4aARJNXm4sVHzGs6HUXsJfODJdjFtTuaDHjLvRoXZi2wFUVWBvIaFg
+/4+PHXjsfMkY15KULKn3f7Xs7K6rmINAb853zti3Qkllv1EeYoECggEBAP9t1Jxe
+hLKnVrJ5jJ0zCT0/ez6qM5cQG8YvXbVICmoAOQ+/NV6qjPABg5j8FuNhpyr45OuJ
+m1oISLgZPVCbIvYx3oZS4ekWUp9Z7jlDGzsWiBCkEUFLRzDLQRUl4bQMI2SWM+vD
+RL9AAM+NHJQ8LJN7ASNdSQw9ZinNCSByCZ52QjPCfRON0OPY4l1FJKHHymzBNXpe
+R5e9a1o9KEIhd7j+3YX9y8SOVrbUe6U8me5LZ6RY+pLB+cA/UHcSQK23hYAkMcvL
+MQny6B57P6rquzFZDG/OUOZWzWub2FSYTTmiYSHPAuB15FyWShs7h7+wK8y2xrSM
+Lq3FWHxzR1OK2HkCggEBAMG4KsAU/lp9rQhNpdw2NQXqbDLgHy09BFMOOWhyp2/Z
+2lbDo9aP746Q56HAfRRgx5oAAtr3SxeN/R/uEJLYzzDU+SrG4TQO/TZ3DPZOAVYM
+oESWG/HXLN4Hw6j4iWt2NvqpnSVJrvYr6zar/QxRHOMwnUoUV3ugmzUkqFC/Nwmm
+nMGJbTQbEha8OyatfwejmhrCkbQMBiCk0AQmgLybUxs2ckGs5jibau7VqXVxly0f
+WkAsWE/qfybQl4oyBhGCFNObr3Co/PHTaD4ACFQQvaEEF4bTuh6wP+MIgJKxL8IB
+SkrKWO5PFbJWY5lacnNMe7ITrWy60HukLlJe5or5lfkCggEBAP3Rwghw1CRDrR9F
+Mbm0UWYPgwTOVN20ICVcRB40LEURW6KOOxaLG+oTVxXay1PAYkGNes2jvEBHIxvt
+2MQUpTVIcPvBuMPKbufykYtNZ+3bgfInVw4vI9sU3uOI9TPZLAJ0T7vkGpiBnUyh
+yNh0w0b6YDMoK8KB8Ndw67TWHUDd+wM8LNYVgpInnylX4ALzae+QPvgOX84laFwP
+kcXFRBcNDExt2uLDHuAnXYbhJYVqYN8rnDPhlbC4OdlYxfTZ/UtMrD769wwP2SER
+ED9jagirmHQx7Ko3b4GTJ/FINtUiyqqx7wXloLtwjMtq6IZPJfcTWXloI6qCBGAG
+ncYinuECggEAfZeiF8BEm3RpTz3QL3HxdHFkTqOhctnhSNuq+n2C8nBCLwhN21ic
+DkkB84txTFnmboBdWYsEYzQKDL5yflIUGeup00L3VKH3Jm2OuM0f7qLm8TCE04kW
+rKhKAO2JYmNVB7QZjsgzp6QXre1ZdLfNy7mD8Dg584vPtGecvCUMULR1YsBvTV3T
+n2vPyaan+dLmoTzN6/XzrwxLVLWFt0HYYoctEkk/RSn17PwXDm5jfbya7YoSg1Vb
+tFV+Oflul8FHMV35I0hcHYhbR/8LZz0nRBH8EsyIGUdZVB76BKDdfqEJgm2ntHEP
+dvytPAo4s2m9tFkvkZOYgOCTq5GdVDK2OQKCAQAsz+y9rDcqFciCESu4IHzmtckT
+0kwP2W5ds5hzUjbY0Y2AKTx2oHNOFak6WW5vxN0+OIn37SNK3RBStPWJiigut4R4
+rGrZM4pijm53s3cWzd0h8XyLGisl2zORu8gD2IQLkQf79F3lEZHGA+J0mkSHB85N
+IuqReFzL6cfOToNd+8WYjMgJcXmVuKiCV1FRK3jrqNpXO2cLtnhFvQMxRUAYU4j+
+2MIdBFVeMq5ftMMOBS21hM9cNLlOzoSN2HmK+ZkmrlTCK0G9lmF427/lqXTmWLed
+sspOUbOLfBOwxdCCc9JUxz5KggKWcDcTqX25M0mv09rpuCxIEg8lez1Ax0if
+-----END RSA PRIVATE KEY-----
diff --git a/adb/apex/com.android.adbd.pk8 b/adb/apex/com.android.adbd.pk8
new file mode 100644
index 0000000..cdddc3f
--- /dev/null
+++ b/adb/apex/com.android.adbd.pk8
Binary files differ
diff --git a/adb/apex/com.android.adbd.x509.pem b/adb/apex/com.android.adbd.x509.pem
new file mode 100644
index 0000000..bb85c1d
--- /dev/null
+++ b/adb/apex/com.android.adbd.x509.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIGHzCCBAegAwIBAgIUW8npFHXBP+wsEAesGMBxaV7TScAwDQYJKoZIhvcNAQEL
+BQAwgZ0xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
+DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
+b2lkMRkwFwYDVQQDDBBjb20uYW5kcm9pZC5hZGJkMSIwIAYJKoZIhvcNAQkBFhNh
+bmRyb2lkQGFuZHJvaWQuY29tMCAXDTE5MDgxNTE5MzkxM1oYDzQ3NTcwNzExMTkz
+OTEzWjCBnTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNV
+BAcMDU1vdW50YWluIFZpZXcxEDAOBgNVBAoMB0FuZHJvaWQxEDAOBgNVBAsMB0Fu
+ZHJvaWQxGTAXBgNVBAMMEGNvbS5hbmRyb2lkLmFkYmQxIjAgBgkqhkiG9w0BCQEW
+E2FuZHJvaWRAYW5kcm9pZC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQC6zbUeWi5vNA6vCC4FBrJQ9re4UexP6TabsDYvWpFBoCluvMkT2ZRmpXMF
+W7EzQ5VmuUvZgLYVHuJmnvHIV3uaRc2VE1SV+spjWTRt+6DtsAN7irR5K66POWMp
++tr5hASdQBVOJdebimsepy0pH6sXREvanrrFzkSM/2Ho0unlwWJ5Y4jcnvdkVHI5
+Ks0vifLmX4y5mYgv1dcXYWzyYx39f8HyePv0cjRhYXiIEYZ49KWU4MjryvQe/mAu
+MQuMp901BLps2W1+oKyPPA4DV69KUXgF66RFfsjjkJJ/CSeQGzTuez+UWzFk3Duc
+6MmbiL1LTki3vyyVtjW1rYFO2s+M6Pa5NZWHgA55uUxiJ987WPyK9lWnMsY6YeKa
+FDBfS1JUzXGPzVncgM7LLvzAEibLdhjII88NsJvzPoHK0SluSn+E7t7iGO1fTjkD
+Js94iUJAp8OQ4GwkcTVgtEAR+NXzownNjHJ6qpiq6tXRqXdBqSat/glf01AgNDtz
+9AGeW7Mz6FqTdOzg3U4lu77+CGd3SZTuQk8C8PUDNhqhQX5H2qhr90bakGaXuYfE
+rWFzIjrVdJIznV1BimOCay5HyyHab4FWlVhAvslEQb2BpHRyi2lhe0laupOpmN44
+LzfjFM18bi2GashIi2OQuYDyAeT5mGtR2g8mC7g44H6dH+wTfQIDAQABo1MwUTAd
+BgNVHQ4EFgQU7lyyxPO5SOOh9a5O0l4+RjckcgcwHwYDVR0jBBgwFoAU7lyyxPO5
+SOOh9a5O0l4+RjckcgcwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
+AgEAStsOy8bkbZg/Ygx47bPkLSz0cJIvATxTChUGOabkz+brLis88ABVWVP0IXps
+tlLlZR5cjXBJguE7GJXzKPWzQZuB8+YwcGHG6QDFpfdMeGrxPDhwNfGy236ArVnx
+K0v1IIxoZRZ0P7aubk3xwUAPgsmT5ayZCKu+dqlEy5B6ioKEsr7Y2RRT/8ifERNm
+cjS9AhcyWrp4R3cjy2iA/RpdsPFwE5ac3I+GtUB4D2up5aDMsy85i9t2/1kuTUaA
+9UHwGXCpcqP8f8BqeLzuxDzYkAvkntlNxbXn1cbn+dTRIOCBoDbtSeqtxhWooOUH
+RQROeRsB7iicdYJJRge0+WyR+216AKUSQPE6/rT0Ifr06ZRwi22/YyySpwuO3SNA
++yWffh+f4h31Dz+p6pu8wjbMDkq4LnCWyjLwfF/yhvWhwwm5+KPAEhvJABeHQc+3
+cslOC9dlXJm9sPoUC7ghmUiFsCmN2hIzQrr2QoK0Obh0AGexOvOAw9cqtOdZQncB
+bqC8c4sVYScVxwDWkg0lNfRMC5boPjBsl7+M2CC1ukgVpXTyDOEjMWILrBXfYCDX
+unBH3kbKQOfL5RT0nE1Lkt1rn5qAWMJg4mvS4QuIurbRtEoj3QYQadF9md4qJXs0
+TvqvY8iEC4xrWU2SQn1K3PutXgaLP9/b6Cy1SBrhBX+AC5s=
+-----END CERTIFICATE-----
diff --git a/adb/apex/ld.config.txt b/adb/apex/ld.config.txt
new file mode 100644
index 0000000..85f9b29
--- /dev/null
+++ b/adb/apex/ld.config.txt
@@ -0,0 +1,51 @@
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Bionic loader config file for the adbd APEX.
+
+dir.adbd = /apex/com.android.adbd/bin/
+
+[adbd]
+additional.namespaces = platform,art,adbd
+
+namespace.default.isolated = true
+namespace.default.links = art,adbd,platform
+namespace.default.link.art.shared_libs = libadbconnection_server.so
+namespace.default.link.platform.allow_all_shared_libs = true
+namespace.default.link.adbd.allow_all_shared_libs = true
+
+###############################################################################
+# "adbd" APEX namespace
+###############################################################################
+namespace.adbd.isolated = true
+namespace.adbd.search.paths = /apex/com.android.adbd/${LIB}
+namespace.adbd.asan.search.paths = /apex/com.android.adbd/${LIB}
+namespace.adbd.links = platform
+namespace.adbd.link.platform.allow_all_shared_libs = true
+
+###############################################################################
+# "art" APEX namespace: used for libadbdconnection_server
+###############################################################################
+namespace.art.isolated = true
+namespace.art.search.paths = /apex/com.android.art/${LIB}
+namespace.art.asan.search.paths = /apex/com.android.art/${LIB}
+namespace.art.links = platform
+namespace.art.link.platform.allow_all_shared_libs = true
+
+###############################################################################
+# "platform" namespace: used for NDK libraries, and libadbd_auth
+###############################################################################
+namespace.platform.isolated = true
+namespace.platform.search.paths = /system/${LIB}
+namespace.platform.asan.search.paths = /data/asan/system/${LIB}
+
+# /system/lib/libc.so, etc are symlinks to
+# /apex/com.android.runtime/lib/bionic/libc.so, etc. Add the path to the
+# permitted paths because linker uses realpath(3) to check the accessibility
+# of the lib. We could add this to search.paths instead but that makes the
+# resolution of bionic libs be dependent on the order of /system/lib and
+# /apex/.../lib/bionic in search.paths. If the latter is after the former,
+# then the latter is never tried because libc.so is always found in
+# /system/lib but fails to pass the accessibility test because of its realpath.
+# It's better to not depend on the ordering if possible.
+namespace.platform.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
+namespace.platform.asan.permitted.paths = /apex/com.android.runtime/${LIB}/bionic
diff --git a/adb/client/fastdeploy.cpp b/adb/client/fastdeploy.cpp
index bdc9e56..5fa0edb 100644
--- a/adb/client/fastdeploy.cpp
+++ b/adb/client/fastdeploy.cpp
@@ -101,17 +101,12 @@
 
 static void push_to_device(const void* data, size_t byte_count, const char* dst, bool sync) {
     std::vector<const char*> srcs;
-    {
-        TemporaryFile temp;
-        android::base::WriteFully(temp.fd, data, byte_count);
-        srcs.push_back(temp.path);
-
-        // On Windows, the file needs to be flushed before pushing to device.
-        // closing the file flushes its content, but we still need to remove it after push.
-        // FileDeleter does exactly that.
-        temp.DoNotRemove();
-    }
-    FileDeleter temp_deleter(srcs.back());
+    TemporaryFile tf;
+    android::base::WriteFully(tf.fd, data, byte_count);
+    srcs.push_back(tf.path);
+    // On Windows, the file needs to be flushed before pushing to device,
+    // but can't be removed until after the push.
+    unix_close(tf.release());
 
     if (!do_sync_push(srcs, dst, sync)) {
         error_exit("Failed to push fastdeploy agent to device.");
diff --git a/adb/client/usb_linux.cpp b/adb/client/usb_linux.cpp
index 24e722e..343e7b5 100644
--- a/adb/client/usb_linux.cpp
+++ b/adb/client/usb_linux.cpp
@@ -609,6 +609,7 @@
     while (true) {
         // TODO: Use inotify.
         find_usb_device("/dev/bus/usb", register_device);
+        adb_notify_device_scan_complete();
         kick_disconnected_devices();
         std::this_thread::sleep_for(1s);
     }
diff --git a/adb/client/usb_osx.cpp b/adb/client/usb_osx.cpp
index 5c0da47..7207ca7 100644
--- a/adb/client/usb_osx.cpp
+++ b/adb/client/usb_osx.cpp
@@ -461,6 +461,7 @@
             std::this_thread::sleep_for(100ms);
         }
 
+        adb_notify_device_scan_complete();
         initialized = true;
     }
 }
diff --git a/adb/client/usb_windows.cpp b/adb/client/usb_windows.cpp
index f23c3a5..197c6fa 100644
--- a/adb/client/usb_windows.cpp
+++ b/adb/client/usb_windows.cpp
@@ -172,6 +172,7 @@
 
     while (true) {
         find_devices();
+        adb_notify_device_scan_complete();
         std::this_thread::sleep_for(1s);
     }
 }
diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp
index 7a3a4f5..2e84ce6 100644
--- a/adb/daemon/auth.cpp
+++ b/adb/daemon/auth.cpp
@@ -31,6 +31,7 @@
 #include <algorithm>
 #include <memory>
 
+#include <adbd_auth.h>
 #include <android-base/file.h>
 #include <android-base/strings.h>
 #include <crypto_utils/android_pubkey.h>
@@ -38,85 +39,57 @@
 #include <openssl/rsa.h>
 #include <openssl/sha.h>
 
-static fdevent* listener_fde = nullptr;
-static fdevent* framework_fde = nullptr;
-static auto& framework_mutex = *new std::mutex();
-static int framework_fd GUARDED_BY(framework_mutex) = -1;
-static auto& connected_keys GUARDED_BY(framework_mutex) = *new std::vector<std::string>;
+static AdbdAuthContext* auth_ctx;
 
 static void adb_disconnected(void* unused, atransport* t);
 static struct adisconnect adb_disconnect = {adb_disconnected, nullptr};
-static atransport* adb_transport;
-static bool needs_retry = false;
 
 bool auth_required = true;
 
-bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig,
-                      std::string* auth_key) {
-    static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr };
-
-    for (const auto& path : key_paths) {
-        if (access(path, R_OK) == 0) {
-            LOG(INFO) << "Loading keys from " << path;
-            std::string content;
-            if (!android::base::ReadFileToString(path, &content)) {
-                PLOG(ERROR) << "Couldn't read " << path;
-                continue;
-            }
-
-            for (const auto& line : android::base::Split(content, "\n")) {
-                if (line.empty()) continue;
-                *auth_key = line;
-                // TODO: do we really have to support both ' ' and '\t'?
-                char* sep = strpbrk(const_cast<char*>(line.c_str()), " \t");
-                if (sep) *sep = '\0';
-
-                // b64_pton requires one additional byte in the target buffer for
-                // decoding to succeed. See http://b/28035006 for details.
-                uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
-                if (b64_pton(line.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
-                    LOG(ERROR) << "Invalid base64 key " << line.c_str() << " in " << path;
-                    continue;
-                }
-
-                RSA* key = nullptr;
-                if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
-                    LOG(ERROR) << "Failed to parse key " << line.c_str() << " in " << path;
-                    continue;
-                }
-
-                bool verified =
-                    (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
-                                reinterpret_cast<const uint8_t*>(sig.c_str()), sig.size(),
-                                key) == 1);
-                RSA_free(key);
-                if (verified) return true;
-            }
-        }
-    }
-    auth_key->clear();
-    return false;
+static void IteratePublicKeys(std::function<bool(std::string_view public_key)> f) {
+    adbd_auth_get_public_keys(
+            auth_ctx,
+            [](const char* public_key, size_t len, void* arg) {
+                return (*static_cast<decltype(f)*>(arg))(std::string_view(public_key, len));
+            },
+            &f);
 }
 
-static bool adbd_send_key_message_locked(std::string_view msg_type, std::string_view key)
-        REQUIRES(framework_mutex) {
-    if (framework_fd < 0) {
-        LOG(ERROR) << "Client not connected to send msg_type " << msg_type;
-        return false;
-    }
-    std::string msg = std::string(msg_type) + std::string(key);
-    int msg_len = msg.length();
-    if (msg_len >= static_cast<int>(MAX_FRAMEWORK_PAYLOAD)) {
-        LOG(ERROR) << "Key too long (" << msg_len << ")";
-        return false;
-    }
+bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig,
+                      std::string* auth_key) {
+    bool authorized = false;
+    auth_key->clear();
 
-    LOG(DEBUG) << "Sending '" << msg << "'";
-    if (!WriteFdExactly(framework_fd, msg.c_str(), msg_len)) {
-        PLOG(ERROR) << "Failed to write " << msg_type;
-        return false;
-    }
-    return true;
+    IteratePublicKeys([&](std::string_view public_key) {
+        // TODO: do we really have to support both ' ' and '\t'?
+        std::vector<std::string> split = android::base::Split(std::string(public_key), " \t");
+        uint8_t keybuf[ANDROID_PUBKEY_ENCODED_SIZE + 1];
+        const std::string& pubkey = split[0];
+        if (b64_pton(pubkey.c_str(), keybuf, sizeof(keybuf)) != ANDROID_PUBKEY_ENCODED_SIZE) {
+            LOG(ERROR) << "Invalid base64 key " << pubkey;
+            return true;
+        }
+
+        RSA* key = nullptr;
+        if (!android_pubkey_decode(keybuf, ANDROID_PUBKEY_ENCODED_SIZE, &key)) {
+            LOG(ERROR) << "Failed to parse key " << pubkey;
+            return true;
+        }
+
+        bool verified =
+                (RSA_verify(NID_sha1, reinterpret_cast<const uint8_t*>(token), token_size,
+                            reinterpret_cast<const uint8_t*>(sig.c_str()), sig.size(), key) == 1);
+        RSA_free(key);
+        if (verified) {
+            *auth_key = public_key;
+            authorized = true;
+            return false;
+        }
+
+        return true;
+    });
+
+    return authorized;
 }
 
 static bool adbd_auth_generate_token(void* token, size_t token_size) {
@@ -127,113 +100,6 @@
     return okay;
 }
 
-static void adb_disconnected(void* unused, atransport* t) {
-    LOG(INFO) << "ADB disconnect";
-    adb_transport = nullptr;
-    needs_retry = false;
-    {
-        std::lock_guard<std::mutex> lock(framework_mutex);
-        if (framework_fd >= 0) {
-            adbd_send_key_message_locked("DC", t->auth_key);
-        }
-        connected_keys.erase(std::remove(connected_keys.begin(), connected_keys.end(), t->auth_key),
-                             connected_keys.end());
-    }
-}
-
-static void framework_disconnected() {
-    LOG(INFO) << "Framework disconnect";
-    if (framework_fde) {
-        fdevent_destroy(framework_fde);
-        {
-            std::lock_guard<std::mutex> lock(framework_mutex);
-            framework_fd = -1;
-        }
-    }
-}
-
-static void adbd_auth_event(int fd, unsigned events, void*) {
-    if (events & FDE_READ) {
-        char response[2];
-        int ret = unix_read(fd, response, sizeof(response));
-        if (ret <= 0) {
-            framework_disconnected();
-        } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') {
-            if (adb_transport) {
-                adbd_auth_verified(adb_transport);
-            }
-        }
-    }
-}
-
-void adbd_auth_confirm_key(atransport* t) {
-    if (!adb_transport) {
-        adb_transport = t;
-        t->AddDisconnect(&adb_disconnect);
-    }
-
-    {
-        std::lock_guard<std::mutex> lock(framework_mutex);
-        if (framework_fd < 0) {
-            LOG(ERROR) << "Client not connected";
-            needs_retry = true;
-            return;
-        }
-
-        adbd_send_key_message_locked("PK", t->auth_key);
-    }
-}
-
-static void adbd_auth_listener(int fd, unsigned events, void* data) {
-    int s = adb_socket_accept(fd, nullptr, nullptr);
-    if (s < 0) {
-        PLOG(ERROR) << "Failed to accept";
-        return;
-    }
-
-    {
-        std::lock_guard<std::mutex> lock(framework_mutex);
-        if (framework_fd >= 0) {
-            LOG(WARNING) << "adb received framework auth socket connection again";
-            framework_disconnected();
-        }
-
-        framework_fd = s;
-        framework_fde = fdevent_create(framework_fd, adbd_auth_event, nullptr);
-        fdevent_add(framework_fde, FDE_READ);
-
-        if (needs_retry) {
-            needs_retry = false;
-            send_auth_request(adb_transport);
-        }
-
-        // if a client connected before the framework was available notify the framework of the
-        // connected key now.
-        if (!connected_keys.empty()) {
-            for (const auto& key : connected_keys) {
-                adbd_send_key_message_locked("CK", key);
-            }
-        }
-    }
-}
-
-void adbd_notify_framework_connected_key(atransport* t) {
-    if (!adb_transport) {
-        adb_transport = t;
-        t->AddDisconnect(&adb_disconnect);
-    }
-    {
-        std::lock_guard<std::mutex> lock(framework_mutex);
-        if (std::find(connected_keys.begin(), connected_keys.end(), t->auth_key) ==
-            connected_keys.end()) {
-            connected_keys.push_back(t->auth_key);
-        }
-        if (framework_fd >= 0) {
-            adbd_send_key_message_locked("CK", t->auth_key);
-        }
-    }
-}
-
 void adbd_cloexec_auth_socket() {
     int fd = android_get_control_socket("adbd");
     if (fd == -1) {
@@ -243,20 +109,23 @@
     fcntl(fd, F_SETFD, FD_CLOEXEC);
 }
 
+static void adbd_auth_key_authorized(void* arg, uint64_t id) {
+    LOG(INFO) << "adb client authorized";
+    auto* transport = static_cast<atransport*>(arg);
+    transport->auth_id = id;
+    adbd_auth_verified(transport);
+}
+
 void adbd_auth_init(void) {
-    int fd = android_get_control_socket("adbd");
-    if (fd == -1) {
-        PLOG(ERROR) << "Failed to get adbd socket";
-        return;
-    }
-
-    if (listen(fd, 4) == -1) {
-        PLOG(ERROR) << "Failed to listen on '" << fd << "'";
-        return;
-    }
-
-    listener_fde = fdevent_create(fd, adbd_auth_listener, nullptr);
-    fdevent_add(listener_fde, FDE_READ);
+    AdbdAuthCallbacks cb;
+    cb.version = 1;
+    cb.callbacks.v1.key_authorized = adbd_auth_key_authorized;
+    auth_ctx = adbd_auth_new(&cb);
+    std::thread([]() {
+        adb_thread_setname("adbd auth");
+        adbd_auth_run(auth_ctx);
+        LOG(FATAL) << "auth thread terminated";
+    }).detach();
 }
 
 void send_auth_request(atransport* t) {
@@ -280,3 +149,18 @@
     handle_online(t);
     send_connect(t);
 }
+
+static void adb_disconnected(void* unused, atransport* t) {
+    LOG(INFO) << "ADB disconnect";
+    adbd_auth_notify_disconnect(auth_ctx, t->auth_id);
+}
+
+void adbd_auth_confirm_key(atransport* t) {
+    LOG(INFO) << "prompting user to authorize key";
+    t->AddDisconnect(&adb_disconnect);
+    adbd_auth_prompt_user(auth_ctx, t->auth_key.data(), t->auth_key.size(), t);
+}
+
+void adbd_notify_framework_connected_key(atransport* t) {
+    adbd_auth_notify_auth(auth_ctx, t->auth_key.data(), t->auth_key.size());
+}
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 9ebab74..7277cc8 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -205,7 +205,11 @@
     // descriptor will always be open.
     adbd_cloexec_auth_socket();
 
-#if defined(ALLOW_ADBD_NO_AUTH)
+#if defined(__ANDROID_RECOVERY__)
+    if (is_device_unlocked() || __android_log_is_debuggable()) {
+        auth_required = false;
+    }
+#elif defined(ALLOW_ADBD_NO_AUTH)
     // If ro.adb.secure is unset, default to no authentication required.
     auth_required = android::base::GetBoolProperty("ro.adb.secure", false);
 #elif defined(__ANDROID__)
@@ -214,8 +218,6 @@
     }
 #endif
 
-    adbd_auth_init();
-
     // Our external storage path may be different than apps, since
     // we aren't able to bind mount after dropping root.
     const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
@@ -230,6 +232,9 @@
     drop_privileges(server_port);
 #endif
 
+    // adbd_auth_init will spawn a thread, so we need to defer it until after selinux transitions.
+    adbd_auth_init();
+
     bool is_usb = false;
 
 #if defined(__ANDROID__)
diff --git a/adb/fastdeploy/deployagent/test/com/android/fastdeploy/FastDeployTest.java b/adb/fastdeploy/deployagent/test/com/android/fastdeploy/FastDeployTest.java
index ef6ccae..4aa2f79 100644
--- a/adb/fastdeploy/deployagent/test/com/android/fastdeploy/FastDeployTest.java
+++ b/adb/fastdeploy/deployagent/test/com/android/fastdeploy/FastDeployTest.java
@@ -20,7 +20,9 @@
 import static org.junit.Assert.assertTrue;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
+import com.android.ddmlib.Log.LogLevel;
 import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
@@ -68,17 +70,19 @@
     }
 
     private boolean isAppInstalled(String packageName) throws DeviceNotAvailableException {
-        final String commandResult = getDevice().executeShellCommand("pm list packages");
+        final String result = getDevice().executeShellCommand("pm list packages");
+        CLog.logAndDisplay(LogLevel.INFO, result);
         final int prefixLength = "package:".length();
-        return Arrays.stream(commandResult.split("\\r?\\n"))
+        return Arrays.stream(result.split("\\r?\\n"))
                 .anyMatch(line -> line.substring(prefixLength).equals(packageName));
     }
 
     // Mostly copied from PkgInstallSignatureVerificationTest.java.
-    private String fastInstallPackage(String apkPath)
+    private void fastInstallPackage(String apkPath)
             throws IOException, DeviceNotAvailableException {
-        return getDevice().executeAdbCommand("install", "-t", "--fastdeploy", "--force-agent",
+        String result = getDevice().executeAdbCommand("install", "-t", "--fastdeploy", "--force-agent",
                 apkPath);
+        CLog.logAndDisplay(LogLevel.INFO, result);
     }
 }
 
diff --git a/adb/transport.h b/adb/transport.h
index c38cb1d..89d76b8 100644
--- a/adb/transport.h
+++ b/adb/transport.h
@@ -277,8 +277,11 @@
     std::string device;
     std::string devpath;
 
+#if !ADB_HOST
     // Used to provide the key to the framework.
     std::string auth_key;
+    uint64_t auth_id;
+#endif
 
     bool IsTcpDevice() const { return type == kTransportLocal; }
 
diff --git a/base/README.md b/base/README.md
new file mode 100644
index 0000000..2ef5c10
--- /dev/null
+++ b/base/README.md
@@ -0,0 +1,42 @@
+# libbase
+
+## Who is this library for?
+
+This library is a collection of convenience functions to make common tasks
+easier and less error-prone.
+
+In this context, "error-prone" covers both "hard to do correctly" and
+"hard to do with good performance", but as a general purpose library,
+libbase's primary focus is on making it easier to do things easily and
+correctly when a compromise has to be made between "simplest API" on the
+one hand and "fastest implementation" on the other. Though obviously
+the ideal is to have both.
+
+## Should my routine be added?
+
+The intention is to cover the 80% use cases, not be all things to all users.
+
+If you have a routine that's really useful in your project,
+congratulations. But that doesn't mean it should be here rather than
+just in your project.
+
+The question for libbase is "should everyone be doing this?"/"does this
+make everyone's code cleaner/safer?". Historically we've considered the
+bar for inclusion to be "are there at least three *unrelated* projects
+that would be cleaned up by doing so".
+
+If your routine is actually something from a future C++ standard (that
+isn't yet in libc++), or it's widely used in another library, that helps
+show that there's precedent. Being able to say "so-and-so has used this
+API for n years" is a good way to reduce concerns about API choices.
+
+## Any other restrictions?
+
+Unlike most Android code, code in libbase has to build for Mac and
+Windows too.
+
+Code here is also expected to have good test coverage.
+
+By its nature, it's difficult to change libbase API. It's often best
+to start using your routine just in your project, and let it "graduate"
+after you're certain that the API is solid.
diff --git a/code_coverage/Android.mk b/code_coverage/Android.mk
new file mode 100644
index 0000000..80ab36b
--- /dev/null
+++ b/code_coverage/Android.mk
@@ -0,0 +1,37 @@
+# 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/code_coverage/empty_policy/code_coverage.arm.policy b/code_coverage/empty_policy/code_coverage.arm.policy
new file mode 100644
index 0000000..4c9132b
--- /dev/null
+++ b/code_coverage/empty_policy/code_coverage.arm.policy
@@ -0,0 +1,2 @@
+# empty unless code_coverage is enabled.
+# code_coverage.arm.policy
diff --git a/code_coverage/empty_policy/code_coverage.arm64.policy b/code_coverage/empty_policy/code_coverage.arm64.policy
new file mode 100644
index 0000000..dc5c35a
--- /dev/null
+++ b/code_coverage/empty_policy/code_coverage.arm64.policy
@@ -0,0 +1,2 @@
+# empty unless code_coverage is enabled.
+# code_coverage.arm64.policy
diff --git a/code_coverage/empty_policy/code_coverage.x86.policy b/code_coverage/empty_policy/code_coverage.x86.policy
new file mode 100644
index 0000000..044f34c
--- /dev/null
+++ b/code_coverage/empty_policy/code_coverage.x86.policy
@@ -0,0 +1,2 @@
+# empty unless code_coverage is enabled.
+# code_coverage.x86.policy
diff --git a/code_coverage/empty_policy/code_coverage.x86_64.policy b/code_coverage/empty_policy/code_coverage.x86_64.policy
new file mode 100644
index 0000000..6dcd22d
--- /dev/null
+++ b/code_coverage/empty_policy/code_coverage.x86_64.policy
@@ -0,0 +1,2 @@
+# empty unless code_coverage is enabled.
+# code_coverage.x86_64.policy
diff --git a/code_coverage/seccomp_policy/code_coverage.arm.policy b/code_coverage/seccomp_policy/code_coverage.arm.policy
new file mode 100644
index 0000000..d6784e3
--- /dev/null
+++ b/code_coverage/seccomp_policy/code_coverage.arm.policy
@@ -0,0 +1,14 @@
+close: 1
+mkdirat: 1
+msync: 1
+munmap: 1
+openat: 1
+write: 1
+fcntl64: 1
+fstat64: 1
+geteuid32: 1
+_llseek: 1
+mmap2: 1
+sigreturn: 1
+gettimeofday: 1
+prctl: 1
diff --git a/code_coverage/seccomp_policy/code_coverage.arm64.policy b/code_coverage/seccomp_policy/code_coverage.arm64.policy
new file mode 100644
index 0000000..4c3dd26
--- /dev/null
+++ b/code_coverage/seccomp_policy/code_coverage.arm64.policy
@@ -0,0 +1,13 @@
+close: 1
+mkdirat: 1
+msync: 1
+munmap: 1
+openat: 1
+write: 1
+fcntl: 1
+fstat: 1
+geteuid: 1
+lseek: 1
+mmap: 1
+rt_sigreturn: 1
+prctl: 1
diff --git a/code_coverage/seccomp_policy/code_coverage.policy.def b/code_coverage/seccomp_policy/code_coverage.policy.def
new file mode 100644
index 0000000..f136084
--- /dev/null
+++ b/code_coverage/seccomp_policy/code_coverage.policy.def
@@ -0,0 +1,51 @@
+// SECCOMP_MODE_STRICT
+//
+// minijail allowances for code coverage
+// this is processed with generate.sh, so we can use appropriate directives
+// size specific: __LP64__ for 64 bit, else 32 bit
+// arch specific: __arm__, __aarch64__, __i386__, __x86_64__
+
+// includes *all* syscalls used during the coverage dumping
+// no skipping just because they might have been in another policy file.
+
+// coverage tool uses different operations on different passes
+// 1st: uses write() to fill the file
+// 2nd-Nth: uses mmap() to update in place
+
+close: 1
+mkdirat: 1
+msync: 1
+munmap: 1
+openat: 1
+write: 1
+
+#if     defined(__LP64__)
+fcntl: 1
+fstat: 1
+geteuid: 1
+lseek: 1
+mmap: 1
+rt_sigreturn: 1
+#else
+fcntl64: 1
+fstat64: 1
+geteuid32: 1
+_llseek: 1
+mmap2: 1
+sigreturn: 1
+#endif
+
+#if     defined(__arm__)
+gettimeofday: 1
+#endif
+
+#if     defined(__i386__)
+madvise: 1
+#endif
+
+#if     defined(__arm__)
+prctl: 1
+#elif   defined(__aarch64__)
+prctl: 1
+#endif
+
diff --git a/code_coverage/seccomp_policy/code_coverage.x86.policy b/code_coverage/seccomp_policy/code_coverage.x86.policy
new file mode 100644
index 0000000..24ff8b9
--- /dev/null
+++ b/code_coverage/seccomp_policy/code_coverage.x86.policy
@@ -0,0 +1,13 @@
+close: 1
+mkdirat: 1
+msync: 1
+munmap: 1
+openat: 1
+write: 1
+fcntl64: 1
+fstat64: 1
+geteuid32: 1
+_llseek: 1
+mmap2: 1
+sigreturn: 1
+madvise: 1
diff --git a/code_coverage/seccomp_policy/code_coverage.x86_64.policy b/code_coverage/seccomp_policy/code_coverage.x86_64.policy
new file mode 100644
index 0000000..3081036
--- /dev/null
+++ b/code_coverage/seccomp_policy/code_coverage.x86_64.policy
@@ -0,0 +1,12 @@
+close: 1
+mkdirat: 1
+msync: 1
+munmap: 1
+openat: 1
+write: 1
+fcntl: 1
+fstat: 1
+geteuid: 1
+lseek: 1
+mmap: 1
+rt_sigreturn: 1
diff --git a/code_coverage/seccomp_policy/generate.sh b/code_coverage/seccomp_policy/generate.sh
new file mode 100755
index 0000000..ae582c6
--- /dev/null
+++ b/code_coverage/seccomp_policy/generate.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# generate the arch-specific files from the generic one
+
+set -ex
+
+cd "$(dirname "$0")"
+CPP='cpp -undef -E -P code_coverage.policy.def'
+$CPP -D__arm__ -o code_coverage.arm.policy
+$CPP -D__aarch64__ -D__LP64__ -o code_coverage.arm64.policy
+$CPP -D__i386__ -o code_coverage.x86.policy
+$CPP -D__x86_64__ -D__LP64__ -o code_coverage.x86_64.policy
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index a8059b7..75ebd94 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1407,9 +1407,8 @@
             return -1;
         }
     } else {
-        // TODO(b/135984674): support remounting for ext4.
-        LERROR << "Remounting in checkpointing mode is not yet supported for ext4";
-        return -1;
+        // STOPSHIP(b/143970043): support remounting for ext4.
+        LWARNING << "Remounting into checkpointing is not supported for ex4. Proceed with caution";
     }
     return 0;
 }
diff --git a/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp b/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
index 7d96a67..4fd8759 100644
--- a/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_metadata_updater_test.cpp
@@ -325,7 +325,7 @@
     EXPECT_TRUE(CheckGroupName("product", "another_group"));
 }
 
-INSTANTIATE_TEST_SUITE_P(, SnapshotMetadataUpdaterTest, testing::Values(0, 1));
+INSTANTIATE_TEST_SUITE_P(Snapshot, SnapshotMetadataUpdaterTest, testing::Values(0, 1));
 
 }  // namespace snapshot
 }  // namespace android
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 3c3d9a6..af268f9 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1338,7 +1338,7 @@
     ASSERT_TRUE(new_sm->CancelUpdate());
 }
 
-INSTANTIATE_TEST_SUITE_P(, FlashAfterUpdateTest, Combine(Values(0, 1), Bool()),
+INSTANTIATE_TEST_SUITE_P(Snapshot, FlashAfterUpdateTest, Combine(Values(0, 1), Bool()),
                          [](const TestParamInfo<FlashAfterUpdateTest::ParamType>& info) {
                              return "Flash"s + (std::get<0>(info.param) ? "New"s : "Old"s) +
                                     "Slot"s + (std::get<1>(info.param) ? "After"s : "Before"s) +
diff --git a/healthd/BatteryMonitor.cpp b/healthd/BatteryMonitor.cpp
index 9e168e9..bdf4aac 100644
--- a/healthd/BatteryMonitor.cpp
+++ b/healthd/BatteryMonitor.cpp
@@ -73,12 +73,25 @@
     return std::nullopt;
 }
 
+static void initHealthInfo(HealthInfo_2_1* health_info_2_1) {
+    *health_info_2_1 = HealthInfo_2_1{};
+
+    // HIDL enum values are zero initialized, so they need to be initialized
+    // properly.
+    health_info_2_1->batteryCapacityLevel = BatteryCapacityLevel::UNKNOWN;
+    auto* props = &health_info_2_1->legacy.legacy;
+    props->batteryStatus = BatteryStatus::UNKNOWN;
+    props->batteryHealth = BatteryHealth::UNKNOWN;
+}
+
 BatteryMonitor::BatteryMonitor()
     : mHealthdConfig(nullptr),
       mBatteryDevicePresent(false),
       mBatteryFixedCapacity(0),
       mBatteryFixedTemperature(0),
-      mHealthInfo(std::make_unique<HealthInfo_2_1>()) {}
+      mHealthInfo(std::make_unique<HealthInfo_2_1>()) {
+    initHealthInfo(mHealthInfo.get());
+}
 
 BatteryMonitor::~BatteryMonitor() {}
 
@@ -168,7 +181,7 @@
         return ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
 
     auto ret = mapSysfsString(buf.c_str(), supplyTypeMap);
-    if (ret < 0) {
+    if (!ret) {
         KLOG_WARNING(LOG_TAG, "Unknown power supply type '%s'\n", buf.c_str());
         *ret = ANDROID_POWER_SUPPLY_TYPE_UNKNOWN;
     }
@@ -198,7 +211,7 @@
 }
 
 void BatteryMonitor::updateValues(void) {
-    *mHealthInfo = HealthInfo_2_1{};
+    initHealthInfo(mHealthInfo.get());
 
     HealthInfo_1_0& props = mHealthInfo->legacy.legacy;
 
diff --git a/init/Android.bp b/init/Android.bp
index 776a3a6..d939fcc 100644
--- a/init/Android.bp
+++ b/init/Android.bp
@@ -65,6 +65,7 @@
         "libavb",
         "libc++fs",
         "libcgrouprc_format",
+        "liblmkd_utils",
         "libmodprobe",
         "libprotobuf-cpp-lite",
         "libpropertyinfoserializer",
@@ -118,6 +119,7 @@
         "init.cpp",
         "interface_utils.cpp",
         "keychords.cpp",
+        "lmkd_service.cpp",
         "modalias_handler.cpp",
         "mount_handler.cpp",
         "mount_namespace.cpp",
diff --git a/init/AndroidTest.xml b/init/AndroidTest.xml
index 94a02e6..667911d 100644
--- a/init/AndroidTest.xml
+++ b/init/AndroidTest.xml
@@ -17,7 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="systems" />
     <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
-    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
     <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
         <option name="cleanup" value="true" />
         <option name="push" value="CtsInitTestCases->/data/local/tmp/CtsInitTestCases" />
diff --git a/init/README.md b/init/README.md
index cdf3487..e8df4ec 100644
--- a/init/README.md
+++ b/init/README.md
@@ -505,12 +505,23 @@
 > Used to mark the point right after /data is mounted. Used to implement the
   `class_reset_post_data` and `class_start_post_data` commands.
 
-`mkdir <path> [mode] [owner] [group]`
+`mkdir <path> [<mode>] [<owner>] [<group>] [encryption=<action>] [key=<key>]`
 > Create a directory at _path_, optionally with the given mode, owner, and
   group. If not provided, the directory is created with permissions 755 and
   owned by the root user and root group. If provided, the mode, owner and group
   will be updated if the directory exists already.
 
+ > _action_ can be one of:
+  * `None`: take no encryption action; directory will be encrypted if parent is.
+  * `Require`: encrypt directory, abort boot process if encryption fails
+  * `Attempt`: try to set an encryption policy, but continue if it fails
+  * `DeleteIfNecessary`: recursively delete directory if necessary to set
+  encryption policy.
+
+  > _key_ can be one of:
+  * `ref`: use the systemwide DE key
+  * `per_boot_ref`: use the key freshly generated on each boot.
+
 `mount_all <fstab> [ <path> ]\* [--<option>]`
 > Calls fs\_mgr\_mount\_all on the given fs\_mgr-format fstab with optional
   options "early" and "late".
diff --git a/init/builtins.cpp b/init/builtins.cpp
index b2c6461..5ee928e 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -364,67 +364,52 @@
     return {};
 }
 
-// mkdir <path> [mode] [owner] [group]
+// mkdir <path> [mode] [owner] [group] [<option> ...]
 static Result<void> do_mkdir(const BuiltinArguments& args) {
-    mode_t mode = 0755;
-    Result<uid_t> uid = -1;
-    Result<gid_t> gid = -1;
-
-    switch (args.size()) {
-        case 5:
-            gid = DecodeUid(args[4]);
-            if (!gid) {
-                return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
-            }
-            FALLTHROUGH_INTENDED;
-        case 4:
-            uid = DecodeUid(args[3]);
-            if (!uid) {
-                return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
-            }
-            FALLTHROUGH_INTENDED;
-        case 3:
-            mode = std::strtoul(args[2].c_str(), 0, 8);
-            FALLTHROUGH_INTENDED;
-        case 2:
-            break;
-        default:
-            return Error() << "Unexpected argument count: " << args.size();
+    auto options = ParseMkdir(args.args);
+    if (!options) return options.error();
+    std::string ref_basename;
+    if (options->ref_option == "ref") {
+        ref_basename = fscrypt_key_ref;
+    } else if (options->ref_option == "per_boot_ref") {
+        ref_basename = fscrypt_key_per_boot_ref;
+    } else {
+        return Error() << "Unknown key option: '" << options->ref_option << "'";
     }
-    std::string target = args[1];
+
     struct stat mstat;
-    if (lstat(target.c_str(), &mstat) != 0) {
+    if (lstat(options->target.c_str(), &mstat) != 0) {
         if (errno != ENOENT) {
-            return ErrnoError() << "lstat() failed on " << target;
+            return ErrnoError() << "lstat() failed on " << options->target;
         }
-        if (!make_dir(target, mode)) {
-            return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << target;
+        if (!make_dir(options->target, options->mode)) {
+            return ErrnoErrorIgnoreEnoent() << "mkdir() failed on " << options->target;
         }
-        if (lstat(target.c_str(), &mstat) != 0) {
-            return ErrnoError() << "lstat() failed on new " << target;
+        if (lstat(options->target.c_str(), &mstat) != 0) {
+            return ErrnoError() << "lstat() failed on new " << options->target;
         }
     }
     if (!S_ISDIR(mstat.st_mode)) {
-        return Error() << "Not a directory on " << target;
+        return Error() << "Not a directory on " << options->target;
     }
-    bool needs_chmod = (mstat.st_mode & ~S_IFMT) != mode;
-    if ((*uid != static_cast<uid_t>(-1) && *uid != mstat.st_uid) ||
-        (*gid != static_cast<gid_t>(-1) && *gid != mstat.st_gid)) {
-        if (lchown(target.c_str(), *uid, *gid) == -1) {
-            return ErrnoError() << "lchown failed on " << target;
+    bool needs_chmod = (mstat.st_mode & ~S_IFMT) != options->mode;
+    if ((options->uid != static_cast<uid_t>(-1) && options->uid != mstat.st_uid) ||
+        (options->gid != static_cast<gid_t>(-1) && options->gid != mstat.st_gid)) {
+        if (lchown(options->target.c_str(), options->uid, options->gid) == -1) {
+            return ErrnoError() << "lchown failed on " << options->target;
         }
         // chown may have cleared S_ISUID and S_ISGID, chmod again
         needs_chmod = true;
     }
     if (needs_chmod) {
-        if (fchmodat(AT_FDCWD, target.c_str(), mode, AT_SYMLINK_NOFOLLOW) == -1) {
-            return ErrnoError() << "fchmodat() failed on " << target;
+        if (fchmodat(AT_FDCWD, options->target.c_str(), options->mode, AT_SYMLINK_NOFOLLOW) == -1) {
+            return ErrnoError() << "fchmodat() failed on " << options->target;
         }
     }
     if (fscrypt_is_native()) {
-        if (fscrypt_set_directory_policy(target)) {
+        if (!FscryptSetDirectoryPolicy(ref_basename, options->fscrypt_action, options->target)) {
             return reboot_into_recovery(
-                    {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + target});
+                    {"--prompt_and_wipe_data", "--reason=set_policy_failed:"s + options->target});
         }
     }
     return {};
@@ -562,11 +547,25 @@
  *
  * return code is processed based on input code
  */
-static Result<void> queue_fs_event(int code) {
+static Result<void> queue_fs_event(int code, bool userdata_remount) {
     if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
+        if (userdata_remount) {
+            // FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION should only happen on FDE devices. Since we don't
+            // support userdata remount on FDE devices, this should never been triggered. Time to
+            // panic!
+            LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
+            TriggerShutdown("reboot,requested-userdata-remount-on-fde-device");
+        }
         ActionManager::GetInstance().QueueEventTrigger("encrypt");
         return {};
     } else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
+        if (userdata_remount) {
+            // FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED should only happen on FDE devices. Since we
+            // don't support userdata remount on FDE devices, this should never been triggered.
+            // Time to panic!
+            LOG(ERROR) << "Userdata remount is not supported on FDE devices. How did you get here?";
+            TriggerShutdown("reboot,requested-userdata-remount-on-fde-device");
+        }
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "block");
         ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
@@ -589,8 +588,8 @@
         return reboot_into_recovery(options);
         /* If reboot worked, there is no return. */
     } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
-        if (fscrypt_install_keyring()) {
-            return Error() << "fscrypt_install_keyring() failed";
+        if (!userdata_remount && !FscryptInstallKeyring()) {
+            return Error() << "FscryptInstallKeyring() failed";
         }
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "file");
@@ -600,8 +599,8 @@
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
         return {};
     } else if (code == FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED) {
-        if (fscrypt_install_keyring()) {
-            return Error() << "fscrypt_install_keyring() failed";
+        if (!userdata_remount && !FscryptInstallKeyring()) {
+            return Error() << "FscryptInstallKeyring() failed";
         }
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "file");
@@ -611,8 +610,8 @@
         ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
         return {};
     } else if (code == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) {
-        if (fscrypt_install_keyring()) {
-            return Error() << "fscrypt_install_keyring() failed";
+        if (!userdata_remount && !FscryptInstallKeyring()) {
+            return Error() << "FscryptInstallKeyring() failed";
         }
         property_set("ro.crypto.state", "encrypted");
         property_set("ro.crypto.type", "file");
@@ -679,7 +678,7 @@
         /* queue_fs_event will queue event based on mount_fstab return code
          * and return processed return code*/
         initial_mount_fstab_return_code = mount_fstab_return_code;
-        auto queue_fs_result = queue_fs_event(mount_fstab_return_code);
+        auto queue_fs_result = queue_fs_event(mount_fstab_return_code, false);
         if (!queue_fs_result) {
             return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
         }
@@ -1151,7 +1150,7 @@
     if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
         TriggerShutdown("reboot,mount-userdata-failed");
     }
-    if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result) {
+    if (auto result = queue_fs_event(initial_mount_fstab_return_code, true); !result) {
         return Error() << "queue_fs_event() failed: " << result.error();
     }
     return {};
@@ -1257,7 +1256,7 @@
         {"load_system_props",       {0,     0,    {false,  do_load_system_props}}},
         {"loglevel",                {1,     1,    {false,  do_loglevel}}},
         {"mark_post_data",          {0,     0,    {false,  do_mark_post_data}}},
-        {"mkdir",                   {1,     4,    {true,   do_mkdir}}},
+        {"mkdir",                   {1,     6,    {true,   do_mkdir}}},
         // TODO: Do mount operations in vendor_init.
         // mount_all is currently too complex to run in vendor_init as it queues action triggers,
         // imports rc scripts, etc.  It should be simplified and run in vendor_init context.
diff --git a/init/check_builtins.cpp b/init/check_builtins.cpp
index 2efaeea..9d23921 100644
--- a/init/check_builtins.cpp
+++ b/init/check_builtins.cpp
@@ -121,22 +121,10 @@
 }
 
 Result<void> check_mkdir(const BuiltinArguments& args) {
-    if (args.size() >= 4) {
-        if (!args[3].empty()) {
-            auto uid = DecodeUid(args[3]);
-            if (!uid) {
-                return Error() << "Unable to decode UID for '" << args[3] << "': " << uid.error();
-            }
-        }
-
-        if (args.size() == 5 && !args[4].empty()) {
-            auto gid = DecodeUid(args[4]);
-            if (!gid) {
-                return Error() << "Unable to decode GID for '" << args[4] << "': " << gid.error();
-            }
-        }
+    auto options = ParseMkdir(args.args);
+    if (!options) {
+        return options.error();
     }
-
     return {};
 }
 
diff --git a/init/fscrypt_init_extensions.cpp b/init/fscrypt_init_extensions.cpp
index 5fa07dd..7820f3d 100644
--- a/init/fscrypt_init_extensions.cpp
+++ b/init/fscrypt_init_extensions.cpp
@@ -41,19 +41,15 @@
 
 using namespace android::fscrypt;
 
-static int set_policy_on(const std::string& ref_basename, const std::string& dir);
-
-int fscrypt_install_keyring() {
+bool FscryptInstallKeyring() {
     key_serial_t device_keyring = add_key("keyring", "fscrypt", 0, 0, KEY_SPEC_SESSION_KEYRING);
 
     if (device_keyring == -1) {
         PLOG(ERROR) << "Failed to create keyring";
-        return -1;
+        return false;
     }
-
     LOG(INFO) << "Keyring created with id " << device_keyring << " in process " << getpid();
-
-    return 0;
+    return true;
 }
 
 // TODO(b/139378601): use a single central implementation of this.
@@ -97,102 +93,57 @@
     }
 }
 
-int fscrypt_set_directory_policy(const std::string& dir) {
-    const std::string prefix = "/data/";
-
-    if (!android::base::StartsWith(dir, prefix)) {
-        return 0;
-    }
-
-    // Special-case /data/media/obb per b/64566063
-    if (dir == "/data/media/obb") {
-        // Try to set policy on this directory, but if it is non-empty this may fail.
-        set_policy_on(fscrypt_key_ref, dir);
-        return 0;
-    }
-
-    // Only set policy on first level /data directories
-    // To make this less restrictive, consider using a policy file.
-    // However this is overkill for as long as the policy is simply
-    // to apply a global policy to all /data folders created via makedir
-    if (dir.find_first_of('/', prefix.size()) != std::string::npos) {
-        return 0;
-    }
-
-    // Special case various directories that must not be encrypted,
-    // often because their subdirectories must be encrypted.
-    // This isn't a nice way to do this, see b/26641735
-    std::vector<std::string> directories_to_exclude = {
-        "lost+found",
-        "system_ce", "system_de",
-        "misc_ce", "misc_de",
-        "vendor_ce", "vendor_de",
-        "media",
-        "data", "user", "user_de",
-        "apex", "preloads", "app-staging",
-        "gsi",
-    };
-    for (const auto& d : directories_to_exclude) {
-        if ((prefix + d) == dir) {
-            LOG(INFO) << "Not setting policy on " << dir;
-            return 0;
-        }
-    }
-    std::vector<std::string> per_boot_directories = {
-            "per_boot",
-    };
-    for (const auto& d : per_boot_directories) {
-        if ((prefix + d) == dir) {
-            LOG(INFO) << "Setting per_boot key on " << dir;
-            return set_policy_on(fscrypt_key_per_boot_ref, dir);
-        }
-    }
-    int err = set_policy_on(fscrypt_key_ref, dir);
-    if (err == 0) {
-        return 0;
-    }
-    // Empty these directories if policy setting fails.
-    std::vector<std::string> wipe_on_failure = {
-            "rollback", "rollback-observer",  // b/139193659
-    };
-    for (const auto& d : wipe_on_failure) {
-        if ((prefix + d) == dir) {
-            LOG(ERROR) << "Setting policy failed, deleting: " << dir;
-            delete_dir_contents(dir);
-            err = set_policy_on(fscrypt_key_ref, dir);
-            break;
-        }
-    }
-    return err;
-}
-
-// Set an encryption policy on the given directory.  The policy (key reference
+// Look up an encryption policy  The policy (key reference
 // and encryption options) to use is read from files that were written by vold.
-static int set_policy_on(const std::string& ref_basename, const std::string& dir) {
-    EncryptionPolicy policy;
+static bool LookupPolicy(const std::string& ref_basename, EncryptionPolicy* policy) {
     std::string ref_filename = std::string("/data") + ref_basename;
-    if (!android::base::ReadFileToString(ref_filename, &policy.key_raw_ref)) {
-        LOG(ERROR) << "Unable to read system policy to set on " << dir;
-        return -1;
+    if (!android::base::ReadFileToString(ref_filename, &policy->key_raw_ref)) {
+        LOG(ERROR) << "Unable to read system policy with name " << ref_filename;
+        return false;
     }
 
     auto options_filename = std::string("/data") + fscrypt_key_mode;
     std::string options_string;
     if (!android::base::ReadFileToString(options_filename, &options_string)) {
         LOG(ERROR) << "Cannot read encryption options string";
-        return -1;
+        return false;
     }
-    if (!ParseOptions(options_string, &policy.options)) {
+    if (!ParseOptions(options_string, &policy->options)) {
         LOG(ERROR) << "Invalid encryption options string: " << options_string;
-        return -1;
+        return false;
     }
+    return true;
+}
 
+static bool EnsurePolicyOrLog(const EncryptionPolicy& policy, const std::string& dir) {
     if (!EnsurePolicy(policy, dir)) {
         std::string ref_hex;
         BytesToHex(policy.key_raw_ref, &ref_hex);
         LOG(ERROR) << "Setting " << ref_hex << " policy on " << dir << " failed!";
-        return -1;
+        return false;
     }
+    return true;
+}
 
-    return 0;
+static bool SetPolicyOn(const std::string& ref_basename, const std::string& dir) {
+    EncryptionPolicy policy;
+    if (!LookupPolicy(ref_basename, &policy)) return false;
+    if (!EnsurePolicyOrLog(policy, dir)) return false;
+    return true;
+}
+
+bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action,
+                               const std::string& dir) {
+    if (action == FscryptAction::kNone) {
+        return true;
+    }
+    if (SetPolicyOn(ref_basename, dir) || action == FscryptAction::kAttempt) {
+        return true;
+    }
+    if (action == FscryptAction::kDeleteIfNecessary) {
+        LOG(ERROR) << "Setting policy failed, deleting: " << dir;
+        delete_dir_contents(dir);
+        return SetPolicyOn(ref_basename, dir);
+    }
+    return false;
 }
diff --git a/init/fscrypt_init_extensions.h b/init/fscrypt_init_extensions.h
index 2163ef6..d357bb2 100644
--- a/init/fscrypt_init_extensions.h
+++ b/init/fscrypt_init_extensions.h
@@ -18,5 +18,13 @@
 
 #include <string>
 
-int fscrypt_install_keyring();
-int fscrypt_set_directory_policy(const std::string& dir);
+enum class FscryptAction {
+    kNone,
+    kAttempt,
+    kRequire,
+    kDeleteIfNecessary,
+};
+
+bool FscryptInstallKeyring();
+bool FscryptSetDirectoryPolicy(const std::string& ref_basename, FscryptAction action,
+                               const std::string& dir);
diff --git a/init/init.cpp b/init/init.cpp
index f775d8f..6ea2d00 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -59,6 +59,7 @@
 #include "first_stage_mount.h"
 #include "import_parser.h"
 #include "keychords.h"
+#include "lmkd_service.h"
 #include "mount_handler.h"
 #include "mount_namespace.h"
 #include "property_service.h"
@@ -684,9 +685,15 @@
     InitKernelLogging(argv);
     LOG(INFO) << "init second stage started!";
 
+    // Will handle EPIPE at the time of write by checking the errno
+    signal(SIGPIPE, SIG_IGN);
+
     // Set init and its forked children's oom_adj.
-    if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) {
-        LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error();
+    if (auto result =
+                WriteFile("/proc/1/oom_score_adj", StringPrintf("%d", DEFAULT_OOM_SCORE_ADJUST));
+        !result) {
+        LOG(ERROR) << "Unable to write " << DEFAULT_OOM_SCORE_ADJUST
+                   << " to /proc/1/oom_score_adj: " << result.error();
     }
 
     // Set up a session keyring that all processes will have access to. It
diff --git a/init/lmkd_service.cpp b/init/lmkd_service.cpp
new file mode 100644
index 0000000..dd1ab4d
--- /dev/null
+++ b/init/lmkd_service.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 "lmkd_service.h"
+
+#include <errno.h>
+
+#include <android-base/logging.h>
+#include <liblmkd_utils.h>
+
+#include "service_list.h"
+
+namespace android {
+namespace init {
+
+enum LmkdRegistrationResult {
+    LMKD_REG_SUCCESS,
+    LMKD_CONN_FAILED,
+    LMKD_REG_FAILED,
+};
+
+static int lmkd_socket = -1;
+
+static LmkdRegistrationResult RegisterProcess(uid_t uid, pid_t pid, int oom_score_adjust) {
+    // connect to lmkd if not already connected
+    if (lmkd_socket < 0) {
+        lmkd_socket = lmkd_connect();
+        if (lmkd_socket < 0) {
+            return LMKD_CONN_FAILED;
+        }
+    }
+
+    // register service with lmkd
+    struct lmk_procprio params;
+    params.pid = pid;
+    params.uid = uid;
+    params.oomadj = oom_score_adjust;
+    params.ptype = PROC_TYPE_SERVICE;
+    if (lmkd_register_proc(lmkd_socket, &params) != 0) {
+        // data transfer failed, reset the connection
+        close(lmkd_socket);
+        lmkd_socket = -1;
+        return LMKD_REG_FAILED;
+    }
+
+    return LMKD_REG_SUCCESS;
+}
+
+static bool UnregisterProcess(pid_t pid) {
+    if (lmkd_socket < 0) {
+        // no connection or it was lost, no need to unregister
+        return false;
+    }
+
+    // unregister service
+    struct lmk_procremove params;
+    params.pid = pid;
+    if (lmkd_unregister_proc(lmkd_socket, &params) != 0) {
+        // data transfer failed, reset the connection
+        close(lmkd_socket);
+        lmkd_socket = -1;
+        return false;
+    }
+
+    return true;
+}
+
+static void RegisterServices(pid_t exclude_pid) {
+    for (const auto& service : ServiceList::GetInstance().services()) {
+        auto svc = service.get();
+        if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
+            // skip if process is excluded or not yet forked (pid==0)
+            if (svc->pid() == exclude_pid || svc->pid() == 0) {
+                continue;
+            }
+            if (RegisterProcess(svc->uid(), svc->pid(), svc->oom_score_adjust()) !=
+                LMKD_REG_SUCCESS) {
+                // a failure here resets the connection, will retry during next registration
+                break;
+            }
+        }
+    }
+}
+
+void LmkdRegister(const std::string& name, uid_t uid, pid_t pid, int oom_score_adjust) {
+    bool new_connection = lmkd_socket == -1;
+    LmkdRegistrationResult result;
+
+    result = RegisterProcess(uid, pid, oom_score_adjust);
+    if (result == LMKD_REG_FAILED) {
+        // retry one time if connection to lmkd was lost
+        result = RegisterProcess(uid, pid, oom_score_adjust);
+        new_connection = result == LMKD_REG_SUCCESS;
+    }
+    switch (result) {
+        case LMKD_REG_SUCCESS:
+            // register existing services once new connection is established
+            if (new_connection) {
+                RegisterServices(pid);
+            }
+            break;
+        case LMKD_CONN_FAILED:
+            PLOG(ERROR) << "lmkd connection failed when " << name << " process got started";
+            break;
+        case LMKD_REG_FAILED:
+            PLOG(ERROR) << "lmkd failed to register " << name << " process";
+            break;
+    }
+}
+
+void LmkdUnregister(const std::string& name, pid_t pid) {
+    if (!UnregisterProcess(pid)) {
+        PLOG(ERROR) << "lmkd failed to unregister " << name << " process";
+    }
+}
+
+}  // namespace init
+}  // namespace android
diff --git a/init/lmkd_service.h b/init/lmkd_service.h
new file mode 100644
index 0000000..5b51d52
--- /dev/null
+++ b/init/lmkd_service.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <sys/types.h>
+
+#include <string>
+
+namespace android {
+namespace init {
+
+static const int MIN_OOM_SCORE_ADJUST = -1000;
+static const int MAX_OOM_SCORE_ADJUST = 1000;
+// service with default score is unkillable
+static const int DEFAULT_OOM_SCORE_ADJUST = MIN_OOM_SCORE_ADJUST;
+
+#if defined(__ANDROID__)
+
+void LmkdRegister(const std::string& name, uid_t uid, pid_t pid, int oom_score_adjust);
+void LmkdUnregister(const std::string& name, pid_t pid);
+
+#else  // defined(__ANDROID__)
+
+static inline void LmkdRegister(const std::string&, uid_t, pid_t, int) {}
+static inline void LmkdUnregister(const std::string&, pid_t) {}
+
+#endif  // defined(__ANDROID__)
+
+}  // namespace init
+}  // namespace android
diff --git a/init/reboot.cpp b/init/reboot.cpp
index fc18ecb..4a16969 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -57,6 +57,7 @@
 #include "action_manager.h"
 #include "builtin_arguments.h"
 #include "init.h"
+#include "mount_namespace.h"
 #include "property_service.h"
 #include "reboot_utils.h"
 #include "service.h"
@@ -713,6 +714,18 @@
     SendStartSendingMessagesMessage();
 }
 
+static Result<void> UnmountAllApexes() {
+    const char* args[] = {"/system/bin/apexd", "--unmount-all"};
+    int status;
+    if (logwrap_fork_execvp(arraysize(args), args, &status, false, LOG_KLOG, true, nullptr) != 0) {
+        return ErrnoError() << "Failed to call '/system/bin/apexd --unmount-all'";
+    }
+    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+        return {};
+    }
+    return Error() << "'/system/bin/apexd --unmount-all' failed : " << status;
+}
+
 static Result<void> DoUserspaceReboot() {
     LOG(INFO) << "Userspace reboot initiated";
     auto guard = android::base::make_scope_guard([] {
@@ -746,30 +759,20 @@
         // TODO(b/135984674): store information about offending services for debugging.
         return Error() << r << " post-data services are still running";
     }
-    // We only really need to restart vold if userdata is ext4 filesystem.
-    // TODO(b/135984674): get userdata fs type here, and do nothing in case of f2fs.
-    // First shutdown volumes managed by vold. They will be recreated by
-    // system_server.
-    Service* vold_service = ServiceList::GetInstance().FindService("vold");
-    if (vold_service != nullptr && vold_service->IsRunning()) {
-        if (auto result = ShutdownVold(); !result) {
-            return result;
-        }
-        LOG(INFO) << "Restarting vold";
-        vold_service->Restart();
-    }
-    // Again, we only need to kill zram backing device in case of ext4 userdata.
-    // TODO(b/135984674): get userdata fs type here, and do nothing in case of f2fs.
-    if (auto result = KillZramBackingDevice(); !result) {
-        return result;
-    }
+    // TODO(b/143970043): in case of ext4 we probably we will need to restart vold and kill zram
+    //  backing device.
     if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */), 5s,
                                              false /* SIGKILL */);
         r > 0) {
         // TODO(b/135984674): store information about offending services for debugging.
         return Error() << r << " debugging services are still running";
     }
-    // TODO(b/135984674): deactivate APEX modules and switch back to bootstrap namespace.
+    if (auto result = UnmountAllApexes(); !result) {
+        return result;
+    }
+    if (!SwitchToBootstrapMountNamespaceIfNeeded()) {
+        return Error() << "Failed to switch to bootstrap namespace";
+    }
     // Re-enable services
     for (const auto& s : were_enabled) {
         LOG(INFO) << "Re-enabling service '" << s->name() << "'";
diff --git a/init/selinux.cpp b/init/selinux.cpp
index a15d136..a9cd290 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -514,9 +514,6 @@
 
 }  // namespace
 
-// The files and directories that were created before initial sepolicy load or
-// files on ramdisk need to have their security context restored to the proper
-// value. This must happen before /dev is populated by ueventd.
 void SelinuxRestoreContext() {
     LOG(INFO) << "Running restorecon...";
     selinux_android_restorecon("/dev", 0);
@@ -560,15 +557,12 @@
     return 0;
 }
 
-// This function sets up SELinux logging to be written to kmsg, to match init's logging.
 void SelinuxSetupKernelLogging() {
     selinux_callback cb;
     cb.func_log = SelinuxKlogCallback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 }
 
-// This function returns the Android version with which the vendor SEPolicy was compiled.
-// It is used for version checks such as whether or not vendor_init should be used
 int SelinuxGetVendorAndroidVersion() {
     static int vendor_android_version = [] {
         if (!IsSplitPolicyDevice()) {
@@ -594,7 +588,6 @@
     return vendor_android_version;
 }
 
-// This function initializes SELinux then execs init to run in the init SELinux context.
 int SetupSelinux(char** argv) {
     SetStdioToDevNull(argv);
     InitKernelLogging(argv);
diff --git a/init/selinux.h b/init/selinux.h
index 63ad470..1a41bfd 100644
--- a/init/selinux.h
+++ b/init/selinux.h
@@ -19,10 +19,19 @@
 namespace android {
 namespace init {
 
+// Initialize SELinux, then exec init to run in the init SELinux context.
 int SetupSelinux(char** argv);
+
+// Restore the proper security context to files and directories on ramdisk, and
+// those that were created before initial sepolicy load.
+// This must happen before /dev is populated by ueventd.
 void SelinuxRestoreContext();
 
+// Set up SELinux logging to be written to kmsg, to match init's logging.
 void SelinuxSetupKernelLogging();
+
+// Return the Android API level with which the vendor SEPolicy was compiled.
+// Used for version checks such as whether or not vendor_init should be used.
 int SelinuxGetVendorAndroidVersion();
 
 static constexpr char kEnvSelinuxStartedAt[] = "SELINUX_STARTED_AT";
diff --git a/init/service.cpp b/init/service.cpp
index c8568a0..f8e98a2 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -36,6 +36,7 @@
 #include <processgroup/processgroup.h>
 #include <selinux/selinux.h>
 
+#include "lmkd_service.h"
 #include "service_list.h"
 #include "util.h"
 
@@ -151,7 +152,7 @@
       seclabel_(seclabel),
       onrestart_(false, subcontext_for_restart_commands, "<Service '" + name + "' onrestart>", 0,
                  "onrestart", {}),
-      oom_score_adjust_(-1000),
+      oom_score_adjust_(DEFAULT_OOM_SCORE_ADJUST),
       start_order_(0),
       args_(args) {}
 
@@ -199,6 +200,10 @@
 
         if (r == 0) process_cgroup_empty_ = true;
     }
+
+    if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
+        LmkdUnregister(name_, pid_);
+    }
 }
 
 void Service::SetProcessAttributesAndCaps() {
@@ -502,7 +507,7 @@
         return ErrnoError() << "Failed to fork";
     }
 
-    if (oom_score_adjust_ != -1000) {
+    if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
         std::string oom_str = std::to_string(oom_score_adjust_);
         std::string oom_file = StringPrintf("/proc/%d/oom_score_adj", pid);
         if (!WriteStringToFile(oom_str, oom_file)) {
@@ -563,6 +568,10 @@
         }
     }
 
+    if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) {
+        LmkdRegister(name_, proc_attr_.uid, pid_, oom_score_adjust_);
+    }
+
     NotifyStateChange("running");
     reboot_on_failure.Disable();
     return {};
diff --git a/init/service_parser.cpp b/init/service_parser.cpp
index e6a341d..154d1dd 100644
--- a/init/service_parser.cpp
+++ b/init/service_parser.cpp
@@ -29,6 +29,7 @@
 #include <hidl-util/FQName.h>
 #include <system/thread_defs.h>
 
+#include "lmkd_service.h"
 #include "rlimit_parser.h"
 #include "service_utils.h"
 #include "util.h"
@@ -261,8 +262,10 @@
 }
 
 Result<void> ServiceParser::ParseOomScoreAdjust(std::vector<std::string>&& args) {
-    if (!ParseInt(args[1], &service_->oom_score_adjust_, -1000, 1000)) {
-        return Error() << "oom_score_adjust value must be in range -1000 - +1000";
+    if (!ParseInt(args[1], &service_->oom_score_adjust_, MIN_OOM_SCORE_ADJUST,
+                  MAX_OOM_SCORE_ADJUST)) {
+        return Error() << "oom_score_adjust value must be in range " << MIN_OOM_SCORE_ADJUST
+                       << " - +" << MAX_OOM_SCORE_ADJUST;
     }
     return {};
 }
diff --git a/init/service_test.cpp b/init/service_test.cpp
index c9cc7bd..c158b0a 100644
--- a/init/service_test.cpp
+++ b/init/service_test.cpp
@@ -23,6 +23,7 @@
 
 #include <gtest/gtest.h>
 
+#include "lmkd_service.h"
 #include "util.h"
 
 namespace android {
@@ -49,7 +50,7 @@
     EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory->ioprio_class());
     EXPECT_EQ(0, service_in_old_memory->ioprio_pri());
     EXPECT_EQ(0, service_in_old_memory->priority());
-    EXPECT_EQ(-1000, service_in_old_memory->oom_score_adjust());
+    EXPECT_EQ(DEFAULT_OOM_SCORE_ADJUST, service_in_old_memory->oom_score_adjust());
     EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
 
     for (std::size_t i = 0; i < memory_size; ++i) {
@@ -68,7 +69,7 @@
     EXPECT_EQ(IoSchedClass_NONE, service_in_old_memory2->ioprio_class());
     EXPECT_EQ(0, service_in_old_memory2->ioprio_pri());
     EXPECT_EQ(0, service_in_old_memory2->priority());
-    EXPECT_EQ(-1000, service_in_old_memory2->oom_score_adjust());
+    EXPECT_EQ(DEFAULT_OOM_SCORE_ADJUST, service_in_old_memory2->oom_score_adjust());
     EXPECT_FALSE(service_in_old_memory->process_cgroup_empty());
 }
 
diff --git a/init/util.cpp b/init/util.cpp
index 40db838..ada9e78 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -434,6 +434,142 @@
     return {};
 }
 
+static FscryptAction FscryptInferAction(const std::string& dir) {
+    const std::string prefix = "/data/";
+
+    if (!android::base::StartsWith(dir, prefix)) {
+        return FscryptAction::kNone;
+    }
+
+    // Special-case /data/media/obb per b/64566063
+    if (dir == "/data/media/obb") {
+        // Try to set policy on this directory, but if it is non-empty this may fail.
+        return FscryptAction::kAttempt;
+    }
+
+    // Only set policy on first level /data directories
+    // To make this less restrictive, consider using a policy file.
+    // However this is overkill for as long as the policy is simply
+    // to apply a global policy to all /data folders created via makedir
+    if (dir.find_first_of('/', prefix.size()) != std::string::npos) {
+        return FscryptAction::kNone;
+    }
+
+    // Special case various directories that must not be encrypted,
+    // often because their subdirectories must be encrypted.
+    // This isn't a nice way to do this, see b/26641735
+    std::vector<std::string> directories_to_exclude = {
+            "lost+found", "system_ce", "system_de", "misc_ce",     "misc_de",
+            "vendor_ce",  "vendor_de", "media",     "data",        "user",
+            "user_de",    "apex",      "preloads",  "app-staging", "gsi",
+    };
+    for (const auto& d : directories_to_exclude) {
+        if ((prefix + d) == dir) {
+            return FscryptAction::kNone;
+        }
+    }
+    // Empty these directories if policy setting fails.
+    std::vector<std::string> wipe_on_failure = {
+            "rollback", "rollback-observer",  // b/139193659
+    };
+    for (const auto& d : wipe_on_failure) {
+        if ((prefix + d) == dir) {
+            return FscryptAction::kDeleteIfNecessary;
+        }
+    }
+    return FscryptAction::kRequire;
+}
+
+Result<MkdirOptions> ParseMkdir(const std::vector<std::string>& args) {
+    mode_t mode = 0755;
+    Result<uid_t> uid = -1;
+    Result<gid_t> gid = -1;
+    FscryptAction fscrypt_inferred_action = FscryptInferAction(args[1]);
+    FscryptAction fscrypt_action = fscrypt_inferred_action;
+    std::string ref_option = "ref";
+    bool set_option_encryption = false;
+    bool set_option_key = false;
+
+    for (size_t i = 2; i < args.size(); i++) {
+        switch (i) {
+            case 2:
+                mode = std::strtoul(args[2].c_str(), 0, 8);
+                break;
+            case 3:
+                uid = DecodeUid(args[3]);
+                if (!uid) {
+                    return Error()
+                           << "Unable to decode UID for '" << args[3] << "': " << uid.error();
+                }
+                break;
+            case 4:
+                gid = DecodeUid(args[4]);
+                if (!gid) {
+                    return Error()
+                           << "Unable to decode GID for '" << args[4] << "': " << gid.error();
+                }
+                break;
+            default:
+                auto parts = android::base::Split(args[i], "=");
+                if (parts.size() != 2) {
+                    return Error() << "Can't parse option: '" << args[i] << "'";
+                }
+                auto optname = parts[0];
+                auto optval = parts[1];
+                if (optname == "encryption") {
+                    if (set_option_encryption) {
+                        return Error() << "Duplicated option: '" << optname << "'";
+                    }
+                    if (optval == "Require") {
+                        fscrypt_action = FscryptAction::kRequire;
+                    } else if (optval == "None") {
+                        fscrypt_action = FscryptAction::kNone;
+                    } else if (optval == "Attempt") {
+                        fscrypt_action = FscryptAction::kAttempt;
+                    } else if (optval == "DeleteIfNecessary") {
+                        fscrypt_action = FscryptAction::kDeleteIfNecessary;
+                    } else {
+                        return Error() << "Unknown encryption option: '" << optval << "'";
+                    }
+                    set_option_encryption = true;
+                } else if (optname == "key") {
+                    if (set_option_key) {
+                        return Error() << "Duplicated option: '" << optname << "'";
+                    }
+                    if (optval == "ref" || optval == "per_boot_ref") {
+                        ref_option = optval;
+                    } else {
+                        return Error() << "Unknown key option: '" << optval << "'";
+                    }
+                    set_option_key = true;
+                } else {
+                    return Error() << "Unknown option: '" << args[i] << "'";
+                }
+        }
+    }
+    if (set_option_key && fscrypt_action == FscryptAction::kNone) {
+        return Error() << "Key option set but encryption action is none";
+    }
+    const std::string prefix = "/data/";
+    if (StartsWith(args[1], prefix) &&
+        args[1].find_first_of('/', prefix.size()) == std::string::npos) {
+        if (!set_option_encryption) {
+            LOG(WARNING) << "Top-level directory needs encryption action, eg mkdir " << args[1]
+                         << " <mode> <uid> <gid> encryption=Require";
+        }
+        if (fscrypt_action == FscryptAction::kNone) {
+            LOG(INFO) << "Not setting encryption policy on: " << args[1];
+        }
+    }
+    if (fscrypt_action != fscrypt_inferred_action) {
+        LOG(WARNING) << "Inferred action different from explicit one, expected "
+                     << static_cast<int>(fscrypt_inferred_action) << " but got "
+                     << static_cast<int>(fscrypt_action);
+    }
+
+    return MkdirOptions{args[1], mode, *uid, *gid, fscrypt_action, ref_option};
+}
+
 Result<std::pair<int, std::vector<std::string>>> ParseRestorecon(
         const std::vector<std::string>& args) {
     struct flag_type {
diff --git a/init/util.h b/init/util.h
index 4cccefe..3d81d72 100644
--- a/init/util.h
+++ b/init/util.h
@@ -25,6 +25,7 @@
 
 #include <android-base/chrono_utils.h>
 
+#include "fscrypt_init_extensions.h"
 #include "result.h"
 
 using android::base::boot_clock;
@@ -60,6 +61,17 @@
 bool IsLegalPropertyName(const std::string& name);
 Result<void> IsLegalPropertyValue(const std::string& name, const std::string& value);
 
+struct MkdirOptions {
+    std::string target;
+    mode_t mode;
+    uid_t uid;
+    gid_t gid;
+    FscryptAction fscrypt_action;
+    std::string ref_option;
+};
+
+Result<MkdirOptions> ParseMkdir(const std::vector<std::string>& args);
+
 Result<std::pair<int, std::vector<std::string>>> ParseRestorecon(
         const std::vector<std::string>& args);
 
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index b9420d4..88e1bdb 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -244,6 +244,7 @@
     defaults: ["libcutils_test_default"],
     host_supported: true,
     shared_libs: test_libraries,
+    require_root: true,
 }
 
 cc_test {
@@ -255,6 +256,7 @@
         "libcgrouprc_format",
     ] + test_libraries,
     stl: "libc++_static",
+    require_root: true,
 
     target: {
         android: {
diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp
index 5fb11a5..2b39ca6 100644
--- a/libcutils/fs_config.cpp
+++ b/libcutils/fs_config.cpp
@@ -85,6 +85,7 @@
     { 00755, AID_ROOT,         AID_SHELL,        0, "system/vendor" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/xbin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "system/apex/*/bin" },
+    { 00751, AID_ROOT,         AID_SHELL,        0, "system_ext/bin" },
     { 00751, AID_ROOT,         AID_SHELL,        0, "vendor/bin" },
     { 00755, AID_ROOT,         AID_SHELL,        0, "vendor" },
     { 00755, AID_ROOT,         AID_ROOT,         0, 0 },
@@ -207,6 +208,7 @@
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/xbin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "system/apex/*/bin/*" },
+    { 00755, AID_ROOT,      AID_SHELL,     0, "system_ext/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/bin/*" },
     { 00755, AID_ROOT,      AID_SHELL,     0, "vendor/xbin/*" },
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
diff --git a/libcutils/fs_config_test.cpp b/libcutils/fs_config_test.cpp
index 9627152..c6684b4 100644
--- a/libcutils/fs_config_test.cpp
+++ b/libcutils/fs_config_test.cpp
@@ -46,7 +46,7 @@
         // clang-format off
     { true,  "system/lib",             "system/lib/hw",           true  },
     { true,  "vendor/lib",             "system/vendor/lib/hw",    true  },
-    { true,  "system/vendor/lib",      "vendor/lib/hw",           true  },
+    { true,  "system/vendor/lib",      "vendor/lib/hw",           false },
     { true,  "system/vendor/lib",      "system/vendor/lib/hw",    true  },
     { true,  "foo/*/bar/*",            "foo/1/bar/2",             true  },
     { true,  "foo/*/bar/*",            "foo/1/bar",               true  },
@@ -56,13 +56,14 @@
     { false, "vendor/bin/wifi",        "system/vendor/bin/wifi",  true  },
     { false, "vendor/bin/wifi",        "system/vendor/bin/wifi2", false },
     { false, "system/vendor/bin/wifi", "system/vendor/bin/wifi",  true, },
-    { false, "odm/bin/wifi",           "system/odm/bin/wifi",     true  },
-    { false, "oem/bin/wifi",           "system/oem/bin/wifi",     true  },
+    { false, "odm/bin/wifi",           "system/odm/bin/wifi",     false },
+    { false, "odm/bin/wifi",           "vendor/odm/bin/wifi",     true  },
+    { false, "oem/bin/wifi",           "system/oem/bin/wifi",     false },
     { false, "data/bin/wifi",          "system/data/bin/wifi",    false },
     { false, "system/bin/*",           "system/bin/wifi",         true  },
     { false, "vendor/bin/*",           "system/vendor/bin/wifi",  true  },
     { false, "system/bin/*",           "system/bin",              false },
-    { false, "system/vendor/bin/*",    "vendor/bin/wifi",         true  },
+    { false, "system/vendor/bin/*",    "vendor/bin/wifi",         false },
     { false, "foo/*/bar/*",            "foo/1/bar/2",             true  },
     { false, "foo/*/bar/*",            "foo/1/bar",               false },
     { false, "foo/*/bar/*",            "foo/1/bar/2/3",           true  },
diff --git a/libcutils/include/cutils/sockets.h b/libcutils/include/cutils/sockets.h
index 285f150..be21a8f 100644
--- a/libcutils/include/cutils/sockets.h
+++ b/libcutils/include/cutils/sockets.h
@@ -103,14 +103,6 @@
 int socket_close(cutils_socket_t sock);
 
 /*
- * Sets socket receive timeout using SO_RCVTIMEO. Setting |timeout_ms| to 0
- * disables receive timeouts.
- *
- * Return 0 on success.
- */
-int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms);
-
-/*
  * Returns the local port the socket is bound to or -1 on error.
  */
 int socket_get_local_port(cutils_socket_t sock);
diff --git a/libcutils/sockets_test.cpp b/libcutils/sockets_test.cpp
index b762ac1..1fa40bc 100644
--- a/libcutils/sockets_test.cpp
+++ b/libcutils/sockets_test.cpp
@@ -73,25 +73,6 @@
     EXPECT_EQ(0, socket_close(client));
 }
 
-// Tests receive timeout. The timing verification logic must be very coarse to
-// make sure different systems can all pass these tests.
-void TestReceiveTimeout(cutils_socket_t sock) {
-    time_t start_time;
-    char buffer[32];
-
-    // Make sure a 20ms timeout completes in 1 second or less.
-    EXPECT_EQ(0, socket_set_receive_timeout(sock, 20));
-    start_time = time(nullptr);
-    EXPECT_EQ(-1, recv(sock, buffer, sizeof(buffer), 0));
-    EXPECT_LE(difftime(time(nullptr), start_time), 1.0);
-
-    // Make sure a 1250ms timeout takes 1 second or more.
-    EXPECT_EQ(0, socket_set_receive_timeout(sock, 1250));
-    start_time = time(nullptr);
-    EXPECT_EQ(-1, recv(sock, buffer, sizeof(buffer), 0));
-    EXPECT_LE(1.0, difftime(time(nullptr), start_time));
-}
-
 // Tests socket_get_local_port().
 TEST(SocketsTest, TestGetLocalPort) {
     cutils_socket_t server;
@@ -157,32 +138,6 @@
     TestConnectedSockets(handler, client, SOCK_STREAM);
 }
 
-// Tests setting a receive timeout for UDP sockets.
-TEST(SocketsTest, TestUdpReceiveTimeout) {
-    cutils_socket_t sock = socket_inaddr_any_server(0, SOCK_DGRAM);
-    ASSERT_NE(INVALID_SOCKET, sock);
-
-    TestReceiveTimeout(sock);
-
-    EXPECT_EQ(0, socket_close(sock));
-}
-
-// Tests setting a receive timeout for TCP sockets.
-TEST(SocketsTest, TestTcpReceiveTimeout) {
-    cutils_socket_t server = socket_inaddr_any_server(0, SOCK_STREAM);
-    ASSERT_NE(INVALID_SOCKET, server);
-
-    cutils_socket_t client = socket_network_client(
-            "localhost", socket_get_local_port(server), SOCK_STREAM);
-    cutils_socket_t handler = accept(server, nullptr, nullptr);
-    EXPECT_EQ(0, socket_close(server));
-
-    TestReceiveTimeout(handler);
-
-    EXPECT_EQ(0, socket_close(client));
-    EXPECT_EQ(0, socket_close(handler));
-}
-
 // Tests socket_send_buffers() failure.
 TEST(SocketsTest, TestSocketSendBuffersFailure) {
     EXPECT_EQ(-1, socket_send_buffers(INVALID_SOCKET, nullptr, 0));
diff --git a/libcutils/sockets_unix.cpp b/libcutils/sockets_unix.cpp
index 6acdcd8..84663e6 100644
--- a/libcutils/sockets_unix.cpp
+++ b/libcutils/sockets_unix.cpp
@@ -31,13 +31,6 @@
     return close(sock);
 }
 
-int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms) {
-    timeval tv;
-    tv.tv_sec = timeout_ms / 1000;
-    tv.tv_usec = (timeout_ms % 1000) * 1000;
-    return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
-}
-
 ssize_t socket_send_buffers(cutils_socket_t sock,
                             const cutils_socket_buffer_t* buffers,
                             size_t num_buffers) {
diff --git a/libcutils/sockets_windows.cpp b/libcutils/sockets_windows.cpp
index df14712..4adb796 100644
--- a/libcutils/sockets_windows.cpp
+++ b/libcutils/sockets_windows.cpp
@@ -54,11 +54,6 @@
     return closesocket(sock);
 }
 
-int socket_set_receive_timeout(cutils_socket_t sock, int timeout_ms) {
-    return setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
-                      reinterpret_cast<char*>(&timeout_ms), sizeof(timeout_ms));
-}
-
 ssize_t socket_send_buffers(cutils_socket_t sock,
                             const cutils_socket_buffer_t* buffers,
                             size_t num_buffers) {
diff --git a/libgrallocusage/Android.bp b/libgrallocusage/Android.bp
index d27feb9..ce0c3c8 100644
--- a/libgrallocusage/Android.bp
+++ b/libgrallocusage/Android.bp
@@ -20,12 +20,7 @@
         "-Werror",
     ],
     cppflags: [
-        "-Weverything",
-        "-Wno-c++98-compat-pedantic",
-        // Hide errors in headers we include
-        "-Wno-global-constructors",
-        "-Wno-exit-time-destructors",
-        "-Wno-padded",
+        "-Wextra",
     ],
     srcs: ["GrallocUsageConversion.cpp"],
     export_include_dirs: ["include"],
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index ce4c53c..aea3350 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -51,7 +51,7 @@
 LIBLOG_O {
   global:
     __android_log_is_loggable_len;
-    __android_log_is_debuggable; # vndk
+    __android_log_is_debuggable; # apex vndk
 };
 
 LIBLOG_Q {
@@ -61,15 +61,15 @@
     __android_log_bwrite; # apex
     __android_log_close; # apex
     __android_log_security; # apex
-    android_log_reset; #vndk
-    android_log_parser_reset; #vndk
+    __android_log_security_bswrite; # apex
+    android_log_reset; # vndk
+    android_log_parser_reset; # vndk
 };
 
 LIBLOG_PRIVATE {
   global:
     __android_log_pmsg_file_read;
     __android_log_pmsg_file_write;
-    __android_log_security_bswrite;
     __android_logger_get_buffer_size;
     __android_logger_property_get_bool;
     android_openEventTagMap;
diff --git a/libprocessgroup/profiles/test.cpp b/libprocessgroup/profiles/test.cpp
index bc9aade..b37e3e6 100644
--- a/libprocessgroup/profiles/test.cpp
+++ b/libprocessgroup/profiles/test.cpp
@@ -33,14 +33,14 @@
 }
 
 // Test suite instantiations
-INSTANTIATE_TEST_SUITE_P(, JsonSchemaTest,
+INSTANTIATE_TEST_SUITE_P(Cgroups, JsonSchemaTest,
                          ::testing::Values(MakeTestParam<Cgroups>("/cgroups.json"),
                                            MakeTestParam<Cgroups>("/cgroups.recovery.json"),
                                            MakeTestParam<TaskProfiles>("/task_profiles.json")));
-INSTANTIATE_TEST_SUITE_P(, CgroupsTest,
+INSTANTIATE_TEST_SUITE_P(Cgroups, CgroupsTest,
                          ::testing::Values(MakeTestParam<Cgroups>("/cgroups.json"),
                                            MakeTestParam<Cgroups>("/cgroups.recovery.json")));
-INSTANTIATE_TEST_SUITE_P(, TaskProfilesTest,
+INSTANTIATE_TEST_SUITE_P(TaskProfiles, TaskProfilesTest,
                          ::testing::Values(MakeTestParam<TaskProfiles>("/task_profiles.json")));
 
 }  // namespace profiles
diff --git a/libunwindstack/tests/ArmExidxDecodeTest.cpp b/libunwindstack/tests/ArmExidxDecodeTest.cpp
index 7b1dd92..69a7816 100644
--- a/libunwindstack/tests/ArmExidxDecodeTest.cpp
+++ b/libunwindstack/tests/ArmExidxDecodeTest.cpp
@@ -1662,7 +1662,7 @@
   ASSERT_EQ(0x10U, (*exidx_->regs())[15]);
 }
 
-INSTANTIATE_TEST_SUITE_P(, ArmExidxDecodeTest,
+INSTANTIATE_TEST_SUITE_P(Unwindstack, ArmExidxDecodeTest,
                          ::testing::Values("logging", "register_logging", "no_logging"));
 
 }  // namespace unwindstack
diff --git a/libutils/include/utils/Flattenable.h b/libutils/include/utils/Flattenable.h
index 953b859..17c5e10 100644
--- a/libutils/include/utils/Flattenable.h
+++ b/libutils/include/utils/Flattenable.h
@@ -52,7 +52,12 @@
 
     template<size_t N>
     static size_t align(void*& buffer) {
-        return align<N>( const_cast<void const*&>(buffer) );
+        static_assert(!(N & (N - 1)), "Can only align to a power of 2.");
+        void* b = buffer;
+        buffer = reinterpret_cast<void*>((uintptr_t(buffer) + (N-1)) & ~(N-1));
+        size_t delta = size_t(uintptr_t(buffer) - uintptr_t(b));
+        memset(b, 0, delta);
+        return delta;
     }
 
     static void advance(void*& buffer, size_t& size, size_t offset) {
diff --git a/libutils/include/utils/Trace.h b/libutils/include/utils/Trace.h
index fec0ffa..9986bf5 100644
--- a/libutils/include/utils/Trace.h
+++ b/libutils/include/utils/Trace.h
@@ -33,7 +33,7 @@
 // ATRACE_NAME traces from its location until the end of its enclosing scope.
 #define _PASTE(x, y) x ## y
 #define PASTE(x, y) _PASTE(x,y)
-#define ATRACE_NAME(name) android::ScopedTrace PASTE(___tracer, __LINE__) (ATRACE_TAG, name)
+#define ATRACE_NAME(name) ::android::ScopedTrace PASTE(___tracer, __LINE__)(ATRACE_TAG, name)
 
 // ATRACE_CALL is an ATRACE_NAME that uses the current function name.
 #define ATRACE_CALL() ATRACE_NAME(__FUNCTION__)
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 667bddc..e3bb2ab 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -196,4 +196,5 @@
     srcs: ["libziparchive_fuzzer.cpp"],
     static_libs: ["libziparchive", "libbase", "libz", "liblog"],
     host_supported: true,
+    corpus: ["testdata/*"],
 }
diff --git a/lmkd/Android.bp b/lmkd/Android.bp
index e8e125b..deebb8e 100644
--- a/lmkd/Android.bp
+++ b/lmkd/Android.bp
@@ -48,6 +48,7 @@
 cc_library_static {
     name: "liblmkd_utils",
     srcs: ["liblmkd_utils.c"],
+    recovery_available: true,
     shared_libs: [
         "libcutils",
     ],
diff --git a/lmkd/include/liblmkd_utils.h b/lmkd/include/liblmkd_utils.h
index 72e3f4a..92e4d41 100644
--- a/lmkd/include/liblmkd_utils.h
+++ b/lmkd/include/liblmkd_utils.h
@@ -40,6 +40,14 @@
 int lmkd_register_proc(int sock, struct lmk_procprio *params);
 
 /*
+ * Unregisters a process previously registered with lmkd.
+ * On success returns 0.
+ * On error, -1 is returned.
+ * In the case of error errno is set appropriately.
+ */
+int lmkd_unregister_proc(int sock, struct lmk_procremove *params);
+
+/*
  * Creates memcg directory for given process.
  * On success returns 0.
  * -1 is returned if path creation failed.
diff --git a/lmkd/include/lmkd.h b/lmkd/include/lmkd.h
index 59377dd..bd9b80e 100644
--- a/lmkd/include/lmkd.h
+++ b/lmkd/include/lmkd.h
@@ -87,21 +87,33 @@
     return idx * sizeof(int);
 }
 
+/* Process types for lmk_procprio.ptype */
+enum proc_type {
+    PROC_TYPE_FIRST,
+    PROC_TYPE_APP = PROC_TYPE_FIRST,
+    PROC_TYPE_SERVICE,
+    PROC_TYPE_COUNT,
+};
+
 /* LMK_PROCPRIO packet payload */
 struct lmk_procprio {
     pid_t pid;
     uid_t uid;
     int oomadj;
+    enum proc_type ptype;
 };
 
 /*
  * For LMK_PROCPRIO packet get its payload.
  * Warning: no checks performed, caller should ensure valid parameters.
  */
-static inline void lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet, struct lmk_procprio* params) {
+static inline void lmkd_pack_get_procprio(LMKD_CTRL_PACKET packet, int field_count,
+                                          struct lmk_procprio* params) {
     params->pid = (pid_t)ntohl(packet[1]);
     params->uid = (uid_t)ntohl(packet[2]);
     params->oomadj = ntohl(packet[3]);
+    /* if field is missing assume PROC_TYPE_APP for backward compatibility */
+    params->ptype = field_count > 3 ? (enum proc_type)ntohl(packet[4]) : PROC_TYPE_APP;
 }
 
 /*
@@ -113,7 +125,8 @@
     packet[1] = htonl(params->pid);
     packet[2] = htonl(params->uid);
     packet[3] = htonl(params->oomadj);
-    return 4 * sizeof(int);
+    packet[4] = htonl((int)params->ptype);
+    return 5 * sizeof(int);
 }
 
 /* LMK_PROCREMOVE packet payload */
@@ -135,7 +148,7 @@
  * Warning: no checks performed, caller should ensure valid parameters.
  */
 static inline size_t lmkd_pack_set_procremove(LMKD_CTRL_PACKET packet,
-                                              struct lmk_procprio* params) {
+                                              struct lmk_procremove* params) {
     packet[0] = htonl(LMK_PROCREMOVE);
     packet[1] = htonl(params->pid);
     return 2 * sizeof(int);
diff --git a/lmkd/liblmkd_utils.c b/lmkd/liblmkd_utils.c
index fa3b7a9..280c149 100644
--- a/lmkd/liblmkd_utils.c
+++ b/lmkd/liblmkd_utils.c
@@ -28,7 +28,7 @@
 int lmkd_connect() {
     return socket_local_client("lmkd",
                                ANDROID_SOCKET_NAMESPACE_RESERVED,
-                               SOCK_SEQPACKET);
+                               SOCK_SEQPACKET | SOCK_CLOEXEC);
 }
 
 int lmkd_register_proc(int sock, struct lmk_procprio *params) {
@@ -42,6 +42,17 @@
     return (ret < 0) ? -1 : 0;
 }
 
+int lmkd_unregister_proc(int sock, struct lmk_procremove *params) {
+    LMKD_CTRL_PACKET packet;
+    size_t size;
+    int ret;
+
+    size = lmkd_pack_set_procremove(packet, params);
+    ret = TEMP_FAILURE_RETRY(write(sock, packet, size));
+
+    return (ret < 0) ? -1 : 0;
+}
+
 int create_memcg(uid_t uid, pid_t pid) {
     char buf[256];
     int tasks_file;
diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c
index 9de7ff7..4352498 100644
--- a/lmkd/lmkd.c
+++ b/lmkd/lmkd.c
@@ -45,6 +45,7 @@
 #include <log/log.h>
 #include <log/log_event_list.h>
 #include <log/log_time.h>
+#include <private/android_filesystem_config.h>
 #include <psi/psi.h>
 #include <system/thread_defs.h>
 
@@ -240,11 +241,12 @@
 /* data required to handle socket events */
 struct sock_event_handler_info {
     int sock;
+    pid_t pid;
     struct event_handler_info handler_info;
 };
 
-/* max supported number of data connections */
-#define MAX_DATA_CONN 2
+/* max supported number of data connections (AMS, init, tests) */
+#define MAX_DATA_CONN 3
 
 /* socket event handler data */
 static struct sock_event_handler_info ctrl_sock;
@@ -254,7 +256,7 @@
 static struct event_handler_info vmpressure_hinfo[VMPRESS_LEVEL_COUNT];
 
 /*
- * 1 ctrl listen socket, 2 ctrl data socket, 3 memory pressure levels,
+ * 1 ctrl listen socket, 3 ctrl data socket, 3 memory pressure levels,
  * 1 lmk events + 1 fd to wait for process death
  */
 #define MAX_EPOLL_EVENTS (1 + MAX_DATA_CONN + VMPRESS_LEVEL_COUNT + 1 + 1)
@@ -490,6 +492,7 @@
     int pidfd;
     uid_t uid;
     int oomadj;
+    pid_t reg_pid; /* PID of the process that registered this record */
     struct proc *pidhash_next;
 };
 
@@ -845,7 +848,35 @@
     return buf;
 }
 
-static void cmd_procprio(LMKD_CTRL_PACKET packet) {
+static bool claim_record(struct proc *procp, pid_t pid) {
+    if (procp->reg_pid == pid) {
+        /* Record already belongs to the registrant */
+        return true;
+    }
+    if (procp->reg_pid == 0) {
+        /* Old registrant is gone, claim the record */
+        procp->reg_pid = pid;
+        return true;
+    }
+    /* The record is owned by another registrant */
+    return false;
+}
+
+static void remove_claims(pid_t pid) {
+    int i;
+
+    for (i = 0; i < PIDHASH_SZ; i++) {
+        struct proc *procp = pidhash[i];
+        while (procp) {
+            if (procp->reg_pid == pid) {
+                procp->reg_pid = 0;
+            }
+            procp = procp->pidhash_next;
+        }
+    }
+}
+
+static void cmd_procprio(LMKD_CTRL_PACKET packet, int field_count, struct ucred *cred) {
     struct proc *procp;
     char path[LINE_MAX];
     char val[20];
@@ -855,7 +886,7 @@
     struct passwd *pwdrec;
     int tgid;
 
-    lmkd_pack_get_procprio(packet, &params);
+    lmkd_pack_get_procprio(packet, field_count, &params);
 
     if (params.oomadj < OOM_SCORE_ADJ_MIN ||
         params.oomadj > OOM_SCORE_ADJ_MAX) {
@@ -863,6 +894,11 @@
         return;
     }
 
+    if (params.ptype < PROC_TYPE_FIRST || params.ptype >= PROC_TYPE_COUNT) {
+        ALOGE("Invalid PROCPRIO process type argument %d", params.ptype);
+        return;
+    }
+
     /* Check if registered process is a thread group leader */
     tgid = proc_get_tgid(params.pid);
     if (tgid >= 0 && tgid != params.pid) {
@@ -889,7 +925,8 @@
         return;
     }
 
-    if (per_app_memcg) {
+    /* lmkd should not change soft limits for services */
+    if (params.ptype == PROC_TYPE_APP && per_app_memcg) {
         if (params.oomadj >= 900) {
             soft_limit_mult = 0;
         } else if (params.oomadj >= 800) {
@@ -954,24 +991,47 @@
         procp->pid = params.pid;
         procp->pidfd = pidfd;
         procp->uid = params.uid;
+        procp->reg_pid = cred->pid;
         procp->oomadj = params.oomadj;
         proc_insert(procp);
     } else {
+        if (!claim_record(procp, cred->pid)) {
+            char buf[LINE_MAX];
+            /* Only registrant of the record can remove it */
+            ALOGE("%s (%d, %d) attempts to modify a process registered by another client",
+                proc_get_name(cred->pid, buf, sizeof(buf)), cred->uid, cred->pid);
+            return;
+        }
         proc_unslot(procp);
         procp->oomadj = params.oomadj;
         proc_slot(procp);
     }
 }
 
-static void cmd_procremove(LMKD_CTRL_PACKET packet) {
+static void cmd_procremove(LMKD_CTRL_PACKET packet, struct ucred *cred) {
     struct lmk_procremove params;
+    struct proc *procp;
 
     lmkd_pack_get_procremove(packet, &params);
+
     if (use_inkernel_interface) {
         stats_remove_taskname(params.pid, kpoll_info.poll_fd);
         return;
     }
 
+    procp = pid_lookup(params.pid);
+    if (!procp) {
+        return;
+    }
+
+    if (!claim_record(procp, cred->pid)) {
+        char buf[LINE_MAX];
+        /* Only registrant of the record can remove it */
+        ALOGE("%s (%d, %d) attempts to unregister a process registered by another client",
+            proc_get_name(cred->pid, buf, sizeof(buf)), cred->uid, cred->pid);
+        return;
+    }
+
     /*
      * WARNING: After pid_remove() procp is freed and can't be used!
      * Therefore placed at the end of the function.
@@ -979,7 +1039,7 @@
     pid_remove(params.pid);
 }
 
-static void cmd_procpurge() {
+static void cmd_procpurge(struct ucred *cred) {
     int i;
     struct proc *procp;
     struct proc *next;
@@ -989,20 +1049,17 @@
         return;
     }
 
-    for (i = 0; i <= ADJTOSLOT(OOM_SCORE_ADJ_MAX); i++) {
-        procadjslot_list[i].next = &procadjslot_list[i];
-        procadjslot_list[i].prev = &procadjslot_list[i];
-    }
-
     for (i = 0; i < PIDHASH_SZ; i++) {
         procp = pidhash[i];
         while (procp) {
             next = procp->pidhash_next;
-            free(procp);
+            /* Purge only records created by the requestor */
+            if (claim_record(procp, cred->pid)) {
+                pid_remove(procp->pid);
+            }
             procp = next;
         }
     }
-    memset(&pidhash[0], 0, sizeof(pidhash));
 }
 
 static void inc_killcnt(int oomadj) {
@@ -1153,19 +1210,50 @@
 
     close(data_sock[dsock_idx].sock);
     data_sock[dsock_idx].sock = -1;
+
+    /* Mark all records of the old registrant as unclaimed */
+    remove_claims(data_sock[dsock_idx].pid);
 }
 
-static int ctrl_data_read(int dsock_idx, char *buf, size_t bufsz) {
-    int ret = 0;
+static ssize_t ctrl_data_read(int dsock_idx, char *buf, size_t bufsz, struct ucred *sender_cred) {
+    struct iovec iov = { buf, bufsz };
+    char control[CMSG_SPACE(sizeof(struct ucred))];
+    struct msghdr hdr = {
+        NULL, 0, &iov, 1, control, sizeof(control), 0,
+    };
+    ssize_t ret;
 
-    ret = TEMP_FAILURE_RETRY(read(data_sock[dsock_idx].sock, buf, bufsz));
-
+    ret = TEMP_FAILURE_RETRY(recvmsg(data_sock[dsock_idx].sock, &hdr, 0));
     if (ret == -1) {
-        ALOGE("control data socket read failed; errno=%d", errno);
-    } else if (ret == 0) {
-        ALOGE("Got EOF on control data socket");
-        ret = -1;
+        ALOGE("control data socket read failed; %s", strerror(errno));
+        return -1;
     }
+    if (ret == 0) {
+        ALOGE("Got EOF on control data socket");
+        return -1;
+    }
+
+    struct ucred* cred = NULL;
+    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
+    while (cmsg != NULL) {
+        if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS) {
+            cred = (struct ucred*)CMSG_DATA(cmsg);
+            break;
+        }
+        cmsg = CMSG_NXTHDR(&hdr, cmsg);
+    }
+
+    if (cred == NULL) {
+        ALOGE("Failed to retrieve sender credentials");
+        /* Close the connection */
+        ctrl_data_close(dsock_idx);
+        return -1;
+    }
+
+    memcpy(sender_cred, cred, sizeof(struct ucred));
+
+    /* Store PID of the peer */
+    data_sock[dsock_idx].pid = cred->pid;
 
     return ret;
 }
@@ -1187,13 +1275,14 @@
 
 static void ctrl_command_handler(int dsock_idx) {
     LMKD_CTRL_PACKET packet;
+    struct ucred cred;
     int len;
     enum lmk_cmd cmd;
     int nargs;
     int targets;
     int kill_cnt;
 
-    len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE);
+    len = ctrl_data_read(dsock_idx, (char *)packet, CTRL_PACKET_MAX_SIZE, &cred);
     if (len <= 0)
         return;
 
@@ -1215,19 +1304,20 @@
         cmd_target(targets, packet);
         break;
     case LMK_PROCPRIO:
-        if (nargs != 3)
+        /* process type field is optional for backward compatibility */
+        if (nargs < 3 || nargs > 4)
             goto wronglen;
-        cmd_procprio(packet);
+        cmd_procprio(packet, nargs, &cred);
         break;
     case LMK_PROCREMOVE:
         if (nargs != 1)
             goto wronglen;
-        cmd_procremove(packet);
+        cmd_procremove(packet, &cred);
         break;
     case LMK_PROCPURGE:
         if (nargs != 0)
             goto wronglen;
-        cmd_procpurge();
+        cmd_procpurge(&cred);
         break;
     case LMK_GETKILLCNT:
         if (nargs != 2)
diff --git a/lmkd/lmkd.rc b/lmkd/lmkd.rc
index 76b6055..982a188 100644
--- a/lmkd/lmkd.rc
+++ b/lmkd/lmkd.rc
@@ -4,5 +4,5 @@
     group lmkd system readproc
     capabilities DAC_OVERRIDE KILL IPC_LOCK SYS_NICE SYS_RESOURCE
     critical
-    socket lmkd seqpacket 0660 system system
+    socket lmkd seqpacket+passcred 0660 system system
     writepid /dev/cpuset/system-background/tasks
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index eac3f06..19f117f 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -294,27 +294,6 @@
 include $(BUILD_PREBUILT)
 
 #######################################
-# {llndk,vndkcore,vndksp,vndkprivate,vndkcorevariant}.libraries.txt
-vndk_libraries_files := \
-  llndk.libraries.txt:$(SOONG_LLNDK_LIBRARIES_FILE)\
-  vndkcore.libraries.txt:$(SOONG_VNDKCORE_LIBRARIES_FILE)\
-  vndksp.libraries.txt:$(SOONG_VNDKSP_LIBRARIES_FILE)\
-  vndkprivate.libraries.txt:$(SOONG_VNDKPRIVATE_LIBRARIES_FILE)\
-  vndkcorevariant.libraries.txt:$(SOONG_VNDKCOREVARIANT_LIBRARIES_FILE)
-
-$(foreach pair,$(vndk_libraries_files),\
-  $(eval _filename := $(call word-colon,1,$(pair)))\
-  $(eval _prebuilt := $(call word-colon,2,$(pair)))\
-  $(eval include $(CLEAR_VARS))\
-  $(eval LOCAL_MODULE := $(_filename))\
-  $(eval LOCAL_MODULE_CLASS := ETC)\
-  $(eval LOCAL_PREBUILT_MODULE_FILE := $(_prebuilt))\
-  $(eval LOCAL_MODULE_PATH := $(TARGET_OUT_ETC))\
-  $(eval LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE)))\
-  $(eval include $(BUILD_PREBUILT)))
-vndk_libraries_files :=
-
-#######################################
 # sanitizer.libraries.txt
 include $(CLEAR_VARS)
 LOCAL_MODULE := sanitizer.libraries.txt
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 66d60fa..0827247 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -347,6 +347,8 @@
 
     # Start logd before any other services run to ensure we capture all of their logs.
     start logd
+    # Start lmkd before any other services run so that it can register them
+    start lmkd
 
     # Start essential services.
     start servicemanager
@@ -486,26 +488,26 @@
 
     # Start bootcharting as soon as possible after the data partition is
     # mounted to collect more data.
-    mkdir /data/bootchart 0755 shell shell
+    mkdir /data/bootchart 0755 shell shell encryption=Require
     bootchart start
 
     # Make sure that apexd is started in the default namespace
     enter_default_mount_ns
 
     # /data/apex is now available. Start apexd to scan and activate APEXes.
-    mkdir /data/apex 0750 root system
+    mkdir /data/apex 0750 root system encryption=None
     mkdir /data/apex/active 0750 root system
     mkdir /data/apex/backup 0700 root system
     mkdir /data/apex/hashtree 0700 root system
     mkdir /data/apex/sessions 0700 root system
-    mkdir /data/app-staging 0750 system system
+    mkdir /data/app-staging 0750 system system encryption=None
     start apexd
 
     # Avoid predictable entropy pool. Carry over entropy from previous boot.
     copy /data/system/entropy.dat /dev/urandom
 
     # create basic filesystem structure
-    mkdir /data/misc 01771 system misc
+    mkdir /data/misc 01771 system misc encryption=Require
     mkdir /data/misc/recovery 0770 system log
     copy /data/misc/recovery/ro.build.fingerprint /data/misc/recovery/ro.build.fingerprint.1
     chmod 0440 /data/misc/recovery/ro.build.fingerprint.1
@@ -548,7 +550,7 @@
     mkdir /data/misc/user 0771 root root
     # give system access to wpa_supplicant.conf for backup and restore
     chmod 0660 /data/misc/wifi/wpa_supplicant.conf
-    mkdir /data/local 0751 root root
+    mkdir /data/local 0751 root root encryption=Require
     mkdir /data/misc/media 0700 media media
     mkdir /data/misc/audioserver 0700 audioserver audioserver
     mkdir /data/misc/cameraserver 0700 cameraserver cameraserver
@@ -567,89 +569,91 @@
     mkdir /data/misc/gcov 0770 root root
     mkdir /data/misc/installd 0700 root root
 
-    mkdir /data/preloads 0775 system system
+    mkdir /data/preloads 0775 system system encryption=None
 
-    mkdir /data/vendor 0771 root root
-    mkdir /data/vendor_ce 0771 root root
-    mkdir /data/vendor_de 0771 root root
+    mkdir /data/vendor 0771 root root encryption=Require
+    mkdir /data/vendor_ce 0771 root root encryption=None
+    mkdir /data/vendor_de 0771 root root encryption=None
     mkdir /data/vendor/hardware 0771 root root
 
     # For security reasons, /data/local/tmp should always be empty.
     # Do not place files or directories in /data/local/tmp
     mkdir /data/local/tmp 0771 shell shell
     mkdir /data/local/traces 0777 shell shell
-    mkdir /data/data 0771 system system
-    mkdir /data/app-private 0771 system system
-    mkdir /data/app-ephemeral 0771 system system
-    mkdir /data/app-asec 0700 root root
-    mkdir /data/app-lib 0771 system system
-    mkdir /data/app 0771 system system
-    mkdir /data/property 0700 root root
-    mkdir /data/tombstones 0771 system system
+    mkdir /data/data 0771 system system encryption=None
+    mkdir /data/app-private 0771 system system encryption=Require
+    mkdir /data/app-ephemeral 0771 system system encryption=Require
+    mkdir /data/app-asec 0700 root root encryption=Require
+    mkdir /data/app-lib 0771 system system encryption=Require
+    mkdir /data/app 0771 system system encryption=Require
+    mkdir /data/property 0700 root root encryption=Require
+    mkdir /data/tombstones 0771 system system encryption=Require
     mkdir /data/vendor/tombstones 0771 root root
     mkdir /data/vendor/tombstones/wifi 0771 wifi wifi
 
     # create dalvik-cache, so as to enforce our permissions
-    mkdir /data/dalvik-cache 0771 root root
+    mkdir /data/dalvik-cache 0771 root root encryption=Require
     # create the A/B OTA directory, so as to enforce our permissions
-    mkdir /data/ota 0771 root root
+    mkdir /data/ota 0771 root root encryption=Require
 
     # create the OTA package directory. It will be accessed by GmsCore (cache
     # group), update_engine and update_verifier.
-    mkdir /data/ota_package 0770 system cache
+    mkdir /data/ota_package 0770 system cache encryption=Require
 
     # create resource-cache and double-check the perms
-    mkdir /data/resource-cache 0771 system system
+    mkdir /data/resource-cache 0771 system system encryption=Require
     chown system system /data/resource-cache
     chmod 0771 /data/resource-cache
 
     # create the lost+found directories, so as to enforce our permissions
-    mkdir /data/lost+found 0770 root root
+    mkdir /data/lost+found 0770 root root encryption=None
 
     # create directory for DRM plug-ins - give drm the read/write access to
     # the following directory.
-    mkdir /data/drm 0770 drm drm
+    mkdir /data/drm 0770 drm drm encryption=Require
 
     # create directory for MediaDrm plug-ins - give drm the read/write access to
     # the following directory.
-    mkdir /data/mediadrm 0770 mediadrm mediadrm
+    mkdir /data/mediadrm 0770 mediadrm mediadrm encryption=Require
 
-    mkdir /data/anr 0775 system system
+    mkdir /data/anr 0775 system system encryption=Require
 
     # NFC: create data/nfc for nv storage
-    mkdir /data/nfc 0770 nfc nfc
+    mkdir /data/nfc 0770 nfc nfc encryption=Require
     mkdir /data/nfc/param 0770 nfc nfc
 
     # Create all remaining /data root dirs so that they are made through init
     # and get proper encryption policy installed
-    mkdir /data/backup 0700 system system
-    mkdir /data/ss 0700 system system
+    mkdir /data/backup 0700 system system encryption=Require
+    mkdir /data/ss 0700 system system encryption=Require
 
-    mkdir /data/system 0775 system system
+    mkdir /data/system 0775 system system encryption=Require
     mkdir /data/system/dropbox 0700 system system
     mkdir /data/system/heapdump 0700 system system
     mkdir /data/system/users 0775 system system
 
-    mkdir /data/system_de 0770 system system
-    mkdir /data/system_ce 0770 system system
+    mkdir /data/system_de 0770 system system encryption=None
+    mkdir /data/system_ce 0770 system system encryption=None
 
-    mkdir /data/misc_de 01771 system misc
-    mkdir /data/misc_ce 01771 system misc
+    mkdir /data/misc_de 01771 system misc encryption=None
+    mkdir /data/misc_ce 01771 system misc encryption=None
 
-    mkdir /data/user 0711 system system
-    mkdir /data/user_de 0711 system system
+    mkdir /data/user 0711 system system encryption=None
+    mkdir /data/user_de 0711 system system encryption=None
     symlink /data/data /data/user/0
 
-    mkdir /data/media 0770 media_rw media_rw
-    mkdir /data/media/obb 0770 media_rw media_rw
+    # Special-case /data/media/obb per b/64566063
+    mkdir /data/media 0770 media_rw media_rw encryption=None
+    mkdir /data/media/obb 0770 media_rw media_rw encryption=Attempt
 
-    mkdir /data/cache 0770 system cache
+    mkdir /data/cache 0770 system cache encryption=Require
     mkdir /data/cache/recovery 0770 system cache
     mkdir /data/cache/backup_stage 0700 system system
     mkdir /data/cache/backup 0700 system system
 
-    mkdir /data/rollback 0700 system system
-    mkdir /data/rollback-observer 0700 system system
+    # Delete these if need be, per b/139193659
+    mkdir /data/rollback 0700 system system encryption=DeleteIfNecessary
+    mkdir /data/rollback-observer 0700 system system encryption=DeleteIfNecessary
 
     # Wait for apexd to finish activating APEXes before starting more processes.
     wait_for_prop apexd.status ready
@@ -867,7 +871,7 @@
     bootchart stop
     # Setup per_boot directory so other .rc could start to use it on boot_completed
     exec - system system -- /bin/rm -rf /data/per_boot
-    mkdir /data/per_boot 0700 system system
+    mkdir /data/per_boot 0700 system system encryption=Require key=per_boot_ref
 
 # system server cannot write to /proc/sys files,
 # and chown/chmod does not work for /proc/sys/ entries.
@@ -924,7 +928,7 @@
   setprop sys.init.userspace_reboot_in_progress 1
   setprop sys.boot_completed 0
   setprop sys.init.updatable_crashing 0
-  setprop apexd.status 0
+  setprop apexd.status ""
 
 on userspace-reboot-fs-remount
   # Make sure that vold is running.
diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc
index b6cba90..a1888fc 100644
--- a/rootdir/init.usb.rc
+++ b/rootdir/init.usb.rc
@@ -9,13 +9,14 @@
     chown system system /sys/class/android_usb/android0/f_rndis/ethaddr
     chmod 0660 /sys/class/android_usb/android0/f_rndis/ethaddr
     mkdir /data/misc/adb 02750 system shell
-    mkdir /data/adb 0700 root root
+    mkdir /data/adb 0700 root root encryption=Require
 
 # adbd is controlled via property triggers in init.<platform>.usb.rc
 service adbd /system/bin/adbd --root_seclabel=u:r:su:s0
     class core
     socket adbd seqpacket 660 system system
     disabled
+    updatable
     seclabel u:r:adbd:s0
 
 on boot