Merge "fastboot: switch to ZipEntry64."
diff --git a/adb/README.md b/adb/README.md
new file mode 100644
index 0000000..224387c
--- /dev/null
+++ b/adb/README.md
@@ -0,0 +1,94 @@
+# ADB Internals
+
+If you are new to adb source code, you should start by reading [OVERVIEW.TXT](OVERVIEW.TXT) which describes the three components of adb pipeline.
+
+This document is here to boost what can be achieved within a "window of naive interest". You will not find function or class documentation here but rather the "big picture" which should allow you to build a mental map to help navigate the code.
+
+## Three components of adb pipeline
+
+As outlined in the overview, this codebase generates three components (Client, Server (a.k.a Host), and Daemon (a.k.a adbd)). The central part is the Server which runs on the Host computer. On one side the Server exposes a "Smart Socket" to Clients such as adb or DDMLIB. On the other side, the Server continuously monitors for connecting Daemons (as USB devices or TCP emulator). Communication with a device is done with a Transport.
+
+```
++----------+              +------------------------+
+|   ADB    +----------+   |      ADB SERVER        |                   +----------+
+|  CLIENT  |          |   |                        |              (USB)|   ADBD   |
++----------+          |   |                     Transport+-------------+ (DEVICE) |
+                      |   |                        |                   +----------+
++-----------          |   |                        |
+|   ADB    |          v   +                        |                   +----------+
+|  CLIENT  +--------->SmartSocket                  |              (USB)|   ADBD   |
++----------+          ^   | (TCP/IP)            Transport+-------------+ (DEVICE) |
+                      |   |                        |                   +----------+
++----------+          |   |                        |
+|  DDMLIB  |          |   |                     Transport+--+          +----------+
+|  CLIENT  +----------+   |                        |        |  (TCP/IP)|   ADBD   |
++----------+              +------------------------+        +----------|(EMULATOR)|
+                                                                       +----------+
+```
+
+The Client and the Server are contained in the same executable and both run on the Host machine. Code sections specific to the Host is enclosed within `ADB_HOST` guard. adbd runs on the Android Device. Daemon specific code is enclosed in `!ADB_HOST` but also sometimes with-in `__ANDROID__` guard.
+
+
+## "SMART SOCKET" and TRANSPORT
+
+A smart socket is a simple TCP socket with a smart protocol built on top of it. This is what Clients connect onto from the Host side. The Client must always initiate communication via a human readable request but the response format varies. The smart protocol is documented in [SERVICES.TXT](SERVICES.TXT).
+
+On the other side, the Server communicate with a device via a Transport. adb initially targeted devices connecting over USB, which is restricted to a fixed number of data streams. Therefore, adb multiplexes multiple byte streams over a single pipe via Transport. When devices connecting over other mechanisms (e.g. emulators over TCP) were introduced, the existing transport protocol was maintained.
+
+## THREADING MODEL and FDEVENT system
+
+At the heart of both the Server and Daemon is a main thread running an fdevent loop, which is an platform-independent abstraction over poll/epoll/WSAPoll monitoring file descriptors events. Requests and services are usually server from the main thread but some service requests result in new threads being spawned.
+
+To allow for operations to run on the Main thread, fdevent features a RunQueue combined with an interrupt fd to force polling to return.
+
+```
++------------+    +-------------------------^
+|  RUNQUEUE  |    |                         |
++------------+    |  POLLING (Main thread)  |
+| Function<> |    |                         |
++------------+    |                         |
+| Function<> |    ^-^-------^-------^------^^
++------------+      |       |       |       |
+|    ...     |      |       |       |       |
++------------+      |       |       |       |
+|            |      |       |       |       |
+|============|      |       |       |       |
+|Interrupt fd+------+  +----+  +----+  +----+
++------------+         fd      Socket  Pipe
+```
+
+## ASOCKET, APACKET, and AMESSAGE
+
+The asocket, apacket, and amessage constructs exist only to wrap data while it transits on a Transport. An asocket handles a stream of apackets. An apacket consists in a amessage header featuring a command (`A_SYNC`, `A_OPEN`, `A_CLSE`, `A_WRTE`, `A_OKAY`, ...) followed by a payload (find more documentation in [protocol.txt](protocol.txt). There is no `A_READ` command because an asocket is unidirectional. To model a bi-directional stream, asocket have a peer which go in the opposite direction.
+
+An asocket features a buffer where the elemental unit is an apacket. Is traffic is inbound, the buffer stores apacket until they are consumed. If the traffic is oubound, the buffer store apackets until they are sent down the wire (with `A_WRTE` commands).
+
+```
++---------------------ASocket------------------------+
+ |                                                   |
+ | +----------------APacket Queue------------------+ |
+ | |                                               | |
+ | |            APacket     APacket     APacket    | |
+ | |          +--------+  +--------+  +--------+   | |
+ | |          |AMessage|  |AMessage|  |AMessage|   | |
+ | |          +--------+  +--------+  +--------+   | |
+ | |          |        |  |        |  |        |   | |
+ | |  .....   |        |  |        |  |        |   | |
+ | |          |  Data  |  |  Data  |  |  Data  |   | |
+ | |          |        |  |        |  |        |   | |
+ | |          |        |  |        |  |        |   | |
+ | |          +--------+  +--------+  +--------+   | |
+ | |                                               | |
+ | +-----------------------------------------------+ |
+ +---------------------------------------------------+
+```
+
+This system allows to multiplex data streams on an unique byte stream.  Without entering too much into details, the amessage fields arg1 and arg2 are used alike in the TCP protocol where local and remote ports identify an unique stream. Note that unlike TCP which feature an "unacknowledged-send window", an apacket is sent only after the previous one has been confirmed to be received.
+
+The two types of asocket (Remote and Local) differentiate between outbound and inbound traffic.
+
+## adbd <-> APPPLICATION communication
+
+This pipeline is detailed in [services.cpp](services.cpp). The JDWP extension implemented by Dalvik/ART are documented in:
+- platform/dalvik/+/master/docs/debugmon.html
+- platform/dalvik/+/master/docs/debugger.html
diff --git a/adb/client/file_sync_client.cpp b/adb/client/file_sync_client.cpp
index 8bbe2a8..2e8b975 100644
--- a/adb/client/file_sync_client.cpp
+++ b/adb/client/file_sync_client.cpp
@@ -1053,7 +1053,7 @@
         if (!sc.SendSmallFile(rpath, mode, lpath, rpath, mtime, buf, data_length, dry_run)) {
             return false;
         }
-        return sc.ReadAcknowledgements();
+        return sc.ReadAcknowledgements(sync);
 #endif
     }
 
@@ -1077,7 +1077,7 @@
             return false;
         }
     }
-    return sc.ReadAcknowledgements();
+    return sc.ReadAcknowledgements(sync);
 }
 
 static bool sync_recv_v1(SyncConnection& sc, const char* rpath, const char* lpath, const char* name,
diff --git a/adb/client/incremental_utils.cpp b/adb/client/incremental_utils.cpp
index 3297a6d..1a071fd 100644
--- a/adb/client/incremental_utils.cpp
+++ b/adb/client/incremental_utils.cpp
@@ -326,7 +326,7 @@
     }
 
     std::vector<int32_t> installationPriorityBlocks;
-    ZipEntry entry;
+    ZipEntry64 entry;
     std::string_view entryName;
     while (Next(cookie, &entry, &entryName) == 0) {
         if (entryName == "classes.dex"sv) {
diff --git a/adb/test_device.py b/adb/test_device.py
index c1caafc..a92d4a7 100755
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -1271,6 +1271,31 @@
                 if temp_dir is not None:
                     shutil.rmtree(temp_dir)
 
+        def test_push_sync_multiple(self):
+            """Sync multiple host directories to a specific path."""
+
+            try:
+                temp_dir = tempfile.mkdtemp()
+                temp_files = make_random_host_files(in_dir=temp_dir, num_files=32)
+
+                device_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'sync_src_dst')
+
+                # Clean up any stale files on the device.
+                device = adb.get_device()  # pylint: disable=no-member
+                device.shell(['rm', '-rf', device_dir])
+                device.shell(['mkdir', '-p', device_dir])
+
+                host_paths = [os.path.join(temp_dir, x.base_name) for x in temp_files]
+                device.push(host_paths, device_dir, sync=True)
+
+                self.verify_sync(device, temp_files, device_dir)
+
+                self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            finally:
+                if temp_dir is not None:
+                    shutil.rmtree(temp_dir)
+
+
         def test_push_dry_run_nonexistent_file(self):
             """Push with dry run."""
 
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index 7912688..78a9005 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -427,6 +427,20 @@
     return true;
 }
 
+// Accepts a device mapper device name (like system_a, vendor_b etc) and
+// returns its UUID.
+bool DeviceMapper::GetDmDeviceUUIDByName(const std::string& name, std::string* uuid) {
+    struct dm_ioctl io;
+    InitIo(&io, name);
+    if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
+        PLOG(WARNING) << "DM_DEV_STATUS failed for " << name;
+        return false;
+    }
+
+    *uuid = std::string(io.uuid);
+    return true;
+}
+
 bool DeviceMapper::GetDeviceNumber(const std::string& name, dev_t* dev) {
     struct dm_ioctl io;
     InitIo(&io, name);
diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h
index abe9c4c..0b2553f 100644
--- a/fs_mgr/libdm/include/libdm/dm.h
+++ b/fs_mgr/libdm/include/libdm/dm.h
@@ -172,6 +172,13 @@
     // could race with ueventd.
     bool GetDmDevicePathByName(const std::string& name, std::string* path);
 
+    // Returns the device mapper UUID for a given name.  If the device does not
+    // exist, false is returned, and the path parameter is not set.
+    //
+    // WaitForFile() should not be used in conjunction with this call, since it
+    // could race with ueventd.
+    bool GetDmDeviceUUIDByName(const std::string& name, std::string* path);
+
     // Returns a device's unique path as generated by ueventd. This will return
     // true as long as the device has been created, even if ueventd has not
     // processed it yet.
diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp
index 7a3d9a9..1bfd9b2 100644
--- a/fs_mgr/tools/dmctl.cpp
+++ b/fs_mgr/tools/dmctl.cpp
@@ -49,6 +49,7 @@
     std::cerr << "  delete <dm-name>" << std::endl;
     std::cerr << "  list <devices | targets> [-v]" << std::endl;
     std::cerr << "  getpath <dm-name>" << std::endl;
+    std::cerr << "  getuuid <dm-name>" << std::endl;
     std::cerr << "  info <dm-name>" << std::endl;
     std::cerr << "  status <dm-name>" << std::endl;
     std::cerr << "  resume <dm-name>" << std::endl;
@@ -391,6 +392,22 @@
     return 0;
 }
 
+static int GetUUIDCmdHandler(int argc, char** argv) {
+    if (argc != 1) {
+        std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
+        return -EINVAL;
+    }
+
+    DeviceMapper& dm = DeviceMapper::Instance();
+    std::string uuid;
+    if (!dm.GetDmDeviceUUIDByName(argv[0], &uuid)) {
+        std::cerr << "Could not query uuid of device \"" << argv[0] << "\"." << std::endl;
+        return -EINVAL;
+    }
+    std::cout << uuid << std::endl;
+    return 0;
+}
+
 static int InfoCmdHandler(int argc, char** argv) {
     if (argc != 1) {
         std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
@@ -504,6 +521,7 @@
         {"list", DmListCmdHandler},
         {"help", HelpCmdHandler},
         {"getpath", GetPathCmdHandler},
+        {"getuuid", GetUUIDCmdHandler},
         {"info", InfoCmdHandler},
         {"table", TableCmdHandler},
         {"status", StatusCmdHandler},
diff --git a/init/subcontext.cpp b/init/subcontext.cpp
index 9d4ea8c..dc2455e 100644
--- a/init/subcontext.cpp
+++ b/init/subcontext.cpp
@@ -30,6 +30,7 @@
 
 #include "action.h"
 #include "builtins.h"
+#include "mount_namespace.h"
 #include "proto_utils.h"
 #include "util.h"
 
@@ -217,7 +218,13 @@
                 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
             }
         }
-
+#if defined(__ANDROID__)
+        // subcontext init runs in "default" mount namespace
+        // so that it can access /apex/*
+        if (auto result = SwitchToMountNamespaceIfNeeded(NS_DEFAULT); !result.ok()) {
+            LOG(FATAL) << "Could not switch to \"default\" mount namespace: " << result.error();
+        }
+#endif
         auto init_path = GetExecutablePath();
         auto child_fd_string = std::to_string(child_fd);
         const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
diff --git a/init/sysprop/api/com.android.sysprop.init-latest.txt b/init/sysprop/api/com.android.sysprop.init-latest.txt
index c835b95..01f4e9a 100644
--- a/init/sysprop/api/com.android.sysprop.init-latest.txt
+++ b/init/sysprop/api/com.android.sysprop.init-latest.txt
@@ -1,8 +1,13 @@
 props {
   module: "android.sysprop.InitProperties"
   prop {
+    api_name: "is_userspace_reboot_supported"
+    prop_name: "init.userspace_reboot.is_supported"
+    integer_as_bool: true
+  }
+  prop {
     api_name: "userspace_reboot_in_progress"
-    scope: Public
+    access: ReadWrite
     prop_name: "sys.init.userspace_reboot.in_progress"
     integer_as_bool: true
   }
diff --git a/libcutils/trace-dev.cpp b/libcutils/trace-dev.cpp
index 5a09a2d..1ab63dc 100644
--- a/libcutils/trace-dev.cpp
+++ b/libcutils/trace-dev.cpp
@@ -30,9 +30,9 @@
 
 static void atrace_init_once()
 {
-    atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+    atrace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
     if (atrace_marker_fd == -1) {
-        atrace_marker_fd = open("/sys/kernel/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
+        atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY | O_CLOEXEC);
     }
 
     if (atrace_marker_fd == -1) {
diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt
index 5de422f..967205f 100644
--- a/rootdir/etc/public.libraries.android.txt
+++ b/rootdir/etc/public.libraries.android.txt
@@ -10,6 +10,7 @@
 libGLESv1_CM.so
 libGLESv2.so
 libGLESv3.so
+libicu.so
 libicui18n.so
 libicuuc.so
 libjnigraphics.so
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 196806d..91f2c57 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -464,6 +464,10 @@
     # The bind+remount combination allows this to work in containers.
     mount rootfs rootfs / remount bind ro nodev
 
+    # Mount default storage into root namespace
+    mount none /mnt/user/0 /storage bind rec
+    mount none none /storage slave rec
+
     # Make sure /sys/kernel/debug (if present) is labeled properly
     # Note that tracefs may be mounted under debug, so we need to cross filesystems
     restorecon --recursive --cross-filesystems /sys/kernel/debug
@@ -809,22 +813,6 @@
     # Enable FUSE by default
     setprop persist.sys.fuse true
 
-# Switch between sdcardfs and FUSE depending on persist property
-# TODO: Move this to ro property before launch because FDE devices
-# interact with persistent properties differently during boot
-on zygote-start && property:persist.sys.fuse=true
-  # Mount default storage into root namespace
-  mount none /mnt/user/0 /storage bind rec
-  mount none none /storage slave rec
-on zygote-start && property:persist.sys.fuse=false
-  # Mount default storage into root namespace
-  mount none /mnt/runtime/default /storage bind rec
-  mount none none /storage slave rec
-on zygote-start && property:persist.sys.fuse=""
-  # Mount default storage into root namespace
-  mount none /mnt/runtime/default /storage bind rec
-  mount none none /storage slave rec
-
 # It is recommended to put unnecessary data/ initialization from post-fs-data
 # to start-zygote in device's init.rc to unblock zygote start.
 on zygote-start && property:ro.crypto.state=unencrypted
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index 9c2cdf2..1994bdb 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -17,6 +17,9 @@
     devname uevent_devpath
     dirname /dev/snd
 
+subsystem dma_heap
+   devname uevent_devpath
+   dirname /dev/dma_heap
 # ueventd can only set permissions on device nodes and their associated
 # sysfs attributes, not on arbitrary paths.
 #
@@ -39,6 +42,7 @@
 /dev/vndbinder            0666   root       root
 
 /dev/pmsg0                0222   root       log
+/dev/dma_heap/system      0666   system     system
 
 # kms driver for drm based gpu
 /dev/dri/*                0666   root       graphics
diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp
index 6840baa..27e1a3f 100644
--- a/trusty/keymaster/Android.bp
+++ b/trusty/keymaster/Android.bp
@@ -75,3 +75,36 @@
 
     vintf_fragments: ["4.0/android.hardware.keymaster@4.0-service.trusty.xml"],
 }
+
+prebuilt_etc {
+    name: "keymaster_soft_attestation_keys.xml",
+    vendor: true,
+    src: "set_attestation_key/keymaster_soft_attestation_keys.xml",
+}
+
+cc_binary {
+    name: "trusty_keymaster_set_attestation_key",
+    vendor: true,
+
+    srcs: [
+        "set_attestation_key/set_attestation_key.cpp",
+        "ipc/trusty_keymaster_ipc.cpp",
+    ],
+
+    local_include_dirs: ["include"],
+
+    shared_libs: [
+        "libc",
+        "libcrypto",
+        "liblog",
+        "libtrusty",
+        "libhardware",
+        "libkeymaster_messages",
+        "libxml2",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
index 13e6725..ce2cc2e 100644
--- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
+++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h
@@ -53,6 +53,19 @@
     KM_DELETE_ALL_KEYS              = (23 << KEYMASTER_REQ_SHIFT),
     KM_DESTROY_ATTESTATION_IDS      = (24 << KEYMASTER_REQ_SHIFT),
     KM_IMPORT_WRAPPED_KEY           = (25 << KEYMASTER_REQ_SHIFT),
+
+    // Bootloader/provisioning calls.
+    KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_ATTESTATION_KEY = (0x2000 << KEYMASTER_REQ_SHIFT),
+    KM_APPEND_ATTESTATION_CERT_CHAIN = (0x3000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_GET_CA_REQUEST = (0x4000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_BEGIN = (0x5000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_UPDATE = (0x6000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_SET_CA_RESPONSE_FINISH = (0x7000 << KEYMASTER_REQ_SHIFT),
+    KM_ATAP_READ_UUID = (0x8000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_PRODUCT_ID = (0x9000 << KEYMASTER_REQ_SHIFT),
+    KM_CLEAR_ATTESTATION_CERT_CHAIN = (0xa000 << KEYMASTER_REQ_SHIFT),
+    KM_SET_WRAPPED_ATTESTATION_KEY = (0xb000 << KEYMASTER_REQ_SHIFT),
 };
 
 #ifdef __ANDROID__
diff --git a/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml b/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml
new file mode 100644
index 0000000..fce2ac2
--- /dev/null
+++ b/trusty/keymaster/set_attestation_key/keymaster_soft_attestation_keys.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0"?>
+<AndroidAttestation>
+  <NumberOfKeyboxes>10</NumberOfKeyboxes>
+  <Keybox DeviceID="dev1">
+    <Key algorithm="rsa">
+      <PrivateKey format="pem">
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1qEIEir6LR752/q7yXPKb
+KvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX4YVBeuVKvClqOm21wAQI
+O2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmdXX0jYvKcXgLocQIDAQAB
+AoGBAL6GCwuZqAKm+xpZQ4p7txUGWwmjbcbpysxr88AsNNfXnpTGYGQo2Ix7f2V3
+wc3qZAdKvo5yht8fCBHclygmCGjeldMu/Ja20IT/JxpfYN78xwPno45uKbqaPF/C
+woB2tqiWrx0014gozpvdsfNPnJQEQweBKY4gExZyW728mTpBAkEA4cbZJ2RsCRbs
+NoJtWUmDdAwh8bB0xKGlmGfGaXlchdPcRkxbkp6Uv7NODcxQFLEPEzQat/3V9gQU
+0qMmytQcxQJBANpIWZd4XNVjD7D9jFJU+Y5TjhiYOq6ea35qWntdNDdVuSGOvUAy
+DSg4fXifdvohi8wti2il9kGPu+ylF5qzr70CQFD+/DJklVlhbtZTThVFCTKdk6PY
+ENvlvbmCKSz3i9i624Agro1X9LcdBThv/p6dsnHKNHejSZnbdvjl7OnA1J0CQBW3
+TPJ8zv+Ls2vwTZ2DRrCaL3DS9EObDyasfgP36dH3fUuRX9KbKCPwOstdUgDghX/y
+qAPpPu6W1iNc6VRCvCECQQCQp0XaiXCyzWSWYDJCKMX4KFb/1mW6moXI1g8bi+5x
+fs0scurgHa2GunZU1M9FrbXx8rMdn4Eiz6XxpVcPmy0l
+-----END RSA PRIVATE KEY-----
+      </PrivateKey>
+      <CertificateChain>
+        <NumberOfCertificates>2</NumberOfCertificates>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICtjCCAh+gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDAeFw0xNjAxMDQx
+MjQwNTNaFw0zNTEyMzAxMjQwNTNaMHYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApD
+YWxpZm9ybmlhMRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJv
+aWQxKTAnBgNVBAMMIEFuZHJvaWQgU29mdHdhcmUgQXR0ZXN0YXRpb24gS2V5MIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDAgyPcVogbuDAgafWwhWHG7r5/BeL1
+qEIEir6LR752/q7yXPKbKvoyABQWAUKZiaFfz8aBXrNjWDwv0vIL5Jgyg92BSxbX
+4YVBeuVKvClqOm21wAQIO2jFVsHwIzmRZBmGTVC3TUCuykhMdzVsiVoMJ1q/rEmd
+XX0jYvKcXgLocQIDAQABo2YwZDAdBgNVHQ4EFgQU1AwQG/jNY7n3OVK1DhNcpteZ
+k4YwHwYDVR0jBBgwFoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wEgYDVR0TAQH/BAgw
+BgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAni1IX4xn
+M9waha2Z11Aj6hTsQ7DhnerCI0YecrUZ3GAi5KVoMWwLVcTmnKItnzpPk2sxixZ4
+Fg2Iy9mLzICdhPDCJ+NrOPH90ecXcjFZNX2W88V/q52PlmEmT7K+gbsNSQQiis6f
+9/VCLiVE+iEHElqDtVWtGIL4QBSbnCBjBH8=
+-----END CERTIFICATE-----
+        </Certificate>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICpzCCAhCgAwIBAgIJAP+U2d2fB8gMMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW
+aWV3MRUwEwYDVQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQwHhcN
+MTYwMTA0MTIzMTA4WhcNMzUxMjMwMTIzMTA4WjBjMQswCQYDVQQGEwJVUzETMBEG
+A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMGA1UE
+CgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCia63rbi5EYe/VDoLmt5TRdSMfd5tjkWP/96r/C3JHTsAs
+Q+wzfNes7UA+jCigZtX3hwszl94OuE4TQKuvpSe/lWmgMdsGUmX4RFlXYfC78hdL
+t0GAZMAoDo9Sd47b0ke2RekZyOmLw9vCkT/X11DEHTVm+Vfkl5YLCazOkjWFmwID
+AQABo2MwYTAdBgNVHQ4EFgQUKfrxrMxN0kyWQCd1trDpMuUH/i4wHwYDVR0jBBgw
+FoAUKfrxrMxN0kyWQCd1trDpMuUH/i4wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B
+Af8EBAMCAoQwDQYJKoZIhvcNAQELBQADgYEAT3LzNlmNDsG5dFsxWfbwjSVJMJ6j
+HBwp0kUtILlNX2S06IDHeHqcOd6os/W/L3BfRxBcxebrTQaZYdKumgf/93y4q+uc
+DyQHXrF/unlx/U1bnt8Uqf7f7XzAiF343ZtkMlbVNZriE/mPzsF83O+kqrJVw4Op
+Lvtc9mL1J1IXvmM=
+-----END CERTIFICATE-----
+        </Certificate>
+      </CertificateChain>
+    </Key>
+  </Keybox>
+  <Keybox DeviceID="dev1">
+    <Key algorithm="ecdsa">
+      <PrivateKey format="pem">
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEICHghkMqFRmEWc82OlD8FMnarfk19SfC39ceTW28QuVEoAoGCCqGSM49
+AwEHoUQDQgAE6555+EJjWazLKpFMiYbMcK2QZpOCqXMmE/6sy/ghJ0whdJdKKv6l
+uU1/ZtTgZRBmNbxTt6CjpnFYPts+Ea4QFA==
+-----END EC PRIVATE KEY-----
+      </PrivateKey>
+      <CertificateChain>
+        <NumberOfCertificates>2</NumberOfCertificates>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICeDCCAh6gAwIBAgICEAEwCgYIKoZIzj0EAwIwgZgxCzAJBgNVBAYTAlVTMRMw
+EQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYD
+VQQKDAxHb29nbGUsIEluYy4xEDAOBgNVBAsMB0FuZHJvaWQxMzAxBgNVBAMMKkFu
+ZHJvaWQgS2V5c3RvcmUgU29mdHdhcmUgQXR0ZXN0YXRpb24gUm9vdDAeFw0xNjAx
+MTEwMDQ2MDlaFw0yNjAxMDgwMDQ2MDlaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UE
+CAwKQ2FsaWZvcm5pYTEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdB
+bmRyb2lkMTswOQYDVQQDDDJBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVz
+dGF0aW9uIEludGVybWVkaWF0ZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOue
+efhCY1msyyqRTImGzHCtkGaTgqlzJhP+rMv4ISdMIXSXSir+pblNf2bU4GUQZjW8
+U7ego6ZxWD7bPhGuEBSjZjBkMB0GA1UdDgQWBBQ//KzWGrE6noEguNUlHMVlux6R
+qTAfBgNVHSMEGDAWgBTIrel3TEXDo88NFhDkeUM6IVowzzASBgNVHRMBAf8ECDAG
+AQH/AgEAMA4GA1UdDwEB/wQEAwIChDAKBggqhkjOPQQDAgNIADBFAiBLipt77oK8
+wDOHri/AiZi03cONqycqRZ9pDMfDktQPjgIhAO7aAV229DLp1IQ7YkyUBO86fMy9
+Xvsiu+f+uXc/WT/7
+-----END CERTIFICATE-----
+        </Certificate>
+        <Certificate format="pem">
+-----BEGIN CERTIFICATE-----
+MIICizCCAjKgAwIBAgIJAKIFntEOQ1tXMAoGCCqGSM49BAMCMIGYMQswCQYDVQQG
+EwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmll
+dzEVMBMGA1UECgwMR29vZ2xlLCBJbmMuMRAwDgYDVQQLDAdBbmRyb2lkMTMwMQYD
+VQQDDCpBbmRyb2lkIEtleXN0b3JlIFNvZnR3YXJlIEF0dGVzdGF0aW9uIFJvb3Qw
+HhcNMTYwMTExMDA0MzUwWhcNMzYwMTA2MDA0MzUwWjCBmDELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDEzMDEGA1UEAwwq
+QW5kcm9pZCBLZXlzdG9yZSBTb2Z0d2FyZSBBdHRlc3RhdGlvbiBSb290MFkwEwYH
+KoZIzj0CAQYIKoZIzj0DAQcDQgAE7l1ex+HA220Dpn7mthvsTWpdamguD/9/SQ59
+dx9EIm29sa/6FsvHrcV30lacqrewLVQBXT5DKyqO107sSHVBpKNjMGEwHQYDVR0O
+BBYEFMit6XdMRcOjzw0WEOR5QzohWjDPMB8GA1UdIwQYMBaAFMit6XdMRcOjzw0W
+EOR5QzohWjDPMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgKEMAoGCCqG
+SM49BAMCA0cAMEQCIDUho++LNEYenNVg8x1YiSBq3KNlQfYNns6KGYxmSGB7AiBN
+C/NR2TB8fVvaNTQdqEcbY6WFZTytTySn502vQX3xvw==
+-----END CERTIFICATE-----
+        </Certificate>
+      </CertificateChain>
+    </Key>
+  </Keybox>
+</AndroidAttestation>
diff --git a/trusty/keymaster/set_attestation_key/set_attestation_key.cpp b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
new file mode 100644
index 0000000..a89a4a8
--- /dev/null
+++ b/trusty/keymaster/set_attestation_key/set_attestation_key.cpp
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <getopt.h>
+#include <libxml/xmlreader.h>
+#include <openssl/pem.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <string>
+
+using std::string;
+
+#include <trusty_keymaster/ipc/trusty_keymaster_ipc.h>
+
+static const char* _sopts = "h";
+static const struct option _lopts[] = {
+        {"help", no_argument, 0, 'h'},
+        {0, 0, 0, 0},
+};
+
+static const char* usage =
+        "Usage: %s [options] xml-file\n"
+        "\n"
+        "options:\n"
+        "  -h, --help            prints this message and exit\n"
+        "\n";
+
+static void print_usage_and_exit(const char* prog, int code) {
+    fprintf(stderr, usage, prog);
+    exit(code);
+}
+
+static void parse_options(int argc, char** argv) {
+    int c;
+    int oidx = 0;
+
+    while (1) {
+        c = getopt_long(argc, argv, _sopts, _lopts, &oidx);
+        if (c == -1) {
+            break; /* done */
+        }
+
+        switch (c) {
+            case 'h':
+                print_usage_and_exit(argv[0], EXIT_SUCCESS);
+                break;
+
+            default:
+                print_usage_and_exit(argv[0], EXIT_FAILURE);
+        }
+    }
+}
+
+struct SetAttestationKeyRequest : public keymaster::KeymasterMessage {
+    explicit SetAttestationKeyRequest(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t) + key_data.SerializedSize(); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        buf = keymaster::append_uint32_to_buf(buf, end, algorithm);
+        return key_data.Serialize(buf, end);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return keymaster::copy_uint32_from_buf(buf_ptr, end, &algorithm) &&
+               key_data.Deserialize(buf_ptr, end);
+    }
+
+    keymaster_algorithm_t algorithm;
+    keymaster::Buffer key_data;
+};
+
+struct KeymasterNoResponse : public keymaster::KeymasterResponse {
+    explicit KeymasterNoResponse(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : keymaster::KeymasterResponse(ver) {}
+
+    size_t NonErrorSerializedSize() const override { return 0; }
+    uint8_t* NonErrorSerialize(uint8_t* buf, const uint8_t*) const override { return buf; }
+    bool NonErrorDeserialize(const uint8_t**, const uint8_t*) override { return true; }
+};
+
+struct SetAttestationKeyResponse : public KeymasterNoResponse {};
+
+struct ClearAttestationCertChainRequest : public keymaster::KeymasterMessage {
+    explicit ClearAttestationCertChainRequest(int32_t ver = keymaster::MAX_MESSAGE_VERSION)
+        : KeymasterMessage(ver) {}
+
+    size_t SerializedSize() const override { return sizeof(uint32_t); }
+    uint8_t* Serialize(uint8_t* buf, const uint8_t* end) const override {
+        return keymaster::append_uint32_to_buf(buf, end, algorithm);
+    }
+    bool Deserialize(const uint8_t** buf_ptr, const uint8_t* end) override {
+        return keymaster::copy_uint32_from_buf(buf_ptr, end, &algorithm);
+    }
+
+    keymaster_algorithm_t algorithm;
+};
+
+struct ClearAttestationCertChainResponse : public KeymasterNoResponse {};
+
+static int set_attestation_key_or_cert_bin(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                           const void* key_data, size_t key_data_size) {
+    int ret;
+
+    SetAttestationKeyRequest req;
+    req.algorithm = algorithm;
+    req.key_data.Reinitialize(key_data, key_data_size);
+    SetAttestationKeyResponse rsp;
+
+    ret = trusty_keymaster_send(cmd, req, &rsp);
+    if (ret) {
+        fprintf(stderr, "trusty_keymaster_send cmd 0x%x failed %d\n", cmd, ret);
+        return ret;
+    }
+
+    return 0;
+}
+
+static int set_attestation_key_or_cert_pem(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                           const xmlChar* pemkey) {
+    int ret;
+    int sslret;
+
+    /* Convert from pem to binary */
+    BIO* bio = BIO_new_mem_buf(pemkey, xmlStrlen(pemkey));
+    if (!bio) {
+        fprintf(stderr, "BIO_new_mem_buf failed\n");
+        ERR_print_errors_fp(stderr);
+        return -1;
+    }
+
+    char* key_name;
+    char* key_header;
+    uint8_t* key;
+    long keylen;
+    sslret = PEM_read_bio(bio, &key_name, &key_header, &key, &keylen);
+    BIO_free(bio);
+
+    if (!sslret) {
+        fprintf(stderr, "PEM_read_bio failed\n");
+        ERR_print_errors_fp(stderr);
+        return -1;
+    }
+
+    /* Send key in binary format to trusty */
+    ret = set_attestation_key_or_cert_bin(cmd, algorithm, key, keylen);
+
+    OPENSSL_free(key_name);
+    OPENSSL_free(key_header);
+    OPENSSL_free(key);
+
+    return ret;
+}
+
+static int set_attestation_key_or_cert_iecs(uint32_t cmd, keymaster_algorithm_t algorithm,
+                                            const xmlChar* key_base64) {
+    int ret;
+    int sslret;
+
+    /* Remove all whitespace. EVP_DecodeBase64 does not support whitespace. */
+    string key_base64_str((const char*)key_base64);
+    key_base64_str.erase(remove_if(key_base64_str.begin(), key_base64_str.end(), isspace),
+                         key_base64_str.end());
+
+    /* Convert from base64 to binary */
+    uint8_t* key;
+    size_t keylen;
+    size_t key_base64_len = key_base64_str.length();
+
+    sslret = EVP_DecodedLength(&keylen, key_base64_len);
+    if (!sslret) {
+        fprintf(stderr, "invalid input length, %zu\n", key_base64_len);
+        return -1;
+    }
+    key = (uint8_t*)malloc(keylen);
+    if (!key) {
+        fprintf(stderr, "failed to allocate key, size %zu\n", key_base64_len);
+        return -1;
+    }
+    sslret = EVP_DecodeBase64(key, &keylen, keylen, (const uint8_t*)key_base64_str.data(),
+                              key_base64_len);
+    if (!sslret) {
+        fprintf(stderr, "EVP_DecodeBase64 failed\n");
+        ERR_print_errors_fp(stderr);
+        free(key);
+        return -1;
+    }
+
+    /* Send key in binary format to trusty */
+    ret = set_attestation_key_or_cert_bin(cmd, algorithm, key, keylen);
+
+    free(key);
+
+    return ret;
+}
+
+static int str_to_algorithm(keymaster_algorithm_t* algorithm, const xmlChar* algorithm_str) {
+    if (xmlStrEqual(algorithm_str, BAD_CAST "rsa")) {
+        *algorithm = KM_ALGORITHM_RSA;
+    } else if (xmlStrEqual(algorithm_str, BAD_CAST "ecdsa")) {
+        *algorithm = KM_ALGORITHM_EC;
+    } else {
+        printf("unsupported algorithm: %s\n", algorithm_str);
+        return -1;
+    }
+    return 0;
+}
+
+static int set_attestation_key_or_cert(uint32_t cmd, const xmlChar* algorithm_str,
+                                       const xmlChar* format, const xmlChar* str) {
+    int ret;
+    keymaster_algorithm_t algorithm;
+
+    ret = str_to_algorithm(&algorithm, algorithm_str);
+    if (ret) {
+        return ret;
+    }
+
+    if (xmlStrEqual(format, BAD_CAST "pem")) {
+        ret = set_attestation_key_or_cert_pem(cmd, algorithm, str);
+    } else if (xmlStrEqual(format, BAD_CAST "iecs")) {
+        ret = set_attestation_key_or_cert_iecs(cmd, algorithm, str);
+    } else {
+        printf("unsupported key/cert format: %s\n", format);
+        return -1;
+    }
+    return ret;
+}
+
+static int clear_cert_chain(const xmlChar* algorithm_str) {
+    int ret;
+    ClearAttestationCertChainRequest req;
+    ClearAttestationCertChainResponse rsp;
+
+    ret = str_to_algorithm(&req.algorithm, algorithm_str);
+    if (ret) {
+        return ret;
+    }
+
+    ret = trusty_keymaster_send(KM_CLEAR_ATTESTATION_CERT_CHAIN, req, &rsp);
+    if (ret) {
+        fprintf(stderr, "%s: trusty_keymaster_send failed %d\n", __func__, ret);
+        return ret;
+    }
+    return 0;
+}
+
+static int process_xml(xmlTextReaderPtr xml) {
+    int ret;
+    const xmlChar* algorithm = NULL;
+    const xmlChar* element = NULL;
+    const xmlChar* element_format = NULL;
+
+    while ((ret = xmlTextReaderRead(xml)) == 1) {
+        int nodetype = xmlTextReaderNodeType(xml);
+        const xmlChar *name, *value;
+        name = xmlTextReaderConstName(xml);
+        switch (nodetype) {
+            case XML_READER_TYPE_ELEMENT:
+                element = name;
+                element_format = xmlTextReaderGetAttribute(xml, BAD_CAST "format");
+                if (xmlStrEqual(name, BAD_CAST "Key")) {
+                    algorithm = xmlTextReaderGetAttribute(xml, BAD_CAST "algorithm");
+                } else if (xmlStrEqual(name, BAD_CAST "CertificateChain")) {
+                    ret = clear_cert_chain(algorithm);
+                    if (ret) {
+                        fprintf(stderr, "%s, algorithm %s: Clear cert chain cmd failed, %d\n",
+                                element, algorithm, ret);
+                        return ret;
+                    }
+                    printf("%s, algorithm %s: Clear cert chain cmd done\n", element, algorithm);
+                }
+                break;
+            case XML_READER_TYPE_TEXT:
+                value = xmlTextReaderConstValue(xml);
+                uint32_t cmd;
+                if (xmlStrEqual(element, BAD_CAST "PrivateKey")) {
+                    cmd = KM_SET_ATTESTATION_KEY;
+                } else if (xmlStrEqual(element, BAD_CAST "WrappedPrivateKey")) {
+                    cmd = KM_SET_WRAPPED_ATTESTATION_KEY;
+                } else if (xmlStrEqual(element, BAD_CAST "Certificate")) {
+                    cmd = KM_APPEND_ATTESTATION_CERT_CHAIN;
+                } else {
+                    break;
+                }
+
+                ret = set_attestation_key_or_cert(cmd, algorithm, element_format, value);
+                if (ret) {
+                    fprintf(stderr, "%s, algorithm %s, format %s: Cmd 0x%x failed, %d\n", element,
+                            algorithm, element_format, cmd, ret);
+                    return ret;
+                }
+                printf("%s, algorithm %s, format %s: Cmd 0x%x done\n", element, algorithm,
+                       element_format, cmd);
+                break;
+            case XML_READER_TYPE_END_ELEMENT:
+                element = NULL;
+                break;
+        }
+    }
+    return ret;
+}
+
+static int parse_xml_file(const char* filename) {
+    int ret;
+    xmlTextReaderPtr xml = xmlReaderForFile(filename, NULL, 0);
+    if (!xml) {
+        fprintf(stderr, "failed to open %s\n", filename);
+        return -1;
+    }
+
+    ret = process_xml(xml);
+
+    xmlFreeTextReader(xml);
+    if (ret != 0) {
+        fprintf(stderr, "Failed to parse or process %s\n", filename);
+        return -1;
+    }
+
+    return 0;
+}
+
+int main(int argc, char** argv) {
+    int ret = 0;
+
+    parse_options(argc, argv);
+    if (optind + 1 != argc) {
+        print_usage_and_exit(argv[0], EXIT_FAILURE);
+    }
+
+    ret = trusty_keymaster_connect();
+    if (ret) {
+        fprintf(stderr, "trusty_keymaster_connect failed %d\n", ret);
+    } else {
+        ret = parse_xml_file(argv[optind]);
+        trusty_keymaster_disconnect();
+    }
+
+    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/trusty/trusty-test.mk b/trusty/trusty-test.mk
index fd353d1..dc4c962 100644
--- a/trusty/trusty-test.mk
+++ b/trusty/trusty-test.mk
@@ -14,3 +14,5 @@
 
 PRODUCT_PACKAGES += \
 	spiproxyd \
+	trusty_keymaster_set_attestation_key \
+	keymaster_soft_attestation_keys.xml \
\ No newline at end of file