Merge "Make CarSystemUI use its own custom user switching dialog." into rvc-dev
diff --git a/car-lib/src/android/car/watchdog/CarWatchdogManager.java b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
index fff1283..d8fb7d9 100644
--- a/car-lib/src/android/car/watchdog/CarWatchdogManager.java
+++ b/car-lib/src/android/car/watchdog/CarWatchdogManager.java
@@ -51,7 +51,7 @@
public final class CarWatchdogManager extends CarManagerBase {
private static final String TAG = CarWatchdogManager.class.getSimpleName();
- private static final boolean DEBUG = true; // STOPSHIP if true (b/151474489)
+ private static final boolean DEBUG = false; // STOPSHIP if true
private static final int INVALID_SESSION_ID = -1;
private static final int NUMBER_OF_CONDITIONS_TO_BE_MET = 2;
// Message ID representing main thread activeness checking.
diff --git a/evs/apps/default/Android.bp b/evs/apps/default/Android.bp
index 7fd60ef..df6fd0d 100644
--- a/evs/apps/default/Android.bp
+++ b/evs/apps/default/Android.bp
@@ -63,10 +63,6 @@
"LabeledChecker.png",
],
- strip: {
- keep_symbols: true,
- },
-
init_rc: ["evs_app.rc"],
cflags: ["-DLOG_TAG=\"EvsApp\""] + [
diff --git a/evs/apps/default/ConfigManager.h b/evs/apps/default/ConfigManager.h
index 6acd83d..9c6d1a2 100644
--- a/evs/apps/default/ConfigManager.h
+++ b/evs/apps/default/ConfigManager.h
@@ -19,6 +19,8 @@
#include <vector>
#include <string>
+#include <system/graphics-base.h>
+
class ConfigManager {
public:
@@ -91,6 +93,12 @@
const DisplayInfo& getActiveDisplay() const { return mDisplays[mActiveDisplayId]; };
void useExternalMemory(bool flag) { mUseExternalMemory = flag; }
bool getUseExternalMemory() const { return mUseExternalMemory; }
+ void setExternalMemoryFormat(android_pixel_format_t format) {
+ mExternalMemoryFormat = format;
+ }
+ android_pixel_format_t getExternalMemoryFormat() const {
+ return mExternalMemoryFormat;
+ }
private:
// Camera information
@@ -103,6 +111,9 @@
// Memory management
bool mUseExternalMemory;
+ // Format of external memory
+ android_pixel_format_t mExternalMemoryFormat;
+
// Car body information (assumes front wheel steering and origin at center of rear axel)
// Note that units aren't specified and don't matter as long as all length units are consistent
// within the JSON file from which we parse. That is, if everything is in meters, that's fine.
diff --git a/evs/apps/default/RenderDirectView.cpp b/evs/apps/default/RenderDirectView.cpp
index 2938521..68b731e 100644
--- a/evs/apps/default/RenderDirectView.cpp
+++ b/evs/apps/default/RenderDirectView.cpp
@@ -116,7 +116,8 @@
mCameraDesc.v1.cameraId.c_str(),
foundCfg ? std::move(targetCfg) : nullptr,
sDisplay,
- mConfig.getUseExternalMemory()));
+ mConfig.getUseExternalMemory(),
+ mConfig.getExternalMemoryFormat()));
if (!mTexture) {
LOG(ERROR) << "Failed to set up video texture for " << mCameraDesc.v1.cameraId;
// TODO: For production use, we may actually want to fail in this case, but not yet...
diff --git a/evs/apps/default/StreamHandler.cpp b/evs/apps/default/StreamHandler.cpp
index b1cfd1f..d350af1 100644
--- a/evs/apps/default/StreamHandler.cpp
+++ b/evs/apps/default/StreamHandler.cpp
@@ -30,6 +30,7 @@
StreamHandler::StreamHandler(android::sp <IEvsCamera> pCamera,
uint32_t numBuffers,
bool useOwnBuffers,
+ android_pixel_format_t format,
int32_t width,
int32_t height)
: mCamera(pCamera),
@@ -46,7 +47,6 @@
const auto usage = GRALLOC_USAGE_HW_TEXTURE |
GRALLOC_USAGE_SW_READ_RARELY |
GRALLOC_USAGE_SW_WRITE_OFTEN;
- const auto format = HAL_PIXEL_FORMAT_RGBA_8888;
for (auto i = 0; i < numBuffers; ++i) {
unsigned pixelsPerLine;
android::status_t result = alloc.allocate(width,
@@ -64,10 +64,10 @@
BufferDesc_1_1 buf;
AHardwareBuffer_Desc* pDesc =
reinterpret_cast<AHardwareBuffer_Desc *>(&buf.buffer.description);
- pDesc->width = 640;
- pDesc->height = 360;
+ pDesc->width = width;
+ pDesc->height = height;
pDesc->layers = 1;
- pDesc->format = HAL_PIXEL_FORMAT_RGBA_8888;
+ pDesc->format = format;
pDesc->usage = GRALLOC_USAGE_HW_TEXTURE |
GRALLOC_USAGE_SW_READ_RARELY |
GRALLOC_USAGE_SW_WRITE_OFTEN;
diff --git a/evs/apps/default/StreamHandler.h b/evs/apps/default/StreamHandler.h
index f877c78..cb22b36 100644
--- a/evs/apps/default/StreamHandler.h
+++ b/evs/apps/default/StreamHandler.h
@@ -51,6 +51,7 @@
StreamHandler(android::sp <IEvsCamera> pCamera,
uint32_t numBuffers = 2,
bool useOwnBuffers = false,
+ android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888,
int32_t width = 640,
int32_t height = 360);
void shutdown();
diff --git a/evs/apps/default/VideoTex.cpp b/evs/apps/default/VideoTex.cpp
index 94e734a..7491dfe 100644
--- a/evs/apps/default/VideoTex.cpp
+++ b/evs/apps/default/VideoTex.cpp
@@ -137,29 +137,39 @@
const char* evsCameraId,
std::unique_ptr<Stream> streamCfg,
EGLDisplay glDisplay,
- bool useExternalMemory) {
+ bool useExternalMemory,
+ android_pixel_format_t format) {
// Set up the camera to feed this texture
sp<IEvsCamera> pCamera = nullptr;
+ sp<StreamHandler> pStreamHandler = nullptr;
if (streamCfg != nullptr) {
pCamera = pEnum->openCamera_1_1(evsCameraId, *streamCfg);
+
+ // Initialize the stream that will help us update this texture's contents
+ pStreamHandler = new StreamHandler(pCamera,
+ 2, // number of buffers
+ useExternalMemory,
+ format,
+ streamCfg->width,
+ streamCfg->height);
} else {
pCamera =
IEvsCamera::castFrom(pEnum->openCamera(evsCameraId))
.withDefault(nullptr);
+
+ // Initialize the stream with the default resolution
+ pStreamHandler = new StreamHandler(pCamera,
+ 2, // number of buffers
+ useExternalMemory,
+ format);
}
- if (pCamera.get() == nullptr) {
+ if (pCamera == nullptr) {
LOG(ERROR) << "Failed to allocate new EVS Camera interface for " << evsCameraId;
return nullptr;
}
- // Initialize the stream that will help us update this texture's contents
- sp<StreamHandler> pStreamHandler = new StreamHandler(pCamera,
- 2, // number of buffers
- useExternalMemory,
- streamCfg->width,
- streamCfg->height);
- if (pStreamHandler.get() == nullptr) {
+ if (pStreamHandler == nullptr) {
LOG(ERROR) << "Failed to allocate FrameHandler";
return nullptr;
}
diff --git a/evs/apps/default/VideoTex.h b/evs/apps/default/VideoTex.h
index d884faa..097d086 100644
--- a/evs/apps/default/VideoTex.h
+++ b/evs/apps/default/VideoTex.h
@@ -16,6 +16,9 @@
#ifndef VIDEOTEX_H
#define VIDEOTEX_H
+#include "StreamHandler.h"
+#include "TexWrapper.h"
+
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES2/gl2.h>
@@ -25,9 +28,7 @@
#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
-
-#include "TexWrapper.h"
-#include "StreamHandler.h"
+#include <system/graphics-base.h>
using ::android::hardware::camera::device::V3_2::Stream;
using namespace ::android::hardware::automotive::evs::V1_1;
@@ -38,7 +39,8 @@
const char *evsCameraId,
std::unique_ptr<Stream> streamCfg,
EGLDisplay glDisplay,
- bool useExternalMemory);
+ bool useExternalMemory,
+ android_pixel_format_t format);
public:
VideoTex() = delete;
@@ -62,10 +64,13 @@
};
+// Creates a video texture to draw the camera preview. format is effective only
+// when useExternalMemory is true.
VideoTex* createVideoTexture(sp<IEvsEnumerator> pEnum,
const char * deviceName,
std::unique_ptr<Stream> streamCfg,
EGLDisplay glDisplay,
- bool useExternalMemory = false);
+ bool useExternalMemory = false,
+ android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888);
#endif // VIDEOTEX_H
diff --git a/evs/apps/default/evs_app.cpp b/evs/apps/default/evs_app.cpp
index a968990..9f2f2c8 100644
--- a/evs/apps/default/evs_app.cpp
+++ b/evs/apps/default/evs_app.cpp
@@ -14,24 +14,25 @@
* limitations under the License.
*/
+#include "ConfigManager.h"
+#include "EvsStateControl.h"
+#include "EvsVehicleListener.h"
+
#include <stdio.h>
+#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
+#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h> // arraysize
+#include <android-base/strings.h>
#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/ProcessState.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include <utils/Log.h>
-#include "android-base/macros.h" // arraysize
-#include "android-base/logging.h"
-#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
-#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
-
-#include <hwbinder/ProcessState.h>
-
-#include "EvsStateControl.h"
-#include "EvsVehicleListener.h"
-#include "ConfigManager.h"
+using android::base::EqualsIgnoreCase;
// libhidl:
using android::hardware::configureRpcThreadpool;
@@ -66,6 +67,24 @@
}
+static bool convertStringToFormat(const char* str, android_pixel_format_t* output) {
+ bool result = true;
+ if (EqualsIgnoreCase(str, "RGBA8888")) {
+ *output = HAL_PIXEL_FORMAT_RGBA_8888;
+ } else if (EqualsIgnoreCase(str, "YV12")) {
+ *output = HAL_PIXEL_FORMAT_YV12;
+ } else if (EqualsIgnoreCase(str, "NV21")) {
+ *output = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+ } else if (EqualsIgnoreCase(str, "YUYV")) {
+ *output = HAL_PIXEL_FORMAT_YCBCR_422_I;
+ } else {
+ result = false;
+ }
+
+ return result;
+}
+
+
// Main entry point
int main(int argc, char** argv)
{
@@ -77,6 +96,7 @@
const char* evsServiceName = "default";
int displayId = 1;
bool useExternalMemory = false;
+ android_pixel_format_t extMemoryFormat = HAL_PIXEL_FORMAT_RGBA_8888;
for (int i=1; i< argc; i++) {
if (strcmp(argv[i], "--test") == 0) {
useVehicleHal = false;
@@ -90,6 +110,19 @@
displayId = std::stoi(argv[++i]);
} else if (strcmp(argv[i], "--extmem") == 0) {
useExternalMemory = true;
+ if (i + 1 >= argc) {
+ // use RGBA8888 by default
+ LOG(INFO) << "External buffer format is not set. "
+ << "RGBA8888 will be used.";
+ } else {
+ if (!convertStringToFormat(argv[i + 1], &extMemoryFormat)) {
+ LOG(WARNING) << "Color format string " << argv[i + 1]
+ << " is unknown or not supported. RGBA8888 will be used.";
+ } else {
+ // move the index
+ ++i;
+ }
+ }
} else {
printf("Ignoring unrecognized command line arg '%s'\n", argv[i]);
printHelp = true;
@@ -97,11 +130,23 @@
}
if (printHelp) {
printf("Options include:\n");
- printf(" --test Do not talk to Vehicle Hal, but simulate 'reverse' instead\n");
- printf(" --hw Bypass EvsManager by connecting directly to EvsEnumeratorHw\n");
- printf(" --mock Connect directly to EvsEnumeratorHw-Mock\n");
- printf(" --display Specify the display to use\n");
- printf(" --extmem Application allocates buffers to capture camera frames\n");
+ printf(" --test\n\tDo not talk to Vehicle Hal, but simulate 'reverse' instead\n");
+ printf(" --hw\n\tBypass EvsManager by connecting directly to EvsEnumeratorHw\n");
+ printf(" --mock\n\tConnect directly to EvsEnumeratorHw-Mock\n");
+ printf(" --display\n\tSpecify the display to use\n");
+ printf(" --extmem <format>\n\t"
+ "Application allocates buffers to capture camera frames. "
+ "Available format strings are (case insensitive):\n");
+ printf("\t\tRGBA8888: 4x8-bit RGBA format. This is the default format to be used "
+ "when no format is specified.\n");
+ printf("\t\tYV12: YUV420 planar format with a full resolution Y plane "
+ "followed by a V values, with U values last.\n");
+ printf("\t\tNV21: A biplanar format with a full resolution Y plane "
+ "followed by a single chrome plane with weaved V and U values.\n");
+ printf("\t\tYUYV: Packed format with a half horizontal chrome resolution. "
+ "Known as YUV4:2:2.\n");
+
+ return EXIT_FAILURE;
}
// Load our configuration information
@@ -140,6 +185,7 @@
}
config.setActiveDisplayId(displayId);
config.useExternalMemory(useExternalMemory);
+ config.setExternalMemoryFormat(extMemoryFormat);
// Connect to the Vehicle HAL so we can monitor state
sp<IVehicle> pVnet;
diff --git a/evs/apps/demo_app_evs_support_lib/Android.bp b/evs/apps/demo_app_evs_support_lib/Android.bp
index 5380a4a..ae0073a 100644
--- a/evs/apps/demo_app_evs_support_lib/Android.bp
+++ b/evs/apps/demo_app_evs_support_lib/Android.bp
@@ -30,10 +30,6 @@
include_dirs: ["packages/services/Car/evs/support_library"],
- strip: {
- keep_symbols: true,
- },
-
init_rc: ["evs_app_support_lib.rc"],
cflags: ["-DLOG_TAG=\"EvsAppSupportLib\""] + [
diff --git a/evs/manager/1.0/Android.bp b/evs/manager/1.0/Android.bp
index 260e0b7..82bcdd8 100644
--- a/evs/manager/1.0/Android.bp
+++ b/evs/manager/1.0/Android.bp
@@ -39,10 +39,6 @@
init_rc: ["android.automotive.evs.manager@1.0.rc"],
- strip: {
- keep_symbols: true,
- },
-
cflags: ["-DLOG_TAG=\"EvsManagerV1_0\""] + [
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
diff --git a/evs/manager/1.1/Android.bp b/evs/manager/1.1/Android.bp
index 694aa06..891d615 100644
--- a/evs/manager/1.1/Android.bp
+++ b/evs/manager/1.1/Android.bp
@@ -20,35 +20,36 @@
name: "android.automotive.evs.manager@1.1",
srcs: [
- "service.cpp",
"Enumerator.cpp",
"HalCamera.cpp",
- "VirtualCamera.cpp",
"HalDisplay.cpp",
+ "VirtualCamera.cpp",
+ "service.cpp",
+ "stats/CameraUsageStats.cpp",
+ "stats/LooperWrapper.cpp",
+ "stats/StatsCollector.cpp",
"sync/unique_fd.cpp",
"sync/unique_fence.cpp",
"sync/unique_timeline.cpp",
],
shared_libs: [
- "libbase",
- "libcutils",
- "libutils",
- "libui",
- "libsync",
- "libhidlbase",
- "libhardware",
- "libcamera_metadata",
"android.hardware.automotive.evs@1.0",
"android.hardware.automotive.evs@1.1",
+ "libbase",
+ "libcamera_metadata",
+ "libcutils",
+ "libhardware",
+ "libhidlbase",
+ "libprocessgroup",
+ "libstatslog",
+ "libsync",
+ "libui",
+ "libutils",
],
init_rc: ["android.automotive.evs.manager@1.1.rc"],
- strip: {
- keep_symbols: true,
- },
-
cflags: ["-DLOG_TAG=\"EvsManagerV1_1\""] + [
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
diff --git a/evs/manager/1.1/Enumerator.cpp b/evs/manager/1.1/Enumerator.cpp
index 8417828..a86202e 100644
--- a/evs/manager/1.1/Enumerator.cpp
+++ b/evs/manager/1.1/Enumerator.cpp
@@ -14,22 +14,50 @@
* limitations under the License.
*/
-#include <android-base/parseint.h>
-#include <android-base/strings.h>
-#include <android-base/logging.h>
-#include <hwbinder/IPCThreadState.h>
-#include <cutils/android_filesystem_config.h>
-
#include "Enumerator.h"
#include "HalDisplay.h"
+#include <android-base/chrono_utils.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
+#include <cutils/android_filesystem_config.h>
+#include <hwbinder/IPCThreadState.h>
+
+namespace {
+
+ const char* kSingleIndent = "\t";
+ const char* kDumpOptionAll = "all";
+ const char* kDumpDeviceCamera = "camera";
+ const char* kDumpDeviceDisplay = "display";
+
+ const char* kDumpCameraCommandCurrent = "--current";
+ const char* kDumpCameraCommandCollected = "--collected";
+ const char* kDumpCameraCommandCustom = "--custom";
+ const char* kDumpCameraCommandCustomStart = "start";
+ const char* kDumpCameraCommandCustomStop = "stop";
+
+ const int kDumpCameraMinNumArgs = 4;
+ const int kOptionDumpDeviceTypeIndex = 1;
+ const int kOptionDumpCameraTypeIndex = 2;
+ const int kOptionDumpCameraCommandIndex = 3;
+ const int kOptionDumpCameraArgsStartIndex = 4;
+
+}
+
namespace android {
namespace automotive {
namespace evs {
namespace V1_1 {
namespace implementation {
+using ::android::base::Error;
using ::android::base::EqualsIgnoreCase;
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::base::WriteStringToFd;
using CameraDesc_1_0 = ::android::hardware::automotive::evs::V1_0::CameraDesc;
using CameraDesc_1_1 = ::android::hardware::automotive::evs::V1_1::CameraDesc;
@@ -43,15 +71,32 @@
// Get an internal display identifier.
mHwEnumerator->getDisplayIdList(
[this](const auto& displayPorts) {
- if (displayPorts.size() > 0) {
- mInternalDisplayPort = displayPorts[0];
- } else {
+ for (auto& port : displayPorts) {
+ mDisplayPorts.push_back(port);
+ }
+
+ // The first element is the internal display
+ mInternalDisplayPort = mDisplayPorts.front();
+ if (mDisplayPorts.size() < 1) {
LOG(WARNING) << "No display is available to EVS service.";
}
}
);
}
+ // Starts the statistics collection
+ mMonitorEnabled = false;
+ mClientsMonitor = new StatsCollector();
+ if (mClientsMonitor != nullptr) {
+ auto result = mClientsMonitor->startCollection();
+ if (!result.ok()) {
+ LOG(ERROR) << "Failed to start the usage monitor: "
+ << result.error();
+ } else {
+ mMonitorEnabled = true;
+ }
+ }
+
return result;
}
@@ -188,7 +233,10 @@
if (device == nullptr) {
LOG(ERROR) << "Failed to open hardware camera " << cameraId;
} else {
- hwCamera = new HalCamera(device, cameraId);
+ // Calculates the usage statistics record identifier
+ auto fn = mCameraDevices.hash_function();
+ auto recordId = fn(cameraId) & 0xFF;
+ hwCamera = new HalCamera(device, cameraId, recordId);
if (hwCamera == nullptr) {
LOG(ERROR) << "Failed to allocate camera wrapper object";
mHwEnumerator->closeCamera(device);
@@ -239,6 +287,9 @@
// NOTE: This should drop our last reference to the camera, resulting in its
// destruction.
mActiveCameras.erase(halCamera->getId());
+ if (mMonitorEnabled) {
+ mClientsMonitor->unregisterClientToMonitor(halCamera->getId());
+ }
}
}
@@ -277,7 +328,10 @@
success = false;
break;
} else {
- hwCamera = new HalCamera(device, id, streamCfg);
+ // Calculates the usage statistics record identifier
+ auto fn = mCameraDevices.hash_function();
+ auto recordId = fn(id) & 0xFF;
+ hwCamera = new HalCamera(device, id, recordId, streamCfg);
if (hwCamera == nullptr) {
LOG(ERROR) << "Failed to allocate camera wrapper object";
mHwEnumerator->closeCamera(device);
@@ -295,6 +349,10 @@
// Add the hardware camera to our list, which will keep it alive via ref count
mActiveCameras.try_emplace(id, hwCamera);
+ if (mMonitorEnabled) {
+ mClientsMonitor->registerClientToMonitor(hwCamera);
+ }
+
sourceCameras.push_back(hwCamera);
} else {
if (it->second->getStreamConfig().id != streamCfg.id) {
@@ -392,7 +450,7 @@
// TODO: Because of b/129284474, an additional class, HalDisplay, has been defined and
// wraps the IEvsDisplay object the driver returns. We may want to remove this
// additional class when it is fixed properly.
- sp<IEvsDisplay_1_0> pHalDisplay = new HalDisplay(pActiveDisplay);
+ sp<IEvsDisplay_1_0> pHalDisplay = new HalDisplay(pActiveDisplay, mInternalDisplayPort);
mActiveDisplay = pHalDisplay;
return pHalDisplay;
@@ -444,6 +502,11 @@
return nullptr;
}
+ if (std::find(mDisplayPorts.begin(), mDisplayPorts.end(), id) == mDisplayPorts.end()) {
+ LOG(ERROR) << "No display is available on the port " << static_cast<int32_t>(id);
+ return nullptr;
+ }
+
// We simply keep track of the most recently opened display instance.
// In the underlying layers we expect that a new open will cause the previous
// object to be destroyed. This avoids any race conditions associated with
@@ -462,7 +525,7 @@
// TODO: Because of b/129284474, an additional class, HalDisplay, has been defined and
// wraps the IEvsDisplay object the driver returns. We may want to remove this
// additional class when it is fixed properly.
- sp<IEvsDisplay_1_1> pHalDisplay = new HalDisplay(pActiveDisplay);
+ sp<IEvsDisplay_1_1> pHalDisplay = new HalDisplay(pActiveDisplay, id);
mActiveDisplay = pHalDisplay;
return pHalDisplay;
@@ -504,7 +567,7 @@
if (fd.getNativeHandle() != nullptr && fd->numFds > 0) {
cmdDump(fd->data[0], options);
} else {
- LOG(ERROR) << "Invalid parameters";
+ LOG(ERROR) << "Given file descriptor is not valid.";
}
return {};
@@ -513,7 +576,8 @@
void Enumerator::cmdDump(int fd, const hidl_vec<hidl_string>& options) {
if (options.size() == 0) {
- dprintf(fd, "No option is given");
+ WriteStringToFd("No option is given.\n", fd);
+ cmdHelp(fd);
return;
}
@@ -525,19 +589,27 @@
} else if (EqualsIgnoreCase(option, "--dump")) {
cmdDumpDevice(fd, options);
} else {
- dprintf(fd, "Invalid option: %s\n", option.c_str());
+ WriteStringToFd(StringPrintf("Invalid option: %s\n", option.c_str()),
+ fd);
}
}
void Enumerator::cmdHelp(int fd) {
- dprintf(fd, "Usage: \n\n");
- dprintf(fd, "--help: shows this help.\n");
- dprintf(fd, "--list [all|camera|display]: list camera or display devices or both "
- "available to EVS manager.\n");
- dprintf(fd, "--dump [all|camera|display] <device id>: "
- "show current status of the target device or all devices "
- "when no device is given.\n");
+ WriteStringToFd("Usage: \n\n"
+ "--help: shows this help.\n"
+ "--list [all|camera|display]: lists camera or display devices or both "
+ "available to EVS manager.\n"
+ "--dump camera [all|device_id] --[current|collected|custom] [args]\n"
+ "\tcurrent: shows the current status\n"
+ "\tcollected: shows 10 most recent periodically collected camera usage "
+ "statistics\n"
+ "\tcustom: starts/stops collecting the camera usage statistics\n"
+ "\t\tstart [interval] [duration]: starts collecting usage statistics "
+ "at every [interval] during [duration]. Interval and duration are in "
+ "milliseconds.\n"
+ "\t\tstop: stops collecting usage statistics and shows collected records.\n"
+ "--dump display: shows current status of the display\n", fd);
}
@@ -546,18 +618,25 @@
bool listDisplays = true;
if (options.size() > 1) {
const std::string option = options[1];
- const bool listAll = EqualsIgnoreCase(option, "all");
- listCameras = listAll || EqualsIgnoreCase(option, "camera");
- listDisplays = listAll || EqualsIgnoreCase(option, "display");
+ const bool listAll = EqualsIgnoreCase(option, kDumpOptionAll);
+ listCameras = listAll || EqualsIgnoreCase(option, kDumpDeviceCamera);
+ listDisplays = listAll || EqualsIgnoreCase(option, kDumpDeviceDisplay);
if (!listCameras && !listDisplays) {
- dprintf(fd, "Unrecognized option, %s, is ignored.\n", option.c_str());
+ WriteStringToFd(StringPrintf("Unrecognized option, %s, is ignored.\n",
+ option.c_str()),
+ fd);
+
+ // Nothing to show, return
+ return;
}
}
+ std::string buffer;
if (listCameras) {
- dprintf(fd, "Camera devices available to EVS service:\n");
+ StringAppendF(&buffer,"Camera devices available to EVS service:\n");
if (mCameraDevices.size() < 1) {
- // Camera devices may not be enumerated yet.
+ // Camera devices may not be enumerated yet. This may fail if the
+ // user is not permitted to use EVS service.
getCameraList_1_1(
[](const auto cameras) {
if (cameras.size() < 1) {
@@ -567,62 +646,203 @@
}
for (auto& [id, desc] : mCameraDevices) {
- dprintf(fd, "\t%s\n", id.c_str());
+ StringAppendF(&buffer, "%s%s\n", kSingleIndent, id.c_str());
}
- dprintf(fd, "\nCamera devices currently in use:\n");
+ StringAppendF(&buffer, "%sCamera devices currently in use:\n", kSingleIndent);
for (auto& [id, ptr] : mActiveCameras) {
- dprintf(fd, "\t%s\n", id.c_str());
+ StringAppendF(&buffer, "%s%s\n", kSingleIndent, id.c_str());
}
- dprintf(fd, "\n");
+ StringAppendF(&buffer, "\n");
}
if (listDisplays) {
if (mHwEnumerator != nullptr) {
- dprintf(fd, "Display devices available to EVS service:\n");
+ StringAppendF(&buffer, "Display devices available to EVS service:\n");
// Get an internal display identifier.
mHwEnumerator->getDisplayIdList(
[&](const auto& displayPorts) {
- for (auto& port : displayPorts) {
- dprintf(fd, "\tdisplay port %u\n", (unsigned)port);
+ for (auto&& port : displayPorts) {
+ StringAppendF(&buffer, "%sdisplay port %u\n",
+ kSingleIndent,
+ static_cast<unsigned>(port));
}
}
);
+ } else {
+ LOG(WARNING) << "EVS HAL implementation is not available.";
}
}
+
+ WriteStringToFd(buffer, fd);
}
void Enumerator::cmdDumpDevice(int fd, const hidl_vec<hidl_string>& options) {
+ // Dumps both cameras and displays if the target device type is not given
bool dumpCameras = true;
bool dumpDisplays = true;
- if (options.size() > 1) {
- const std::string option = options[1];
- const bool dumpAll = EqualsIgnoreCase(option, "all");
- dumpCameras = dumpAll || EqualsIgnoreCase(option, "camera");
- dumpDisplays = dumpAll || EqualsIgnoreCase(option, "display");
+ const auto numOptions = options.size();
+ if (numOptions > kOptionDumpDeviceTypeIndex) {
+ const std::string target = options[kOptionDumpDeviceTypeIndex];
+ const bool dumpAll = EqualsIgnoreCase(target, kDumpOptionAll);
+ dumpCameras = dumpAll || EqualsIgnoreCase(target, kDumpDeviceCamera);
+ dumpDisplays = dumpAll || EqualsIgnoreCase(target, kDumpDeviceDisplay);
if (!dumpCameras && !dumpDisplays) {
- dprintf(fd, "Unrecognized option, %s, is ignored.\n", option.c_str());
+ WriteStringToFd(StringPrintf("Unrecognized option, %s, is ignored.\n",
+ target.c_str()),
+ fd);
+ return;
}
}
if (dumpCameras) {
- const bool dumpAllCameras = options.size() < 3;
- std::string deviceId = "";
- if (!dumpAllCameras) {
- deviceId = options[2];
+ // --dump camera [all|device_id] --[current|collected|custom] [args]
+ if (numOptions < kDumpCameraMinNumArgs) {
+ WriteStringToFd(StringPrintf("Necessary arguments are missing. "
+ "Please check the usages:\n"),
+ fd);
+ cmdHelp(fd);
+ return;
}
- for (auto& [id, ptr] : mActiveCameras) {
- if (!dumpAllCameras && !EqualsIgnoreCase(id, deviceId)) {
- continue;
- }
- ptr->dump(fd);
+ const std::string deviceId = options[kOptionDumpCameraTypeIndex];
+ auto target = mActiveCameras.find(deviceId);
+ const bool dumpAllCameras = EqualsIgnoreCase(deviceId,
+ kDumpOptionAll);
+ if (!dumpAllCameras && target == mActiveCameras.end()) {
+ // Unknown camera identifier
+ WriteStringToFd(StringPrintf("Given camera ID %s is unknown or not active.\n",
+ deviceId.c_str()),
+ fd);
+ return;
}
+
+ const std::string command = options[kOptionDumpCameraCommandIndex];
+ std::string cameraInfo;
+ if (EqualsIgnoreCase(command, kDumpCameraCommandCurrent)) {
+ // Active stream configuration from each active HalCamera objects
+ if (!dumpAllCameras) {
+ StringAppendF(&cameraInfo, "HalCamera: %s\n%s",
+ deviceId.c_str(),
+ target->second->toString(kSingleIndent).c_str());
+ } else {
+ for (auto&& [id, handle] : mActiveCameras) {
+ // Appends the current status
+ cameraInfo += handle->toString(kSingleIndent);
+ }
+ }
+ } else if (EqualsIgnoreCase(command, kDumpCameraCommandCollected)) {
+ // Reads the usage statistics from active HalCamera objects
+ std::unordered_map<std::string, std::string> usageStrings;
+ if (mMonitorEnabled) {
+ auto result = mClientsMonitor->toString(&usageStrings, kSingleIndent);
+ if (!result.ok()) {
+ LOG(ERROR) << "Failed to get the monitoring result";
+ return;
+ }
+
+ if (!dumpAllCameras) {
+ cameraInfo += usageStrings[deviceId];
+ } else {
+ for (auto&& [id, stats] : usageStrings) {
+ cameraInfo += stats;
+ }
+ }
+ } else {
+ WriteStringToFd(StringPrintf("Client monitor is not available.\n"),
+ fd);
+ return;
+ }
+ } else if (EqualsIgnoreCase(command, kDumpCameraCommandCustom)) {
+ // Additional arguments are expected for this command:
+ // --dump camera device_id --custom start [interval] [duration]
+ // or, --dump camera device_id --custom stop
+ if (numOptions < kDumpCameraMinNumArgs + 1) {
+ WriteStringToFd(StringPrintf("Necessary arguments are missing. "
+ "Please check the usages:\n"),
+ fd);
+ cmdHelp(fd);
+ return;
+ }
+
+ if (!mMonitorEnabled) {
+ WriteStringToFd(StringPrintf("Client monitor is not available."), fd);
+ return;
+ }
+
+ const std::string subcommand = options[kOptionDumpCameraArgsStartIndex];
+ if (EqualsIgnoreCase(subcommand, kDumpCameraCommandCustomStart)) {
+ using std::chrono::nanoseconds;
+ using std::chrono::milliseconds;
+ using std::chrono::duration_cast;
+ nanoseconds interval = 0ns;
+ nanoseconds duration = 0ns;
+ if (numOptions > kOptionDumpCameraArgsStartIndex + 2) {
+ duration = duration_cast<nanoseconds>(
+ milliseconds(
+ std::stoi(options[kOptionDumpCameraArgsStartIndex + 2])
+ ));
+ }
+
+ if (numOptions > kOptionDumpCameraArgsStartIndex + 1) {
+ interval = duration_cast<nanoseconds>(
+ milliseconds(
+ std::stoi(options[kOptionDumpCameraArgsStartIndex + 1])
+ ));
+ }
+
+ // Starts a custom collection
+ auto result = mClientsMonitor->startCustomCollection(interval, duration);
+ if (!result) {
+ LOG(ERROR) << "Failed to start a custom collection. "
+ << result.error();
+ StringAppendF(&cameraInfo, "Failed to start a custom collection. %s\n",
+ result.error().message().c_str());
+ }
+ } else if (EqualsIgnoreCase(subcommand, kDumpCameraCommandCustomStop)) {
+ if (!mMonitorEnabled) {
+ WriteStringToFd(StringPrintf("Client monitor is not available."), fd);
+ return;
+ }
+
+ auto result = mClientsMonitor->stopCustomCollection(deviceId);
+ if (!result) {
+ LOG(ERROR) << "Failed to stop a custom collection. "
+ << result.error();
+ StringAppendF(&cameraInfo, "Failed to stop a custom collection. %s\n",
+ result.error().message().c_str());
+ } else {
+ // Pull the custom collection
+ cameraInfo += *result;
+ }
+ } else {
+ WriteStringToFd(StringPrintf("Unknown argument: %s\n",
+ subcommand.c_str()),
+ fd);
+ cmdHelp(fd);
+ return;
+ }
+ } else {
+ WriteStringToFd(StringPrintf("Unknown command: %s\n"
+ "Please check the usages:\n", command.c_str()),
+ fd);
+ cmdHelp(fd);
+ return;
+ }
+
+ // Outputs the report
+ WriteStringToFd(cameraInfo, fd);
}
if (dumpDisplays) {
- dprintf(fd, "Not implemented yet\n");
+ HalDisplay* pDisplay =
+ reinterpret_cast<HalDisplay*>(mActiveDisplay.promote().get());
+ if (!pDisplay) {
+ WriteStringToFd("No active display is found.\n", fd);
+ } else {
+ WriteStringToFd(pDisplay->toString(kSingleIndent), fd);
+ }
}
}
diff --git a/evs/manager/1.1/Enumerator.h b/evs/manager/1.1/Enumerator.h
index f23871e..7708295 100644
--- a/evs/manager/1.1/Enumerator.h
+++ b/evs/manager/1.1/Enumerator.h
@@ -17,13 +17,14 @@
#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
#define ANDROID_AUTOMOTIVE_EVS_V1_1_EVSCAMERAENUMERATOR_H
+#include "HalCamera.h"
+#include "VirtualCamera.h"
+#include "stats/StatsCollector.h"
+
#include <list>
#include <unordered_map>
#include <unordered_set>
-#include "HalCamera.h"
-#include "VirtualCamera.h"
-
#include <android/hardware/automotive/evs/1.1/IEvsEnumerator.h>
#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
@@ -93,9 +94,18 @@
std::unordered_map<std::string,
CameraDesc> mCameraDevices;
+ // List of available physical display devices
+ std::list<uint8_t> mDisplayPorts;
+
// Display port the internal display is connected to.
uint8_t mInternalDisplayPort;
+ // Collecting camera usage statistics from clients
+ sp<StatsCollector> mClientsMonitor;
+
+ // Boolean flag to tell whether the camera usages are being monitored or not
+ bool mMonitorEnabled;
+
// LSHAL dump
void cmdDump(int fd, const hidl_vec<hidl_string>& options);
void cmdHelp(int fd);
diff --git a/evs/manager/1.1/HalCamera.cpp b/evs/manager/1.1/HalCamera.cpp
index f0ae13d..a90e83b 100644
--- a/evs/manager/1.1/HalCamera.cpp
+++ b/evs/manager/1.1/HalCamera.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
-
+#include "Enumerator.h"
#include "HalCamera.h"
#include "VirtualCamera.h"
-#include "Enumerator.h"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/strings.h>
namespace android {
namespace automotive {
@@ -30,6 +32,15 @@
// TODO(changyeon):
// We need to hook up death monitoring to detect stream death so we can attempt a reconnect
+using ::android::base::StringAppendF;
+using ::android::base::WriteStringToFd;
+
+HalCamera::~HalCamera() {
+ // Reports the usage statistics before the destruction
+ // EvsUsageStatsReported atom is defined in
+ // frameworks/base/cmds/statsd/src/atoms.proto
+ mUsageStats->writeStats();
+}
sp<VirtualCamera> HalCamera::makeVirtualCamera() {
@@ -310,6 +321,9 @@
if (mFrames[i].refCount <= 0) {
// Since all our clients are done with this buffer, return it to the device layer
mHwCamera->doneWithFrame(buffer);
+
+ // Counts a returned buffer
+ mUsageStats->framesReturned();
}
}
@@ -336,6 +350,9 @@
returnedBuffers.resize(1);
returnedBuffers[0] = buffer;
mHwCamera->doneWithFrame_1_1(returnedBuffers);
+
+ // Counts a returned buffer
+ mUsageStats->framesReturned();
}
}
@@ -352,6 +369,10 @@
LOG(INFO) << "A delivered frame from EVS v1.0 HW module is rejected.";
mHwCamera->doneWithFrame(buffer);
+ // Reports a received and returned buffer
+ mUsageStats->framesReceived();
+ mUsageStats->framesReturned();
+
return Void();
}
@@ -378,7 +399,9 @@
// Skip current frame because it arrives too soon.
LOG(DEBUG) << "Skips a frame from " << getId();
mNextRequests->push_back(req);
- ++mSyncFrames;
+
+ // Reports a skipped frame
+ mUsageStats->framesSkippedToSync();
} else if (vCam != nullptr && vCam->deliverFrame(buffer[0])) {
// Forward a frame and move a timeline.
LOG(DEBUG) << getId() << " forwarded the buffer #" << buffer[0].bufferId;
@@ -387,7 +410,9 @@
}
}
}
- ++mFramesReceived;
+
+ // Reports the number of received buffers
+ mUsageStats->framesReceived(buffer.size());
// Frames are being forwarded to active v1.0 clients and v1.1 clients if we
// failed to create a timeline.
@@ -409,8 +434,10 @@
// right away.
LOG(INFO) << "Trivially rejecting frame (" << buffer[0].bufferId
<< ") from " << getId() << " with no acceptance";
- ++mFramesNotUsed;
mHwCamera->doneWithFrame_1_1(buffer);
+
+ // Reports a returned buffer
+ mUsageStats->framesReturned();
} else {
// Add an entry for this frame in our tracking list.
unsigned i;
@@ -559,47 +586,68 @@
}
-void HalCamera::dump(int fd) const {
- dprintf(fd, "HalCamera: %s\n", mId.c_str());
- const auto timeElapsedNano = android::elapsedRealtimeNano() - mTimeCreated;
- dprintf(fd, "\tCreated: %ld (elapsed %ld ns)\n", (long)mTimeCreated, (long)timeElapsedNano);
- dprintf(fd, "\tFrames received: %lu (%f fps)\n",
- (unsigned long)mFramesReceived,
- (double)mFramesReceived / timeElapsedNano * 1e+9);
- dprintf(fd, "\tFrames not used: %lu\n", (unsigned long)mFramesNotUsed);
- dprintf(fd, "\tFrames skipped to sync: %lu\n", (unsigned long)mSyncFrames);
- dprintf(fd, "\tActive Stream Configuration:\n");
- dprintf(fd, "\t\tid: %d\n", mStreamConfig.id);
- dprintf(fd, "\t\twidth: %d\n", mStreamConfig.width);
- dprintf(fd, "\t\theight: %d\n", mStreamConfig.height);
- dprintf(fd, "\t\tformat: %d\n", mStreamConfig.width);
- dprintf(fd, "\t\tusage: 0x%lX\n", (unsigned long)mStreamConfig.usage);
- dprintf(fd, "\t\trotation: 0x%X\n", mStreamConfig.rotation);
+CameraUsageStatsRecord HalCamera::getStats() const {
+ return mUsageStats->snapshot();
+}
- dprintf(fd, "\tActive clients:\n");
+
+Stream HalCamera::getStreamConfiguration() const {
+ return mStreamConfig;
+}
+
+
+std::string HalCamera::toString(const char* indent) const {
+ std::string buffer;
+
+ const auto timeElapsedMs = android::uptimeMillis() - mTimeCreatedMs;
+ StringAppendF(&buffer, "%sCreated: @%" PRId64 " (elapsed %" PRId64 " ms)\n",
+ indent, mTimeCreatedMs, timeElapsedMs);
+
+ std::string double_indent(indent);
+ double_indent += indent;
+ buffer += CameraUsageStats::toString(getStats(), double_indent.c_str());
for (auto&& client : mClients) {
auto handle = client.promote();
if (!handle) {
continue;
}
- dprintf(fd, "\t\tClient %p\n", handle.get());
- handle->dump(fd, "\t\t\t");
- {
- std::scoped_lock<std::mutex> lock(mFrameMutex);
- dprintf(fd, "\t\t\tUse a fence-based delivery: %s\n",
- mTimelines.find((uint64_t)handle.get()) != mTimelines.end() ? "T" : "F");
- }
+ StringAppendF(&buffer, "%sClient %p\n",
+ indent, handle.get());
+ buffer += handle->toString(double_indent.c_str());
}
- dprintf(fd, "\tMaster client: %p\n", mMaster.promote().get());
- dprintf(fd, "\tSynchronization support: %s\n", mSyncSupported ? "T" : "F");
+ StringAppendF(&buffer, "%sMaster client: %p\n"
+ "%sSynchronization support: %s\n",
+ indent, mMaster.promote().get(),
+ indent, mSyncSupported ? "T":"F");
+
+ buffer += HalCamera::toString(mStreamConfig, indent);
+
+ return buffer;
}
-double HalCamera::getFramerate() const {
- const auto timeElapsed = android::elapsedRealtimeNano() - mTimeCreated;
- return static_cast<double>(mFramesReceived) / timeElapsed;
+std::string HalCamera::toString(Stream configuration, const char* indent) {
+ std::string streamInfo;
+ std::string double_indent(indent);
+ double_indent += indent;
+ StringAppendF(&streamInfo, "%sActive Stream Configuration\n"
+ "%sid: %d\n"
+ "%swidth: %d\n"
+ "%sheight: %d\n"
+ "%sformat: 0x%X\n"
+ "%susage: 0x%" PRIx64 "\n"
+ "%srotation: 0x%X\n\n",
+ indent,
+ double_indent.c_str(), configuration.id,
+ double_indent.c_str(), configuration.width,
+ double_indent.c_str(), configuration.height,
+ double_indent.c_str(), configuration.format,
+ double_indent.c_str(), configuration.usage,
+ double_indent.c_str(), configuration.rotation);
+
+ return streamInfo;
}
diff --git a/evs/manager/1.1/HalCamera.h b/evs/manager/1.1/HalCamera.h
index 240737e..7e010a6 100644
--- a/evs/manager/1.1/HalCamera.h
+++ b/evs/manager/1.1/HalCamera.h
@@ -17,20 +17,21 @@
#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_HALCAMERA_H
#define ANDROID_AUTOMOTIVE_EVS_V1_1_HALCAMERA_H
-#include <android/hardware/automotive/evs/1.1/types.h>
-#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
-#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
-#include <utils/Mutex.h>
-#include <utils/SystemClock.h>
+#include "stats/CameraUsageStats.h"
+#include "sync/unique_fd.h"
+#include "sync/unique_fence.h"
+#include "sync/unique_timeline.h"
#include <deque>
#include <list>
#include <thread>
#include <unordered_map>
-#include "sync/unique_fd.h"
-#include "sync/unique_fence.h"
-#include "sync/unique_timeline.h"
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCamera.h>
+#include <android/hardware/automotive/evs/1.1/IEvsCameraStream.h>
+#include <utils/Mutex.h>
+#include <utils/SystemClock.h>
using namespace ::android::hardware::automotive::evs::V1_1;
using ::android::hardware::camera::device::V3_2::Stream;
@@ -60,19 +61,22 @@
// stream from the hardware camera and distribute it to the associated VirtualCamera objects.
class HalCamera : public IEvsCameraStream_1_1 {
public:
- HalCamera(sp<IEvsCamera_1_1> hwCamera, std::string deviceId = "", Stream cfg = {})
+ HalCamera(sp<IEvsCamera_1_1> hwCamera,
+ std::string deviceId = "",
+ int32_t recordId = 0,
+ Stream cfg = {})
: mHwCamera(hwCamera),
mId(deviceId),
mStreamConfig(cfg),
mSyncSupported(UniqueTimeline::Supported()),
- mTimeCreated(android::elapsedRealtimeNano()),
- mFramesReceived(0),
- mFramesNotUsed(0),
- mSyncFrames(0) {
+ mTimeCreatedMs(android::uptimeMillis()),
+ mUsageStats(new CameraUsageStats(recordId)) {
mCurrentRequests = &mFrameRequests[0];
mNextRequests = &mFrameRequests[1];
}
+ virtual ~HalCamera();
+
// Factory methods for client VirtualCameras
sp<VirtualCamera> makeVirtualCamera();
bool ownVirtualCamera(sp<VirtualCamera> virtualCamera);
@@ -101,8 +105,17 @@
Return<EvsResult> getParameter(CameraParam id, int32_t& value);
bool isSyncSupported() const { return mSyncSupported; }
- void dump(int fd) const;
- double getFramerate() const;
+ // Returns a snapshot of collected usage statistics
+ CameraUsageStatsRecord getStats() const;
+
+ // Returns active stream configuration
+ Stream getStreamConfiguration() const;
+
+ // Returns a string showing the current status
+ std::string toString(const char* indent = "") const;
+
+ // Returns a string showing current stream configuration
+ static std::string toString(Stream configuration, const char* indent = "");
// Methods from ::android::hardware::automotive::evs::V1_0::IEvsCameraStream follow.
Return<void> deliverFrame(const BufferDesc_1_0& buffer) override;
@@ -145,11 +158,11 @@
std::unique_ptr<UniqueTimeline>> mTimelines GUARDED_BY(mFrameMutex);
bool mSyncSupported;
- // debugging information
- int64_t mTimeCreated;
- uint64_t mFramesReceived;
- uint64_t mFramesNotUsed;
- uint64_t mSyncFrames;
+ // Time this object was created
+ int64_t mTimeCreatedMs;
+
+ // usage statistics to collect
+ android::sp<CameraUsageStats> mUsageStats;
};
} // namespace implementation
diff --git a/evs/manager/1.1/HalDisplay.cpp b/evs/manager/1.1/HalDisplay.cpp
index 4f7b4fd..b1e1aa6 100644
--- a/evs/manager/1.1/HalDisplay.cpp
+++ b/evs/manager/1.1/HalDisplay.cpp
@@ -14,17 +14,26 @@
* limitations under the License.
*/
-#include <android-base/logging.h>
#include "HalDisplay.h"
+#include <inttypes.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <ui/DisplayConfig.h>
+#include <ui/DisplayState.h>
+
+using android::base::StringAppendF;
+
namespace android {
namespace automotive {
namespace evs {
namespace V1_1 {
namespace implementation {
-HalDisplay::HalDisplay(sp<IEvsDisplay_1_0> display) :
- mHwDisplay(display) {
+HalDisplay::HalDisplay(sp<IEvsDisplay_1_0> display, int32_t id) :
+ mHwDisplay(display),
+ mId(id) {
// nothing to do.
}
@@ -114,6 +123,38 @@
return Void();
}
+
+std::string HalDisplay::toString(const char* indent) {
+ std::string buffer;
+ android::DisplayConfig displayConfig;
+ android::ui::DisplayState displayState;
+
+ if (mId == std::numeric_limits<int32_t>::min()) {
+ // Display identifier has not set
+ StringAppendF(&buffer, "HalDisplay: Display port is unknown.\n");
+ } else {
+ StringAppendF(&buffer, "HalDisplay: Display port %" PRId32 "\n", mId);
+ }
+
+ getDisplayInfo_1_1([&](auto& config, auto& state) {
+ displayConfig =
+ *(reinterpret_cast<const android::DisplayConfig*>(config.data()));
+ displayState =
+ *(reinterpret_cast<const android::ui::DisplayState*>(state.data()));
+ });
+
+ StringAppendF(&buffer, "%sWidth: %" PRId32 "\n",
+ indent, displayConfig.resolution.getWidth());
+ StringAppendF(&buffer, "%sHeight: %" PRId32 "\n",
+ indent, displayConfig.resolution.getHeight());
+ StringAppendF(&buffer, "%sRefresh rate: %f\n",
+ indent, displayConfig.refreshRate);
+ StringAppendF(&buffer, "%sRotation: %" PRId32 "\n",
+ indent, static_cast<int32_t>(displayState.orientation));
+
+ return buffer;
+}
+
} // namespace implementation
} // namespace V1_1
} // namespace evs
diff --git a/evs/manager/1.1/HalDisplay.h b/evs/manager/1.1/HalDisplay.h
index de9690b..672ad55 100644
--- a/evs/manager/1.1/HalDisplay.h
+++ b/evs/manager/1.1/HalDisplay.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_DISPLAYPROXY_H
#define ANDROID_AUTOMOTIVE_EVS_V1_1_DISPLAYPROXY_H
+#include <limits>
+
#include <android/hardware/automotive/evs/1.1/types.h>
#include <android/hardware/automotive/evs/1.1/IEvsDisplay.h>
@@ -42,7 +44,8 @@
// manager directly to use the IEvsDisplay object the driver provides.
class HalDisplay : public IEvsDisplay_1_1 {
public:
- explicit HalDisplay(sp<IEvsDisplay_1_0> display);
+ explicit HalDisplay(sp<IEvsDisplay_1_0> display,
+ int32_t port = std::numeric_limits<int32_t>::min());
virtual ~HalDisplay() override;
inline void shutdown();
@@ -58,8 +61,12 @@
// Methods from ::android::hardware::automotive::evs::V1_1::IEvsDisplay follow.
Return<void> getDisplayInfo_1_1(getDisplayInfo_1_1_cb _info_cb) override;
+ // Returns a string showing the current status
+ std::string toString(const char* indent = "");
+
private:
sp<IEvsDisplay_1_0> mHwDisplay; // The low level display interface that backs this proxy
+ int32_t mId; // Display identifier
};
} // namespace implementation
diff --git a/evs/manager/1.1/VirtualCamera.cpp b/evs/manager/1.1/VirtualCamera.cpp
index 09c6804..8b94a15 100644
--- a/evs/manager/1.1/VirtualCamera.cpp
+++ b/evs/manager/1.1/VirtualCamera.cpp
@@ -14,13 +14,18 @@
* limitations under the License.
*/
-#include <android/hardware_buffer.h>
-#include <android-base/logging.h>
-
#include "VirtualCamera.h"
#include "HalCamera.h"
#include "Enumerator.h"
+#include <android/hardware_buffer.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+using ::android::base::StringAppendF;
+using ::android::base::StringPrintf;
+using ::android::base::WriteStringToFd;
using ::android::hardware::automotive::evs::V1_0::DisplayState;
@@ -893,15 +898,27 @@
}
-void VirtualCamera::dump(int fd, const char* prefix) const {
- dprintf(fd, "%sLogical camera device: %s\n",
- prefix, mHalCamera.size() > 1 ? "T" : "F");
- dprintf(fd, "%sFramesAllowed: %u\n", prefix, mFramesAllowed);
- dprintf(fd, "%sFrames in use:\n", prefix);
+std::string VirtualCamera::toString(const char* indent) const {
+ std::string buffer;
+ StringAppendF(&buffer, "%sLogical camera device: %s\n"
+ "%sFramesAllowed: %u\n"
+ "%sFrames in use:\n",
+ indent, mHalCamera.size() > 1 ? "T" : "F",
+ indent, mFramesAllowed,
+ indent);
+
+ std::string next_indent(indent);
+ next_indent += "\t";
for (auto&& [id, queue] : mFramesHeld) {
- dprintf(fd, "%s\t%s, %d\n", prefix, id.c_str(), (int)queue.size());
+ StringAppendF(&buffer, "%s%s: %d\n",
+ next_indent.c_str(),
+ id.c_str(),
+ static_cast<int>(queue.size()));
}
- dprintf(fd, "%sCurrent stream state: %d\n", prefix, mStreamState);
+ StringAppendF(&buffer, "%sCurrent stream state: %d\n",
+ indent, mStreamState);
+
+ return buffer;
}
diff --git a/evs/manager/1.1/VirtualCamera.h b/evs/manager/1.1/VirtualCamera.h
index e57ddcf..76a8648 100644
--- a/evs/manager/1.1/VirtualCamera.h
+++ b/evs/manager/1.1/VirtualCamera.h
@@ -108,7 +108,7 @@
importExternalBuffers_cb _hidl_cb) override;
// Dump current status to a given file descriptor
- void dump(int fd, const char* prefix = "") const;
+ std::string toString(const char* indent = "") const;
private:
diff --git a/evs/manager/1.1/stats/CameraUsageStats.cpp b/evs/manager/1.1/stats/CameraUsageStats.cpp
new file mode 100644
index 0000000..11f8229
--- /dev/null
+++ b/evs/manager/1.1/stats/CameraUsageStats.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 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 "CameraUsageStats.h"
+
+#include <statslog.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+using ::android::base::Result;
+using ::android::base::StringAppendF;
+
+
+void CameraUsageStats::framesReceived(int n) {
+ AutoMutex lock(mMutex);
+ mStats.framesReceived += n;
+}
+
+
+void CameraUsageStats::framesReturned(int n) {
+ AutoMutex lock(mMutex);
+ mStats.framesReturned += n;
+}
+
+
+void CameraUsageStats::framesIgnored(int n) {
+ AutoMutex lock(mMutex);
+ mStats.framesIgnored += n;
+}
+
+
+void CameraUsageStats::framesSkippedToSync(int n) {
+ AutoMutex lock(mMutex);
+ mStats.framesSkippedToSync += n;
+}
+
+
+void CameraUsageStats::eventsReceived() {
+ AutoMutex lock(mMutex);
+ ++mStats.erroneousEventsCount;
+}
+
+
+int64_t CameraUsageStats::getTimeCreated() const {
+ AutoMutex lock(mMutex);
+ return mTimeCreatedMs;
+}
+
+
+int64_t CameraUsageStats::getFramesReceived() const {
+ AutoMutex lock(mMutex);
+ return mStats.framesReceived;
+}
+
+
+int64_t CameraUsageStats::getFramesReturned() const {
+ AutoMutex lock(mMutex);
+ return mStats.framesReturned;
+}
+
+
+CameraUsageStatsRecord CameraUsageStats::snapshot() const {
+ AutoMutex lock(mMutex);
+ return mStats;
+}
+
+
+Result<void> CameraUsageStats::writeStats() const {
+ AutoMutex lock(mMutex);
+ const auto duration = android::uptimeMillis() - mTimeCreatedMs;
+ // TODO(b/156131016): calculates and reports frame roundtrip latencies
+ android::util::stats_write(android::util::EVS_USAGE_STATS_REPORTED,
+ mId,
+ mStats.peakClientsCount,
+ mStats.erroneousEventsCount,
+ mStats.framesFirstRoundtripLatency,
+ mStats.framesAvgRoundtripLatency,
+ mStats.framesPeakRoundtripLatency,
+ mStats.framesReceived,
+ mStats.framesIgnored,
+ mStats.framesSkippedToSync,
+ duration);
+ return {};
+}
+
+
+std::string CameraUsageStats::toString(const CameraUsageStatsRecord& record, const char* indent) {
+ return record.toString(indent);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
diff --git a/evs/manager/1.1/stats/CameraUsageStats.h b/evs/manager/1.1/stats/CameraUsageStats.h
new file mode 100644
index 0000000..4bc4ea8
--- /dev/null
+++ b/evs/manager/1.1/stats/CameraUsageStats.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
+#define ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
+
+#include <inttypes.h>
+
+#include <android-base/result.h>
+#include <android-base/stringprintf.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/SystemClock.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+struct CameraUsageStatsRecord {
+public:
+ // Time a snapshot is generated
+ nsecs_t timestamp;
+
+ // Total number of frames received
+ int64_t framesReceived;
+
+ // Total number of frames returned to EVS HAL
+ int64_t framesReturned;
+
+ // Number of frames ignored because no clients are listening
+ int64_t framesIgnored;
+
+ // Number of frames skipped to synchronize camera frames
+ int64_t framesSkippedToSync;
+
+ // Roundtrip latency of the very first frame after the stream started.
+ int64_t framesFirstRoundtripLatency;
+
+ // Peak mFrame roundtrip latency
+ int64_t framesPeakRoundtripLatency;
+
+ // Average mFrame roundtrip latency
+ double framesAvgRoundtripLatency;
+
+ // Number of the erroneous streaming events
+ int32_t erroneousEventsCount;
+
+ // Peak number of active clients
+ int32_t peakClientsCount;
+
+ // Calculates a delta between two records
+ CameraUsageStatsRecord& operator-=(const CameraUsageStatsRecord& rhs) {
+ // Only calculates differences in the frame statistics
+ framesReceived = framesReceived - rhs.framesReceived;
+ framesReturned = framesReturned - rhs.framesReturned;
+ framesIgnored = framesIgnored - rhs.framesIgnored;
+ framesSkippedToSync = framesSkippedToSync - rhs.framesSkippedToSync;
+ erroneousEventsCount = erroneousEventsCount - rhs.erroneousEventsCount;
+
+ return *this;
+ }
+
+ friend CameraUsageStatsRecord operator-(CameraUsageStatsRecord lhs,
+ const CameraUsageStatsRecord& rhs) noexcept {
+ lhs -= rhs; // reuse compound assignment
+ return lhs;
+ }
+
+ // Constructs a string that shows collected statistics
+ std::string toString(const char* indent = "") const {
+ std::string buffer;
+ android::base::StringAppendF(&buffer,
+ "%sTime Collected: @%" PRId64 "ms\n"
+ "%sFrames Received: %" PRId64 "\n"
+ "%sFrames Returned: %" PRId64 "\n"
+ "%sFrames Ignored : %" PRId64 "\n"
+ "%sFrames Skipped To Sync: %" PRId64 "\n\n",
+ indent, ns2ms(timestamp),
+ indent, framesReceived,
+ indent, framesReturned,
+ indent, framesIgnored,
+ indent, framesSkippedToSync);
+
+ return buffer;
+ }
+};
+
+
+class CameraUsageStats : public RefBase {
+public:
+ CameraUsageStats(int32_t id)
+ : mMutex(Mutex()),
+ mId(id),
+ mTimeCreatedMs(android::uptimeMillis()),
+ mStats({}) {}
+
+private:
+ // Mutex to protect a collection record
+ mutable Mutex mMutex;
+
+ // Unique identifier
+ int32_t mId;
+
+ // Time this object was created
+ int64_t mTimeCreatedMs;
+
+ // Usage statistics to collect
+ CameraUsageStatsRecord mStats GUARDED_BY(mMutex);
+
+public:
+ void framesReceived(int n = 1) EXCLUDES(mMutex);
+ void framesReturned(int n = 1) EXCLUDES(mMutex);
+ void framesIgnored(int n = 1) EXCLUDES(mMutex);
+ void framesSkippedToSync(int n = 1) EXCLUDES(mMutex);
+ void eventsReceived() EXCLUDES(mMutex);
+ int64_t getTimeCreated() const EXCLUDES(mMutex);
+ int64_t getFramesReceived() const EXCLUDES(mMutex);
+ int64_t getFramesReturned() const EXCLUDES(mMutex);
+
+ // Returns the statistics collected so far
+ CameraUsageStatsRecord snapshot() const EXCLUDES(mMutex);
+
+ // Reports the usage statistics
+ android::base::Result<void> writeStats() const EXCLUDES(mMutex);
+
+ // Generates a string with current statistics
+ static std::string toString(const CameraUsageStatsRecord& record, const char* indent = "");
+};
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif // ANDROID_AUTOMOTIVE_EVS_V1_1_CAMERAUSAGESTATS_H
diff --git a/evs/manager/1.1/stats/LooperWrapper.cpp b/evs/manager/1.1/stats/LooperWrapper.cpp
new file mode 100644
index 0000000..041a723
--- /dev/null
+++ b/evs/manager/1.1/stats/LooperWrapper.cpp
@@ -0,0 +1,82 @@
+/**
+ * Copyright 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 "LooperWrapper.h"
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+using android::sp;
+
+void LooperWrapper::wake() {
+ if (mLooper == nullptr) {
+ LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+ return;
+ }
+
+ return mLooper->wake();
+}
+
+int LooperWrapper::pollAll(int timeoutMillis) {
+ if (mLooper == nullptr) {
+ LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+ return 0;
+ }
+
+ return mLooper->pollAll(timeoutMillis);
+}
+
+void LooperWrapper::sendMessage(const sp<MessageHandler>& handler,
+ const Message& message) {
+ if (mLooper == nullptr) {
+ LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+ return;
+ }
+
+ return mLooper->sendMessage(handler, message);
+}
+
+void LooperWrapper::sendMessageAtTime(nsecs_t uptime,
+ const sp<MessageHandler>& handler,
+ const Message& message) {
+ if (mLooper == nullptr) {
+ LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+ return;
+ }
+
+ return mLooper->sendMessageAtTime(uptime, handler, message);
+}
+
+void LooperWrapper::removeMessages(const sp<MessageHandler>& handler) {
+ if (mLooper == nullptr) {
+ LOG(WARNING) << __FUNCTION__ << ": Looper is invalid.";
+ return;
+ }
+
+ return mLooper->removeMessages(handler);
+}
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
diff --git a/evs/manager/1.1/stats/LooperWrapper.h b/evs/manager/1.1/stats/LooperWrapper.h
new file mode 100644
index 0000000..fb9ec12
--- /dev/null
+++ b/evs/manager/1.1/stats/LooperWrapper.h
@@ -0,0 +1,57 @@
+/**
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_AUTMOTIVE_EVS_V1_1_EVSLOOPERWRAPPER_H_
+#define ANDROID_AUTMOTIVE_EVS_V1_1_EVSLOOPERWRAPPER_H_
+
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+// This class wraps around android::Looper methods. Please refer to
+// utils/Looper.h for the details.
+class LooperWrapper : public RefBase {
+public:
+ LooperWrapper() : mLooper(nullptr) {}
+ virtual ~LooperWrapper() {}
+
+ void setLooper(android::sp<Looper> looper) { mLooper = looper; }
+ void wake();
+ virtual nsecs_t now() { return systemTime(SYSTEM_TIME_MONOTONIC); }
+ virtual int pollAll(int timeoutMillis);
+ virtual void sendMessage(const android::sp<MessageHandler>& handler, const Message& message);
+ virtual void sendMessageAtTime(nsecs_t uptime, const android::sp<MessageHandler>& handler,
+ const Message& message);
+ virtual void removeMessages(const android::sp<MessageHandler>& handler);
+
+protected:
+ android::sp<Looper> mLooper;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif // ANDROID_AUTMOTIVE_EVS_V1_1_EVSLOOPERWRAPPER_H_
+
diff --git a/evs/manager/1.1/stats/StatsCollector.cpp b/evs/manager/1.1/stats/StatsCollector.cpp
new file mode 100644
index 0000000..de85e5a
--- /dev/null
+++ b/evs/manager/1.1/stats/StatsCollector.cpp
@@ -0,0 +1,468 @@
+/*
+ * Copyright 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 "HalCamera.h"
+#include "StatsCollector.h"
+#include "VirtualCamera.h"
+
+#include <processgroup/sched_policy.h>
+#include <pthread.h>
+
+#include <android-base/file.h>
+#include <android-base/strings.h>
+#include <android-base/stringprintf.h>
+#include <utils/SystemClock.h>
+
+namespace {
+
+ const char* kSingleIndent = "\t";
+ const char* kDoubleIndent = "\t\t";
+ const char* kDumpAllDevices = "all";
+
+}
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+using android::base::Error;
+using android::base::EqualsIgnoreCase;
+using android::base::Result;
+using android::base::StringAppendF;
+using android::base::StringPrintf;
+using android::base::WriteStringToFd;
+using android::hardware::automotive::evs::V1_1::BufferDesc;
+
+namespace {
+
+const auto kPeriodicCollectionInterval = 10s;
+const auto kPeriodicCollectionCacheSize = 180;
+const auto kMinCollectionInterval = 1s;
+const auto kCustomCollectionMaxDuration = 30min;
+const auto kMaxDumpHistory = 10;
+
+}
+
+void StatsCollector::handleMessage(const Message& message) {
+ const auto received = static_cast<CollectionEvent>(message.what);
+ Result<void> ret;
+ switch (received) {
+ case CollectionEvent::PERIODIC:
+ ret = handleCollectionEvent(received, &mPeriodicCollectionInfo);
+ break;
+
+ case CollectionEvent::CUSTOM_START:
+ ret = handleCollectionEvent(received, &mCustomCollectionInfo);
+ break;
+
+ case CollectionEvent::CUSTOM_END: {
+ AutoMutex lock(mMutex);
+ if (mCurrentCollectionEvent != CollectionEvent::CUSTOM_START) {
+ LOG(WARNING) << "Ignoring a message to end custom collection "
+ << "as current collection is " << toString(mCurrentCollectionEvent);
+ return;
+ }
+
+ // Starts a periodic collection
+ mLooper->removeMessages(this);
+ mCurrentCollectionEvent = CollectionEvent::PERIODIC;
+ mPeriodicCollectionInfo.lastCollectionTime = mLooper->now();
+ mLooper->sendMessage(this, CollectionEvent::PERIODIC);
+ return;
+ }
+
+ default:
+ LOG(WARNING) << "Unknown event is received: " << received;
+ break;
+ }
+
+ if (!ret.ok()) {
+ Mutex::Autolock lock(mMutex);
+ LOG(ERROR) << "Terminating data collection: "
+ << ret.error();
+
+ mCurrentCollectionEvent = CollectionEvent::TERMINATED;
+ mLooper->removeMessages(this);
+ mLooper->wake();
+ }
+}
+
+
+Result<void> StatsCollector::handleCollectionEvent(CollectionEvent event,
+ CollectionInfo* info) {
+ AutoMutex lock(mMutex);
+ if (mCurrentCollectionEvent != event) {
+ LOG(WARNING) << "Skipping " << toString(event) << " collection event "
+ << "on collection event " << toString(mCurrentCollectionEvent);
+ return {};
+ }
+
+ if (info->maxCacheSize < 1) {
+ return Error() << "Maximum cache size must be greater than 0";
+ }
+
+ using std::chrono::duration_cast;
+ using std::chrono::seconds;
+ if (info->interval < kMinCollectionInterval) {
+ LOG(WARNING) << "Collection interval of "
+ << duration_cast<seconds>(info->interval).count()
+ << " seconds for " << toString(event)
+ << " collection cannot be shorter than "
+ << duration_cast<seconds>(kMinCollectionInterval).count()
+ << " seconds.";
+ info->interval = kMinCollectionInterval;
+ }
+
+ auto ret = collectLocked(info);
+ if (!ret) {
+ return Error() << toString(event) << " collection failed: "
+ << ret.error();
+ }
+
+ // Arms a message for next periodic collection
+ info->lastCollectionTime += info->interval.count();
+ mLooper->sendMessageAtTime(info->lastCollectionTime, this, event);
+ return {};
+}
+
+
+Result<void> StatsCollector::collectLocked(CollectionInfo* info) REQUIRES(mMutex) {
+ for (auto&& [id, ptr] : mClientsToMonitor) {
+ auto pClient = ptr.promote();
+ if (!pClient) {
+ LOG(DEBUG) << id << " seems not alive.";
+ continue;
+ }
+
+ // Pulls a snapshot and puts a timestamp
+ auto snapshot = pClient->getStats();
+ snapshot.timestamp = mLooper->now();
+
+ // Removes the oldest record if cache is full
+ if (info->records[id].history.size() > info->maxCacheSize) {
+ info->records[id].history.pop_front();
+ }
+
+ // Stores the latest record and the deltas
+ auto delta = snapshot - info->records[id].latest;
+ info->records[id].history.emplace_back(delta);
+ info->records[id].latest = snapshot;
+ }
+
+ return {};
+}
+
+
+Result<void> StatsCollector::startCollection() {
+ {
+ AutoMutex lock(mMutex);
+ if (mCurrentCollectionEvent != CollectionEvent::INIT ||
+ mCollectionThread.joinable()) {
+ return Error(INVALID_OPERATION)
+ << "Camera usages collection is already running.";
+ }
+
+ // Create the collection info w/ the default values
+ mPeriodicCollectionInfo = {
+ .interval = kPeriodicCollectionInterval,
+ .maxCacheSize = kPeriodicCollectionCacheSize,
+ .lastCollectionTime = 0,
+ };
+
+ }
+
+ // Starts a background worker thread
+ mCollectionThread = std::thread([&]() {
+ {
+ AutoMutex lock(mMutex);
+ if (mCurrentCollectionEvent != CollectionEvent::INIT) {
+ LOG(ERROR) << "Skipping the statistics collection because "
+ << "the current collection event is "
+ << toString(mCurrentCollectionEvent);
+ return;
+ }
+
+ // Staring with a periodic collection
+ mCurrentCollectionEvent = CollectionEvent::PERIODIC;
+ }
+
+ if (set_sched_policy(0, SP_BACKGROUND) != 0) {
+ PLOG(WARNING) << "Failed to set background scheduling prioirty";
+ }
+
+ auto ret = pthread_setname_np(pthread_self(), "EvsCameraUsageCollect");
+ if (ret != 0) {
+ PLOG(WARNING) << "Failed to name a collection thread";
+ }
+
+ // Sets a looper for the communication
+ mLooper->setLooper(Looper::prepare(/*opts=*/0));
+
+ // Starts collecting the usage statistics periodically
+ mLooper->sendMessage(this, CollectionEvent::PERIODIC);
+
+ // Polls the messages until the collection is stopped.
+ bool isActive = true;
+ while (isActive) {
+ mLooper->pollAll(/*timeoutMillis=*/-1);
+ {
+ AutoMutex lock(mMutex);
+ isActive = mCurrentCollectionEvent != CollectionEvent::TERMINATED;
+ }
+ }
+ });
+
+ return {};
+}
+
+
+Result<void> StatsCollector::stopCollection() {
+ {
+ AutoMutex lock(mMutex);
+ if (mCurrentCollectionEvent == CollectionEvent::TERMINATED) {
+ LOG(WARNING) << "Camera usage data collection was stopped already.";
+ return {};
+ }
+
+ LOG(INFO) << "Stopping a camera usage data collection";
+ mCurrentCollectionEvent = CollectionEvent::TERMINATED;
+ }
+
+ // Join a background thread
+ if (mCollectionThread.joinable()) {
+ mLooper->removeMessages(this);
+ mLooper->wake();
+ mCollectionThread.join();
+ }
+
+ return {};
+}
+
+
+Result<void> StatsCollector::startCustomCollection(
+ std::chrono::nanoseconds interval,
+ std::chrono::nanoseconds maxDuration) {
+ using std::chrono::duration_cast;
+ using std::chrono::milliseconds;
+ if (interval < kMinCollectionInterval || maxDuration < kMinCollectionInterval) {
+ return Error(INVALID_OPERATION)
+ << "Collection interval and maximum maxDuration must be >= "
+ << duration_cast<milliseconds>(kMinCollectionInterval).count()
+ << " milliseconds.";
+ }
+
+ if (maxDuration > kCustomCollectionMaxDuration) {
+ return Error(INVALID_OPERATION)
+ << "Collection maximum maxDuration must be less than "
+ << duration_cast<milliseconds>(kCustomCollectionMaxDuration).count()
+ << " milliseconds.";
+ }
+
+ {
+ AutoMutex lock(mMutex);
+ if (mCurrentCollectionEvent != CollectionEvent::PERIODIC) {
+ return Error(INVALID_OPERATION)
+ << "Cannot start a custom collection when "
+ << "the current collection event " << toString(mCurrentCollectionEvent)
+ << " != " << toString(CollectionEvent::PERIODIC) << " collection event";
+ }
+
+ // Notifies the user if a preview custom collection result is
+ // not used yet.
+ if (mCustomCollectionInfo.records.size() > 0) {
+ LOG(WARNING) << "Previous custom collection result, which was done at "
+ << mCustomCollectionInfo.lastCollectionTime
+ << " has not pulled yet will be overwritten.";
+ }
+
+ // Programs custom collection configurations
+ mCustomCollectionInfo = {
+ .interval = interval,
+ .maxCacheSize = std::numeric_limits<std::size_t>::max(),
+ .lastCollectionTime = mLooper->now(),
+ .records = {},
+ };
+
+ mLooper->removeMessages(this);
+ nsecs_t uptime = mLooper->now() + maxDuration.count();
+ mLooper->sendMessageAtTime(uptime, this, CollectionEvent::CUSTOM_END);
+ mCurrentCollectionEvent = CollectionEvent::CUSTOM_START;
+ mLooper->sendMessage(this, CollectionEvent::CUSTOM_START);
+ }
+
+ return {};
+}
+
+
+Result<std::string> StatsCollector::stopCustomCollection(std::string targetId) {
+ Mutex::Autolock lock(mMutex);
+ if (mCurrentCollectionEvent == CollectionEvent::CUSTOM_START) {
+ // Stops a running custom collection
+ mLooper->removeMessages(this);
+ mLooper->sendMessage(this, CollectionEvent::CUSTOM_END);
+ }
+
+ auto ret = collectLocked(&mCustomCollectionInfo);
+ if (!ret) {
+ return Error() << toString(mCurrentCollectionEvent) << " collection failed: "
+ << ret.error();
+ }
+
+ // Prints out the all collected statistics
+ std::string buffer;
+ using std::chrono::duration_cast;
+ using std::chrono::seconds;
+ const intmax_t interval =
+ duration_cast<seconds>(mCustomCollectionInfo.interval).count();
+ if (EqualsIgnoreCase(targetId, kDumpAllDevices)) {
+ for (auto& [id, records] : mCustomCollectionInfo.records) {
+
+ StringAppendF(&buffer, "%s\n"
+ "%sNumber of collections: %zu\n"
+ "%sCollection interval: %" PRIdMAX " secs\n",
+ id.c_str(),
+ kSingleIndent, records.history.size(),
+ kSingleIndent, interval);
+ auto it = records.history.rbegin();
+ while (it != records.history.rend()) {
+ buffer += it++->toString(kDoubleIndent);
+ }
+ }
+
+ // Clears the collection
+ mCustomCollectionInfo = {};
+ } else {
+ auto it = mCustomCollectionInfo.records.find(targetId);
+ if (it != mCustomCollectionInfo.records.end()) {
+ StringAppendF(&buffer, "%s\n"
+ "%sNumber of collections: %zu\n"
+ "%sCollection interval: %" PRIdMAX " secs\n",
+ targetId.c_str(),
+ kSingleIndent, it->second.history.size(),
+ kSingleIndent, interval);
+ auto recordIter = it->second.history.rbegin();
+ while (recordIter != it->second.history.rend()) {
+ buffer += recordIter++->toString(kDoubleIndent);
+ }
+
+ // Clears the collection
+ mCustomCollectionInfo = {};
+ } else {
+ // Keeps the collection as the users may want to execute a command
+ // again with a right device id
+ StringAppendF(&buffer, "%s has not been monitored.", targetId.c_str());
+ }
+ }
+
+ return buffer;
+}
+
+
+Result<void> StatsCollector::registerClientToMonitor(android::sp<HalCamera>& camera) {
+ if (!camera) {
+ return Error(BAD_VALUE) << "Given camera client is invalid";
+ }
+
+ AutoMutex lock(mMutex);
+ const auto id = camera->getId();
+ if (mClientsToMonitor.find(id) != mClientsToMonitor.end()) {
+ LOG(WARNING) << id << " is already registered.";
+ } else {
+ mClientsToMonitor.insert_or_assign(id, camera);
+ }
+
+ return {};
+}
+
+
+Result<void> StatsCollector::unregisterClientToMonitor(const std::string& id) {
+ AutoMutex lock(mMutex);
+ auto entry = mClientsToMonitor.find(id);
+ if (entry != mClientsToMonitor.end()) {
+ mClientsToMonitor.erase(entry);
+ } else {
+ LOG(WARNING) << id << " has not been registerd.";
+ }
+
+ return {};
+}
+
+
+std::string StatsCollector::toString(const CollectionEvent& event) const {
+ switch(event) {
+ case CollectionEvent::INIT:
+ return "CollectionEvent::INIT";
+ case CollectionEvent::PERIODIC:
+ return "CollectionEvent::PERIODIC";
+ case CollectionEvent::CUSTOM_START:
+ return "CollectionEvent::CUSTOM_START";
+ case CollectionEvent::CUSTOM_END:
+ return "CollectionEvent::CUSTOM_END";
+ case CollectionEvent::TERMINATED:
+ return "CollectionEvent::TERMINATED";
+
+ default:
+ return "Unknown";
+ }
+}
+
+
+Result<void> StatsCollector::toString(std::unordered_map<std::string, std::string>* usages,
+ const char* indent) EXCLUDES(mMutex) {
+ std::string double_indent(indent);
+ double_indent += indent;
+
+ {
+ AutoMutex lock(mMutex);
+ using std::chrono::duration_cast;
+ using std::chrono::seconds;
+ const intmax_t interval =
+ duration_cast<seconds>(mPeriodicCollectionInfo.interval).count();
+
+ for (auto&& [id, records] : mPeriodicCollectionInfo.records) {
+ std::string buffer;
+ StringAppendF(&buffer, "%s\n"
+ "%sNumber of collections: %zu\n"
+ "%sCollection interval: %" PRIdMAX "secs\n",
+ id.c_str(),
+ indent, records.history.size(),
+ indent, interval);
+
+ // Adding up to kMaxDumpHistory records
+ auto it = records.history.rbegin();
+ auto count = 0;
+ while (it != records.history.rend() && count < kMaxDumpHistory) {
+ buffer += it->toString(double_indent.c_str());
+ ++it;
+ ++count;
+ }
+
+ usages->insert_or_assign(id, std::move(buffer));
+ }
+ }
+
+ return {};
+}
+
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
diff --git a/evs/manager/1.1/stats/StatsCollector.h b/evs/manager/1.1/stats/StatsCollector.h
new file mode 100644
index 0000000..031b342
--- /dev/null
+++ b/evs/manager/1.1/stats/StatsCollector.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_AUTOMOTIVE_EVS_V1_1_EVSSTATSCOLLECTOR_H
+#define ANDROID_AUTOMOTIVE_EVS_V1_1_EVSSTATSCOLLECTOR_H
+
+#include "CameraUsageStats.h"
+#include "LooperWrapper.h"
+
+#include <deque>
+#include <thread>
+#include <unordered_map>
+#include <vector>
+
+#include <android/hardware/automotive/evs/1.1/types.h>
+#include <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <android-base/result.h>
+#include <utils/Mutex.h>
+
+namespace android {
+namespace automotive {
+namespace evs {
+namespace V1_1 {
+namespace implementation {
+
+class HalCamera; // From VirtualCamera.h
+
+enum CollectionEvent {
+ INIT = 0,
+ PERIODIC,
+ CUSTOM_START,
+ CUSTOM_END,
+ TERMINATED,
+
+ LAST_EVENT,
+};
+
+
+struct CollectionRecord {
+ // Latest statistics collection
+ CameraUsageStatsRecord latest = {};
+
+ // History of collected statistics records
+ std::deque<CameraUsageStatsRecord> history;
+};
+
+
+struct CollectionInfo {
+ // Collection interval between two subsequent collections
+ std::chrono::nanoseconds interval = 0ns;
+
+ // The maximum number of records this collection stores
+ size_t maxCacheSize = 0;
+
+ // Time when the latest collection was done
+ nsecs_t lastCollectionTime = 0;
+
+ // Collected statistics records per instances
+ std::unordered_map<std::string, CollectionRecord> records;
+};
+
+
+class StatsCollector : public MessageHandler {
+public:
+ explicit StatsCollector() :
+ mLooper(new LooperWrapper()),
+ mCurrentCollectionEvent(CollectionEvent::INIT),
+ mPeriodicCollectionInfo({}),
+ mCustomCollectionInfo({}) {}
+
+ virtual ~StatsCollector() { stopCollection(); }
+
+ // Starts collecting CameraUsageStats
+ android::base::Result<void> startCollection();
+
+ // Stops collecting the statistics
+ android::base::Result<void> stopCollection();
+
+ // Starts collecting CameraUsageStarts during a given duration at a given
+ // interval.
+ android::base::Result<void> startCustomCollection(
+ std::chrono::nanoseconds interval,
+ std::chrono::nanoseconds duration) EXCLUDES(mMutex);
+
+ // Stops current custom collection and shows the result from the device with
+ // a given unique id. If this is "all",all results
+ // will be returned.
+ android::base::Result<std::string> stopCustomCollection(
+ std::string id = "") EXCLUDES(mMutex);
+
+ // Registers HalCamera object to monitor
+ android::base::Result<void> registerClientToMonitor(
+ android::sp<HalCamera>& camera) EXCLUDES(mMutex);
+
+ // Unregister HalCamera object
+ android::base::Result<void> unregisterClientToMonitor(
+ const std::string& id) EXCLUDES(mMutex);
+
+ // Returns a string that contains the latest statistics pulled from
+ // currently active clients
+ android::base::Result<void> toString(
+ std::unordered_map<std::string, std::string>* usages,
+ const char* indent = "") EXCLUDES(mMutex);
+
+private:
+ // Mutex to protect records
+ mutable Mutex mMutex;
+
+ // Looper to message the collection thread
+ android::sp<LooperWrapper> mLooper;
+
+ // Background thread to pull stats from the clients
+ std::thread mCollectionThread;
+
+ // Current state of the monitor
+ CollectionEvent mCurrentCollectionEvent GUARDED_BY(mMutex);
+
+ // Periodic collection information
+ CollectionInfo mPeriodicCollectionInfo GUARDED_BY(mMutex);
+
+ // A collection during the custom period the user sets
+ CollectionInfo mCustomCollectionInfo GUARDED_BY(mMutex);
+
+ // A list of HalCamera objects to monitor
+ std::unordered_map<std::string,
+ android::wp<HalCamera>> mClientsToMonitor GUARDED_BY(mMutex);
+
+ // Handles the messages from the looper
+ void handleMessage(const Message& message) override;
+
+ // Handles each CollectionEvent
+ android::base::Result<void> handleCollectionEvent(
+ CollectionEvent event, CollectionInfo* info) EXCLUDES(mMutex);
+
+ // Pulls the statistics from each active HalCamera objects and generates the
+ // records
+ android::base::Result<void> collectLocked(CollectionInfo* info) REQUIRES(mMutex);
+
+ // Returns a string corresponding to a given collection event
+ std::string toString(const CollectionEvent& event) const;
+};
+
+} // namespace implementation
+} // namespace V1_1
+} // namespace evs
+} // namespace automotive
+} // namespace android
+
+#endif // ANDROID_AUTOMOTIVE_EVS_V1_1_EVSSTATSCOLLECTOR_H
diff --git a/evs/sampleDriver/Android.bp b/evs/sampleDriver/Android.bp
index 1722200..1bee713 100644
--- a/evs/sampleDriver/Android.bp
+++ b/evs/sampleDriver/Android.bp
@@ -58,10 +58,6 @@
init_rc: ["android.hardware.automotive.evs@1.1-sample.rc"],
- strip: {
- keep_symbols: true,
- },
-
cflags: ["-DLOG_TAG=\"EvsSampleDriver\""] + [
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
diff --git a/evs/sampleDriver/EvsEnumerator.cpp b/evs/sampleDriver/EvsEnumerator.cpp
index e108007..ef6009e 100644
--- a/evs/sampleDriver/EvsEnumerator.cpp
+++ b/evs/sampleDriver/EvsEnumerator.cpp
@@ -534,6 +534,12 @@
}
// Create a new display interface and return it
+ if (sDisplayPortList.find(port) == sDisplayPortList.end()) {
+ LOG(ERROR) << "No display is available on the port "
+ << static_cast<int32_t>(port);
+ return nullptr;
+ }
+
pActiveDisplay = new EvsGlDisplay(sDisplayProxy, sDisplayPortList[port]);
sActiveDisplay = pActiveDisplay;
diff --git a/evs/support_library/Android.bp b/evs/support_library/Android.bp
index 6556404..8b77a5d 100644
--- a/evs/support_library/Android.bp
+++ b/evs/support_library/Android.bp
@@ -56,10 +56,6 @@
"camera_config.json",
],
- strip: {
- keep_symbols: true,
- },
-
cflags: ["-DLOG_TAG=\"libevssupport\""] + [
"-DGL_GLEXT_PROTOTYPES",
"-DEGL_EGLEXT_PROTOTYPES",
diff --git a/service/src/com/android/car/vms/VmsBrokerService.java b/service/src/com/android/car/vms/VmsBrokerService.java
index aed7e69..b2dbaa1 100644
--- a/service/src/com/android/car/vms/VmsBrokerService.java
+++ b/service/src/com/android/car/vms/VmsBrokerService.java
@@ -53,6 +53,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -111,7 +112,17 @@
@Override
public void dump(PrintWriter writer) {
- // TODO(b/149125079): Implement dumpsys
+ writer.println("*" + TAG + "*");
+ synchronized (mLock) {
+ writer.println("mAvailableLayers: " + mAvailableLayers.getAvailableLayers());
+ writer.println();
+ writer.println("mSubscriptionState: " + mSubscriptionState);
+ writer.println();
+ writer.println("mClientMap:");
+ mClientMap.values().stream()
+ .sorted(Comparator.comparingInt(VmsClientInfo::getUid))
+ .forEach(client -> client.dump(writer, " "));
+ }
}
@Override
diff --git a/service/src/com/android/car/vms/VmsClientInfo.java b/service/src/com/android/car/vms/VmsClientInfo.java
index b1ad912..d64b6b7 100644
--- a/service/src/com/android/car/vms/VmsClientInfo.java
+++ b/service/src/com/android/car/vms/VmsClientInfo.java
@@ -28,6 +28,7 @@
import com.android.internal.annotations.GuardedBy;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -180,6 +181,52 @@
}
}
+ void dump(PrintWriter writer, String indent) {
+ synchronized (mLock) {
+ String prefix = indent;
+ writer.println(prefix + "VmsClient [" + mPackageName + "]");
+
+ prefix = indent + " ";
+ writer.println(prefix + "UID: " + mUid);
+ writer.println(prefix + "Legacy Client: " + mLegacyClient);
+ writer.println(prefix + "Monitoring: " + mMonitoringEnabled);
+
+ if (mProviderIds.size() > 0) {
+ writer.println(prefix + "Offerings:");
+ for (int i = 0; i < mProviderIds.size(); i++) {
+ prefix = indent + " ";
+ int providerId = mProviderIds.keyAt(i);
+ writer.println(prefix + "Provider [" + providerId + "]");
+
+ for (VmsLayerDependency layerOffering : mOfferings.get(
+ providerId, Collections.emptySet())) {
+ prefix = indent + " ";
+ writer.println(prefix + layerOffering.getLayer());
+ if (!layerOffering.getDependencies().isEmpty()) {
+ prefix = indent + " ";
+ writer.println(prefix + "Dependencies: "
+ + layerOffering.getDependencies());
+ }
+ }
+ }
+ }
+
+ if (!mLayerSubscriptions.isEmpty() || !mLayerAndProviderSubscriptions.isEmpty()) {
+ prefix = indent + " ";
+ writer.println(prefix + "Subscriptions:");
+
+ prefix = indent + " ";
+ for (VmsLayer layer : mLayerSubscriptions) {
+ writer.println(prefix + layer);
+ }
+ for (Map.Entry<VmsLayer, Set<Integer>> layerEntry :
+ mLayerAndProviderSubscriptions.entrySet()) {
+ writer.println(prefix + layerEntry.getKey() + ": " + layerEntry.getValue());
+ }
+ }
+ }
+ }
+
private static <K, V> Map<K, Set<V>> deepCopy(Map<K, Set<V>> original) {
return original.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,
diff --git a/service/src/com/android/car/watchdog/CarWatchdogService.java b/service/src/com/android/car/watchdog/CarWatchdogService.java
index 041ba29..8a1ebc7 100644
--- a/service/src/com/android/car/watchdog/CarWatchdogService.java
+++ b/service/src/com/android/car/watchdog/CarWatchdogService.java
@@ -68,7 +68,7 @@
*/
public final class CarWatchdogService extends ICarWatchdogService.Stub implements CarServiceBase {
- private static final boolean DEBUG = true; // STOPSHIP if true (b/151474489)
+ private static final boolean DEBUG = false; // STOPSHIP if true
private static final String TAG = TAG_WATCHDOG;
private static final int[] ALL_TIMEOUTS =
{ TIMEOUT_CRITICAL, TIMEOUT_MODERATE, TIMEOUT_NORMAL };
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTest.java b/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTest.java
index 93f2530..ee6dbbb 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarActivityViewDisplayIdTest.java
@@ -24,7 +24,6 @@
import static org.junit.Assume.assumeTrue;
import static org.testng.Assert.assertThrows;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import org.junit.Test;
@@ -42,7 +41,6 @@
private static final int NONEXISTENT_DISPLAY_ID = Integer.MAX_VALUE;
@Test
- @FlakyTest
public void testSingleActivityView() throws Exception {
ActivityViewTestActivity activity = startActivityViewTestActivity(DEFAULT_DISPLAY);
activity.waitForActivityViewReady();
@@ -65,7 +63,6 @@
}
@Test
- @FlakyTest
public void testDoubleActivityView() throws Exception {
ActivityViewTestActivity activity1 = startActivityViewTestActivity(DEFAULT_DISPLAY);
activity1.waitForActivityViewReady();
@@ -100,7 +97,6 @@
}
@Test
- @FlakyTest
public void testThrowsExceptionOnReportingNonExistingDisplay() throws Exception {
ActivityViewTestActivity activity = startActivityViewTestActivity(DEFAULT_DISPLAY);
activity.waitForActivityViewReady();
@@ -125,7 +121,6 @@
// TODO(b/143353546): Make the following tests not to rely on CarLauncher.
@Test
- @FlakyTest
public void testThrowsExceptionOnReportingNonOwningDisplay() throws Exception {
int displayIdOfCarLauncher = waitForActivityViewDisplayReady(CAR_LAUNCHER_PKG_NAME);
assumeTrue(INVALID_DISPLAY != displayIdOfCarLauncher);
diff --git a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
index e18a200..cb58d3f 100644
--- a/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
+++ b/tests/android_car_api_test/src/android/car/apitest/CarUserManagerTest.java
@@ -65,7 +65,7 @@
* Stopping the user takes a while, even when calling force stop - change it to false if this
* test becomes flaky.
*/
- private static final boolean TEST_STOP = true;
+ private static final boolean TEST_STOP = false;
private static final UserManager sUserManager = UserManager.get(sContext);
@@ -165,10 +165,10 @@
// Switch back to the previous user
switchUser(oldUserId);
- // Must force stop the user, otherwise it can take minutes for its process to finish
- forceStopUser(newUserId);
-
if (TEST_STOP) {
+ // Must force stop the user, otherwise it can take minutes for its process to finish
+ forceStopUser(newUserId);
+
// waitForEvents() will also return events for previous user...
List<UserLifecycleEvent> allEvents = stopListener.waitForEvents();
Log.d(TAG, "All received events on stopListener: " + allEvents);
@@ -183,6 +183,8 @@
assertWithMessage("wrong userHandle on %s", event)
.that(event.getUserHandle().getIdentifier()).isEqualTo(newUserId);
}
+ } else {
+ Log.w(TAG, "NOT testing user stop events");
}
// Make sure unregistered listener din't receive any more events
diff --git a/watchdog/server/src/WatchdogProcessService.cpp b/watchdog/server/src/WatchdogProcessService.cpp
index 749ed30..8d4ec06 100644
--- a/watchdog/server/src/WatchdogProcessService.cpp
+++ b/watchdog/server/src/WatchdogProcessService.cpp
@@ -15,7 +15,7 @@
*/
#define LOG_TAG "carwatchdogd"
-#define DEBUG true // TODO(b/151474489): stop ship if true.
+#define DEBUG false // STOPSHIP if true.
#include "WatchdogProcessService.h"