DO NOT MERGE - Added missing theme packages on preinstalled XML. am: ed05e95960
Change-Id: Iba74c201a4bc8f54ae089ba31bd84429961ebb71
diff --git a/common/libs/utils/environment.cpp b/common/libs/utils/environment.cpp
index 11a0b8c..e6cacd0 100644
--- a/common/libs/utils/environment.cpp
+++ b/common/libs/utils/environment.cpp
@@ -17,6 +17,8 @@
#include "common/libs/utils/environment.h"
#include <stdlib.h>
+#include <stdio.h>
+#include <iostream>
namespace cvd {
@@ -29,4 +31,55 @@
return valstr;
}
+/**
+ * at runtime, return the arch of the host: e.g. aarch64, x86_64, etc
+ *
+ * uses "`which uname` -m"
+ *
+ * @return arch string on success, "" on failure
+ */
+std::string HostArch() {
+ static std::string arch;
+ static bool cached = false;
+
+ if (cached) {
+ return arch;
+ }
+ cached = true;
+
+ // good to check if uname exists and is executable
+ // or, guarantee uname is availabe by dependency list
+ FILE* pip = popen("uname -m", "r");
+ if (!pip) {
+ return std::string{};
+ }
+
+ auto read_from_file =
+ [](FILE* fp, size_t len) {
+ /*
+ * to see if input is longer than len,
+ * we read up to len+1. If the length is len+1,
+ * then the input is too long
+ */
+ decltype(len) upper = len + 1;
+ std::string format("%");
+ format.append(std::to_string(upper)).append("s");
+ std::shared_ptr<char> buf(new char[upper],
+ std::default_delete<char[]>());
+ if (fscanf(fp, format.c_str(), buf.get()) == EOF) {
+ return std::string{};
+ }
+ std::string result(buf.get());
+ return (result.length() < upper) ? result : std::string{};
+ };
+ arch = read_from_file(pip, 20);
+ pclose(pip);
+
+ // l and r trim on arch
+ static const char* whitespace = "\t\n\r\f\v ";
+ arch.erase(arch.find_last_not_of(whitespace) + 1); // r trim
+ arch.erase(0, arch.find_first_not_of(whitespace)); // l trim
+ return arch;
+}
+
} // namespace cvd
diff --git a/common/libs/utils/environment.h b/common/libs/utils/environment.h
index 1aab8de..5a83b49 100644
--- a/common/libs/utils/environment.h
+++ b/common/libs/utils/environment.h
@@ -22,4 +22,6 @@
std::string StringFromEnv(const std::string& varname,
const std::string& defval);
+std::string HostArch();
+
} // namespace cvd
diff --git a/common/libs/utils/network.cpp b/common/libs/utils/network.cpp
index cece2b6..5b67c8e 100644
--- a/common/libs/utils/network.cpp
+++ b/common/libs/utils/network.cpp
@@ -23,10 +23,19 @@
#include <android-base/strings.h>
#include "common/libs/glog/logging.h"
+#include "common/libs/utils/environment.h"
#include "common/libs/utils/subprocess.h"
namespace cvd {
namespace {
+
+static std::string DefaultHostArtifactsPath(const std::string& file_name) {
+ return (cvd::StringFromEnv("ANDROID_HOST_OUT",
+ cvd::StringFromEnv("HOME", ".")) +
+ "/") +
+ file_name;
+}
+
// This should be the size of virtio_net_hdr_v1, from linux/virtio_net.h, but
// the version of that header that ships with android in Pie does not include
// that struct (it was added in Q).
@@ -52,28 +61,41 @@
return tap_fd;
}
- struct ifreq ifr;
- memset(&ifr, 0, sizeof(ifr));
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
- strncpy(ifr.ifr_name, interface_name.c_str(), IFNAMSIZ);
+ if (cvd::HostArch() == "aarch64") {
+ auto tapsetiff_path = DefaultHostArtifactsPath("bin/tapsetiff");
+ cvd::Command cmd(tapsetiff_path);
+ cmd.AddParameter(tap_fd);
+ cmd.AddParameter(interface_name.c_str());
+ int ret = cmd.Start().Wait();
+ if (ret != 0) {
+ LOG(ERROR) << "Unable to run tapsetiff.py. Exited with status " << ret;
+ tap_fd->Close();
+ return cvd::SharedFD();
+ }
+ } else {
+ struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
+ strncpy(ifr.ifr_name, interface_name.c_str(), IFNAMSIZ);
- int err = tap_fd->Ioctl(TUNSETIFF, &ifr);
- if (err < 0) {
- LOG(ERROR) << "Unable to connect to " << interface_name
- << " tap interface: " << tap_fd->StrError();
- tap_fd->Close();
- return cvd::SharedFD();
- }
+ int err = tap_fd->Ioctl(TUNSETIFF, &ifr);
+ if (err < 0) {
+ LOG(ERROR) << "Unable to connect to " << interface_name
+ << " tap interface: " << tap_fd->StrError();
+ tap_fd->Close();
+ return cvd::SharedFD();
+ }
- // The interface's configuration may have been modified or just not set
- // correctly on creation. While qemu checks this and enforces the right
- // configuration, crosvm does not, so it needs to be set before it's passed to
- // it.
- tap_fd->Ioctl(TUNSETOFFLOAD,
- reinterpret_cast<void*>(TUN_F_CSUM | TUN_F_UFO | TUN_F_TSO4 |
+ // The interface's configuration may have been modified or just not set
+ // correctly on creation. While qemu checks this and enforces the right
+ // configuration, crosvm does not, so it needs to be set before it's passed to
+ // it.
+ tap_fd->Ioctl(TUNSETOFFLOAD,
+ reinterpret_cast<void*>(TUN_F_CSUM | TUN_F_UFO | TUN_F_TSO4 |
TUN_F_TSO6));
- int len = SIZE_OF_VIRTIO_NET_HDR_V1;
- tap_fd->Ioctl(TUNSETVNETHDRSZ, &len);
+ int len = SIZE_OF_VIRTIO_NET_HDR_V1;
+ tap_fd->Ioctl(TUNSETVNETHDRSZ, &len);
+ }
return tap_fd;
}
diff --git a/guest/hals/hwcomposer/common/Android.bp b/guest/hals/hwcomposer/common/Android.bp
index 25d02f8..fa023f1 100644
--- a/guest/hals/hwcomposer/common/Android.bp
+++ b/guest/hals/hwcomposer/common/Android.bp
@@ -18,26 +18,31 @@
defaults: ["cuttlefish_guest_only"],
vendor: true,
srcs: [
+ "base_composer.cpp",
+ "cpu_composer.cpp",
+ "drm_utils.cpp",
+ "geometry_utils.cpp",
+ "gralloc_utils.cpp",
"hwcomposer.cpp",
"screen_view.cpp",
- "base_composer.cpp",
- "geometry_utils.cpp",
- "cpu_composer.cpp",
"stats_keeper.cpp",
],
static_libs: [
"libyuv_static",
],
+ header_libs: ["libhardware_headers"],
shared_libs: [
- "liblog",
- "libhardware",
+ "android.hardware.graphics.mapper@4.0",
"libbase",
"libcutils",
- "libutils",
- "libsync",
- "libhardware",
- "libjpeg",
"libcuttlefish_utils",
"libcuttlefish_fs",
+ "libdrm",
+ "libgralloctypes",
+ "libhidlbase",
+ "libjpeg",
+ "liblog",
+ "libsync",
+ "libutils",
],
}
diff --git a/guest/hals/hwcomposer/common/base_composer.cpp b/guest/hals/hwcomposer/common/base_composer.cpp
index 0113849..cd3ac65 100644
--- a/guest/hals/hwcomposer/common/base_composer.cpp
+++ b/guest/hals/hwcomposer/common/base_composer.cpp
@@ -19,39 +19,78 @@
#include <string.h>
#include <cutils/properties.h>
-#include <hardware/gralloc.h>
#include <log/log.h>
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
namespace cvd {
BaseComposer::BaseComposer(std::unique_ptr<ScreenView> screen_view)
- : screen_view_(std::move(screen_view)) {
- hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
- reinterpret_cast<const hw_module_t**>(&gralloc_module_));
-}
+ : screen_view_(std::move(screen_view)), gralloc_() {}
void BaseComposer::Dump(char* buff __unused, int buff_len __unused) {}
int BaseComposer::PostFrameBufferTarget(buffer_handle_t buffer_handle) {
auto buffer_id = screen_view_->NextBuffer();
void* frame_buffer = screen_view_->GetBuffer(buffer_id);
- const private_handle_t* p_handle =
- reinterpret_cast<const private_handle_t*>(buffer_handle);
- void* buffer;
- int retval = gralloc_module_->lock(gralloc_module_, buffer_handle,
- GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
- p_handle->x_res, p_handle->y_res, &buffer);
- if (retval != 0) {
- ALOGE("Got error code %d from lock function", retval);
+
+ auto imported_buffer_opt = gralloc_.Import(buffer_handle);
+ if (!imported_buffer_opt) {
+ ALOGE("Failed to Import() framebuffer for post.");
return -1;
}
+ GrallocBuffer& imported_buffer = *imported_buffer_opt;
+
+ auto buffer_opt = imported_buffer.Lock();
+ if (!buffer_opt) {
+ ALOGE("Failed to Lock() framebuffer for post.");
+ return -1;
+ }
+
+ void* buffer = *buffer_opt;
memcpy(frame_buffer, buffer, screen_view_->buffer_size());
+
+ imported_buffer.Unlock();
+
screen_view_->Broadcast(buffer_id);
return 0;
} // namespace cvd
+bool BaseComposer::IsValidLayer(const hwc_layer_1_t& layer) {
+ auto buffer_opt = gralloc_.Import(layer.handle);
+ if (!buffer_opt) {
+ ALOGE("Failed to import and validate layer buffer handle.");
+ return false;
+ }
+ GrallocBuffer& buffer = *buffer_opt;
+
+ auto buffer_width_opt = buffer.GetWidth();
+ if (!buffer_width_opt) {
+ ALOGE("Failed to get layer buffer width.");
+ return false;
+ }
+ uint32_t buffer_width = *buffer_width_opt;
+
+ auto buffer_height_opt = buffer.GetHeight();
+ if (!buffer_height_opt) {
+ ALOGE("Failed to get layer buffer height.");
+ return false;
+ }
+ uint32_t buffer_height = *buffer_height_opt;
+
+ if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
+ layer.sourceCrop.right > buffer_width ||
+ layer.sourceCrop.bottom > buffer_height) {
+ ALOGE(
+ "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
+ "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
+ "%d]",
+ __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
+ layer.sourceCrop.top, layer.sourceCrop.bottom, buffer_width,
+ buffer_height);
+ return false;
+ }
+ return true;
+}
+
int BaseComposer::PrepareLayers(size_t num_layers, hwc_layer_1_t* layers) {
// find unsupported overlays
for (size_t i = 0; i < num_layers; i++) {
diff --git a/guest/hals/hwcomposer/common/base_composer.h b/guest/hals/hwcomposer/common/base_composer.h
index 69e618a..c1ffbfe 100644
--- a/guest/hals/hwcomposer/common/base_composer.h
+++ b/guest/hals/hwcomposer/common/base_composer.h
@@ -18,6 +18,7 @@
#include <memory>
+#include "guest/hals/hwcomposer/common/gralloc_utils.h"
#include "guest/hals/hwcomposer/common/hwcomposer.h"
#include "guest/hals/hwcomposer/common/screen_view.h"
@@ -28,6 +29,7 @@
BaseComposer(std::unique_ptr<ScreenView> screen_view);
virtual ~BaseComposer() = default;
+ virtual bool IsValidLayer(const hwc_layer_1_t& layer);
// Sets the composition type of each layer and returns the number of layers
// to be composited by the hwcomposer.
virtual int PrepareLayers(size_t num_layers, hwc_layer_1_t* layers);
@@ -42,7 +44,7 @@
protected:
std::unique_ptr<ScreenView> screen_view_;
- const gralloc_module_t* gralloc_module_;
+ Gralloc gralloc_;
private:
// Returns buffer offset or negative on error.
diff --git a/guest/hals/hwcomposer/common/cpu_composer.cpp b/guest/hals/hwcomposer/common/cpu_composer.cpp
index 35bc701..966aabf 100644
--- a/guest/hals/hwcomposer/common/cpu_composer.cpp
+++ b/guest/hals/hwcomposer/common/cpu_composer.cpp
@@ -21,13 +21,14 @@
#include <utility>
#include <vector>
+#include <drm_fourcc.h>
#include <hardware/hwcomposer.h>
#include <hardware/hwcomposer_defs.h>
#include <libyuv.h>
#include <log/log.h>
-#include <system/graphics.h>
#include "common/libs/utils/size_utils.h"
+#include "guest/hals/hwcomposer/common/drm_utils.h"
#include "guest/hals/hwcomposer/common/geometry_utils.h"
namespace cvd {
@@ -61,59 +62,22 @@
bool v_flip);
int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip);
-ConverterFunction GetConverter(uint32_t format) {
- switch (format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+
+ConverterFunction GetConverterForDrmFormat(uint32_t drm_format) {
+ switch (drm_format) {
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_XBGR8888:
return &DoCopy;
-
- case HAL_PIXEL_FORMAT_YV12:
+ case DRM_FORMAT_YVU420:
return &ConvertFromYV12;
-
- // Unsupported formats
- // TODO(jemoreira): Conversion from these formats should be implemented as
- // we find evidence of its usage.
- // case HAL_PIXEL_FORMAT_BGRA_8888:
-
- // case HAL_PIXEL_FORMAT_RGB_888:
- // case HAL_PIXEL_FORMAT_RGB_565:
-
- // case HAL_PIXEL_FORMAT_sRGB_A_8888:
- // case HAL_PIXEL_FORMAT_sRGB_X_8888:
-
- // case HAL_PIXEL_FORMAT_Y8:
- // case HAL_PIXEL_FORMAT_Y16:
-
- // case HAL_PIXEL_FORMAT_RAW_SENSOR:
- // case HAL_PIXEL_FORMAT_BLOB:
-
- // case HAL_PIXEL_FORMAT_YCbCr_420_888:
- // case HAL_PIXEL_FORMAT_YCbCr_422_SP:
- // case HAL_PIXEL_FORMAT_YCrCb_420_SP:
- // case HAL_PIXEL_FORMAT_YCbCr_422_I:
- default:
- ALOGW("Unsupported format: 0x%04x, returning null converter function",
- format);
}
- return NULL;
+ ALOGW("Unsupported format: %d(%s), returning null converter",
+ drm_format, GetDrmFormatString(drm_format));
+ return nullptr;
}
-// Whether we support a given format
-bool IsFormatSupported(uint32_t format) { return GetConverter(format) != NULL; }
-
-bool CanCompositeLayer(const hwc_layer_1_t& layer) {
- if (layer.handle == NULL) {
- ALOGW("%s received a layer with a null handler", __FUNCTION__);
- return false;
- }
- int format = reinterpret_cast<const private_handle_t*>(layer.handle)->format;
- if (!IsFormatSupported(format)) {
- ALOGD("Unsupported pixel format: 0x%x, doing software composition instead",
- format);
- return false;
- }
- return true;
+bool IsDrmFormatSupported(uint32_t drm_format) {
+ return GetConverterForDrmFormat(drm_format) != nullptr;
}
/*******************************************************************************
@@ -140,66 +104,109 @@
struct BufferSpec {
uint8_t* buffer;
- size_t size;
+ std::optional<android_ycbcr> buffer_ycbcr;
int width;
int height;
- int stride;
int crop_x;
int crop_y;
int crop_width;
int crop_height;
- uint32_t format;
+ uint32_t drm_format;
+ int stride_bytes;
+ int sample_bytes;
- BufferSpec(uint8_t* buffer, size_t size, int width, int height, int stride)
+ BufferSpec(uint8_t* buffer,
+ std::optional<android_ycbcr> buffer_ycbcr,
+ int width,
+ int height,
+ int crop_x,
+ int crop_y,
+ int crop_width,
+ int crop_height,
+ uint32_t drm_format,
+ int stride_bytes,
+ int sample_bytes)
: buffer(buffer),
- size(size),
+ buffer_ycbcr(buffer_ycbcr),
width(width),
height(height),
- stride(stride),
- crop_x(0),
- crop_y(0),
- crop_width(width),
- crop_height(height),
- format(HAL_PIXEL_FORMAT_RGBA_8888) {}
+ crop_x(crop_x),
+ crop_y(crop_y),
+ crop_width(crop_width),
+ crop_height(crop_height),
+ drm_format(drm_format),
+ stride_bytes(stride_bytes),
+ sample_bytes(sample_bytes) {}
+
+ BufferSpec(uint8_t* buffer,
+ int width,
+ int height,
+ int stride_bytes)
+ : BufferSpec(buffer,
+ /*buffer_ycbcr=*/std::nullopt,
+ width,
+ height,
+ /*crop_x=*/0,
+ /*crop_y=*/0,
+ /*crop_width=*/width,
+ /*crop_height=*/height,
+ /*drm_format=*/DRM_FORMAT_ABGR8888,
+ stride_bytes,
+ /*sample_bytes=*/4) {}
+
};
int ConvertFromYV12(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
- // use the stride in pixels as the source width
- int stride_in_pixels = src.stride / formatToBytesPerPixel(src.format);
-
// The following calculation of plane offsets and alignments are based on
// swiftshader's Sampler::setTextureLevel() implementation
// (Renderer/Sampler.cpp:225)
- uint8_t* src_y = src.buffer;
- int stride_y = stride_in_pixels;
- uint8_t* src_v = src_y + stride_y * src.height;
- int stride_v = cvd::AlignToPowerOf2(stride_y / 2, 4);
- uint8_t* src_u = src_v + stride_v * src.height / 2;
- int stride_u = cvd::AlignToPowerOf2(stride_y / 2, 4);
+
+ auto& src_buffer_ycbcr_opt = src.buffer_ycbcr;
+ if (!src_buffer_ycbcr_opt) {
+ ALOGE("%s called on non ycbcr buffer", __FUNCTION__);
+ return -1;
+ }
+ auto& src_buffer_ycbcr = *src_buffer_ycbcr_opt;
+
+ // The libyuv::I420ToARGB() function is for tri-planar.
+ if (src_buffer_ycbcr.chroma_step != 1) {
+ ALOGE("%s called with bad chroma step", __FUNCTION__);
+ return -1;
+ }
+
+ uint8_t* src_y = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.y);
+ int stride_y = src_buffer_ycbcr.ystride;
+ uint8_t* src_u = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.cb);
+ int stride_u = src_buffer_ycbcr.cstride;
+ uint8_t* src_v = reinterpret_cast<uint8_t*>(src_buffer_ycbcr.cr);
+ int stride_v = src_buffer_ycbcr.cstride;
// Adjust for crop
src_y += src.crop_y * stride_y + src.crop_x;
src_v += (src.crop_y / 2) * stride_v + (src.crop_x / 2);
src_u += (src.crop_y / 2) * stride_u + (src.crop_x / 2);
- uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
- dst.crop_x * formatToBytesPerPixel(dst.format);
+ uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+ dst.crop_x * dst.sample_bytes;
// YV12 is the same as I420, with the U and V planes swapped
- return libyuv::I420ToARGB(src_y, stride_y, src_v, stride_v, src_u, stride_u,
- dst_buffer, dst.stride, dst.crop_width,
+ return libyuv::I420ToARGB(src_y, stride_y,
+ src_v, stride_v,
+ src_u, stride_u,
+ dst_buffer, dst.stride_bytes,
+ dst.crop_width,
v_flip ? -dst.crop_height : dst.crop_height);
}
int DoConversion(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
- return (*GetConverter(src.format))(src, dst, v_flip);
+ return (*GetConverterForDrmFormat(src.drm_format))(src, dst, v_flip);
}
int DoCopy(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
// Point to the upper left corner of the crop rectangle
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
- dst.crop_x * formatToBytesPerPixel(dst.format);
+ uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+ src.crop_x * src.sample_bytes;
+ uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+ dst.crop_x * dst.sample_bytes;
int width = src.crop_width;
int height = src.crop_height;
@@ -211,17 +218,19 @@
// byte stream, while libyuv formats are named based on the order of those
// pixel components in an integer written from left to right. So
// libyuv::FOURCC_ARGB is equivalent to HAL_PIXEL_FORMAT_BGRA_8888.
- return libyuv::ARGBCopy(src_buffer, src.stride, dst_buffer, dst.stride, width,
- height);
+ auto ret = libyuv::ARGBCopy(src_buffer, src.stride_bytes,
+ dst_buffer, dst.stride_bytes,
+ width, height);
+ return ret;
}
int DoRotation(const BufferSpec& src, const BufferSpec& dst,
libyuv::RotationMode rotation, bool v_flip) {
// Point to the upper left corner of the crop rectangles
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
- dst.crop_x * formatToBytesPerPixel(dst.format);
+ uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+ src.crop_x * src.sample_bytes;
+ uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+ dst.crop_x * dst.sample_bytes;
int width = src.crop_width;
int height = src.crop_height;
@@ -229,16 +238,17 @@
height = -height;
}
- return libyuv::ARGBRotate(src_buffer, src.stride, dst_buffer, dst.stride,
+ return libyuv::ARGBRotate(src_buffer, src.stride_bytes,
+ dst_buffer, dst.stride_bytes,
width, height, rotation);
}
int DoScaling(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
// Point to the upper left corner of the crop rectangles
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride +
- dst.crop_x * formatToBytesPerPixel(dst.format);
+ uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+ src.crop_x * src.sample_bytes;
+ uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+ dst.crop_x * dst.sample_bytes;
int src_width = src.crop_width;
int src_height = src.crop_height;
int dst_width = dst.crop_width;
@@ -248,36 +258,37 @@
src_height = -src_height;
}
- return libyuv::ARGBScale(src_buffer, src.stride, src_width, src_height,
- dst_buffer, dst.stride, dst_width, dst_height,
+ return libyuv::ARGBScale(src_buffer, src.stride_bytes, src_width, src_height,
+ dst_buffer, dst.stride_bytes, dst_width, dst_height,
libyuv::kFilterBilinear);
}
-int DoAttenuation(const BufferSpec& src, const BufferSpec& dest, bool v_flip) {
+int DoAttenuation(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
// Point to the upper left corner of the crop rectangles
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dest.buffer + dest.crop_y * dest.stride +
- dest.crop_x * formatToBytesPerPixel(dest.format);
- int width = dest.crop_width;
- int height = dest.crop_height;
+ uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+ src.crop_x * src.sample_bytes;
+ uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+ dst.crop_x * dst.sample_bytes;
+ int width = dst.crop_width;
+ int height = dst.crop_height;
if (v_flip) {
height = -height;
}
- return libyuv::ARGBAttenuate(src_buffer, src.stride, dst_buffer, dest.stride,
+ return libyuv::ARGBAttenuate(src_buffer, src.stride_bytes,
+ dst_buffer, dst.stride_bytes,
width, height);
}
-int DoBlending(const BufferSpec& src, const BufferSpec& dest, bool v_flip) {
+int DoBlending(const BufferSpec& src, const BufferSpec& dst, bool v_flip) {
// Point to the upper left corner of the crop rectangles
- uint8_t* src_buffer = src.buffer + src.crop_y * src.stride +
- src.crop_x * formatToBytesPerPixel(src.format);
- uint8_t* dst_buffer = dest.buffer + dest.crop_y * dest.stride +
- dest.crop_x * formatToBytesPerPixel(dest.format);
- int width = dest.crop_width;
- int height = dest.crop_height;
+ uint8_t* src_buffer = src.buffer + src.crop_y * src.stride_bytes +
+ src.crop_x * src.sample_bytes;
+ uint8_t* dst_buffer = dst.buffer + dst.crop_y * dst.stride_bytes +
+ dst.crop_x * dst.sample_bytes;
+ int width = dst.crop_width;
+ int height = dst.crop_height;
if (v_flip) {
height = -height;
@@ -286,21 +297,127 @@
// libyuv's ARGB format is hwcomposer's BGRA format, since blending only cares
// for the position of alpha in the pixel and not the position of the colors
// this function is perfectly usable.
- return libyuv::ARGBBlend(src_buffer, src.stride, dst_buffer, dest.stride,
- dst_buffer, dest.stride, width, height);
+ return libyuv::ARGBBlend(src_buffer, src.stride_bytes,
+ dst_buffer, dst.stride_bytes,
+ dst_buffer, dst.stride_bytes,
+ width, height);
+}
+
+std::optional<BufferSpec> GetBufferSpec(GrallocBuffer& buffer,
+ const hwc_rect_t& buffer_crop) {
+ auto buffer_format_opt = buffer.GetDrmFormat();
+ if (!buffer_format_opt) {
+ ALOGE("Failed to get gralloc buffer format.");
+ return std::nullopt;
+ }
+ uint32_t buffer_format = *buffer_format_opt;
+
+ auto buffer_width_opt = buffer.GetWidth();
+ if (!buffer_width_opt) {
+ ALOGE("Failed to get gralloc buffer width.");
+ return std::nullopt;
+ }
+ uint32_t buffer_width = *buffer_width_opt;
+
+ auto buffer_height_opt = buffer.GetHeight();
+ if (!buffer_height_opt) {
+ ALOGE("Failed to get gralloc buffer height.");
+ return std::nullopt;
+ }
+ uint32_t buffer_height = *buffer_height_opt;
+
+ uint8_t* buffer_data = nullptr;
+ uint32_t buffer_stride_bytes = 0;
+ std::optional<android_ycbcr> buffer_ycbcr_data;
+
+ if (buffer_format == DRM_FORMAT_NV12 ||
+ buffer_format == DRM_FORMAT_NV21 ||
+ buffer_format == DRM_FORMAT_YVU420) {
+ buffer_ycbcr_data = buffer.LockYCbCr();
+ if (!buffer_ycbcr_data) {
+ ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
+ return std::nullopt;
+ }
+ } else {
+ auto buffer_data_opt = buffer.Lock();
+ if (!buffer_data_opt) {
+ ALOGE("%s failed to lock gralloc buffer.", __FUNCTION__);
+ return std::nullopt;
+ }
+ buffer_data = reinterpret_cast<uint8_t*>(*buffer_data_opt);
+
+ auto buffer_stride_bytes_opt = buffer.GetMonoPlanarStrideBytes();
+ if (!buffer_stride_bytes_opt) {
+ ALOGE("%s failed to get plane stride.", __FUNCTION__);
+ return std::nullopt;
+ }
+ buffer_stride_bytes = *buffer_stride_bytes_opt;
+ }
+
+ return BufferSpec(
+ buffer_data,
+ buffer_ycbcr_data,
+ buffer_width,
+ buffer_height,
+ buffer_crop.left,
+ buffer_crop.top,
+ buffer_crop.right - buffer_crop.left,
+ buffer_crop.bottom - buffer_crop.top,
+ buffer_format,
+ buffer_stride_bytes,
+ GetDrmFormatBytesPerPixel(buffer_format));
}
} // namespace
+bool CpuComposer::CanCompositeLayer(const hwc_layer_1_t& layer) {
+ buffer_handle_t buffer_handle = layer.handle;
+ if (buffer_handle == nullptr) {
+ ALOGW("%s received a layer with a null handle", __FUNCTION__);
+ return false;
+ }
+
+ auto buffer_opt = gralloc_.Import(buffer_handle);
+ if (!buffer_opt) {
+ ALOGE("Failed to import layer buffer.");
+ return false;
+ }
+ GrallocBuffer& buffer = *buffer_opt;
+
+ auto buffer_format_opt = buffer.GetDrmFormat();
+ if (!buffer_format_opt) {
+ ALOGE("Failed to get layer buffer format.");
+ return false;
+ }
+ uint32_t buffer_format = *buffer_format_opt;
+
+ if (!IsDrmFormatSupported(buffer_format)) {
+ ALOGD("Unsupported pixel format: 0x%x, doing software composition instead",
+ buffer_format);
+ return false;
+ }
+ return true;
+}
+
void CpuComposer::CompositeLayer(hwc_layer_1_t* src_layer, int buffer_idx) {
libyuv::RotationMode rotation =
GetRotationFromTransform(src_layer->transform);
- const private_handle_t* src_priv_handle =
- reinterpret_cast<const private_handle_t*>(src_layer->handle);
+ auto src_imported_buffer_opt = gralloc_.Import(src_layer->handle);
+ if (!src_imported_buffer_opt) {
+ ALOGE("Failed to import layer buffer.");
+ return;
+ }
+ GrallocBuffer& src_imported_buffer = *src_imported_buffer_opt;
+
+ auto src_layer_spec_opt = GetBufferSpec(src_imported_buffer, src_layer->sourceCrop);
+ if (!src_layer_spec_opt) {
+ return;
+ }
+ BufferSpec src_layer_spec = *src_layer_spec_opt;
// TODO(jemoreira): Remove the hardcoded fomat.
- bool needs_conversion = src_priv_handle->format != HAL_PIXEL_FORMAT_RGBX_8888;
+ bool needs_conversion = src_layer_spec.drm_format != DRM_FORMAT_XBGR8888;
bool needs_scaling = LayerNeedsScaling(*src_layer);
bool needs_rotation = rotation != libyuv::kRotate0;
bool needs_transpose = needs_rotation && rotation != libyuv::kRotate180;
@@ -310,47 +427,21 @@
bool needs_copy = !(needs_conversion || needs_scaling || needs_rotation ||
needs_vflip || needs_attenuation || needs_blending);
- uint8_t* src_buffer;
uint8_t* dst_buffer =
- reinterpret_cast<uint8_t*>(screen_view_->GetBuffer(buffer_idx));
- int retval = gralloc_module_->lock(
- gralloc_module_, src_layer->handle, GRALLOC_USAGE_SW_READ_OFTEN, 0, 0,
- src_priv_handle->x_res, src_priv_handle->y_res,
- reinterpret_cast<void**>(&src_buffer));
- if (retval) {
- ALOGE("Got error code %d from lock function", retval);
- return;
- }
- if (retval) {
- ALOGE("Got error code %d from lock function", retval);
- // TODO(jemoreira): Use a lock_guard-like object.
- gralloc_module_->unlock(gralloc_module_, src_priv_handle);
- return;
- }
+ reinterpret_cast<uint8_t*>(screen_view_->GetBuffer(buffer_idx));
- BufferSpec src_layer_spec(src_buffer, src_priv_handle->total_size,
- src_priv_handle->x_res, src_priv_handle->y_res,
- src_priv_handle->stride_in_pixels *
- formatToBytesPerPixel(src_priv_handle->format));
- src_layer_spec.crop_x = src_layer->sourceCrop.left;
- src_layer_spec.crop_y = src_layer->sourceCrop.top;
- src_layer_spec.crop_width =
- src_layer->sourceCrop.right - src_layer->sourceCrop.left;
- src_layer_spec.crop_height =
- src_layer->sourceCrop.bottom - src_layer->sourceCrop.top;
- src_layer_spec.format = src_priv_handle->format;
-
- BufferSpec dst_layer_spec(dst_buffer, screen_view_->buffer_size(),
- screen_view_->x_res(), screen_view_->y_res(),
- screen_view_->line_length());
- dst_layer_spec.crop_x = src_layer->displayFrame.left;
- dst_layer_spec.crop_y = src_layer->displayFrame.top;
- dst_layer_spec.crop_width =
- src_layer->displayFrame.right - src_layer->displayFrame.left;
- dst_layer_spec.crop_height =
- src_layer->displayFrame.bottom - src_layer->displayFrame.top;
- // TODO(jemoreira): Remove the hardcoded fomat.
- dst_layer_spec.format = HAL_PIXEL_FORMAT_RGBX_8888;
+ BufferSpec dst_layer_spec(
+ dst_buffer,
+ /*buffer_ycbcr=*/std::nullopt,
+ screen_view_->x_res(),
+ screen_view_->y_res(),
+ src_layer->displayFrame.left,
+ src_layer->displayFrame.top,
+ src_layer->displayFrame.right - src_layer->displayFrame.left,
+ src_layer->displayFrame.bottom - src_layer->displayFrame.top,
+ DRM_FORMAT_XBGR8888,
+ screen_view_->line_length(),
+ 4);
// Add the destination layer to the bottom of the buffer stack
std::vector<BufferSpec> dest_buffer_stack(1, dst_layer_spec);
@@ -367,16 +458,20 @@
(needs_attenuation ? 1 : 0) +
(needs_blending ? 1 : 0) + (needs_copy ? 1 : 0) - 1;
- int x_res = src_layer->displayFrame.right - src_layer->displayFrame.left;
- int y_res = src_layer->displayFrame.bottom - src_layer->displayFrame.top;
- size_t output_frame_size =
- x_res * cvd::AlignToPowerOf2(y_res * screen_view_->bytes_per_pixel(), 4);
- while (needed_tmp_buffers > 0) {
- BufferSpec tmp(
- RotateTmpBuffer(needed_tmp_buffers), output_frame_size, x_res, y_res,
- cvd::AlignToPowerOf2(x_res * screen_view_->bytes_per_pixel(), 4));
- dest_buffer_stack.push_back(tmp);
- needed_tmp_buffers--;
+ int tmp_buffer_width =
+ src_layer->displayFrame.right - src_layer->displayFrame.left;
+ int tmp_buffer_height =
+ src_layer->displayFrame.bottom - src_layer->displayFrame.top;
+ int tmp_buffer_stride_bytes =
+ cvd::AlignToPowerOf2(tmp_buffer_width * screen_view_->bytes_per_pixel(), 4);
+
+ for (int i = 0; i < needed_tmp_buffers; i++) {
+ BufferSpec tmp_buffer_spec(
+ RotateTmpBuffer(i),
+ tmp_buffer_width,
+ tmp_buffer_height,
+ tmp_buffer_stride_bytes);
+ dest_buffer_stack.push_back(tmp_buffer_spec);
}
// Conversion and scaling should always be the first operations, so that every
@@ -395,17 +490,16 @@
// Make width and height match the crop sizes on the source
int src_width = src_layer_spec.crop_width;
int src_height = src_layer_spec.crop_height;
- int dst_stride =
+ int dst_stride_bytes =
cvd::AlignToPowerOf2(src_width * screen_view_->bytes_per_pixel(), 4);
- size_t needed_size = dst_stride * src_height;
+ size_t needed_size = dst_stride_bytes * src_height;
dst_buffer_spec.width = src_width;
dst_buffer_spec.height = src_height;
- // Ajust the stride accordingly
- dst_buffer_spec.stride = dst_stride;
+ // Adjust the stride accordingly
+ dst_buffer_spec.stride_bytes = dst_stride_bytes;
// Crop sizes also need to be adjusted
dst_buffer_spec.crop_width = src_width;
dst_buffer_spec.crop_height = src_height;
- dst_buffer_spec.size = needed_size;
// crop_x and y are fine at 0, format is already set to match destination
// In case of a scale, the source frame may be bigger than the default tmp
@@ -414,7 +508,8 @@
dst_buffer_spec.buffer = GetSpecialTmpBuffer(needed_size);
}
}
- retval = DoConversion(src_layer_spec, dst_buffer_spec, needs_vflip);
+
+ int retval = DoConversion(src_layer_spec, dst_buffer_spec, needs_vflip);
if (retval) {
ALOGE("Got error code %d from DoConversion function", retval);
}
@@ -435,10 +530,10 @@
std::swap(dst_buffer_spec.crop_width, dst_buffer_spec.crop_height);
// TODO (jemoreira): Aligment (To align here may cause the needed size to
// be bigger than the buffer, so care should be taken)
- dst_buffer_spec.stride =
+ dst_buffer_spec.stride_bytes =
dst_buffer_spec.width * screen_view_->bytes_per_pixel();
}
- retval = DoScaling(src_layer_spec, dst_buffer_spec, needs_vflip);
+ int retval = DoScaling(src_layer_spec, dst_buffer_spec, needs_vflip);
needs_vflip = false;
if (retval) {
ALOGE("Got error code %d from DoScaling function", retval);
@@ -448,8 +543,8 @@
}
if (needs_rotation) {
- retval = DoRotation(src_layer_spec, dest_buffer_stack.back(), rotation,
- needs_vflip);
+ int retval = DoRotation(src_layer_spec, dest_buffer_stack.back(), rotation,
+ needs_vflip);
needs_vflip = false;
if (retval) {
ALOGE("Got error code %d from DoTransform function", retval);
@@ -459,8 +554,8 @@
}
if (needs_attenuation) {
- retval =
- DoAttenuation(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
+ int retval = DoAttenuation(src_layer_spec, dest_buffer_stack.back(),
+ needs_vflip);
needs_vflip = false;
if (retval) {
ALOGE("Got error code %d from DoBlending function", retval);
@@ -470,7 +565,7 @@
}
if (needs_copy) {
- retval = DoCopy(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
+ int retval = DoCopy(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
needs_vflip = false;
if (retval) {
ALOGE("Got error code %d from DoBlending function", retval);
@@ -482,7 +577,8 @@
// Blending (if needed) should always be the last operation, so that it reads
// and writes in the destination layer and not some temporary buffer.
if (needs_blending) {
- retval = DoBlending(src_layer_spec, dest_buffer_stack.back(), needs_vflip);
+ int retval = DoBlending(src_layer_spec, dest_buffer_stack.back(),
+ needs_vflip);
needs_vflip = false;
if (retval) {
ALOGE("Got error code %d from DoBlending function", retval);
@@ -491,7 +587,7 @@
dest_buffer_stack.pop_back();
}
- gralloc_module_->unlock(gralloc_module_, src_priv_handle);
+ src_imported_buffer.Unlock();
}
/* static */ const int CpuComposer::kNumTmpBufferPieces = 2;
diff --git a/guest/hals/hwcomposer/common/cpu_composer.h b/guest/hals/hwcomposer/common/cpu_composer.h
index a4ace22..f331e2d 100644
--- a/guest/hals/hwcomposer/common/cpu_composer.h
+++ b/guest/hals/hwcomposer/common/cpu_composer.h
@@ -20,8 +20,6 @@
#include <hardware/gralloc.h>
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
#include "guest/hals/hwcomposer/common/base_composer.h"
#include "guest/hals/hwcomposer/common/hwcomposer.h"
@@ -41,6 +39,7 @@
static const int kNumTmpBufferPieces;
uint8_t* RotateTmpBuffer(unsigned int order);
uint8_t* GetSpecialTmpBuffer(size_t needed_size);
+ bool CanCompositeLayer(const hwc_layer_1_t& layer);
void CompositeLayer(hwc_layer_1_t* src_layer, int32_t fb_offset);
std::vector<uint8_t> tmp_buffer_;
std::vector<uint8_t> special_tmp_buffer_;
diff --git a/guest/hals/hwcomposer/common/drm_utils.cpp b/guest/hals/hwcomposer/common/drm_utils.cpp
new file mode 100644
index 0000000..d4c864e
--- /dev/null
+++ b/guest/hals/hwcomposer/common/drm_utils.cpp
@@ -0,0 +1,180 @@
+/*
+ * 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 "guest/hals/hwcomposer/common/drm_utils.h"
+
+#include <drm_fourcc.h>
+#include <log/log.h>
+#include <system/graphics.h>
+
+namespace cvd {
+
+const char* GetDrmFormatString(uint32_t drm_format) {
+ switch (drm_format) {
+ case DRM_FORMAT_ABGR1555:
+ return "DRM_FORMAT_ABGR1555";
+ case DRM_FORMAT_ABGR2101010:
+ return "DRM_FORMAT_ABGR2101010";
+ case DRM_FORMAT_ABGR4444:
+ return "DRM_FORMAT_ABGR4444";
+ case DRM_FORMAT_ABGR8888:
+ return "DRM_FORMAT_ABGR8888";
+ case DRM_FORMAT_ARGB1555:
+ return "DRM_FORMAT_ARGB1555";
+ case DRM_FORMAT_ARGB2101010:
+ return "DRM_FORMAT_ARGB2101010";
+ case DRM_FORMAT_ARGB4444:
+ return "DRM_FORMAT_ARGB4444";
+ case DRM_FORMAT_ARGB8888:
+ return "DRM_FORMAT_ARGB8888";
+ case DRM_FORMAT_AYUV:
+ return "DRM_FORMAT_AYUV";
+ case DRM_FORMAT_BGR233:
+ return "DRM_FORMAT_BGR233";
+ case DRM_FORMAT_BGR565:
+ return "DRM_FORMAT_BGR565";
+ case DRM_FORMAT_BGR888:
+ return "DRM_FORMAT_BGR888";
+ case DRM_FORMAT_BGRA1010102:
+ return "DRM_FORMAT_BGRA1010102";
+ case DRM_FORMAT_BGRA4444:
+ return "DRM_FORMAT_BGRA4444";
+ case DRM_FORMAT_BGRA5551:
+ return "DRM_FORMAT_BGRA5551";
+ case DRM_FORMAT_BGRA8888:
+ return "DRM_FORMAT_BGRA8888";
+ case DRM_FORMAT_BGRX1010102:
+ return "DRM_FORMAT_BGRX1010102";
+ case DRM_FORMAT_BGRX4444:
+ return "DRM_FORMAT_BGRX4444";
+ case DRM_FORMAT_BGRX5551:
+ return "DRM_FORMAT_BGRX5551";
+ case DRM_FORMAT_BGRX8888:
+ return "DRM_FORMAT_BGRX8888";
+ case DRM_FORMAT_C8:
+ return "DRM_FORMAT_C8";
+ case DRM_FORMAT_GR88:
+ return "DRM_FORMAT_GR88";
+ case DRM_FORMAT_NV12:
+ return "DRM_FORMAT_NV12";
+ case DRM_FORMAT_NV21:
+ return "DRM_FORMAT_NV21";
+ case DRM_FORMAT_R8:
+ return "DRM_FORMAT_R8";
+ case DRM_FORMAT_RG88:
+ return "DRM_FORMAT_RG88";
+ case DRM_FORMAT_RGB332:
+ return "DRM_FORMAT_RGB332";
+ case DRM_FORMAT_RGB565:
+ return "DRM_FORMAT_RGB565";
+ case DRM_FORMAT_RGB888:
+ return "DRM_FORMAT_RGB888";
+ case DRM_FORMAT_RGBA1010102:
+ return "DRM_FORMAT_RGBA1010102";
+ case DRM_FORMAT_RGBA4444:
+ return "DRM_FORMAT_RGBA4444";
+ case DRM_FORMAT_RGBA5551:
+ return "DRM_FORMAT_RGBA5551";
+ case DRM_FORMAT_RGBA8888:
+ return "DRM_FORMAT_RGBA8888";
+ case DRM_FORMAT_RGBX1010102:
+ return "DRM_FORMAT_RGBX1010102";
+ case DRM_FORMAT_RGBX4444:
+ return "DRM_FORMAT_RGBX4444";
+ case DRM_FORMAT_RGBX5551:
+ return "DRM_FORMAT_RGBX5551";
+ case DRM_FORMAT_RGBX8888:
+ return "DRM_FORMAT_RGBX8888";
+ case DRM_FORMAT_UYVY:
+ return "DRM_FORMAT_UYVY";
+ case DRM_FORMAT_VYUY:
+ return "DRM_FORMAT_VYUY";
+ case DRM_FORMAT_XBGR1555:
+ return "DRM_FORMAT_XBGR1555";
+ case DRM_FORMAT_XBGR2101010:
+ return "DRM_FORMAT_XBGR2101010";
+ case DRM_FORMAT_XBGR4444:
+ return "DRM_FORMAT_XBGR4444";
+ case DRM_FORMAT_XBGR8888:
+ return "DRM_FORMAT_XBGR8888";
+ case DRM_FORMAT_XRGB1555:
+ return "DRM_FORMAT_XRGB1555";
+ case DRM_FORMAT_XRGB2101010:
+ return "DRM_FORMAT_XRGB2101010";
+ case DRM_FORMAT_XRGB4444:
+ return "DRM_FORMAT_XRGB4444";
+ case DRM_FORMAT_XRGB8888:
+ return "DRM_FORMAT_XRGB8888";
+ case DRM_FORMAT_YUYV:
+ return "DRM_FORMAT_YUYV";
+ case DRM_FORMAT_YVU420:
+ return "DRM_FORMAT_YVU420";
+ case DRM_FORMAT_YVYU:
+ return "DRM_FORMAT_YVYU";
+ }
+ return "Unknown";
+}
+
+int GetDrmFormatBytesPerPixel(uint32_t drm_format) {
+ switch (drm_format) {
+ case DRM_FORMAT_ABGR8888:
+ case DRM_FORMAT_ARGB8888:
+ case DRM_FORMAT_XBGR8888:
+ return 4;
+ case DRM_FORMAT_BGR888:
+ return 3;
+ case DRM_FORMAT_RGB565:
+ case DRM_FORMAT_YVU420:
+#ifdef GRALLOC_MODULE_API_VERSION_0_2
+ case DRM_FORMAT_FLEX_YCbCr_420_888:
+#endif
+ return 2;
+ case DRM_FORMAT_R8:
+ return 1;
+ }
+ ALOGE("%s: format size unknown %d(%s)", __FUNCTION__, drm_format,
+ GetDrmFormatString(drm_format));
+ return 8;
+}
+
+int GetDrmFormatFromHalFormat(int hal_format) {
+ switch (hal_format) {
+ case HAL_PIXEL_FORMAT_RGBA_FP16:
+ return DRM_FORMAT_ABGR16161616F;
+ case HAL_PIXEL_FORMAT_RGBA_8888:
+ return DRM_FORMAT_ABGR8888;
+ case HAL_PIXEL_FORMAT_RGBX_8888:
+ return DRM_FORMAT_XBGR8888;
+ case HAL_PIXEL_FORMAT_BGRA_8888:
+ return DRM_FORMAT_ARGB8888;
+ case HAL_PIXEL_FORMAT_RGB_888:
+ return DRM_FORMAT_BGR888;
+ case HAL_PIXEL_FORMAT_RGB_565:
+ return DRM_FORMAT_BGR565;
+ case HAL_PIXEL_FORMAT_YV12:
+ return DRM_FORMAT_YVU420;
+ case HAL_PIXEL_FORMAT_YCbCr_420_888:
+ return DRM_FORMAT_YVU420;
+ case HAL_PIXEL_FORMAT_BLOB:
+ return DRM_FORMAT_R8;
+ default:
+ break;
+ }
+ ALOGE("%s unhandled hal format: %d", __FUNCTION__, hal_format);
+ return 0;
+}
+
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/common/drm_utils.h b/guest/hals/hwcomposer/common/drm_utils.h
new file mode 100644
index 0000000..15f788d
--- /dev/null
+++ b/guest/hals/hwcomposer/common/drm_utils.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <cstdlib>
+
+namespace cvd {
+
+const char* GetDrmFormatString(uint32_t drm_format);
+
+int GetDrmFormatBytesPerPixel(uint32_t drm_format);
+
+int GetDrmFormatFromHalFormat(int hal_format);
+
+} // namespace cvd
diff --git a/guest/hals/hwcomposer/common/gralloc_utils.cpp b/guest/hals/hwcomposer/common/gralloc_utils.cpp
new file mode 100644
index 0000000..bb2350f
--- /dev/null
+++ b/guest/hals/hwcomposer/common/gralloc_utils.cpp
@@ -0,0 +1,529 @@
+/*
+ * 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 "guest/hals/hwcomposer/common/gralloc_utils.h"
+
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponent.h>
+#include <aidl/android/hardware/graphics/common/PlaneLayoutComponentType.h>
+#include <drm_fourcc.h>
+#include <gralloctypes/Gralloc4.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+// TODO(b/146515640): remove this.
+#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
+#include "guest/hals/hwcomposer/common/drm_utils.h"
+
+using aidl::android::hardware::graphics::common::PlaneLayout;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
+using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::IMapper;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_vec;
+using MetadataType =
+ android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
+
+// TODO(b/146515640): remove this.
+using cuttlefish_gralloc0_buffer_handle_t = private_handle_t;
+
+namespace cvd {
+
+Gralloc::Gralloc() {
+ android::hardware::preloadPassthroughService<IMapper>();
+
+ gralloc4_ = IMapper::getService();
+ if (gralloc4_ != nullptr) {
+ ALOGE("%s using Gralloc4.", __FUNCTION__);
+ return;
+ }
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+
+
+ hw_get_module(GRALLOC_HARDWARE_MODULE_ID,
+ reinterpret_cast<const hw_module_t**>(&gralloc0_));
+ if (gralloc0_ != nullptr) {
+ ALOGE("%s using Gralloc0.", __FUNCTION__);
+ return;
+ }
+ ALOGE("%s Gralloc0 not available.", __FUNCTION__);
+
+ ALOGE("%s No Grallocs available!", __FUNCTION__);
+}
+
+Error Gralloc::GetMetadata(buffer_handle_t buffer, MetadataType type,
+ hidl_vec<uint8_t>* metadata) {
+ if (gralloc4_ == nullptr) {
+ ALOGE("%s Gralloc4 not available.", __FUNCTION__);
+ return Error::NO_RESOURCES;
+ }
+
+ if (metadata == nullptr) {
+ return Error::BAD_VALUE;
+ }
+
+ Error error = Error::NONE;
+
+ auto native_handle = const_cast<native_handle_t*>(buffer);
+
+ auto ret = gralloc4_->get(native_handle, type,
+ [&](const auto& get_error, const auto& get_metadata) {
+ error = get_error;
+ *metadata = get_metadata;
+ });
+
+ if (!ret.isOk()) {
+ error = Error::NO_RESOURCES;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("%s failed to get metadata %s", __FUNCTION__, type.name.c_str());
+ }
+ return error;
+}
+
+std::optional<uint32_t> Gralloc::GetWidth(buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ hidl_vec<uint8_t> encoded_width;
+
+ Error error = GetMetadata(buffer, android::gralloc4::MetadataType_Width,
+ &encoded_width);
+ if (error != Error::NONE) {
+ return std::nullopt;
+ }
+
+ uint64_t width = 0;
+ android::gralloc4::decodeWidth(encoded_width, &width);
+ return static_cast<uint32_t>(width);
+ }
+ if (gralloc0_ != nullptr) {
+ const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+ reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+ return gralloc0_buffer->x_res;
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> Gralloc::GetHeight(buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ hidl_vec<uint8_t> encoded_height;
+
+ Error error = GetMetadata(buffer, android::gralloc4::MetadataType_Height,
+ &encoded_height);
+ if (error != Error::NONE) {
+ return std::nullopt;
+ }
+
+ uint64_t height = 0;
+ android::gralloc4::decodeHeight(encoded_height, &height);
+ return static_cast<uint32_t>(height);
+ }
+ if (gralloc0_ != nullptr) {
+ const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+ reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+ return gralloc0_buffer->y_res;
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> Gralloc::GetDrmFormat(buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ hidl_vec<uint8_t> encoded_format;
+
+ Error error = GetMetadata(buffer,
+ android::gralloc4::MetadataType_PixelFormatFourCC,
+ &encoded_format);
+ if (error != Error::NONE) {
+ return std::nullopt;
+ }
+
+ uint32_t format = 0;
+ android::gralloc4::decodePixelFormatFourCC(encoded_format, &format);
+ return static_cast<uint32_t>(format);
+ }
+ if (gralloc0_ != nullptr) {
+ const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+ reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+ return GetDrmFormatFromHalFormat(gralloc0_buffer->format);
+ }
+ return std::nullopt;
+}
+
+std::optional<std::vector<PlaneLayout>> Gralloc::GetPlaneLayouts(
+ buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ hidl_vec<uint8_t> encoded_layouts;
+
+ Error error = GetMetadata(buffer,
+ android::gralloc4::MetadataType_PlaneLayouts,
+ &encoded_layouts);
+ if (error != Error::NONE) {
+ return std::nullopt;
+ }
+
+ std::vector<PlaneLayout> plane_layouts;
+ android::gralloc4::decodePlaneLayouts(encoded_layouts, &plane_layouts);
+ return plane_layouts;
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> Gralloc::GetMonoPlanarStrideBytes(
+ buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ auto plane_layouts_opt = GetPlaneLayouts(buffer);
+ if (!plane_layouts_opt) {
+ return std::nullopt;
+ }
+
+ std::vector<PlaneLayout>& plane_layouts = *plane_layouts_opt;
+ if (plane_layouts.size() != 1) {
+ return std::nullopt;
+ }
+
+ return static_cast<uint32_t>(plane_layouts[0].strideInBytes);
+ }
+ if (gralloc0_ != nullptr) {
+ const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+ reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+ int bytes_per_pixel = formatToBytesPerPixel(gralloc0_buffer->format);
+ return gralloc0_buffer->stride_in_pixels * bytes_per_pixel;
+ }
+ return std::nullopt;
+}
+
+std::optional<GrallocBuffer> Gralloc::Import(buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ buffer_handle_t imported_buffer;
+
+ Error error;
+ auto ret = gralloc4_->importBuffer(buffer,
+ [&](const auto& err, const auto& buf) {
+ error = err;
+ if (err == Error::NONE) {
+ imported_buffer =
+ static_cast<buffer_handle_t>(buf);
+ }
+ });
+
+ if (!ret.isOk() || error != Error::NONE) {
+ ALOGE("%s failed to import buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+ return GrallocBuffer(this, imported_buffer);
+ }
+ if (gralloc0_ != nullptr) {
+ return GrallocBuffer(this, buffer);
+ }
+ return std::nullopt;
+}
+
+void Gralloc::Release(buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ auto native_buffer = const_cast<native_handle_t*>(buffer);
+ auto ret = gralloc4_->freeBuffer(native_buffer);
+
+ if (!ret.isOk()) {
+ ALOGE("%s failed to release buffer", __FUNCTION__);
+ }
+ return;
+ }
+ if (gralloc0_) {
+ // no-opt
+ }
+}
+
+std::optional<void*> Gralloc::Lock(buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ auto native_buffer = const_cast<native_handle_t*>(buffer);
+
+ const auto buffer_usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN);
+
+ auto width_opt = GetWidth(buffer);
+ if (!width_opt) {
+ return std::nullopt;
+ }
+
+ auto height_opt = GetHeight(buffer);
+ if (!height_opt) {
+ return std::nullopt;
+ }
+
+ IMapper::Rect buffer_region;
+ buffer_region.left = 0;
+ buffer_region.top = 0;
+ buffer_region.width = *width_opt;
+ buffer_region.height = *height_opt;
+
+ // Empty fence, lock immedietly.
+ hidl_handle fence;
+
+ Error error = Error::NONE;
+ void* data = nullptr;
+
+ auto ret = gralloc4_->lock(native_buffer, buffer_usage, buffer_region,
+ fence,
+ [&](const auto& lock_error,
+ const auto& lock_data) {
+ error = lock_error;
+ if (lock_error == Error::NONE) {
+ data = lock_data;
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = Error::NO_RESOURCES;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("%s failed to lock buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ return data;
+ }
+ if (gralloc0_ != nullptr) {
+ const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+ reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+ void* data = nullptr;
+ int ret = gralloc0_->lock(gralloc0_,
+ gralloc0_buffer,
+ GRALLOC_USAGE_SW_READ_OFTEN,
+ 0,
+ 0,
+ gralloc0_buffer->x_res,
+ gralloc0_buffer->y_res,
+ &data);
+
+ if (ret) {
+ ALOGE("%s failed to lock buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+ return data;
+ }
+ return std::nullopt;
+}
+
+std::optional<android_ycbcr> Gralloc::LockYCbCr(buffer_handle_t buffer) {
+ auto format_opt = GetDrmFormat(buffer);
+ if (!format_opt) {
+ ALOGE("%s failed to check format of buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ if (*format_opt != DRM_FORMAT_NV12 &&
+ *format_opt != DRM_FORMAT_NV21 &&
+ *format_opt != DRM_FORMAT_YVU420) {
+ ALOGE("%s called on non-ycbcr buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ if (gralloc4_ != nullptr) {
+ auto lock_opt = Lock(buffer);
+ if (!lock_opt) {
+ ALOGE("%s failed to lock buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ auto plane_layouts_opt = GetPlaneLayouts(buffer);
+ if (!plane_layouts_opt) {
+ ALOGE("%s failed to get plane layouts", __FUNCTION__);
+ return std::nullopt;
+ }
+
+ android_ycbcr buffer_ycbcr;
+ buffer_ycbcr.y = nullptr;
+ buffer_ycbcr.cb = nullptr;
+ buffer_ycbcr.cr = nullptr;
+ buffer_ycbcr.ystride = 0;
+ buffer_ycbcr.cstride = 0;
+ buffer_ycbcr.chroma_step = 0;
+
+ for (const auto& plane_layout : *plane_layouts_opt) {
+ for (const auto& plane_layout_component : plane_layout.components) {
+ const auto& type = plane_layout_component.type;
+
+ if (!android::gralloc4::isStandardPlaneLayoutComponentType(type)) {
+ continue;
+ }
+
+ auto* component_data =
+ reinterpret_cast<uint8_t*>(*lock_opt) +
+ plane_layout.offsetInBytes +
+ plane_layout_component.offsetInBits / 8;
+
+ switch (static_cast<PlaneLayoutComponentType>(type.value)) {
+ case PlaneLayoutComponentType::Y:
+ buffer_ycbcr.y = component_data;
+ buffer_ycbcr.ystride = plane_layout.strideInBytes;
+ break;
+ case PlaneLayoutComponentType::CB:
+ buffer_ycbcr.cb = component_data;
+ buffer_ycbcr.cstride = plane_layout.strideInBytes;
+ buffer_ycbcr.chroma_step = plane_layout.sampleIncrementInBits / 8;
+ break;
+ case PlaneLayoutComponentType::CR:
+ buffer_ycbcr.cr = component_data;
+ buffer_ycbcr.cstride = plane_layout.strideInBytes;
+ buffer_ycbcr.chroma_step = plane_layout.sampleIncrementInBits / 8;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return buffer_ycbcr;
+ }
+ if (gralloc0_ != nullptr) {
+ auto lock_opt = Lock(buffer);
+ if (!lock_opt) {
+ ALOGE("%s failed to lock buffer", __FUNCTION__);
+ return std::nullopt;
+ }
+ void* data = *lock_opt;
+
+ const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+ reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+ android_ycbcr buffer_ycbcr;
+ formatToYcbcr(gralloc0_buffer->format,
+ gralloc0_buffer->x_res,
+ gralloc0_buffer->y_res,
+ data,
+ &buffer_ycbcr);
+ return buffer_ycbcr;
+ }
+ return std::nullopt;
+}
+
+void Gralloc::Unlock(buffer_handle_t buffer) {
+ if (gralloc4_ != nullptr) {
+ auto native_handle = const_cast<native_handle_t*>(buffer);
+
+ Error error = Error::NONE;
+ auto ret = gralloc4_->unlock(native_handle,
+ [&](const auto& unlock_error, const auto&) {
+ error = unlock_error;
+ });
+
+ if (!ret.isOk()) {
+ error = Error::NO_RESOURCES;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("%s failed to unlock buffer", __FUNCTION__);
+ }
+ return;
+ }
+ if (gralloc0_ != nullptr) {
+ const cuttlefish_gralloc0_buffer_handle_t* gralloc0_buffer =
+ reinterpret_cast<const cuttlefish_gralloc0_buffer_handle_t*>(buffer);
+
+ gralloc0_->unlock(gralloc0_, gralloc0_buffer);
+ return;
+ }
+}
+
+
+GrallocBuffer::GrallocBuffer(Gralloc* gralloc, buffer_handle_t buffer) :
+ gralloc_(gralloc), buffer_(buffer) {}
+
+GrallocBuffer::~GrallocBuffer() { Release(); }
+
+GrallocBuffer::GrallocBuffer(GrallocBuffer&& rhs) {
+ *this = std::move(rhs);
+}
+
+GrallocBuffer& GrallocBuffer::operator=(GrallocBuffer&& rhs) {
+ gralloc_ = rhs.gralloc_;
+ buffer_ = rhs.buffer_;
+ rhs.gralloc_ = nullptr;
+ rhs.buffer_ = nullptr;
+ return *this;
+}
+
+void GrallocBuffer::Release() {
+ if (gralloc_ && buffer_) {
+ gralloc_->Release(buffer_);
+ gralloc_ = nullptr;
+ buffer_ = nullptr;
+ }
+}
+
+std::optional<void*> GrallocBuffer::Lock() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->Lock(buffer_);
+ }
+ return std::nullopt;
+}
+
+ std::optional<android_ycbcr> GrallocBuffer::LockYCbCr() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->LockYCbCr(buffer_);
+ }
+ return std::nullopt;
+ }
+
+void GrallocBuffer::Unlock() {
+ if (gralloc_ && buffer_) {
+ gralloc_->Unlock(buffer_);
+ }
+}
+
+std::optional<uint32_t> GrallocBuffer::GetWidth() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetWidth(buffer_);
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetHeight() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetHeight(buffer_);
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetDrmFormat() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetDrmFormat(buffer_);
+ }
+ return std::nullopt;
+}
+
+std::optional<std::vector<PlaneLayout>>
+GrallocBuffer::GetPlaneLayouts() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetPlaneLayouts(buffer_);
+ }
+ return std::nullopt;
+}
+
+std::optional<uint32_t> GrallocBuffer::GetMonoPlanarStrideBytes() {
+ if (gralloc_ && buffer_) {
+ return gralloc_->GetMonoPlanarStrideBytes(buffer_);
+ }
+ return std::nullopt;
+}
+
+} // namespace cvd
\ No newline at end of file
diff --git a/guest/hals/hwcomposer/common/gralloc_utils.h b/guest/hals/hwcomposer/common/gralloc_utils.h
new file mode 100644
index 0000000..370f2bb
--- /dev/null
+++ b/guest/hals/hwcomposer/common/gralloc_utils.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <optional>
+#include <vector>
+
+#include <aidl/android/hardware/graphics/common/PlaneLayout.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <hardware/gralloc.h>
+#include <system/graphics.h>
+#include <utils/StrongPointer.h>
+
+namespace cvd {
+
+class Gralloc;
+
+// A gralloc 4.0 buffer that has been imported in the current process and
+// that will be released upon destruction. Users must ensure that the Gralloc
+// instance that this buffer is created with out lives this buffer.
+class GrallocBuffer {
+ public:
+ GrallocBuffer(Gralloc* gralloc, buffer_handle_t buffer);
+ virtual ~GrallocBuffer();
+
+ GrallocBuffer(const GrallocBuffer& rhs) = delete;
+ GrallocBuffer& operator=(const GrallocBuffer& rhs) = delete;
+
+ GrallocBuffer(GrallocBuffer&& rhs);
+ GrallocBuffer& operator=(GrallocBuffer&& rhs);
+
+ // Locks the buffer for reading and returns the mapped address if successful.
+ // Fails and returns nullopt if the underlying buffer is a YCbCr buffer.
+ std::optional<void*> Lock();
+
+ // Locks the buffer for reading and returns the mapped addresses and strides
+ // of each plane if successful. Fails and returns nullopt if the underlying
+ // buffer is not a YCbCr buffer.
+ std::optional<android_ycbcr> LockYCbCr();
+
+ // Unlocks the buffer from reading.
+ void Unlock();
+
+ std::optional<uint32_t> GetWidth();
+ std::optional<uint32_t> GetHeight();
+ std::optional<uint32_t> GetDrmFormat();
+
+ // Returns the stride of the buffer if it is a single plane buffer or fails
+ // and returns nullopt if the buffer is for a multi plane buffer.
+ std::optional<uint32_t> GetMonoPlanarStrideBytes();
+
+ private:
+ std::optional<
+ std::vector<aidl::android::hardware::graphics::common::PlaneLayout>>
+ GetPlaneLayouts();
+
+ void Release();
+
+ Gralloc* gralloc_ = nullptr;
+ buffer_handle_t buffer_ = nullptr;
+};
+
+class Gralloc {
+ public:
+ Gralloc();
+ virtual ~Gralloc() = default;
+
+ // Imports the given buffer handle into the current process and returns an
+ // imported buffer which can be used for reading. Users must ensure that the
+ // Gralloc instance outlives any GrallocBuffers.
+ std::optional<GrallocBuffer> Import(buffer_handle_t buffer);
+
+ private:
+ // The below functions are made avaialble only to GrallocBuffer so that
+ // users only call gralloc functions on *imported* buffers.
+ friend class GrallocBuffer;
+
+ // See GrallocBuffer::Release.
+ void Release(buffer_handle_t buffer);
+
+ // See GrallocBuffer::Lock.
+ std::optional<void*> Lock(buffer_handle_t buffer);
+
+ // See GrallocBuffer::LockYCbCr.
+ std::optional<android_ycbcr> LockYCbCr(buffer_handle_t buffer);
+
+ // See GrallocBuffer::Unlock.
+ void Unlock(buffer_handle_t buffer);
+
+ // See GrallocBuffer::GetWidth.
+ std::optional<uint32_t> GetWidth(buffer_handle_t buffer);
+
+ // See GrallocBuffer::GetHeight.
+ std::optional<uint32_t> GetHeight(buffer_handle_t buffer);
+
+ // See GrallocBuffer::GetDrmFormat.
+ std::optional<uint32_t> GetDrmFormat(buffer_handle_t buffer);
+
+ // See GrallocBuffer::GetPlaneLayouts.
+ std::optional<
+ std::vector<aidl::android::hardware::graphics::common::PlaneLayout>>
+ GetPlaneLayouts(buffer_handle_t buffer);
+
+ // Returns the stride of the buffer if it is a single plane buffer or fails
+ // and returns nullopt if the buffer is for a multi plane buffer.
+ std::optional<uint32_t> GetMonoPlanarStrideBytes(buffer_handle_t);
+
+ // See GrallocBuffer::GetMetadata.
+ android::hardware::graphics::mapper::V4_0::Error GetMetadata(
+ buffer_handle_t buffer,
+ android::hardware::graphics::mapper::V4_0::IMapper::MetadataType type,
+ android::hardware::hidl_vec<uint8_t>* metadata);
+
+ const gralloc_module_t* gralloc0_ = nullptr;
+
+ android::sp<android::hardware::graphics::mapper::V4_0::IMapper> gralloc4_;
+};
+
+} // namespace cvd
\ No newline at end of file
diff --git a/guest/hals/hwcomposer/common/hwcomposer.cpp b/guest/hals/hwcomposer/common/hwcomposer.cpp
index c165f7e..4b51202 100644
--- a/guest/hals/hwcomposer/common/hwcomposer.cpp
+++ b/guest/hals/hwcomposer/common/hwcomposer.cpp
@@ -52,8 +52,6 @@
#include <utils/String8.h>
#include <utils/Vector.h>
-#include "guest/hals/gralloc/legacy/gralloc_vsoc_priv.h"
-
#include "guest/hals/hwcomposer/common/base_composer.h"
#include "guest/hals/hwcomposer/common/cpu_composer.h"
#include "guest/hals/hwcomposer/common/geometry_utils.h"
@@ -181,7 +179,7 @@
}
// Ensures that the layer does not include any inconsistencies
-bool IsValidLayer(const hwc_layer_1_t& layer) {
+bool IsValidLayer(hwc_composer_device_1_t* dev, const hwc_layer_1_t& layer) {
if (layer.flags & HWC_SKIP_LAYER) {
// A layer we are asked to skip validate should not be marked as skip
ALOGE("%s: Layer is marked as skip", __FUNCTION__);
@@ -197,13 +195,6 @@
layer.displayFrame.top, layer.displayFrame.bottom);
return false;
}
- // Validate the handle
- if (private_handle_t::validate(layer.handle) != 0) {
- ALOGE("%s: Layer contains an invalid gralloc handle.", __FUNCTION__);
- return false;
- }
- const private_handle_t* p_handle =
- reinterpret_cast<const private_handle_t*>(layer.handle);
// Check sourceCrop
if (layer.sourceCrop.left > layer.sourceCrop.right ||
layer.sourceCrop.top > layer.sourceCrop.bottom) {
@@ -214,22 +205,13 @@
layer.sourceCrop.top, layer.sourceCrop.bottom);
return false;
}
- if (layer.sourceCrop.left < 0 || layer.sourceCrop.top < 0 ||
- layer.sourceCrop.right > p_handle->x_res ||
- layer.sourceCrop.bottom > p_handle->y_res) {
- ALOGE(
- "%s: Invalid sourceCrop for buffer handle: sourceCrop = [left = %d, "
- "right = %d, top = %d, bottom = %d], handle = [width = %d, height = "
- "%d]",
- __FUNCTION__, layer.sourceCrop.left, layer.sourceCrop.right,
- layer.sourceCrop.top, layer.sourceCrop.bottom, p_handle->x_res,
- p_handle->y_res);
- return false;
- }
- return true;
+
+ auto* cvd_hwc_dev = reinterpret_cast<cvd_hwc_composer_device_1_t*>(dev);
+ return cvd_hwc_dev->composer->IsValidLayer(layer);
}
-bool IsValidComposition(int num_layers, hwc_layer_1_t* layers, bool on_set) {
+bool IsValidComposition(hwc_composer_device_1_t* dev, int num_layers,
+ hwc_layer_1_t* layers, bool on_set) {
if (num_layers == 0) {
ALOGE("Composition requested with 0 layers");
return false;
@@ -266,7 +248,7 @@
case HWC_FRAMEBUFFER_TARGET:
// In the call to prepare() the framebuffer target does not have a valid
// buffer_handle, so we don't validate it yet.
- if (on_set && check_fb_target && !IsValidLayer(layers[idx])) {
+ if (on_set && check_fb_target && !IsValidLayer(dev, layers[idx])) {
ALOGE("%s: Invalid layer found", __FUNCTION__);
LogLayers(num_layers, layers, idx);
return false;
@@ -274,7 +256,7 @@
break;
case HWC_OVERLAY:
if (!(layers[idx].flags & HWC_SKIP_LAYER) &&
- !IsValidLayer(layers[idx])) {
+ !IsValidLayer(dev, layers[idx])) {
ALOGE("%s: Invalid layer found", __FUNCTION__);
LogLayers(num_layers, layers, idx);
return false;
@@ -352,7 +334,7 @@
hwc_display_contents_1_t* list = displays[disp];
if (!list) return 0;
- if (!IsValidComposition(list->numHwLayers, &list->hwLayers[0], false)) {
+ if (!IsValidComposition(dev, list->numHwLayers, &list->hwLayers[0], false)) {
LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
return -1;
}
@@ -377,7 +359,7 @@
ALOGW("Received request for empty composition, treating as valid noop");
return 0;
}
- if (!IsValidComposition(contents->numHwLayers, layers, true)) {
+ if (!IsValidComposition(dev, contents->numHwLayers, layers, true)) {
LOG_ALWAYS_FATAL("%s: Invalid composition requested", __FUNCTION__);
return -1;
}
diff --git a/guest/hals/hwcomposer/common/hwcomposer.h b/guest/hals/hwcomposer/common/hwcomposer.h
index c7698b3..60a786c 100644
--- a/guest/hals/hwcomposer/common/hwcomposer.h
+++ b/guest/hals/hwcomposer/common/hwcomposer.h
@@ -1,4 +1,3 @@
-#pragma once
/*
* Copyright (C) 2019 The Android Open Source Project
*
@@ -14,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#pragma once
#include <memory>
diff --git a/guest/hals/hwcomposer/cutf_cvm/Android.bp b/guest/hals/hwcomposer/cutf_cvm/Android.bp
index 8b9115a..b6ad6f7 100644
--- a/guest/hals/hwcomposer/cutf_cvm/Android.bp
+++ b/guest/hals/hwcomposer/cutf_cvm/Android.bp
@@ -19,28 +19,33 @@
defaults: ["cuttlefish_guest_only"],
vendor: true,
srcs: [
- "vsocket_screen_view.cpp",
"hwcomposer.cpp",
+ "vsocket_screen_view.cpp",
],
include_dirs: [
"device/google/cuttlefish",
],
export_include_dirs: ["."],
static_libs: [
- "libyuv_static",
- "hwcomposer_common"
+ "hwcomposer_common",
+ "libyuv_static",
],
shared_libs: [
- "liblog",
- "libhardware",
+ "android.hardware.graphics.mapper@4.0",
"libbase",
"libcutils",
- "libutils",
- "libsync",
- "libjpeg",
+ "libcuttlefish_device_config",
"libcuttlefish_utils",
"libcuttlefish_fs",
- "libcuttlefish_device_config",
+ "libdrm",
+ "libgralloctypes",
+ "libhardware",
+ "libhidlbase",
+ "libjpeg",
+ "liblog",
+ "libminigbm",
+ "libsync",
+ "libutils",
],
}
@@ -77,17 +82,20 @@
export_include_dirs: ["."],
static_libs: [
+ "hwcomposer_common",
"libyuv_static",
- "hwcomposer_common"
],
shared_libs: [
- "libutils",
+ "android.hardware.graphics.mapper@4.0",
"libcutils",
- "liblog",
- "libhardware",
+ "libcuttlefish_device_config",
"libcuttlefish_utils",
"libcuttlefish_fs",
- "libcuttlefish_device_config",
+ "libgralloctypes",
+ "libhardware",
+ "libhidlbase",
+ "liblog",
+ "libutils",
],
}
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index 827ac4f..b67c360 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -275,8 +275,9 @@
tmp_config_obj.AssemblyPath(kKernelDefaultPath.c_str()));
tmp_config_obj.set_use_unpacked_kernel(true);
}
+
tmp_config_obj.set_decompress_kernel(FLAGS_decompress_kernel);
- if (FLAGS_decompress_kernel) {
+ if (tmp_config_obj.decompress_kernel()) {
tmp_config_obj.set_decompressed_kernel_image_path(
tmp_config_obj.AssemblyPath("vmlinux"));
}
@@ -433,6 +434,16 @@
void SetDefaultFlagsForCrosvm() {
SetCommandLineOptionWithMode("logcat_mode", cvd::kLogcatVsockMode,
google::FlagSettingMode::SET_FLAGS_DEFAULT);
+
+ // Crosvm requires a specific setting for kernel decompression; it must be
+ // on for aarch64 and off for x86, no other mode is supported.
+ bool decompress_kernel = false;
+ if (cvd::HostArch() == "aarch64") {
+ decompress_kernel = true;
+ }
+ SetCommandLineOptionWithMode("decompress_kernel",
+ (decompress_kernel ? "true" : "false"),
+ google::FlagSettingMode::SET_FLAGS_DEFAULT);
}
bool ParseCommandLineFlags(int* argc, char*** argv) {
diff --git a/host/commands/tapsetiff/Android.bp b/host/commands/tapsetiff/Android.bp
new file mode 100644
index 0000000..c860241
--- /dev/null
+++ b/host/commands/tapsetiff/Android.bp
@@ -0,0 +1,19 @@
+//
+// 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.
+
+sh_binary_host {
+ name: "tapsetiff",
+ src: "tapsetiff.py",
+}
diff --git a/host/commands/tapsetiff/tapsetiff.py b/host/commands/tapsetiff/tapsetiff.py
new file mode 100755
index 0000000..3e7c9e4
--- /dev/null
+++ b/host/commands/tapsetiff/tapsetiff.py
@@ -0,0 +1,30 @@
+#!/usr/bin/python
+
+# 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.
+
+import fcntl
+import struct
+import sys
+
+TUNSETIFF = 0x400454ca
+IFF_TAP = 0x0002
+IFF_NO_PI = 0x1000
+IFF_VNET_HDR = 0x4000
+
+tun_fd = int(sys.argv[1])
+tap_name = sys.argv[2]
+
+ifr = struct.pack('16sH', tap_name, IFF_TAP | IFF_NO_PI | IFF_VNET_HDR)
+fcntl.ioctl(tun_fd, TUNSETIFF, ifr)
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index 4676915..86bc75b 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -25,6 +25,7 @@
#include <android-base/strings.h>
#include <glog/logging.h>
+#include "common/libs/utils/environment.h"
#include "common/libs/utils/network.h"
#include "common/libs/utils/subprocess.h"
#include "host/libs/config/cuttlefish_config.h"
@@ -108,7 +109,11 @@
std::vector<std::string> CrosvmManager::ConfigureBootDevices() {
// PCI domain 0, bus 0, device 1, function 0
// TODO There is no way to control this assignment with crosvm (yet)
- return { "androidboot.boot_devices=pci0000:00/0000:00:01.0" };
+ if (cvd::HostArch() == "x86_64") {
+ return { "androidboot.boot_devices=pci0000:00/0000:00:01.0" };
+ } else {
+ return { "androidboot.boot_devices=10000.pci" };
+ }
}
CrosvmManager::CrosvmManager(const vsoc::CuttlefishConfig* config)
@@ -140,7 +145,6 @@
if (!config_->final_ramdisk_path().empty()) {
crosvm_cmd.AddParameter("--initrd=", config_->final_ramdisk_path());
}
- crosvm_cmd.AddParameter("--null-audio");
crosvm_cmd.AddParameter("--mem=", config_->memory_mb());
crosvm_cmd.AddParameter("--cpus=", config_->cpus());
crosvm_cmd.AddParameter("--params=", kernel_cmdline_);
diff --git a/host_package.mk b/host_package.mk
index 24a5210..0644114 100644
--- a/host_package.mk
+++ b/host_package.mk
@@ -40,6 +40,11 @@
x86_64-linux-gnu/libgbm.so.1 \
x86_64-linux-gnu/libminijail.so \
x86_64-linux-gnu/libvirglrenderer.so.1 \
+ x86_64-linux-gnu/libc++.so.1 \
+ x86_64-linux-gnu/libandroid-emu-shared.so \
+ x86_64-linux-gnu/libemugl_common.so \
+ x86_64-linux-gnu/libOpenglRender.so \
+ x86_64-linux-gnu/libgfxstream_backend.so \
logcat_receiver \
config_server \
tombstone_receiver \
@@ -51,6 +56,7 @@
fsck.f2fs \
resize.f2fs \
make_f2fs \
+ tapsetiff
cvd_host_tests := \
monotonic_time_test \
diff --git a/shared/auto/OWNERS b/shared/auto/OWNERS
index 53bbd52..1b990ef 100644
--- a/shared/auto/OWNERS
+++ b/shared/auto/OWNERS
@@ -1,3 +1,5 @@
# Android Auto leads
ankitarora@google.com
egranata@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/shared/device.mk b/shared/device.mk
index 3a9797c..02e002d 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -28,6 +28,8 @@
PRODUCT_USE_DYNAMIC_PARTITIONS := true
DISABLE_RILD_OEM_HOOK := true
+PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for vulkan
+
TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE ?= f2fs
TARGET_VULKAN_SUPPORT ?= true
diff --git a/shared/sepolicy/vendor/genfs_contexts b/shared/sepolicy/vendor/genfs_contexts
index 5ac5257..82dea3d 100644
--- a/shared/sepolicy/vendor/genfs_contexts
+++ b/shared/sepolicy/vendor/genfs_contexts
@@ -6,7 +6,15 @@
genfscon sysfs /devices/pci0000:00/0000:00:0a.0/subsystem_vendor u:object_r:sysfs_gpu:s0
genfscon sysfs /devices/pci0000:00/0000:00:0a.0/uevent u:object_r:sysfs_gpu:s0
genfscon sysfs /devices/pci0000:00/0000:00:0a.0/vendor u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/pnp0/00:00/rtc u:object_r:sysfs_rtc:s0 # also used by qemu
+## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
+## x86 rtc_cmos on crosvm does not currently expose rtcN/hctosys
+## find /sys/devices/platform/* -type d -name 'wakeup[0-9]'
+genfscon sysfs /devices/platform/rtc_cmos/wakeup/wakeup0 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup1 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/wakeup2 u:object_r:sysfs_wakeup:s0 # <= 5.5
+genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/alarmtimer.0.auto/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0 # >5.5
+genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup3 u:object_r:sysfs_wakeup:s0
+
# crosvm (arm64)
genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:07.0/virtio6/net u:object_r:sysfs_net:s0 # buried_eth0 & wlan0
genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:08.0/virtio7/net u:object_r:sysfs_net:s0 # rmnet0
@@ -15,21 +23,32 @@
genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0a.0/subsystem_vendor u:object_r:sysfs_gpu:s0
genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0a.0/uevent u:object_r:sysfs_gpu:s0
genfscon sysfs /devices/platform/10000.pci/pci0000:00/0000:00:0a.0/vendor u:object_r:sysfs_gpu:s0
-genfscon sysfs /devices/platform/2000.rtc/rtc u:object_r:sysfs_rtc:s0
+## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
+genfscon sysfs /devices/platform/2000.rtc/rtc u:object_r:sysfs_rtc:s0
+## find /sys/devices/platform/* -type d -name 'wakeup[0-9]'
+## arm64 2000.rtc on crosvm does not currently expose a wakeup node
+genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc2/wakeup1 u:object_r:sysfs_wakeup:s0 # <= 5.5
+genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc2/alarmtimer.0.auto/wakeup/wakeup1 u:object_r:sysfs_wakeup:s0 # >5.5
+
# qemu (x86)
genfscon sysfs /devices/pci0000:00/0000:00:04.0/virtio2/net u:object_r:sysfs_net:s0 # buried_eth0 & wlan0
genfscon sysfs /devices/pci0000:00/0000:00:05.0/virtio3/net u:object_r:sysfs_net:s0 # rmnet0
+# FIXME: Add sysfs_gpu labels for qemu
+## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
+genfscon sysfs /devices/pnp0/00:00/rtc u:object_r:sysfs_rtc:s0
+## find /sys/devices/platform/* -type d -name 'wakeup[0-9][0-9]'
+genfscon sysfs /devices/pnp0/00:00/wakeup/wakeup13 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/pnp0/00:00/rtc/rtc0/wakeup14 u:object_r:sysfs_wakeup:s0 # <= 5.5
+genfscon sysfs /devices/pnp0/00:00/rtc/rtc0/alarmtimer.0.auto/wakeup/wakeup14 u:object_r:sysfs_wakeup:s0 # >5.5
+genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup15 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup16 u:object_r:sysfs_wakeup:s0
+
+# common to qemu (x86) and crosvm (arm64)
+genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup0 u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0
# common on all platforms / vm managers
+genfscon sysfs /devices/platform/rtc-test.0/rtc u:object_r:sysfs_rtc:s0
+genfscon sysfs /devices/platform/rtc-test.1/rtc u:object_r:sysfs_rtc:s0
+genfscon sysfs /devices/platform/rtc-test.2/rtc u:object_r:sysfs_rtc:s0
genfscon sysfs /bus/iio/devices u:object_r:sysfs_iio_devices:s0
-genfscon sysfs /devices/platform/rtc-test.0/rtc/rtc0/hctosys u:object_r:sysfs_rtc:s0
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/hctosys u:object_r:sysfs_rtc:s0
-genfscon sysfs /devices/platform/rtc-test.2/rtc/rtc2/hctosys u:object_r:sysfs_rtc:s0
-# TODO(b/148802006): Work around core policy sysfs_wakeup label not working
-# All kernels
-genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup0 u:object_r:sysfs_wakeup:s0
-genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0
-# Kernels <=5.5
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/wakeup1 u:object_r:sysfs_wakeup:s0
-# Kernels >5.5
-genfscon sysfs /devices/platform/rtc-test.1/rtc/rtc1/alarmtimer.0.auto/wakeup/wakeup1 u:object_r:sysfs_wakeup:s0
diff --git a/vsoc_arm64/auto/OWNERS b/vsoc_arm64/auto/OWNERS
index 53bbd52..1b990ef 100644
--- a/vsoc_arm64/auto/OWNERS
+++ b/vsoc_arm64/auto/OWNERS
@@ -1,3 +1,5 @@
# Android Auto leads
ankitarora@google.com
egranata@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/vsoc_x86/auto/OWNERS b/vsoc_x86/auto/OWNERS
index 53bbd52..1b990ef 100644
--- a/vsoc_x86/auto/OWNERS
+++ b/vsoc_x86/auto/OWNERS
@@ -1,3 +1,5 @@
# Android Auto leads
ankitarora@google.com
egranata@google.com
+gurunagarajan@google.com
+keunyoung@google.com
diff --git a/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml b/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
index 99af23c..9893ad9 100644
--- a/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
+++ b/vsoc_x86/auto/preinstalled-packages-product-car-cuttlefish.xml
@@ -61,12 +61,16 @@
<install-in user-type="FULL" />
<install-in user-type="SYSTEM" />
</install-in-user-type>
-
<!-- Required in SettingHelperImpl to start settings with shell command.-->
<install-in-user-type package="com.android.car.settings">
<install-in user-type="FULL" />
<install-in user-type="SYSTEM" />
</install-in-user-type>
+ <!-- Required for Wifi -->
+ <install-in-user-type package="com.android.networkstack">
+ <install-in user-type="FULL" />
+ <install-in user-type="SYSTEM" />
+ </install-in-user-type>
<!--
Apps that do need to run on SYSTEM and evaluated by package owner.
@@ -224,9 +228,6 @@
<install-in-user-type package="com.android.musicfx">
<install-in user-type="FULL" />
</install-in-user-type>
- <install-in-user-type package="com.android.networkstack">
- <install-in user-type="FULL" />
- </install-in-user-type>
<install-in-user-type package="com.google.android.marvin.talkback">
<install-in user-type="FULL" />
</install-in-user-type>