Merge changes I02c1e5f2,Ie9292dfd,I232d4a02,I7fcd05f6,Ic3e4750f into emu-master-dev
* changes:
[Bluetooth] Make nimble examples discoverable by emulator.
[Bluetooth] Disable failing e2e tests in nimble.
[Bluetooth] Make the timing related tests runnable.
[Bluetooth] Fix nimble OS binding bugs.
[Bluetooth] Enable nimble e2e tests
diff --git a/android-qemu2-glue/main.cpp b/android-qemu2-glue/main.cpp
index 9e90f83..b434a15 100755
--- a/android-qemu2-glue/main.cpp
+++ b/android-qemu2-glue/main.cpp
@@ -23,6 +23,7 @@
#include "android/base/threads/Async.h"
#include "android/base/threads/Thread.h"
#include "android/boot-properties.h"
+#include "android/bootconfig.h"
#include "android/camera/camera-virtualscene.h"
#include "android/cmdline-option.h"
#include "android/config/BluetoothConfig.h"
@@ -2031,6 +2032,8 @@
// won't appreciate it.
args.add("-nodefaults");
+ std::string bootconfigInitrdPath;
+
if (hw->hw_arc) {
args.add2("-kernel", hw->kernel_path);
@@ -2047,7 +2050,15 @@
avd_dir, avd_dir, avd_dir);
} else {
if (hw->disk_ramdisk_path) {
- args.add({"-kernel", hw->kernel_path, "-initrd", hw->disk_ramdisk_path});
+ args.add2("-kernel", hw->kernel_path);
+
+ if (fc::isEnabled(fc::AndroidbootProps)) {
+ bootconfigInitrdPath =
+ getWriteableFilename(hw->disk_dataPartition_path, "initrd");
+ args.add2("-initrd", bootconfigInitrdPath.c_str());
+ } else {
+ args.add2("-initrd", hw->disk_ramdisk_path);
+ }
} else {
derror("disk_ramdisk_path is required but missing");
return 1;
@@ -2127,7 +2138,10 @@
args.add("null,id=forhvc1");
}
- boot_property_add_logcat_pipe_virtconsole("*:V");
+ if (!fc::isEnabled(fc::AndroidbootProps)) {
+ // it is going to bootconfig, `androidboot.logcat`
+ boot_property_add_logcat_pipe_virtconsole("*:V");
+ }
} else {
args.add("null,id=forhvc1");
}
@@ -2502,8 +2516,24 @@
hw->display_settings_xml);
std::vector<std::string> kernelCmdLineUserspaceBootOpts;
- for (const auto& kv: userspaceBootOpts) {
- kernelCmdLineUserspaceBootOpts.push_back(kv.first + "=" + kv.second);
+ if (fc::isEnabled(fc::AndroidbootProps)) {
+ const int r = createRamdiskWithBootconfig(
+ hw->disk_ramdisk_path,
+ bootconfigInitrdPath.c_str(),
+ userspaceBootOpts);
+ if (r) {
+ fprintf(stderr, "%s:%d Could not prepare the ramdisk with bootconfig, "
+ "error=%d src=%s dst=%s\n", __func__, __LINE__,
+ r, hw->disk_ramdisk_path, bootconfigInitrdPath.c_str());
+
+ return r;
+ }
+
+ kernelCmdLineUserspaceBootOpts.push_back("bootconfig");
+ } else {
+ for (const auto& kv: userspaceBootOpts) {
+ kernelCmdLineUserspaceBootOpts.push_back(kv.first + "=" + kv.second);
+ }
}
std::string append_arg = emulator_getKernelParameters(
diff --git a/android/android-emu/android-emu.cmake b/android/android-emu/android-emu.cmake
index ec3deb1..19a8788 100644
--- a/android/android-emu/android-emu.cmake
+++ b/android/android-emu/android-emu.cmake
@@ -23,6 +23,7 @@
android/base/async/CallbackRegistry.cpp
android/base/LayoutResolver.cpp
android/boot-properties.c
+ android/bootconfig.cpp
android/car-cluster.cpp
android/car.cpp
android/cmdline-option.cpp
@@ -818,6 +819,7 @@
android/base/IOVector_unittest.cpp
android/base/LayoutResolver_unittest.cpp
android/base/testing/ProtobufMatchers.cpp
+ android/bootconfig_unittest.cpp
android/camera/CameraFormatConverters_unittest.cpp
android/cmdline-option_unittest.cpp
android/CommonReportedInfo_unittest.cpp
diff --git a/android/android-emu/android/bootconfig.cpp b/android/android-emu/android/bootconfig.cpp
new file mode 100644
index 0000000..48ba137
--- /dev/null
+++ b/android/android-emu/android/bootconfig.cpp
@@ -0,0 +1,126 @@
+#include "android/bootconfig.h"
+
+#include <numeric>
+#include <memory>
+#include <string_view>
+#include <stdio.h>
+
+namespace {
+using namespace std::literals;
+
+constexpr std::string_view kBootconfigMagic = "#BOOTCONFIG\n"sv;
+constexpr uint32_t kBootconfigAlign = 4;
+
+std::pair<int, size_t> copyFile(FILE* src, FILE* dst) {
+ size_t sz = 0;
+ std::vector<char> buf(64 * 1024);
+
+ while (true) {
+ const size_t szR = ::fread(buf.data(), 1, buf.size(), src);
+ if (!szR) {
+ return {::ferror(src), sz};
+ }
+
+ const size_t szW = ::fwrite(buf.data(), 1, szR, dst);
+ if (szR != szW) {
+ return {::ferror(dst), sz};
+ }
+
+ sz += szR;
+ }
+}
+
+void host2le32(const uint32_t v32, void* dst) {
+ auto m8 = static_cast<uint8_t*>(dst);
+ m8[0] = v32;
+ m8[1] = v32 >> 8;
+ m8[2] = v32 >> 16;
+ m8[3] = v32 >> 24;
+}
+
+std::vector<char> flattenBootconfig(const std::vector<std::pair<std::string, std::string>>& bootconfig) {
+ std::vector<char> bits;
+
+ for (const auto& kv: bootconfig) {
+ bits.insert(bits.end(), kv.first.begin(), kv.first.end());
+ bits.push_back('=');
+ bits.push_back('\"');
+ bits.insert(bits.end(), kv.second.begin(), kv.second.end());
+ bits.push_back('\"');
+ bits.push_back('\n');
+ }
+ bits.push_back(0); // it is ASCIIZ
+
+ return bits;
+}
+
+int appendBootconfig(const size_t srcSize,
+ const std::vector<std::pair<std::string, std::string>>& bootconfig,
+ FILE* dst) {
+ const std::vector<char> blob = buildBootconfigBlob(srcSize, bootconfig);
+
+ if (blob.size() != ::fwrite(blob.data(), 1, blob.size(), dst)) {
+ return ::ferror(dst);
+ }
+
+ return 0;
+}
+} // namespace
+
+std::vector<char> buildBootconfigBlob(const size_t srcSize,
+ const std::vector<std::pair<std::string, std::string>>& bootconfig) {
+ std::vector<char> blob = flattenBootconfig(bootconfig);
+
+ const size_t unaligend = (srcSize + blob.size()) % kBootconfigAlign;
+ if (unaligend) {
+ blob.insert(blob.end(), kBootconfigAlign - unaligend, '+');
+ }
+
+ const uint32_t csum =
+ std::accumulate(blob.begin(), blob.end(), 0,
+ [](const uint32_t z, const char c){
+ return z + static_cast<uint8_t>(c);
+ });
+
+ const size_t size = blob.size();
+
+ blob.insert(blob.end(), 8, '+'); // size(u32, LE), csum(u32, LE)
+ host2le32(size, &blob[blob.size() - 8]);
+ host2le32(csum, &blob[blob.size() - 4]);
+
+ blob.insert(blob.end(), kBootconfigMagic.begin(), kBootconfigMagic.end());
+
+ return blob;
+}
+
+int createRamdiskWithBootconfig(const char* srcRamdiskPath,
+ const char* dstRamdiskPath,
+ const std::vector<std::pair<std::string, std::string>>& bootconfig) {
+ struct FILE_deleter {
+ void operator()(FILE* fp) const {
+ ::fclose(fp);
+ }
+ };
+
+ std::unique_ptr<FILE, FILE_deleter> srcRamdisk(::fopen(srcRamdiskPath, "rb"));
+ if (!srcRamdisk) {
+ fprintf(stderr, "%s:%d Can't open '%s' for reading\n", __func__, __LINE__, srcRamdiskPath);
+ return 1;
+ }
+
+ std::unique_ptr<FILE, FILE_deleter> dstRamdisk(::fopen(dstRamdiskPath, "wb"));
+ if (!dstRamdisk) {
+ fprintf(stderr, "%s:%d Can't open '%s' for writing\n", __func__, __LINE__, dstRamdiskPath);
+ return 1;
+ }
+
+ const auto r = copyFile(srcRamdisk.get(), dstRamdisk.get());
+ if (r.first) {
+ fprintf(stderr, "%s:%d Error copying '%s' into '%s'\n",
+ __func__, __LINE__, srcRamdiskPath, dstRamdiskPath);
+ return r.first;
+ }
+
+ return appendBootconfig(r.second, bootconfig, dstRamdisk.get());
+}
+
diff --git a/android/android-emu/android/bootconfig.h b/android/android-emu/android/bootconfig.h
new file mode 100644
index 0000000..eee57b9
--- /dev/null
+++ b/android/android-emu/android/bootconfig.h
@@ -0,0 +1,31 @@
+// Copyright 2021 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "android/utils/compiler.h"
+
+ANDROID_BEGIN_HEADER
+
+// [src ramdisk][bootconfig][padding][size(le32)][csum(le32)][#BOOTCONFIG\n]
+// ^ 4 byte aligned
+
+std::vector<char> buildBootconfigBlob(const size_t srcSize,
+ const std::vector<std::pair<std::string, std::string>>& bootconfig);
+
+int createRamdiskWithBootconfig(const char* srcRamdiskPath,
+ const char* dstRamdiskPath,
+ const std::vector<std::pair<std::string, std::string>>& bootconfig);
+
+ANDROID_END_HEADER
diff --git a/android/android-emu/android/bootconfig_unittest.cpp b/android/android-emu/android/bootconfig_unittest.cpp
new file mode 100644
index 0000000..56a9b99
--- /dev/null
+++ b/android/android-emu/android/bootconfig_unittest.cpp
@@ -0,0 +1,90 @@
+// Copyright 2021 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+#include "android/bootconfig.h"
+
+#include <string_view>
+#include <gtest/gtest.h>
+#include <string.h>
+
+namespace android {
+
+using namespace std::literals;
+
+namespace {
+constexpr std::string_view kBootconfigMagic = "#BOOTCONFIG\n"sv;
+
+uint32_t loadLE32(const void* m) {
+ const uint8_t* m8 = static_cast<const uint8_t*>(m);
+ return uint32_t(m8[0]) | (uint32_t(m8[1]) << 8)
+ | (uint32_t(m8[2]) << 16) | (uint32_t(m8[3]) << 24);
+}
+} // namespace
+
+TEST(buildBootconfigBlob, OptsMagic) {
+ const std::vector<std::pair<std::string, std::string>> bootconfig = {
+ {"a", "b"},
+ {"c", "2"},
+ };
+
+ constexpr auto propsBlob = "a=\"b\"\nc=\"2\"\n\0"sv;
+
+ const auto blob = buildBootconfigBlob(0, bootconfig);
+
+ EXPECT_GT(blob.size(), propsBlob.size() + kBootconfigMagic.size());
+ EXPECT_TRUE(!memcmp(blob.data(), propsBlob.data(), propsBlob.size()));
+ EXPECT_TRUE(!memcmp(&blob[blob.size() - kBootconfigMagic.size()],
+ kBootconfigMagic.data(), kBootconfigMagic.size()));
+}
+
+TEST(buildBootconfigBlob, SizeAlignmentCsum) {
+ const std::vector<std::pair<std::string, std::string>> bootconfig = {
+ {"a", "b"},
+ };
+
+ constexpr auto propsBlob = "a=\"b\"\n\0"sv; // 7 byte long
+ constexpr uint32_t propsCsum = 'a' + '=' + '\"' + 'b' + '\"' + '\n';
+
+ {
+ const auto blob = buildBootconfigBlob(0, bootconfig);
+ EXPECT_EQ(blob.size() - kBootconfigMagic.size() - 8 - propsBlob.size(), 1);
+
+ const char* lencsum = &blob[blob.size() - kBootconfigMagic.size() - 8];
+ EXPECT_EQ(loadLE32(lencsum), propsBlob.size() + 1);
+ EXPECT_EQ(loadLE32(lencsum + 4), propsCsum + '+');
+ }
+ {
+ const auto blob = buildBootconfigBlob(1, bootconfig);
+ EXPECT_EQ(blob.size() - kBootconfigMagic.size() - 8 - propsBlob.size(), 0);
+
+ const char* lencsum = &blob[blob.size() - kBootconfigMagic.size() - 8];
+ EXPECT_EQ(loadLE32(lencsum), propsBlob.size());
+ EXPECT_EQ(loadLE32(lencsum + 4), propsCsum);
+ }
+ {
+ const auto blob = buildBootconfigBlob(2, bootconfig);
+ EXPECT_EQ(blob.size() - kBootconfigMagic.size() - 8 - propsBlob.size(), 3);
+
+ const char* lencsum = &blob[blob.size() - kBootconfigMagic.size() - 8];
+ EXPECT_EQ(loadLE32(lencsum), propsBlob.size() + 3);
+ EXPECT_EQ(loadLE32(lencsum + 4), propsCsum + '+' + '+' + '+');
+ }
+ {
+ const auto blob = buildBootconfigBlob(3, bootconfig);
+ EXPECT_EQ(blob.size() - kBootconfigMagic.size() - 8 - propsBlob.size(), 2);
+
+ const char* lencsum = &blob[blob.size() - kBootconfigMagic.size() - 8];
+ EXPECT_EQ(loadLE32(lencsum), propsBlob.size() + 2);
+ EXPECT_EQ(loadLE32(lencsum + 4), propsCsum + '+' + '+');
+ }
+}
+
+} // namespace android
diff --git a/android/android-emu/android/emulation/MediaFfmpegVideoHelper.cpp b/android/android-emu/android/emulation/MediaFfmpegVideoHelper.cpp
index 7b369f8..0a7234b 100644
--- a/android/android-emu/android/emulation/MediaFfmpegVideoHelper.cpp
+++ b/android/android-emu/android/emulation/MediaFfmpegVideoHelper.cpp
@@ -185,6 +185,12 @@
}
}
+int MediaFfmpegVideoHelper::frameReorderBufferSize() const {
+ if (!mCodecCtx) return 0;
+ // the has_bframe: Size of the frame reordering buffer in the decoder.
+ return mCodecCtx->has_b_frames;
+}
+
void MediaFfmpegVideoHelper::decode(const uint8_t* data,
size_t len,
uint64_t pts) {
diff --git a/android/android-emu/android/emulation/MediaFfmpegVideoHelper.h b/android/android-emu/android/emulation/MediaFfmpegVideoHelper.h
index 1244d64..a253e20 100644
--- a/android/android-emu/android/emulation/MediaFfmpegVideoHelper.h
+++ b/android/android-emu/android/emulation/MediaFfmpegVideoHelper.h
@@ -59,6 +59,9 @@
void flush() override;
void deInit() override;
+ // this is special helper function, mostly used by apple vtb
+ // to reorder the output frames
+ int frameReorderBufferSize() const;
private:
std::vector<uint8_t> mDecodedFrame;
diff --git a/android/android-emu/android/emulation/MediaVideoToolBoxVideoHelper.cpp b/android/android-emu/android/emulation/MediaVideoToolBoxVideoHelper.cpp
index f3d4c14..1eb215f 100644
--- a/android/android-emu/android/emulation/MediaVideoToolBoxVideoHelper.cpp
+++ b/android/android-emu/android/emulation/MediaVideoToolBoxVideoHelper.cpp
@@ -67,6 +67,8 @@
bool MediaVideoToolBoxVideoHelper::init() {
VTB_DPRINT("init calling");
constexpr int numthreads = 1;
+ mFfmpegVideoHelper.reset(new MediaFfmpegVideoHelper(264, numthreads));
+ mFfmpegVideoHelper->init();
mVtbReady = false;
return true;
}
@@ -89,16 +91,39 @@
fflush(stdout);
}
+void MediaVideoToolBoxVideoHelper::extractFrameInfo() {
+ // at this moment, ffmpeg should have decoded the first frame to obtain
+ // w/h/colorspace info and number of b frame buffers
+
+ if (mObtainedAuxInfo) return;
+
+ mFfmpegVideoHelper->flush();
+ MediaSnapshotState::FrameInfo frame;
+ bool success = mFfmpegVideoHelper->receiveFrame(&frame);
+ if (success) {
+ mColorAspects = frame.color;
+ mVtbBufferSize = mFfmpegVideoHelper->frameReorderBufferSize();
+ }
+ mObtainedAuxInfo = true;
+}
+
void MediaVideoToolBoxVideoHelper::decode(const uint8_t* frame,
size_t szBytes,
uint64_t inputPts) {
VTB_DPRINT("%s(frame=%p, sz=%zu)", __func__, frame, szBytes);
+ if (!mObtainedAuxInfo) {
+ // uses ffmpeg to preprocess until vtb is ready
+ VTB_DPRINT("before ffmpeg decode");
+ mFfmpegVideoHelper->decode(frame, szBytes, inputPts);
+ VTB_DPRINT("after ffmpeg decode");
+ }
parseInputFrames(frame, szBytes);
// has to go in the FIFO order
for (int i = 0; i < mInputFrames.size(); ++i) {
InputFrame& f = mInputFrames[i];
+ bool isidr=false;
switch (f.type) {
case H264NaluType::SPS:
mSPS.assign(f.data, f.data + f.size);
@@ -114,8 +139,13 @@
break;
case H264NaluType::CodedSliceIDR:
VTB_DPRINT("this is an IDR frame");
+ isidr=true;
case H264NaluType::CodedSliceNonIDR:
+ if(isidr==false) {
+ VTB_DPRINT("this is an non-IDR frame");
+ }
if (!mVtbReady) {
+ extractFrameInfo();
createCMFormatDescription();
Boolean needNewSession = ( VTDecompressionSessionCanAcceptFormatDescription(mDecoderSession, mCmFmtDesc) == false);
if (needNewSession) {
@@ -203,11 +233,13 @@
void MediaVideoToolBoxVideoHelper::parseInputFrames(const uint8_t* frame,
size_t sz) {
mInputFrames.clear();
+ VTB_DPRINT("input frame %d bytes", (int)sz);
while (1) {
const uint8_t* remainingFrame = parseOneFrame(frame, sz);
if (remainingFrame == nullptr)
break;
int consumed = (remainingFrame - frame);
+ VTB_DPRINT("consumed %d bytes", consumed);
frame = remainingFrame;
sz = sz - consumed;
}
@@ -238,8 +270,11 @@
// frame as one frame from guest, we need to separate SEI out from IDR:
// video tool box cannot handle SEI+IDR combo-frame; for other cases, there
// is no need to check.
- if (H264NaluType::SEI ==
- H264NaluParser::getFrameNaluType(frame, szBytes, nullptr)) {
+ if (H264NaluType::SEI == H264NaluParser::getFrameNaluType(frame, szBytes, nullptr)
+ || H264NaluType::SPS == H264NaluParser::getFrameNaluType(frame, szBytes, nullptr)
+ || H264NaluType::PPS == H264NaluParser::getFrameNaluType(frame, szBytes, nullptr)
+
+ ) {
nextNalu = H264NaluParser::getNextStartCodeHeader(currentNalu + 3,
remaining - 3);
if (nextNalu != nullptr) {
@@ -646,7 +681,7 @@
copyFrameToCPU();
}
- if (mVtbBufferMap.size() >= mVtbBufferSize) {
+ if (mVtbBufferMap.size() > mVtbBufferSize) {
mSavedDecodedFrames.push_back(std::move(mVtbBufferMap.begin()->second));
mVtbBufferMap.erase(mVtbBufferMap.begin());
}
diff --git a/android/android-emu/android/emulation/MediaVideoToolBoxVideoHelper.h b/android/android-emu/android/emulation/MediaVideoToolBoxVideoHelper.h
index f721dd9..3cfee1e 100644
--- a/android/android-emu/android/emulation/MediaVideoToolBoxVideoHelper.h
+++ b/android/android-emu/android/emulation/MediaVideoToolBoxVideoHelper.h
@@ -174,6 +174,9 @@
// TODO: replace it with webrtc h264 parser once it is built
// for all platforms
std::unique_ptr<MediaFfmpegVideoHelper> mFfmpegVideoHelper;
+ // true once ffmpeg has processed first IDR
+ bool mObtainedAuxInfo {false};
+ void extractFrameInfo();
// vtb decoder does not reorder output frames, that means
// the video could see jumps all the times
diff --git a/android/android-emu/android/userspace-boot-properties.cpp b/android/android-emu/android/userspace-boot-properties.cpp
index d55b3ed..911d088 100644
--- a/android/android-emu/android/userspace-boot-properties.cpp
+++ b/android/android-emu/android/userspace-boot-properties.cpp
@@ -11,6 +11,9 @@
#include "android/userspace-boot-properties.h"
+#include <algorithm>
+#include <string>
+
#include "android/base/StringFormat.h"
#include "android/featurecontrol/FeatureControl.h"
#include "android/version.h"
@@ -23,6 +26,7 @@
"/sys/bus/platform/devices/ANDR0001:00/properties/android/";
static const char kSysfsAndroidDtDirDtb[] =
"/proc/device-tree/firmware/android/";
+
} // namespace
using android::base::StringFormat;
@@ -47,7 +51,77 @@
const bool isX86ish = !strcmp(targetArch, "x86") || !strcmp(targetArch, "x86_64");
const bool hasShellConsole = opts->logcat || opts->shell;
+ const char* checkjniProp;
+ const char* bootanimProp;
+ const char* bootanimPropValue;
+ const char* qemuGlesProp;
+ const char* qemuScreenOffTimeoutProp;
+ const char* qemuEncryptProp;
+ const char* qemuMediaProfileVideoProp;
+ const char* qemuVsyncProp;
+ const char* qemuGltransportNameProp;
+ const char* qemuDrawFlushIntervalProp;
+ const char* qemuOpenglesVersionProp;
+ const char* qemuUirendererProp;
+ const char* dalvikVmHeapsizeProp;
+ const char* qemuLegacyFakeCameraProp;
+ const char* qemuCameraProtocolVerProp;
+ const char* qemuDisplaySettingsXmlProp;
+ const char* qemuVirtioWifiProp;
+ const char* qemuWifiProp;
+ const char* androidQemudProp;
+ const char* qemuHwcodecAvcdecProp;
+ const char* qemuHwcodecVpxdecProp;
+ const char* androidbootLogcatProp;
+
namespace fc = android::featurecontrol;
+ if (fc::isEnabled(fc::AndroidbootProps)) {
+ checkjniProp = "androidboot.dalvik.vm.checkjni";
+ bootanimProp = "androidboot.debug.sf.nobootanimation";
+ bootanimPropValue = "1";
+ qemuGlesProp = nullptr; // deprecated
+ qemuScreenOffTimeoutProp = "androidboot.qemu.settings.system.screen_off_timeout";
+ qemuEncryptProp = nullptr; // deprecated
+ qemuMediaProfileVideoProp = nullptr; // deprecated
+ qemuVsyncProp = "androidboot.qemu.vsync";
+ qemuGltransportNameProp = "androidboot.qemu.gltransport.name";
+ qemuDrawFlushIntervalProp = "androidboot.qemu.gltransport.drawFlushInterval";
+ qemuOpenglesVersionProp = "androidboot.opengles.version";
+ qemuUirendererProp = "androidboot.debug.hwui.renderer";
+ dalvikVmHeapsizeProp = "androidboot.dalvik.vm.heapsize";
+ qemuLegacyFakeCameraProp = "androidboot.qemu.legacy_fake_camera";
+ qemuCameraProtocolVerProp = "androidboot.qemu.camera_protocol_ver";
+ qemuDisplaySettingsXmlProp = nullptr; // deprecated
+ qemuVirtioWifiProp = "androidboot.qemu.virtiowifi";
+ qemuWifiProp = "androidboot.qemu.wifi";
+ androidQemudProp = nullptr; // deprecated
+ qemuHwcodecAvcdecProp = "androidboot.qemu.hwcodec.avcdec";
+ qemuHwcodecVpxdecProp = "androidboot.qemu.hwcodec.vpxdec";
+ androidbootLogcatProp = "androidboot.logcat";
+ } else {
+ checkjniProp = "android.checkjni";
+ bootanimProp = "android.bootanim";
+ bootanimPropValue = "0";
+ qemuGlesProp = "qemu.gles";
+ qemuScreenOffTimeoutProp = "qemu.settings.system.screen_off_timeout";
+ qemuEncryptProp = "qemu.encrypt";
+ qemuMediaProfileVideoProp = "qemu.mediaprofile.video";
+ qemuVsyncProp = "qemu.vsync";
+ qemuGltransportNameProp = "qemu.gltransport";
+ qemuDrawFlushIntervalProp = "qemu.gltransport.drawFlushInterval";
+ qemuOpenglesVersionProp = "qemu.opengles.version";
+ qemuUirendererProp = "qemu.uirenderer";
+ dalvikVmHeapsizeProp = "qemu.dalvik.vm.heapsize";
+ qemuLegacyFakeCameraProp = "qemu.legacy_fake_camera";
+ qemuCameraProtocolVerProp = "qemu.camera_protocol_ver";
+ qemuDisplaySettingsXmlProp = "qemu.display.settings.xml";
+ qemuVirtioWifiProp = "qemu.virtiowifi";
+ qemuWifiProp = "qemu.wifi";
+ androidQemudProp = "android.qemud";
+ qemuHwcodecAvcdecProp = "qemu.hwcodec.avcdec";
+ qemuHwcodecVpxdecProp = "qemu.hwcodec.vpxdec";
+ androidbootLogcatProp = nullptr;
+ }
std::vector<std::pair<std::string, std::string>> params;
@@ -65,75 +139,89 @@
}
if (!opts->no_jni) {
- params.push_back({"android.checkjni", "1"});
+ params.push_back({checkjniProp, "1"});
}
if (opts->no_boot_anim) {
- params.push_back({"android.bootanim", "0"});
+ params.push_back({bootanimProp, bootanimPropValue});
}
// qemu.gles is used to pass the GPU emulation mode to the guest
// through kernel parameters. Note that the ro.opengles.version
// boot property must also be defined for |gles > 0|, but this
// is not handled here (see vl-android.c for QEMU1).
- {
+ if (qemuGlesProp) {
int gles;
switch (glesMode) {
case kAndroidGlesEmulationHost: gles = 1; break;
case kAndroidGlesEmulationGuest: gles = 2; break;
default: gles = 0;
}
- params.push_back({"qemu.gles", StringFormat("%d", gles)});
+ params.push_back({qemuGlesProp, StringFormat("%d", gles)});
}
// To save battery, set the screen off timeout to a high value.
// Using int32_max here. The unit is milliseconds.
- params.push_back({"qemu.settings.system.screen_off_timeout", "2147483647"}); // 596 hours
+ params.push_back({qemuScreenOffTimeoutProp, "2147483647"}); // 596 hours
- if (isQemu2 && fc::isEnabled(fc::EncryptUserData)) {
- params.push_back({"qemu.encrypt", "1"});
+ if (isQemu2 && fc::isEnabled(fc::EncryptUserData) && qemuEncryptProp) {
+ params.push_back({qemuEncryptProp, "1"});
}
// Android media profile selection
// 1. If the SelectMediaProfileConfig is on, then select
// <media_profile_name> if the resolution is above 1080p (1920x1080).
- if (isQemu2 && fc::isEnabled(fc::DynamicMediaProfile)) {
+ if (isQemu2 && fc::isEnabled(fc::DynamicMediaProfile) && qemuMediaProfileVideoProp) {
if ((lcd_width > 1920 && lcd_height > 1080) ||
(lcd_width > 1080 && lcd_height > 1920)) {
fprintf(stderr, "Display resolution > 1080p. Using different media profile.\n");
params.push_back({
- "qemu.mediaprofile.video",
+ qemuMediaProfileVideoProp,
"/data/vendor/etc/media_codecs_google_video_v2.xml"
});
}
}
// Set vsync rate
- params.push_back({"qemu.vsync", StringFormat("%u", lcd_vsync)});
+ params.push_back({qemuVsyncProp, StringFormat("%u", lcd_vsync)});
// Set gl transport props
- params.push_back({"qemu.gltransport", gltransport});
+ params.push_back({qemuGltransportNameProp, gltransport});
params.push_back({
- "qemu.gltransport.drawFlushInterval",
+ qemuDrawFlushIntervalProp,
StringFormat("%u", gltransport_drawFlushInterval)});
// OpenGL ES related setup
// 1. Set opengles.version and set Skia as UI renderer if
// GLESDynamicVersion = on (i.e., is a reasonably good driver)
params.push_back({
- "qemu.opengles.version",
+ qemuOpenglesVersionProp,
StringFormat("%d", bootPropOpenglesVersion)
});
if (fc::isEnabled(fc::GLESDynamicVersion)) {
- params.push_back({"qemu.uirenderer", "skiagl"});
+ params.push_back({qemuUirendererProp, "skiagl"});
}
- if (opts->logcat) {
- std::string param = opts->logcat;
- // Replace any space with a comma.
- std::replace(param.begin(), param.end(), ' ', ',');
- std::replace(param.begin(), param.end(), '\t', ',');
- params.push_back({"androidboot.logcat", param});
+ if (androidbootLogcatProp) {
+ if (opts->logcat) {
+ std::string param = opts->logcat;
+
+ // Replace any space with a comma.
+ std::replace_if(param.begin(), param.end(), [](char c){
+ switch (c) {
+ case ' ':
+ case '\t':
+ return true;
+
+ default:
+ return false;
+ }
+ }, ',');
+
+ params.push_back({androidbootLogcatProp, param});
+ } else {
+ params.push_back({androidbootLogcatProp, "*:V"});
+ }
}
if (opts->bootchart) {
@@ -146,17 +234,17 @@
if (vm_heapSize > 0) {
params.push_back({
- "qemu.dalvik.vm.heapsize",
+ dalvikVmHeapsizeProp,
StringFormat("%dm", vm_heapSize)
});
}
if (opts->legacy_fake_camera) {
- params.push_back({"qemu.legacy_fake_camera", "1"});
+ params.push_back({qemuLegacyFakeCameraProp, "1"});
}
if (apiLevel > 29) {
- params.push_back({"qemu.camera_protocol_ver", "1"});
+ params.push_back({qemuCameraProtocolVerProp, "1"});
}
const bool isDynamicPartition = fc::isEnabled(fc::DynamicPartition);
@@ -182,21 +270,21 @@
}
// display settings file name
- if (displaySettingsXml && displaySettingsXml[0]) {
- params.push_back({"qemu.display.settings.xml", displaySettingsXml});
+ if (displaySettingsXml && displaySettingsXml[0] && qemuDisplaySettingsXmlProp) {
+ params.push_back({qemuDisplaySettingsXmlProp, displaySettingsXml});
}
if (isQemu2) {
if (fc::isEnabled(fc::VirtioWifi)) {
- params.push_back({"qemu.virtiowifi", "1"});
+ params.push_back({qemuVirtioWifiProp, "1"});
} else if (fc::isEnabled(fc::Wifi)) {
- params.push_back({"qemu.wifi", "1"});
+ params.push_back({qemuWifiProp, "1"});
}
}
if (fc::isEnabled(fc::HardwareDecoder)) {
- params.push_back({"qemu.hwcodec.avcdec", "2"});
- params.push_back({"qemu.hwcodec.vpxdec", "2"});
+ params.push_back({qemuHwcodecAvcdecProp, "2"});
+ params.push_back({qemuHwcodecVpxdecProp, "2"});
}
if (isQemu2) {
@@ -207,7 +295,9 @@
});
}
- params.push_back({"android.qemud", "1"});
+ if (androidQemudProp) {
+ params.push_back({androidQemudProp, "1"});
+ }
} else { // !isQemu2
// Technical note: There are several important constraints when
// setting up QEMU1 virtual ttys:
@@ -247,10 +337,9 @@
int logcatSerial = 1;
if (apiLevel < 14) {
- params.push_back({
- "android.qemud",
- StringFormat("%s1", kernelSerialPrefix)
- });
+ if (androidQemudProp) {
+ params.push_back({androidQemudProp, StringFormat("%s1", kernelSerialPrefix)});
+ }
if (isX86ish) {
logcatSerial = 0;
@@ -260,7 +349,9 @@
} else {
// The rild daemon, used for GSM emulation, checks for qemud,
// just set it to a dummy value instead of a serial port.
- params.push_back({"android.qemud", "1"});
+ if (androidQemudProp) {
+ params.push_back({androidQemudProp, "1"});
+ }
}
if (hasShellConsole) {
diff --git a/android/android-emu/android/userspace-boot-properties_unittest.cpp b/android/android-emu/android/userspace-boot-properties_unittest.cpp
index ec288da..e982dfd 100644
--- a/android/android-emu/android/userspace-boot-properties_unittest.cpp
+++ b/android/android-emu/android/userspace-boot-properties_unittest.cpp
@@ -11,6 +11,7 @@
#include "android/userspace-boot-properties.h"
#include "android/base/misc/StringUtils.h"
+#include "android/featurecontrol/FeatureControl.h"
#include <map>
#include <gtest/gtest.h>
@@ -27,7 +28,9 @@
using android::base::join;
-TEST(getUserspaceBootProperties, Simple) {
+namespace fc = android::featurecontrol;
+
+TEST(getUserspaceBootProperties, BootconfigOff) {
const std::vector<std::string> verifiedBootParameters = {
"verifiedBootParameters.foo=value"
};
@@ -38,6 +41,8 @@
opts.bootchart = (char*)"bootchart";
opts.selinux = (char*)"selinux";
+ fc::setEnabledOverride(fc::AndroidbootProps, false);
+
const auto params = getUserspaceBootProperties(
&opts,
"x86_64", // targetArch
@@ -71,7 +76,7 @@
EXPECT_STREQ(paramsMap["qemu.gltransport"].c_str(), "gltransport");
EXPECT_STREQ(paramsMap["qemu.gltransport.drawFlushInterval"].c_str(), "77");
EXPECT_STREQ(paramsMap["qemu.opengles.version"].c_str(), "123");
- EXPECT_STREQ(paramsMap["androidboot.logcat"].c_str(), "logcat");
+ EXPECT_STREQ(paramsMap["androidboot.logcat"].c_str(), "");
EXPECT_STREQ(paramsMap["androidboot.bootchart"].c_str(), "bootchart");
EXPECT_STREQ(paramsMap["androidboot.selinux"].c_str(), "selinux");
EXPECT_STREQ(paramsMap["qemu.dalvik.vm.heapsize"].c_str(), "64m");
@@ -79,4 +84,54 @@
EXPECT_STREQ(paramsMap["qemu.display.settings.xml"].c_str(), "displaySettingsXml");
}
+TEST(getUserspaceBootProperties, BootconfigOn) {
+ const std::vector<std::string> verifiedBootParameters = {
+ "verifiedBootParameters.foo=value"
+ };
+
+ AndroidOptions opts = makeAndroidOptions();
+
+ opts.logcat = (char*)"logcat";
+ opts.bootchart = (char*)"bootchart";
+ opts.selinux = (char*)"selinux";
+
+ fc::setEnabledOverride(fc::AndroidbootProps, true);
+
+ const auto params = getUserspaceBootProperties(
+ &opts,
+ "x86_64", // targetArch
+ "serialno", // serialno
+ true, // isQemu2
+ 600, // lcd_width
+ 800, // lcd_height
+ 60, // lcd_vsync
+ kAndroidGlesEmulationHost, // glesMode
+ 123, // bootPropOpenglesVersion
+ 64, // vm_heapSize
+ 29, // apiLevel
+ "kernelSerialPrefix", // kernelSerialPrefix
+ &verifiedBootParameters, // verifiedBootParameters
+ "gltransport", // gltransport
+ 77, // gltransport_drawFlushInterval
+ "displaySettingsXml"); // displaySettingsXml
+
+ std::map<std::string, std::string> paramsMap;
+ for (const auto& kv : params) {
+ EXPECT_TRUE(paramsMap.insert(kv).second);
+ }
+
+ EXPECT_STREQ(paramsMap["qemu"].c_str(), "1");
+ EXPECT_STREQ(paramsMap["androidboot.hardware"].c_str(), "ranchu");
+ EXPECT_STREQ(paramsMap["androidboot.serialno"].c_str(), "serialno");
+ EXPECT_STREQ(paramsMap["androidboot.dalvik.vm.checkjni"].c_str(), "1");
+ EXPECT_STREQ(paramsMap["androidboot.qemu.gltransport.name"].c_str(), "gltransport");
+ EXPECT_STREQ(paramsMap["androidboot.qemu.gltransport.drawFlushInterval"].c_str(), "77");
+ EXPECT_STREQ(paramsMap["androidboot.opengles.version"].c_str(), "123");
+ EXPECT_STREQ(paramsMap["androidboot.logcat"].c_str(), "logcat");
+ EXPECT_STREQ(paramsMap["androidboot.bootchart"].c_str(), "bootchart");
+ EXPECT_STREQ(paramsMap["androidboot.selinux"].c_str(), "selinux");
+ EXPECT_STREQ(paramsMap["androidboot.dalvik.vm.heapsize"].c_str(), "64m");
+ EXPECT_STREQ(paramsMap["verifiedBootParameters.foo"].c_str(), "value");
+}
+
} // namespace android
diff --git a/android/data/advancedFeatures.ini b/android/data/advancedFeatures.ini
index 75eef6e..2ae5a3b 100644
--- a/android/data/advancedFeatures.ini
+++ b/android/data/advancedFeatures.ini
@@ -388,4 +388,4 @@
# If enabled, the boot userspace properties (e.g. `qemu=1` or
# `qemu.opengles.version=123456`) are passed in the ramdisk instead of
# the kernel command line (which is deprecated for these purposes).
-AndroidbootProps = off
+AndroidbootProps = on
diff --git a/android/data/advancedFeaturesCanary.ini b/android/data/advancedFeaturesCanary.ini
index 6398521..f137894 100644
--- a/android/data/advancedFeaturesCanary.ini
+++ b/android/data/advancedFeaturesCanary.ini
@@ -393,4 +393,4 @@
# If enabled, the boot userspace properties (e.g. `qemu=1` or
# `qemu.opengles.version=123456`) are passed in the ramdisk instead of
# the kernel command line (which is deprecated for these purposes).
-AndroidbootProps = off
+AndroidbootProps = on