Merge "Fix extra_kernel_cmdline being dropped."
diff --git a/OWNERS b/OWNERS
index 9594320..1944029 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,8 +1,11 @@
+# Current team members
 adelva@google.com
-ghartman@google.com
 jemoreira@google.com
 malchev@google.com
 muntsinger@google.com
 natsu@google.com
 rammuthiah@google.com
 schuffelen@google.com
+
+# Former team members
+ghartman@google.com
diff --git a/common/libs/fs/shared_fd.cpp b/common/libs/fs/shared_fd.cpp
index 2f6d100..b85cf7c 100644
--- a/common/libs/fs/shared_fd.cpp
+++ b/common/libs/fs/shared_fd.cpp
@@ -17,6 +17,8 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
 #include <cstddef>
 #include <errno.h>
 #include <fcntl.h>
@@ -52,6 +54,34 @@
     }
   }
 }
+
+/*
+ * Android currently has host prebuilts of glibc 2.15 and 2.17, but
+ * memfd_create was only added in glibc 2.27. It was defined in Linux 3.17,
+ * so we consider it safe to use the low-level arbitrary syscall wrapper.
+ */
+#ifndef __NR_memfd_create
+# if defined(__x86_64__)
+#  define __NR_memfd_create 319
+# elif defined(__i386__)
+#  define __NR_memfd_create 356
+# elif defined(__aarch64__)
+#  define __NR_memfd_create 279
+# else
+/* No interest in other architectures. */
+#  error "Unknown architecture."
+# endif
+#endif
+
+int memfd_create_wrapper(const char* name, unsigned int flags) {
+#ifdef CUTTLEFISH_HOST
+  // TODO(schuffelen): Use memfd_create with a newer host libc.
+  return syscall(__NR_memfd_create, name, flags);
+#else
+  return memfd_create(name, flags);
+#endif
+}
+
 }  // namespace
 
 namespace cvd {
@@ -256,6 +286,12 @@
   return std::shared_ptr<FileInstance>(new FileInstance(fd, errno));
 }
 
+SharedFD SharedFD::MemfdCreate(const char* name, unsigned int flags) {
+  int fd = memfd_create_wrapper(name, flags);
+  int error_num = errno;
+  return std::shared_ptr<FileInstance>(new FileInstance(fd, error_num));
+}
+
 bool SharedFD::SocketPair(int domain, int type, int protocol,
                           SharedFD* fd0, SharedFD* fd1) {
   int fds[2];
diff --git a/common/libs/fs/shared_fd.h b/common/libs/fs/shared_fd.h
index eec17b1..044c7cc 100644
--- a/common/libs/fs/shared_fd.h
+++ b/common/libs/fs/shared_fd.h
@@ -145,6 +145,7 @@
   static bool Pipe(SharedFD* fd0, SharedFD* fd1);
   static SharedFD Event(int initval = 0, int flags = 0);
   static SharedFD Epoll(int flags = 0);
+  static SharedFD MemfdCreate(const char* name, unsigned int flags = 0);
   static bool SocketPair(int domain, int type, int protocol, SharedFD* fd0,
                          SharedFD* fd1);
   static SharedFD Socket(int domain, int socket_type, int protocol);
diff --git a/guest/hals/audio/audio_hw.c b/guest/hals/audio/audio_hw.c
index 40396d7..41a0543 100644
--- a/guest/hals/audio/audio_hw.c
+++ b/guest/hals/audio/audio_hw.c
@@ -34,6 +34,7 @@
 #include <unistd.h>
 
 #include <log/log.h>
+#include <cutils/list.h>
 #include <cutils/str_parms.h>
 
 #include <hardware/hardware.h>
@@ -52,10 +53,13 @@
 #define IN_PERIOD_COUNT 4
 
 struct generic_audio_device {
-    struct audio_hw_device device; // Constant after init
+    struct audio_hw_device device;          // Constant after init
     pthread_mutex_t lock;
-    bool mic_mute;                 // Proteced by this->lock
-    struct mixer* mixer;           // Proteced by this->lock
+    bool mic_mute;                          // Protected by this->lock
+    struct mixer* mixer;                    // Protected by this->lock
+    struct listnode out_streams;            // Record for output streams, protected by this->lock
+    struct listnode in_streams;             // Record for input streams, protected by this->lock
+    audio_patch_handle_t next_patch_handle; // Protected by this->lock
 };
 
 /* If not NULL, this is a pointer to the fallback module.
@@ -172,13 +176,14 @@
 }
 
 struct generic_stream_out {
-    struct audio_stream_out stream;   // Constant after init
+    struct audio_stream_out stream;                 // Constant after init
     pthread_mutex_t lock;
-    struct generic_audio_device *dev; // Constant after init
-    audio_devices_t device;           // Protected by this->lock
-    struct audio_config req_config;   // Constant after init
-    struct pcm_config pcm_config;     // Constant after init
-    audio_vbuffer_t buffer;           // Constant after init
+    struct generic_audio_device *dev;               // Constant after init
+    uint32_t num_devices;                           // Protected by this->lock
+    audio_devices_t devices[AUDIO_PATCH_PORTS_MAX]; // Protected by this->lock
+    struct audio_config req_config;                 // Constant after init
+    struct pcm_config pcm_config;                   // Constant after init
+    audio_vbuffer_t buffer;                         // Constant after init
 
     // Time & Position Keeping
     bool standby;                      // Protected by this->lock
@@ -194,6 +199,11 @@
     pthread_cond_t worker_wake;       // Protected by this->lock
     bool worker_standby;              // Protected by this->lock
     bool worker_exit;                 // Protected by this->lock
+
+    audio_io_handle_t handle;          // Constant after init
+    audio_patch_handle_t patch_handle; // Protected by this->dev->lock
+
+    struct listnode stream_node;       // Protected by this->dev->lock
 };
 
 struct generic_stream_in {
@@ -219,6 +229,11 @@
     pthread_cond_t worker_wake;       // Protected by this->lock
     bool worker_standby;              // Protected by this->lock
     bool worker_exit;                 // Protected by this->lock
+
+    audio_io_handle_t handle;          // Constant after init
+    audio_patch_handle_t patch_handle; // Protected by this->dev->lock
+
+    struct listnode stream_node;       // Protected by this->dev->lock
 };
 
 static struct pcm_config pcm_config_out = {
@@ -290,29 +305,32 @@
                 "\t\tbuffer size: %zu\n"
                 "\t\tchannel mask: %08x\n"
                 "\t\tformat: %d\n"
-                "\t\tdevice: %08x\n"
-                "\t\taudio dev: %p\n\n",
+                "\t\tdevice(s): ",
                 out_get_sample_rate(stream),
                 out_get_buffer_size(stream),
                 out_get_channels(stream),
-                out_get_format(stream),
-                out->device,
-                out->dev);
+                out_get_format(stream));
+    if (out->num_devices == 0) {
+        dprintf(fd, "%08x\n", AUDIO_DEVICE_NONE);
+    } else {
+        for (uint32_t i = 0; i < out->num_devices; i++) {
+            if (i != 0) {
+                dprintf(fd, ", ");
+            }
+            dprintf(fd, "%08x", out->devices[i]);
+        }
+        dprintf(fd, "\n");
+    }
+    dprintf(fd, "\t\taudio dev: %p\n\n", out->dev);
     pthread_mutex_unlock(&out->lock);
     return 0;
 }
 
 static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
 {
-    struct generic_stream_out *out = (struct generic_stream_out *)stream;
     struct str_parms *parms;
     char value[32];
-    int ret = -EINVAL;
     int success;
-    long val;
-    char *end;
-    bool new_device_req = false;
-    int new_device;
 
     if (kvpairs == NULL || kvpairs[0] == 0) {
         return 0;
@@ -320,28 +338,16 @@
     parms = str_parms_create_str(kvpairs);
     success = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
             value, sizeof(value));
-    if (success >= 0) {
-        errno = 0;
-        val = strtol(value, &end, 10);
-        if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int)val == val)) {
-            new_device_req = true;
-            new_device = (int)val;
-            ret = 0;
-        }
-    }
-    str_parms_destroy(parms);
-    if (ret != 0) {
-        ALOGD("%s: Unsupported parameter %s", __FUNCTION__, kvpairs);
-        return ret;
-    }
+    // As the hal version is 3.0, it must not use set parameters API to set audio devices.
+    // Instead, it should use create_audio_patch API.
+    assert(("Must not use set parameters API to set audio devices", success < 0));
 
-    // Try applying change requests
-    pthread_mutex_lock(&out->lock);
-    if (new_device_req) {
-        out->device = new_device;
-    }
-    pthread_mutex_unlock(&out->lock);
-    return ret;
+    str_parms_destroy(parms);
+
+    ALOGW("%s(), unsupported parameter %s", __func__, kvpairs);
+    // There is not any key supported for set_parameters API.
+    // Return error when there is non-null value passed in.
+    return -EINVAL;
 }
 
 static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
@@ -357,7 +363,11 @@
     ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
     if (ret >= 0) {
         pthread_mutex_lock(&out->lock);
-        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, out->device);
+        audio_devices_t device = AUDIO_DEVICE_NONE;
+        for (uint32_t i = 0; i < out->num_devices; i++) {
+            device |= out->devices[i];
+        }
+        str_parms_add_int(reply, AUDIO_PARAMETER_STREAM_ROUTING, device);
         pthread_mutex_unlock(&out->lock);
         get = true;
     }
@@ -834,15 +844,9 @@
 
 static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
 {
-    struct generic_stream_in *in = (struct generic_stream_in *)stream;
     struct str_parms *parms;
     char value[32];
-    int ret = -EINVAL;
     int success;
-    long val;
-    char *end;
-    bool new_device_req = false;
-    int new_device;
 
     if (kvpairs == NULL || kvpairs[0] == 0) {
         return 0;
@@ -850,28 +854,16 @@
     parms = str_parms_create_str(kvpairs);
     success = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING,
             value, sizeof(value));
-    if (success >= 0) {
-        errno = 0;
-        val = strtol(value, &end, 10);
-        if ((errno == 0) && (end != NULL) && (*end == '\0') && ((int)val == val)) {
-            new_device_req = true;
-            new_device = (int)val;
-            ret = 0;
-        }
-    }
-    str_parms_destroy(parms);
-    if (ret != 0) {
-        ALOGD("%s: Unsupported parameter %s", __FUNCTION__, kvpairs);
-        return ret;
-    }
+    // As the hal version is 3.0, it must not use set parameters API to set audio device.
+    // Instead, it should use create_audio_patch API.
+    assert(("Must not use set parameters API to set audio devices", success < 0));
 
-    // Try applying change requests
-    pthread_mutex_lock(&in->lock);
-    if (new_device_req) {
-        in->device = new_device;
-    }
-    pthread_mutex_unlock(&in->lock);
-    return ret;
+    str_parms_destroy(parms);
+
+    ALOGW("%s(), unsupported parameter %s", __func__, kvpairs);
+    // There is not any key supported for set_parameters API.
+    // Return error when there is non-null value passed in.
+    return -EINVAL;
 }
 
 static char * in_get_parameters(const struct audio_stream *stream,
@@ -1222,9 +1214,13 @@
     out->stream.get_presentation_position = out_get_presentation_position;
     out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
 
+    out->handle = handle;
+
     pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
     out->dev = adev;
-    out->device = devices;
+    // Only 1 device is expected despite the argument being named 'devices'
+    out->num_devices = 1;
+    out->devices[0] = devices;
     memcpy(&out->req_config, config, sizeof(struct audio_config));
     memcpy(&out->pcm_config, &pcm_config_out, sizeof(struct pcm_config));
     out->pcm_config.rate = config->sample_rate;
@@ -1250,14 +1246,33 @@
         pthread_create(&out->worker_thread, NULL, out_write_worker, out);
 
     }
-    *stream_out = &out->stream;
 
+    pthread_mutex_lock(&adev->lock);
+    list_add_tail(&adev->out_streams, &out->stream_node);
+    pthread_mutex_unlock(&adev->lock);
+
+    *stream_out = &out->stream;
 
 error:
 
     return ret;
 }
 
+// This must be called with adev->lock held.
+struct generic_stream_out *get_stream_out_by_io_handle_l(
+        struct generic_audio_device *adev, audio_io_handle_t handle) {
+    struct listnode *node;
+
+    list_for_each(node, &adev->out_streams) {
+        struct generic_stream_out *out = node_to_item(
+                node, struct generic_stream_out, stream_node);
+        if (out->handle == handle) {
+            return out;
+        }
+    }
+    return NULL;
+}
+
 static void adev_close_output_stream(struct audio_hw_device *dev,
                                      struct audio_stream_out *stream)
 {
@@ -1272,6 +1287,11 @@
     pthread_join(out->worker_thread, NULL);
     pthread_mutex_destroy(&out->lock);
     audio_vbuffer_destroy(&out->buffer);
+
+    struct generic_audio_device *adev = (struct generic_audio_device *) dev;
+    pthread_mutex_lock(&adev->lock);
+    list_remove(&out->stream_node);
+    pthread_mutex_unlock(&adev->lock);
     free(stream);
 }
 
@@ -1348,6 +1368,20 @@
     return get_input_buffer_size(config->sample_rate, config->format, config->channel_mask);
 }
 
+// This must be called with adev->lock held.
+struct generic_stream_in *get_stream_in_by_io_handle_l(
+        struct generic_audio_device *adev, audio_io_handle_t handle) {
+    struct listnode *node;
+
+    list_for_each(node, &adev->in_streams) {
+        struct generic_stream_in *in = node_to_item(
+                node, struct generic_stream_in, stream_node);
+        if (in->handle == handle) {
+            return in;
+        }
+    }
+    return NULL;
+}
 
 static void adev_close_input_stream(struct audio_hw_device *dev,
                                    struct audio_stream_in *stream)
@@ -1368,6 +1402,11 @@
 
     pthread_mutex_destroy(&in->lock);
     audio_vbuffer_destroy(&in->buffer);
+
+    struct generic_audio_device *adev = (struct generic_audio_device *) dev;
+    pthread_mutex_lock(&adev->lock);
+    list_remove(&in->stream_node);
+    pthread_mutex_unlock(&adev->lock);
     free(stream);
 }
 
@@ -1442,6 +1481,11 @@
         in->worker_exit = false;
         pthread_create(&in->worker_thread, NULL, in_read_worker, in);
     }
+    in->handle = handle;
+
+    pthread_mutex_lock(&adev->lock);
+    list_add_tail(&adev->in_streams, &in->stream_node);
+    pthread_mutex_unlock(&adev->lock);
 
     *stream_in = &in->stream;
 
@@ -1497,6 +1541,159 @@
     return 0;
 }
 
+static int adev_create_audio_patch(struct audio_hw_device *dev,
+                                   unsigned int num_sources,
+                                   const struct audio_port_config *sources,
+                                   unsigned int num_sinks,
+                                   const struct audio_port_config *sinks,
+                                   audio_patch_handle_t *handle) {
+    if (num_sources != 1 || num_sinks == 0 || num_sinks > AUDIO_PATCH_PORTS_MAX) {
+        return -EINVAL;
+    }
+
+    if (sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
+        // If source is a device, the number of sinks should be 1.
+        if (num_sinks != 1 || sinks[0].type != AUDIO_PORT_TYPE_MIX) {
+            return -EINVAL;
+        }
+    } else if (sources[0].type == AUDIO_PORT_TYPE_MIX) {
+        // If source is a mix, all sinks should be device.
+        for (unsigned int i = 0; i < num_sinks; i++) {
+            if (sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
+                ALOGE("%s() invalid sink type %#x for mix source", __func__, sinks[i].type);
+                return -EINVAL;
+            }
+        }
+    } else {
+        // All other cases are invalid.
+        return -EINVAL;
+    }
+
+    struct generic_audio_device* adev = (struct generic_audio_device*) dev;
+    int ret = 0;
+    bool generatedPatchHandle = false;
+    pthread_mutex_lock(&adev->lock);
+    if (*handle == AUDIO_PATCH_HANDLE_NONE) {
+        *handle = ++adev->next_patch_handle;
+        generatedPatchHandle = true;
+    }
+
+    // Only handle patches for mix->devices and device->mix case.
+    if (sources[0].type == AUDIO_PORT_TYPE_DEVICE) {
+        struct generic_stream_in *in =
+                get_stream_in_by_io_handle_l(adev, sinks[0].ext.mix.handle);
+        if (in == NULL) {
+            ALOGE("%s()can not find stream with handle(%d)", __func__, sources[0].ext.mix.handle);
+            ret = -EINVAL;
+            goto error;
+        }
+
+        // Check if the patch handle match the recorded one if a valid patch handle is passed.
+        if (!generatedPatchHandle && in->patch_handle != *handle) {
+            ALOGE("%s() the patch handle(%d) does not match recorded one(%d) for stream "
+                  "with handle(%d) when creating audio patch for device->mix",
+                  __func__, *handle, in->patch_handle, in->handle);
+            ret = -EINVAL;
+            goto error;
+        }
+        pthread_mutex_lock(&in->lock);
+        in->device = sources[0].ext.device.type;
+        pthread_mutex_unlock(&in->lock);
+        in->patch_handle = *handle;
+    } else {
+        struct generic_stream_out *out =
+                get_stream_out_by_io_handle_l(adev, sources[0].ext.mix.handle);
+        if (out == NULL) {
+            ALOGE("%s()can not find stream with handle(%d)", __func__, sources[0].ext.mix.handle);
+            ret = -EINVAL;
+            goto error;
+        }
+
+        // Check if the patch handle match the recorded one if a valid patch handle is passed.
+        if (!generatedPatchHandle && out->patch_handle != *handle) {
+            ALOGE("%s() the patch handle(%d) does not match recorded one(%d) for stream "
+                  "with handle(%d) when creating audio patch for mix->device",
+                  __func__, *handle, out->patch_handle, out->handle);
+            ret = -EINVAL;
+            pthread_mutex_unlock(&out->lock);
+            goto error;
+        }
+        pthread_mutex_lock(&out->lock);
+        for (out->num_devices = 0; out->num_devices < num_sinks; out->num_devices++) {
+            out->devices[out->num_devices] = sinks[out->num_devices].ext.device.type;
+        }
+        pthread_mutex_unlock(&out->lock);
+        out->patch_handle = *handle;
+    }
+
+error:
+    if (ret != 0 && generatedPatchHandle) {
+        *handle = AUDIO_PATCH_HANDLE_NONE;
+    }
+    pthread_mutex_unlock(&adev->lock);
+    return 0;
+}
+
+// This must be called with adev->lock held.
+struct generic_stream_out *get_stream_out_by_patch_handle_l(
+        struct generic_audio_device *adev, audio_patch_handle_t patch_handle) {
+    struct listnode *node;
+
+    list_for_each(node, &adev->out_streams) {
+        struct generic_stream_out *out = node_to_item(
+                node, struct generic_stream_out, stream_node);
+        if (out->patch_handle == patch_handle) {
+            return out;
+        }
+    }
+    return NULL;
+}
+
+// This must be called with adev->lock held.
+struct generic_stream_in *get_stream_in_by_patch_handle_l(
+        struct generic_audio_device *adev, audio_patch_handle_t patch_handle) {
+    struct listnode *node;
+
+    list_for_each(node, &adev->in_streams) {
+        struct generic_stream_in *in = node_to_item(
+                node, struct generic_stream_in, stream_node);
+        if (in->patch_handle == patch_handle) {
+            return in;
+        }
+    }
+    return NULL;
+}
+
+static int adev_release_audio_patch(struct audio_hw_device *dev,
+                                    audio_patch_handle_t patch_handle) {
+    struct generic_audio_device *adev = (struct generic_audio_device *) dev;
+
+    pthread_mutex_lock(&adev->lock);
+    struct generic_stream_out *out = get_stream_out_by_patch_handle_l(adev, patch_handle);
+    if (out != NULL) {
+        pthread_mutex_lock(&out->lock);
+        out->num_devices = 0;
+        memset(out->devices, 0, sizeof(out->devices));
+        pthread_mutex_unlock(&out->lock);
+        out->patch_handle = AUDIO_PATCH_HANDLE_NONE;
+        pthread_mutex_unlock(&adev->lock);
+        return 0;
+    }
+    struct generic_stream_in *in = get_stream_in_by_patch_handle_l(adev, patch_handle);
+    if (in != NULL) {
+        pthread_mutex_lock(&in->lock);
+        in->device = AUDIO_DEVICE_NONE;
+        pthread_mutex_unlock(&in->lock);
+        in->patch_handle = AUDIO_PATCH_HANDLE_NONE;
+        pthread_mutex_unlock(&adev->lock);
+        return 0;
+    }
+
+    pthread_mutex_unlock(&adev->lock);
+    ALOGW("%s() cannot find stream for patch handle: %d", __func__, patch_handle);
+    return -EINVAL;
+}
+
 static int adev_close(hw_device_t *dev)
 {
     struct generic_audio_device *adev = (struct generic_audio_device *)dev;
@@ -1545,7 +1742,7 @@
     pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
 
     adev->device.common.tag = HARDWARE_DEVICE_TAG;
-    adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
+    adev->device.common.version = AUDIO_DEVICE_API_VERSION_3_0;
     adev->device.common.module = (struct hw_module_t *) module;
     adev->device.common.close = adev_close;
 
@@ -1567,9 +1764,15 @@
     adev->device.close_input_stream = adev_close_input_stream;
     adev->device.dump = adev_dump;
     adev->device.get_microphones = adev_get_microphones;
+    adev->device.create_audio_patch = adev_create_audio_patch;
+    adev->device.release_audio_patch = adev_release_audio_patch;
 
     *device = &adev->device.common;
 
+    adev->next_patch_handle = AUDIO_PATCH_HANDLE_NONE;
+    list_init(&adev->out_streams);
+    list_init(&adev->in_streams);
+
     adev->mixer = mixer_open(PCM_CARD);
     struct mixer_ctl *ctl;
 
diff --git a/guest/hals/ril/cuttlefish_ril.cpp b/guest/hals/ril/cuttlefish_ril.cpp
index e5a120f..40fc393 100644
--- a/guest/hals/ril/cuttlefish_ril.cpp
+++ b/guest/hals/ril/cuttlefish_ril.cpp
@@ -2269,7 +2269,7 @@
   return;
 }
 
-// New functions after Q
+// New functions after Q.
 static void request_set_signal_strength_reporting_criteria_1_5(int /*request*/, void* /*data*/,
                                                                size_t /*datalen*/, RIL_Token t) {
   ALOGV("request_set_signal_strength_reporting_criteria_1_5 - void");
@@ -2289,6 +2289,12 @@
   return;
 }
 
+static void request_set_radio_power_1_5(RIL_Token t) {
+  ALOGV("request_set_radio_power_1_5");
+  gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+  return;
+}
+
 static void gce_ril_on_request(int request, void* data, size_t datalen,
                                RIL_Token t) {
   // Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
@@ -2588,6 +2594,9 @@
     case RIL_REQUEST_START_NETWORK_SCAN_1_5:
       request_start_network_scan_1_5(t);
       break;
+    case RIL_REQUEST_SET_RADIO_POWER_1_5:
+      request_set_radio_power_1_5(t);
+      break;
     default:
       ALOGE("Request %d not supported.", request);
       gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
diff --git a/guest/hals/ril/libril/ril.cpp b/guest/hals/ril/libril/ril.cpp
index 8d3497e..03d469a 100644
--- a/guest/hals/ril/libril/ril.cpp
+++ b/guest/hals/ril/libril/ril.cpp
@@ -1173,6 +1173,7 @@
         case RIL_REQUEST_GET_CARRIER_RESTRICTIONS_1_4: return "GET_CARRIER_RESTRICTIONS_1_4";
         case RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION: return "SET_CARRIER_INFO_IMSI_ENCRYPTION";
         case RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA_1_5: return "SET_SIGNAL_STRENGTH_REPORTING_CRITERIA_1_5";
+        case RIL_REQUEST_SET_RADIO_POWER_1_5: return "SET_RADIO_POWER_1_5";
         case RIL_RESPONSE_ACKNOWLEDGEMENT: return "RESPONSE_ACKNOWLEDGEMENT";
         case RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED: return "UNSOL_RESPONSE_RADIO_STATE_CHANGED";
         case RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED: return "UNSOL_RESPONSE_CALL_STATE_CHANGED";
diff --git a/guest/hals/ril/libril/ril.h b/guest/hals/ril/libril/ril.h
index fd8553c..32d5aa0 100644
--- a/guest/hals/ril/libril/ril.h
+++ b/guest/hals/ril/libril/ril.h
@@ -2040,6 +2040,8 @@
     RIL_APN_TYPE_EMERGENCY    = 0x200,        // APN type for Emergency PDN. This is not an IA apn,
                                               // but is used for access to carrier services in an
                                               // emergency call situation.
+    RIL_APN_TYPE_MCX          = 0x400,        // APN type for Mission Critical Service
+    RIL_APN_TYPE_XCAP         = 0x800,        // APN type for XCAP
     RIL_APN_TYPE_ALL          = 0xFFFFFFFF    // All APN types
 } RIL_ApnTypes;
 
@@ -6708,6 +6710,21 @@
  */
 #define RIL_REQUEST_START_NETWORK_SCAN_1_5 159
 
+
+/**
+ * RIL_REQUEST_SET_RADIO_POWER_1_5
+ *
+ * Turn on or off radio power. It can also specify whether turning on radio power is to place an
+ * emergency call and whether the call will be placed on this logical modem.
+ *
+ * Valid errors:
+ *  SUCCESS
+ *  INTERNAL_ERR
+ *  INVALID_ARGUMENTS
+ *
+ */
+#define RIL_REQUEST_SET_RADIO_POWER_1_5 160
+
 /***********************************************************************/
 
 /**
diff --git a/guest/hals/ril/libril/ril_commands.h b/guest/hals/ril/libril/ril_commands.h
index aa5df50..6cf94ba 100644
--- a/guest/hals/ril/libril/ril_commands.h
+++ b/guest/hals/ril/libril/ril_commands.h
@@ -174,3 +174,4 @@
     {RIL_REQUEST_ARE_UICC_APPLICATIONS_ENABLED, radio_1_5::areUiccApplicationsEnabledResponse},
     {RIL_REQUEST_SET_SYSTEM_SELECTION_CHANNELS_1_5, radio_1_5::setSystemSelectionChannelsResponse_1_5},
     {RIL_REQUEST_START_NETWORK_SCAN_1_5, radio_1_5::startNetworkScanResponse_1_5},
+    {RIL_REQUEST_SET_RADIO_POWER_1_5, radio_1_5::setRadioPowerResponse_1_5},
diff --git a/guest/hals/ril/libril/ril_service.cpp b/guest/hals/ril/libril/ril_service.cpp
index ae46c3f..176b383 100755
--- a/guest/hals/ril/libril/ril_service.cpp
+++ b/guest/hals/ril/libril/ril_service.cpp
@@ -541,6 +541,17 @@
             const hidl_vec<::android::hardware::radio::V1_5::RadioAccessSpecifier>& specifiers);
     Return<void> startNetworkScan_1_5(int32_t serial,
             const ::android::hardware::radio::V1_5::NetworkScanRequest& request);
+    Return<void> setupDataCall_1_5(int32_t serial,
+            ::android::hardware::radio::V1_5::AccessNetwork accessNetwork,
+            const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo,
+            bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason reason,
+            const hidl_vec<hidl_string>& addresses, const hidl_vec<hidl_string>& dnses);
+    Return<void> setInitialAttachApn_1_5(int32_t serial,
+            const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo);
+    Return<void> setDataProfile_1_5(int32_t serial,
+            const hidl_vec<::android::hardware::radio::V1_5::DataProfileInfo>& profiles);
+    Return<void> setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
+            bool preferredForEmergencyCall);
 };
 
 struct OemHookImpl : public IOemHook {
@@ -3579,7 +3590,7 @@
     return Void();
 }
 
-// Methods from ::android::hardware::radio::IRadio::V1_5 follow.
+// Methods from ::android::hardware::radio::V1_5::IRadio follow.
 Return<void> RadioImpl_1_5::setSignalStrengthReportingCriteria_1_5(int32_t /* serial */,
         const ::android::hardware::radio::V1_5::SignalThresholdInfo& /* signalThresholdInfo */,
         const ::android::hardware::radio::V1_5::AccessNetwork /* accessNetwork */) {
@@ -3598,6 +3609,16 @@
     return Void();
 }
 
+Return<void> RadioImpl_1_5::setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
+                                          bool preferredForEmergencyCall) {
+#if VDBG
+    RLOGD("setRadioPower_1_5: serial %d powerOn %d forEmergency %d preferredForEmergencyCall %d",
+        serial, powerOn, forEmergencyCall, preferredForEmergencyCall);
+#endif
+    dispatchVoid(serial, mSlotId, RIL_REQUEST_SET_RADIO_POWER_1_5);
+    return Void();
+}
+
 Return<void> RadioImpl_1_5::areUiccApplicationsEnabled(int32_t serial) {
 #if VDBG
     RLOGD("areUiccApplicationsEnabled: serial %d", serial);
@@ -3642,6 +3663,102 @@
     return Void();
 }
 
+Return<void> RadioImpl_1_5::setupDataCall_1_5(int32_t serial ,
+        ::android::hardware::radio::V1_5::AccessNetwork /* accessNetwork */,
+        const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo,
+        bool roamingAllowed, ::android::hardware::radio::V1_2::DataRequestReason /* reason */,
+        const hidl_vec<hidl_string>& /* addresses */, const hidl_vec<hidl_string>& /* dnses */) {
+
+#if VDBG
+    RLOGD("setupDataCall_1_5: serial %d", serial);
+#endif
+
+    char *mvnoTypeStr = NULL;
+    if (!convertMvnoTypeToString(MvnoType::IMSI, mvnoTypeStr)) {
+        RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+                RIL_REQUEST_SETUP_DATA_CALL);
+        if (pRI != NULL) {
+            sendErrorResponse(pRI, RIL_E_INVALID_ARGUMENTS);
+        }
+        return Void();
+    }
+    dispatchStrings(serial, mSlotId, RIL_REQUEST_SETUP_DATA_CALL, true, 15,
+        std::to_string((int) RadioTechnology::UNKNOWN + 2).c_str(),
+        std::to_string((int) dataProfileInfo.base.profileId).c_str(),
+        dataProfileInfo.base.apn.c_str(),
+        dataProfileInfo.base.user.c_str(),
+        dataProfileInfo.base.password.c_str(),
+        std::to_string((int) dataProfileInfo.base.authType).c_str(),
+        getProtocolString(dataProfileInfo.base.protocol),
+        getProtocolString(dataProfileInfo.base.roamingProtocol),
+        std::to_string(dataProfileInfo.supportedApnTypesBitmap).c_str(),
+        std::to_string(dataProfileInfo.base.bearerBitmap).c_str(),
+        dataProfileInfo.base.persistent ? "1" : "0",
+        std::to_string(dataProfileInfo.base.mtu).c_str(),
+        mvnoTypeStr,
+        "302720x94",
+        roamingAllowed ? "1" : "0");
+    return Void();
+}
+
+Return<void> RadioImpl_1_5::setInitialAttachApn_1_5(int32_t  serial ,
+        const ::android::hardware::radio::V1_5::DataProfileInfo& dataProfileInfo) {
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_INITIAL_ATTACH_APN);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
+
+    if (radioService[mSlotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_5->setInitialAttachApnResponse(responseInfo);
+    } else if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_4->setInitialAttachApnResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponse->setInitialAttachApnResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setInitialAttachApnResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
+    }
+
+    return Void();
+}
+
+Return<void> RadioImpl_1_5::setDataProfile_1_5(int32_t  serial ,
+        const hidl_vec<::android::hardware::radio::V1_5::DataProfileInfo>& /* profiles */) {
+    RequestInfo *pRI = android::addRequestToList(serial, mSlotId,
+            RIL_REQUEST_SET_DATA_PROFILE);
+    if (pRI == NULL) {
+        return Void();
+    }
+
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, RESPONSE_SOLICITED, RIL_E_SUCCESS);
+
+    if (radioService[mSlotId]->mRadioResponseV1_5 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_5->setDataProfileResponse(responseInfo);
+    } else if (radioService[mSlotId]->mRadioResponseV1_4 != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponseV1_4->setDataProfileResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else if (radioService[mSlotId]->mRadioResponse != NULL) {
+        Return<void> retStatus
+                = radioService[mSlotId]->mRadioResponse->setDataProfileResponse(responseInfo);
+        radioService[mSlotId]->checkReturnStatus(retStatus);
+    } else {
+        RLOGE("setDataProfileResponse: radioService[%d]->mRadioResponse == NULL", mSlotId);
+    }
+
+    return Void();
+}
+
 // OEM hook methods:
 Return<void> OemHookImpl::setResponseFunctions(
         const ::android::sp<IOemHookResponse>& oemHookResponseParam,
@@ -4836,14 +4953,36 @@
 #if VDBG
     RLOGD("setupDataCallResponse: serial %d", serial);
 #endif
-
-    if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
         RadioResponseInfo responseInfo = {};
         populateResponseInfo(responseInfo, serial, responseType, e);
         ::android::hardware::radio::V1_4::SetupDataCallResult result;
         if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
             if (response != NULL) {
-                RLOGE("setupDataCallResponse: Invalid response");
+                RLOGE("setupDataCallResponse_1_5: Invalid response");
+                if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
+            }
+            result.cause = ::android::hardware::radio::V1_4::DataCallFailCause::ERROR_UNSPECIFIED;
+            result.type = ::android::hardware::radio::V1_4::PdpProtocolType::UNKNOWN;
+            result.ifname = hidl_string();
+            result.addresses = hidl_vec<hidl_string>();
+            result.dnses = hidl_vec<hidl_string>();
+            result.gateways = hidl_vec<hidl_string>();
+            result.pcscf = hidl_vec<hidl_string>();
+        } else {
+            convertRilDataCallToHal((RIL_Data_Call_Response_v11 *) response, result);
+        }
+
+        Return<void> retStatus = radioService[slotId]->mRadioResponseV1_5->setupDataCallResponse_1_5(
+                responseInfo, result);
+        radioService[slotId]->checkReturnStatus(retStatus);
+    } else if (radioService[slotId]->mRadioResponseV1_4 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        ::android::hardware::radio::V1_4::SetupDataCallResult result;
+        if (response == NULL || (responseLen % sizeof(RIL_Data_Call_Response_v11)) != 0) {
+            if (response != NULL) {
+                RLOGE("setupDataCallResponse_1_4: Invalid response");
                 if (e == RIL_E_SUCCESS) responseInfo.error = RadioError::INVALID_RESPONSE;
             }
             result.cause = ::android::hardware::radio::V1_4::DataCallFailCause::ERROR_UNSPECIFIED;
@@ -6740,7 +6879,13 @@
     RLOGD("setInitialAttachApnResponse: serial %d", serial);
 #endif
 
-    if (radioService[slotId]->mRadioResponse != NULL) {
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_5->setInitialAttachApnResponse_1_5(
+                responseInfo);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
         RadioResponseInfo responseInfo = {};
         populateResponseInfo(responseInfo, serial, responseType, e);
         Return<void> retStatus
@@ -7100,7 +7245,13 @@
     RLOGD("setDataProfileResponse: serial %d", serial);
 #endif
 
-    if (radioService[slotId]->mRadioResponse != NULL) {
+    if (radioService[slotId]->mRadioResponseV1_5 != NULL) {
+        RadioResponseInfo responseInfo = {};
+        populateResponseInfo(responseInfo, serial, responseType, e);
+        Return<void> retStatus
+                = radioService[slotId]->mRadioResponseV1_5->setDataProfileResponse_1_5(
+                responseInfo);
+    } else if (radioService[slotId]->mRadioResponse != NULL) {
         RadioResponseInfo responseInfo = {};
         populateResponseInfo(responseInfo, serial, responseType, e);
         Return<void> retStatus
@@ -7931,6 +8082,27 @@
     return 0;
 }
 
+int radio_1_5::setRadioPowerResponse_1_5(int slotId, int responseType, int serial, RIL_Errno e,
+                                         void* /* response */, size_t responseLen) {
+#if VDBG
+    RLOGD("%s(): %d", __FUNCTION__, serial);
+#endif
+    RadioResponseInfo responseInfo = {};
+    populateResponseInfo(responseInfo, serial, responseType, e);
+
+    // If we don't have a radio service, there's nothing we can do
+    if (radioService[slotId]->mRadioResponseV1_5 == NULL) {
+        RLOGE("%s: radioService[%d]->mRadioResponseV1_5 == NULL", __FUNCTION__, slotId);
+        return 0;
+    }
+
+    Return<void> retStatus =
+            radioService[slotId]->mRadioResponseV1_5->setRadioPowerResponse_1_5(
+            responseInfo);
+    radioService[slotId]->checkReturnStatus(retStatus);
+    return 0;
+}
+
 /***************************************************************************************************
  * INDICATION FUNCTIONS
  * The below function handle unsolicited messages coming from the Radio
diff --git a/guest/hals/ril/libril/ril_service.h b/guest/hals/ril/libril/ril_service.h
index 8c3fd71..7bf86ba 100644
--- a/guest/hals/ril/libril/ril_service.h
+++ b/guest/hals/ril/libril/ril_service.h
@@ -798,6 +798,10 @@
                                      int responseType, int serial, RIL_Errno e,
                                      void *response, size_t responselen);
 
+int setRadioPowerResponse_1_5(int slotId, int responseType, int serial, RIL_Errno e,
+                              void *response, size_t responselen);
+
+
 pthread_rwlock_t * getRadioServiceRwlock(int slotId);
 
 void setNitzTimeReceived(int slotId, long timeReceived);
diff --git a/host/commands/fetcher/fetch_cvd.cc b/host/commands/fetcher/fetch_cvd.cc
index 5e314c8..abaede1 100644
--- a/host/commands/fetcher/fetch_cvd.cc
+++ b/host/commands/fetcher/fetch_cvd.cc
@@ -23,6 +23,7 @@
 #include "gflags/gflags.h"
 #include <glog/logging.h>
 
+#include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/archive.h"
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/subprocess.h"
@@ -390,15 +391,9 @@
     return 0;
   }
 
-  if (chdir(target_dir.c_str()) != 0) {
-    int error_num = errno;
-    LOG(FATAL) << "Could not change directory to \"" << target_dir << "\"."
-        << "errno was " << error_num << " \"" << strerror(error_num) << "\"";
-  }
-
   // Ignore return code. We want to make sure there is no running instance,
   // and stop_cvd will exit with an error code if there is already no running instance.
-  cvd::Command stop_cmd("bin/stop_cvd");
+  cvd::Command stop_cmd(target_dir + "/bin/stop_cvd");
   stop_cmd.RedirectStdIO(cvd::Subprocess::StdIOChannel::kStdOut,
                          cvd::Subprocess::StdIOChannel::kStdErr);
   stop_cmd.Start().Wait();
@@ -406,9 +401,35 @@
   // gflags::ParseCommandLineFlags will remove fetch_cvd's flags from this.
   // This depends the remove_flags argument (3rd) is "true".
 
+  auto filelist_fd = cvd::SharedFD::MemfdCreate("files_list");
+  if (!filelist_fd->IsOpen()) {
+    LOG(FATAL) << "Unable to create temp file to write file list. "
+               << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
+  }
+
+  for (const auto& file : config.get_cvd_files()) {
+    std::string file_entry = file.second.file_path + "\n";
+    auto chars_written = filelist_fd->Write(file_entry.c_str(), file_entry.size());
+    if (chars_written != file_entry.size()) {
+      LOG(FATAL) << "Unable to write entry to file list. Expected to write "
+                 << file_entry.size() << " but wrote " << chars_written << ". "
+                 << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
+    }
+  }
+  auto seek_result = filelist_fd->LSeek(0, SEEK_SET);
+  if (seek_result != 0) {
+    LOG(FATAL) << "Unable to seek on file list file. Expected 0, received " << seek_result
+               << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
+  }
+
+  if (filelist_fd->UNMANAGED_Dup2(0) == -1) {
+    LOG(FATAL) << "Unable to set file list to stdin. "
+               << filelist_fd->StrError() << " (" << filelist_fd->GetErrno() << ")";
+  }
+
   // TODO(b/139199114): Go into assemble_cvd when the interface is stable and implemented.
 
-  std::string next_stage = "bin/launch_cvd";
+  std::string next_stage = target_dir + "/bin/launch_cvd";
   std::vector<const char*> next_stage_argv = {"launch_cvd"};
   LOG(INFO) << "Running " << next_stage;
   for (int i = 1; i < argc; i++) {
diff --git a/shared/device.mk b/shared/device.mk
index 8c6748a..1e52385 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -35,7 +35,7 @@
 # Properties that are not vendor-specific. These will go in the product
 # partition, instead of the vendor partition, and do not need vendor
 # sepolicy
-PRODUCT_PRODUCT_PROPERTIES := \
+PRODUCT_PRODUCT_PROPERTIES += \
     persist.adb.tcp.port=5555 \
     persist.traced.enable=1 \
     ro.com.google.locationfeatures=1 \
diff --git a/shared/sepolicy/vendor/priv_app.te b/shared/sepolicy/vendor/priv_app.te
index 7de36ab..05c9e47 100644
--- a/shared/sepolicy/vendor/priv_app.te
+++ b/shared/sepolicy/vendor/priv_app.te
@@ -1,6 +1 @@
 gpu_access(priv_app)
-get_prop(priv_app, hal_camera_prop)
-# b/142672293: No other priv-app should need this allow rule now and GMS core runs in its own domain.
-userdebug_or_eng(`
-  auditallow priv_app hal_camera_prop:file { getattr open read map };
-')