Merge "NNAPI HAL: Remove priority from prepareModelFromCache_1_3"
diff --git a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
index cca65d9..fb02c58 100644
--- a/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
+++ b/automotive/vehicle/2.0/default/VirtualizationGrpcServer.cpp
@@ -1,6 +1,4 @@
#include <android-base/logging.h>
-#include <getopt.h>
-#include <unistd.h>
#include "vhal_v2_0/virtualization/GrpcVehicleServer.h"
#include "vhal_v2_0/virtualization/Utils.h"
@@ -8,42 +6,10 @@
int main(int argc, char* argv[]) {
namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl;
- vhal_impl::VsockServerInfo serverInfo;
+ auto serverInfo = vhal_impl::VsockServerInfo::fromCommandLine(argc, argv);
+ CHECK(serverInfo.has_value()) << "Invalid server CID/port combination";
- // unique values to identify the options
- constexpr int OPT_VHAL_SERVER_CID = 1001;
- constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002;
-
- struct option longOptions[] = {
- {"server_cid", 1, 0, OPT_VHAL_SERVER_CID},
- {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER},
- {nullptr, 0, nullptr, 0},
- };
-
- int optValue;
- while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) {
- switch (optValue) {
- case OPT_VHAL_SERVER_CID:
- serverInfo.serverCid = std::atoi(optarg);
- LOG(DEBUG) << "Vehicle HAL server CID: " << serverInfo.serverCid;
- break;
- case OPT_VHAL_SERVER_PORT_NUMBER:
- serverInfo.serverPort = std::atoi(optarg);
- LOG(DEBUG) << "Vehicle HAL server port: " << serverInfo.serverPort;
- break;
- default:
- // ignore other options
- break;
- }
- }
-
- if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) {
- LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid
- << "; port: " << serverInfo.serverPort;
- // Will abort after logging
- }
-
- auto server = vhal_impl::makeGrpcVehicleServer(vhal_impl::getVsockUri(serverInfo));
+ auto server = vhal_impl::makeGrpcVehicleServer(serverInfo->toUri());
server->Start();
return 0;
}
diff --git a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
index 1de81ae..68813c9 100644
--- a/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
+++ b/automotive/vehicle/2.0/default/VirtualizedVehicleService.cpp
@@ -15,7 +15,6 @@
*/
#include <android-base/logging.h>
-#include <cutils/properties.h>
#include <hidl/HidlTransportSupport.h>
#include <vhal_v2_0/EmulatedVehicleConnector.h>
@@ -29,30 +28,13 @@
using namespace android::hardware::automotive::vehicle::V2_0;
int main(int argc, char* argv[]) {
- constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid";
- constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port";
+ namespace vhal_impl = android::hardware::automotive::vehicle::V2_0::impl;
- auto property_get_uint = [](const char* key, unsigned int default_value) {
- auto value = property_get_int64(key, default_value);
- if (value < 0 || value > UINT_MAX) {
- LOG(DEBUG) << key << ": " << value << " is out of bound, using default value '"
- << default_value << "' instead";
- return default_value;
- }
- return static_cast<unsigned int>(value);
- };
-
- impl::VsockServerInfo serverInfo{property_get_uint(VHAL_SERVER_CID_PROPERTY_KEY, 0),
- property_get_uint(VHAL_SERVER_PORT_PROPERTY_KEY, 0)};
-
- if (serverInfo.serverCid == 0 || serverInfo.serverPort == 0) {
- LOG(FATAL) << "Invalid server information, CID: " << serverInfo.serverCid
- << "; port: " << serverInfo.serverPort;
- // Will abort after logging
- }
+ auto serverInfo = vhal_impl::VsockServerInfo::fromRoPropertyStore();
+ CHECK(serverInfo.has_value()) << "Invalid server CID/port combination";
auto store = std::make_unique<VehiclePropertyStore>();
- auto connector = impl::makeGrpcVehicleClient(impl::getVsockUri(serverInfo));
+ auto connector = impl::makeGrpcVehicleClient(serverInfo->toUri());
auto hal = std::make_unique<impl::EmulatedVehicleHal>(store.get(), connector.get());
auto emulator = std::make_unique<impl::VehicleEmulator>(hal.get());
auto service = std::make_unique<VehicleHalManager>(hal.get());
diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
index 29147ad..1101b08 100644
--- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
+++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server.rc
@@ -3,8 +3,8 @@
# so the command line arguments are expected, though not conventionally used in Android
service vendor.vehicle-hal-2.0-server \
/vendor/bin/hw/android.hardware.automotive.vehicle@2.0-virtualization-grpc-server \
- -server_cid ${ro.vendor.vehiclehal.server.cid:-0} \
- -server_port ${ro.vendor.vehiclehal.server.port:-0}
+ -server_cid ${ro.vendor.vehiclehal.server.cid:-pleaseconfigurethis} \
+ -server_port ${ro.vendor.vehiclehal.server.port:-pleaseconfigurethis}
class hal
user vehicle_network
group system inet
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
index 41d4827..184d8a4 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.cpp
@@ -16,6 +16,11 @@
#include "Utils.h"
+#include <cutils/properties.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <unistd.h>
#include <sstream>
namespace android {
@@ -25,12 +30,83 @@
namespace V2_0 {
namespace impl {
-std::string getVsockUri(const VsockServerInfo& serverInfo) {
+std::string VsockServerInfo::toUri() {
std::stringstream uri_stream;
- uri_stream << "vsock:" << serverInfo.serverCid << ":" << serverInfo.serverPort;
+ uri_stream << "vsock:" << serverCid << ":" << serverPort;
return uri_stream.str();
}
+static std::optional<unsigned> parseUnsignedIntFromString(const char* optarg, const char* name) {
+ auto v = strtoul(optarg, nullptr, 0);
+ if (((v == ULONG_MAX) && (errno == ERANGE)) || (v > UINT_MAX)) {
+ LOG(WARNING) << name << " value is out of range: " << optarg;
+ } else if (v != 0) {
+ return v;
+ } else {
+ LOG(WARNING) << name << " value is invalid or missing: " << optarg;
+ }
+
+ return std::nullopt;
+}
+
+static std::optional<unsigned> getNumberFromProperty(const char* key) {
+ auto value = property_get_int64(key, -1);
+ if ((value <= 0) || (value > UINT_MAX)) {
+ LOG(WARNING) << key << " is missing or out of bounds";
+ return std::nullopt;
+ }
+
+ return static_cast<unsigned int>(value);
+};
+
+std::optional<VsockServerInfo> VsockServerInfo::fromCommandLine(int argc, char* argv[]) {
+ std::optional<unsigned int> cid;
+ std::optional<unsigned int> port;
+
+ // unique values to identify the options
+ constexpr int OPT_VHAL_SERVER_CID = 1001;
+ constexpr int OPT_VHAL_SERVER_PORT_NUMBER = 1002;
+
+ struct option longOptions[] = {
+ {"server_cid", 1, 0, OPT_VHAL_SERVER_CID},
+ {"server_port", 1, 0, OPT_VHAL_SERVER_PORT_NUMBER},
+ {},
+ };
+
+ int optValue;
+ while ((optValue = getopt_long_only(argc, argv, ":", longOptions, 0)) != -1) {
+ switch (optValue) {
+ case OPT_VHAL_SERVER_CID:
+ cid = parseUnsignedIntFromString(optarg, "cid");
+ break;
+ case OPT_VHAL_SERVER_PORT_NUMBER:
+ port = parseUnsignedIntFromString(optarg, "port");
+ break;
+ default:
+ // ignore other options
+ break;
+ }
+ }
+
+ if (cid && port) {
+ return VsockServerInfo{*cid, *port};
+ }
+ return std::nullopt;
+}
+
+std::optional<VsockServerInfo> VsockServerInfo::fromRoPropertyStore() {
+ constexpr const char* VHAL_SERVER_CID_PROPERTY_KEY = "ro.vendor.vehiclehal.server.cid";
+ constexpr const char* VHAL_SERVER_PORT_PROPERTY_KEY = "ro.vendor.vehiclehal.server.port";
+
+ const auto cid = getNumberFromProperty(VHAL_SERVER_CID_PROPERTY_KEY);
+ const auto port = getNumberFromProperty(VHAL_SERVER_PORT_PROPERTY_KEY);
+
+ if (cid && port) {
+ return VsockServerInfo{*cid, *port};
+ }
+ return std::nullopt;
+}
+
} // namespace impl
} // namespace V2_0
} // namespace vehicle
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
index 6b1049c..8a8bce7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/virtualization/Utils.h
@@ -17,8 +17,11 @@
#ifndef android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
#define android_hardware_automotive_vehicle_V2_0_impl_virtualization_Utils_H_
+#include <optional>
#include <string>
+#include <android-base/logging.h>
+
namespace android {
namespace hardware {
namespace automotive {
@@ -29,9 +32,12 @@
struct VsockServerInfo {
unsigned int serverCid{0};
unsigned int serverPort{0};
-};
-std::string getVsockUri(const VsockServerInfo& serverInfo);
+ static std::optional<VsockServerInfo> fromCommandLine(int argc, char* argv[]);
+ static std::optional<VsockServerInfo> fromRoPropertyStore();
+
+ std::string toUri();
+};
} // namespace impl
} // namespace V2_0
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 6145ea2..a91bd88 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2438,6 +2438,217 @@
| VehiclePropertyType:STRING
| VehicleArea:GLOBAL),
+ /**
+ * Defines the initial Android user to be used during initialization.
+ *
+ * This property is called by the Android system when it initializes and it lets the HAL
+ * define which Android user should be started.
+ *
+ * This request is made by setting a VehiclePropValue (defined by InitialUserInfoRequest),
+ * and the HAL must respond with a property change event (defined by InitialUserInfoResponse).
+ * If the HAL doesn't respond after some time (defined by the Android system), the Android
+ * system will proceed as if HAL returned a response of action
+ * InitialUserInfoResponseAction:DEFAULT.
+ *
+ * For example, on first boot, the request could be:
+ *
+ * int32[0]: 42 // request id (arbitrary number set by Android system)
+ * int32[1]: 1 // InitialUserInfoRequestType::FIRST_BOOT
+ * int32[2]: 0 // id of current user (usersInfo.currentUser.userId)
+ * int32[3]: 1 // flag of current user (usersInfo.currentUser.flags = SYSTEM)
+ * int32[4]: 1 // number of existing users (usersInfo.numberUsers);
+ * int32[5]: 0 // user #0 (usersInfo.existingUsers[0].userId)
+ * int32[6]: 1 // flags of user #0 (usersInfo.existingUsers[0].flags)
+ *
+ * And if the HAL want to respond with the creation of an admin user called "Admin", the
+ * response would be:
+ *
+ * int32[0]: 42 // must match the request id from the request
+ * int32[1]: 2 // action = InitialUserInfoResponseAction::CREATE
+ * int32[2]: -1 // userToSwitchOrCreate.userId (not used as user will be created)
+ * int32[3]: 8 // userToSwitchOrCreate.flags = ADMIN
+ * string: "Admin" // userNameToCreate
+ *
+ * NOTE: if the HAL doesn't support user management, then it should not define this property,
+ * which in turn would disable the other user-related properties (for example, the Android
+ * system would never issue them and user-related requests from the HAL layer would be ignored
+ * by the Android System). But if it supports user management, then it must support all
+ * user-related properties (INITIAL_USER_INFO, SWITCH_USER, TODO(b/146207078):others).
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ INITIAL_USER_INFO = (
+ 0x0F07
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:MIXED
+ | VehicleArea:GLOBAL),
+
+ /**
+ * Defines a request to switch the foreground Android user.
+ *
+ * This property is used primarily by the Android System to inform the HAL that the
+ * current foreground Android user is switching, but it could also be used by the HAL to request
+ * the Android system to switch users - the
+ *
+ * When the request is made by Android, it sets a VehiclePropValue and the HAL must responde
+ * with a property change event; when the HAL is making the request, it must also do it through
+ * a property change event (the main difference is that the request id will be positive in the
+ * former case, and negative in the latter; the SwitchUserMessageType will also be different).
+ *
+ * The format of both request is defined by SwitchUserRequest and the format of the response
+ * (when needed) is defined by SwitchUserResponse. How the HAL (or Android System) should
+ * proceed depends on the message type (which is defined by the SwitchUserMessageType
+ * parameter), as defined below.
+ *
+ * 1.LEGACY_ANDROID_SWITCH
+ * -----------------------
+ *
+ * Called by the Android System to indicate the Android user is about to change, when the change
+ * request was made in a way that is not integrated with the HAL (for example, through
+ * adb shell am switch-user).
+ *
+ * The HAL can switch its internal user once it receives this request, but it doesn't need to
+ * reply back to the Android System. If its internal user cannot be changed for some reason,
+ * then it must wait for the SWITCH_USER(type=ANDROID_POST_SWITCH) call to recover
+ * (for example, it could issue a SWITCH_USER(type=VEHICLE_REQUEST) to switch back to
+ * the previous user), but ideally it should never fail (as switching back could result in a
+ * confusing experience for the end user).
+ *
+ * For example, if the system have users (0, 10, 11) and it's switching from 0 to 11 (where none
+ * of them have any special flag), the request would be:
+ *
+ * int32[0]: 42 // request id
+ * int32[1]: 1 // SwitchUserMessageType::LEGACY_ANDROID_SWITCH
+ * int32[2]: 11 // target user id
+ * int32[3]: 0 // target user flags (none)
+ * int32[4]: 10 // current user
+ * int32[5]: 0 // current user flags (none)
+ * int32[6]: 3 // number of users
+ * int32[7]: 0 // user #0 (Android user id 0)
+ * int32[8]: 0 // flags of user #0 (none)
+ * int32[9]: 10 // user #1 (Android user id 10)
+ * int32[10]: 0 // flags of user #1 (none)
+ * int32[11]: 11 // user #2 (Android user id 11)
+ * int32[12]: 0 // flags of user #2 (none)
+ *
+ * 2.ANDROID_SWITCH
+ * ----------------
+ * Called by the Android System to indicate the Android user is about to change, but Android
+ * will wait for the HAL's response (up to some time) before proceeding.
+ *
+ * The HAL must switch its internal user once it receives this request, then respond back to
+ * Android with a SWITCH_USER(type=VEHICLE_RESPONSE) indicating whether its internal
+ * user was switched or not (through the SwitchUserStatus enum).
+ *
+ * For example, if Android has users (0, 10, 11) and it's switching from 10 to 11 (where
+ * none of them have any special flag), the request would be:
+ *
+ * int32[0]: 42 // request id
+ * int32[1]: 2 // SwitchUserMessageType::ANDROID_SWITCH
+ * int32[2]: 11 // target user id
+ * int32[3]: 0 // target user flags (none)
+ * int32[4]: 10 // current user
+ * int32[5]: 0 // current user flags (none)
+ * int32[6]: 3 // number of users
+ * int32[7]: 0 // 1st user (user 0)
+ * int32[8]: 0 // 1st user flags (none)
+ * int32[9]: 10 // 2nd user (user 10)
+ * int32[10]: 0 // 2nd user flags (none)
+ * int32[11]: 11 // 3rd user (user 11)
+ * int32[12]: 0 // 3rd user flags (none)
+ *
+ * If the request succeeded, the HAL must update the propery with:
+ *
+ * int32[0]: 42 // request id
+ * int32[1]: 3 // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+ * int32[2]: 1 // status = SwitchUserStatus::SUCCESS
+ *
+ * But if it failed, the response would be something like:
+ *
+ * int32[0]: 42 // request id
+ * int32[1]: 3 // messageType = SwitchUserMessageType::VEHICLE_RESPONSE
+ * int32[2]: 2 // status = SwitchUserStatus::FAILURE
+ * string: "108-D'OH!" // OEM-spefic error message
+ *
+ * 3.VEHICLE_RESPONSE
+ * ------------------
+ * Called by the HAL to indicate whether a request of type ANDROID_SWITCH should proceed or
+ * abort - see the ANDROID_SWITCH section above for more info.
+ *
+ * 4.VEHICLE_REQUEST
+ * ------------------
+ * Called by the HAL to request that the current foreground Android user is switched.
+ *
+ * This is useful in situations where Android started as one user, but the vehicle identified
+ * the driver as another user. For example, user A unlocked the car using the key fob of user B;
+ * the INITIAL_USER_INFO request returned user B, but then a face recognition subsubsystem
+ * identified the user as A.
+ *
+ * The HAL makes this request by a property change event (passing a negative request id), and
+ * the Android system will response by issuye an ANDROID_POST_SWITCH call which the same
+ * request id.
+ *
+ * For example, if the current foreground Android user is 10 and the HAL asked it to switch to
+ * 11, the request would be:
+ *
+ * int32[0]: -108 // request id
+ * int32[1]: 4 // messageType = SwitchUserMessageType::VEHICLE_REQUEST
+ * int32[2]: 11 // Android user id
+ *
+ * If the request succeeded and Android has 3 users (0, 10, 11), the response would be:
+ *
+ * int32[0]: -108 // request id
+ * int32[1]: 5 // messageType = SwitchUserMessageType::ANDROID_SWITCH
+ * int32[2]: 11 // target user id
+ * int32[3]: 11 // target user id flags (none)
+ * int32[4]: 11 // current user
+ * int32[5]: 0 // current user flags (none)
+ * int32[6]: 3 // number of users
+ * int32[7]: 0 // 1st user (user 0)
+ * int32[8]: 0 // 1st user flags (none)
+ * int32[9]: 10 // 2nd user (user 10)
+ * int32[10]: 4 // 2nd user flags (none)
+ * int32[11]: 11 // 3rd user (user 11)
+ * int32[12]: 3 // 3rd user flags (none)
+ *
+ * Notice that both the current and target user ids are the same - if the request failed, then
+ * they would be different (i.e, target user would be 11, but current user would still be 10).
+ *
+ * 5.ANDROID_POST_SWITCH
+ * ---------------------
+ * Called by the Android System after a request to switch a user was made
+ *
+ * This property is called after switch requests of any type (i.e., LEGACY_ANDROID_SWITCH,
+ * ANDROID_SWITCH, or VEHICLE_REQUEST) and can be used to determine if the request succeeded or
+ * failed:
+ *
+ * 1. When it succeeded, it's called when the Android user is in the boot locked state and the
+ * value of the current and target users ids in the response are different. This would be
+ * equivalent to receiving an Intent.ACTION_LOCKED_BOOT_COMPLETED in an Android app.
+ * 2. When it failed it's called right away and the value of the current and target users ids
+ * in the response are the same.
+ *
+ * The HAL can update its internal state once it receives this request, but it doesn't need to
+ * reply back to the Android System.
+ *
+ * Request: the first N values as defined by INITIAL_USER_INFO (where the request-specific
+ * value at index 1 is SwitchUserMessageType::ANDROID_POST_SWITCH), then 2 more values for the
+ * target user id (i.e., the Android user id that was requested to be switched to) and its flags
+ * (as defined by UserFlags).
+ *
+ * Response: none.
+ *
+ * Example: see VEHICLE_REQUEST section above.
+ *
+ * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+ * @access VehiclePropertyAccess:READ_WRITE
+ */
+ SWITCH_USER = (
+ 0x0F08
+ | VehiclePropertyGroup:SYSTEM
+ | VehiclePropertyType:MIXED
+ | VehicleArea:GLOBAL),
};
/**
@@ -3733,3 +3944,258 @@
enum VmsPublisherInformationIntegerValuesIndex : VmsBaseMessageIntegerValuesIndex {
PUBLISHER_ID = 1,
};
+
+/**
+ * Information about a specific Android user.
+ */
+struct UserInfo {
+
+ UserId userId;
+
+ UserFlags flags;
+};
+
+/**
+ * Id of an Android user.
+ *
+ * Must be > 0 for valid ids, or -1 when it's not used.
+ */
+typedef int32_t UserId;
+
+/**
+ * Flags used to define the characteristics of an Android user.
+ */
+enum UserFlags: int32_t {
+ /**
+ * No flags.
+ */
+ NONE = 0x0,
+
+ /**
+ * System user.
+ * On automotive, that user is always running, although never on foreground (except during
+ * boot or exceptional circumstances).
+ */
+ SYSTEM = 0x01,
+
+ /**
+ * Guest users have restrictions.
+ */
+ GUEST = 0x02,
+
+ /**
+ * Ephemeral users have non-persistent state.
+ */
+ EPHEMERAL = 0x04,
+
+ /**
+ * Admin users have additional privileges such as permission to create other users.
+ */
+ ADMIN = 0x08,
+};
+
+/**
+ * Information about all Android users.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it's part of other structs, which
+ * in turn are converted to a VehiclePropValue.RawValue through libraries provided by the default
+ * Vehicle HAL implementation.
+ */
+struct UsersInfo {
+
+ /** The current foreground user. */
+ UserInfo currentUser;
+
+ /** Number of existing users (includes the current user). */
+ int32_t numberUsers;
+
+ /** List of existing users (includes the current user). */
+ vec<UserInfo> existingUsers;
+ };
+
+/**
+ * Id of a request related to user management.
+ *
+ * This id can be used by the Android system to map responses sent by the HAL, and vice-versa.
+ *
+ * For requests originated by Android, the value is positive (> 0), while for requests originated by
+ * the HAL it must be negative (< 0).
+ */
+typedef int32_t UserRequestId;
+
+/**
+ * Defines the format of a INITIAL_USER_INFO request made by the Android system.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoRequest {
+ /**
+ * Arbitrary id used to map the HAL response to the request.
+ */
+ UserRequestId requestId;
+
+ /**
+ * Type of request.
+ */
+ InitialUserInfoRequestType requestType;
+
+ /**
+ * Information about the current state of the Android system.
+ */
+ UsersInfo usersInfo;
+};
+
+/**
+ * Defines when a INITIAL_USER_INFO request was made.
+ */
+enum InitialUserInfoRequestType : int32_t {
+ /** At the first time Android was booted (or after a factory reset). */
+ FIRST_BOOT = 1,
+
+ /** At the first time Android was booted after the system was updated. */
+ FIRST_BOOT_AFTER_OTA = 2,
+
+ /** When Android was booted "from scratch". */
+ COLD_BOOT = 3,
+
+ /** When Android was resumed after the system was suspended to memory. */
+ RESUME = 4,
+};
+
+/**
+ * Defines the format of a HAL response to a INITIAL_USER_INFO request.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct InitialUserInfoResponse {
+ /**
+ * Id of the request being responded.
+ */
+ UserRequestId requestId;
+
+ /**
+ * which action the Android system should take.
+ */
+ InitialUserInfoResponseAction action;
+
+ /**
+ * Information about the user that should be switched to or created.
+ */
+ UserInfo userToSwitchOrCreate;
+
+ /**
+ * Name of the user that should be created.
+ */
+ string userNameToCreate;
+};
+
+/**
+ * Defines which action the Android system should take in an INITIAL_USER_INFO request.
+ */
+enum InitialUserInfoResponseAction : int32_t {
+ /**
+ * Let the Android System decide what to do.
+ *
+ * For example, it might create a new user on first boot, and switch to the last
+ * active user afterwards.
+ */
+ DEFAULT = 0,
+
+ /**
+ * Switch to an existing Android user.
+ */
+ SWITCH = 1,
+
+ /**
+ * Create a new Android user (and switch to it).
+ */
+ CREATE = 2,
+};
+
+/**
+ * Defines the format of a SWITCH_USER property.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserRequest {
+ /**
+ * Arbitrary id used to map the response to the request.
+ */
+ UserRequestId requestId;
+
+ /**
+ * Type of message.
+ */
+ SwitchUserMessageType messageType;
+
+ /**
+ * Information about the Android user being switched to.
+ *
+ * Only the user id (but not the flags) should be set when the request is made by HAL.
+ */
+ UserInfo targetUser;
+
+ /**
+ * Information about the current state of the Android system.
+ *
+ * Should not be set when the request is made by HAL.
+ */
+ UsersInfo usersInfo;
+};
+
+/**
+ * Defines the reason a SWITCH_USER call was made.
+ *
+ * The meaning of each constant is explained in that property.
+ */
+enum SwitchUserMessageType: int32_t {
+ LEGACY_ANDROID_SWITCH = 1,
+ ANDROID_SWITCH = 2,
+ VEHICLE_RESPONSE = 3,
+ VEHICLE_REQUEST = 4,
+ ANDROID_POST_SWITCH = 5,
+};
+
+/**
+ * Defines the result of a SwitchUserRequest.
+ *
+ * NOTE: this struct is not used in the HAL properties directly, it must be converted to
+ * VehiclePropValue.RawValue through libraries provided by the default Vehicle HAL implementation.
+ */
+struct SwitchUserResponse {
+ /**
+ * Id of the request being responded.
+ */
+ UserRequestId requestId;
+
+ /**
+ * Type of message.
+ */
+ SwitchUserMessageType messageType;
+
+ /**
+ * Status of the request.
+ */
+ SwitchUserStatus status;
+
+ /**
+ * HAL-specific error message.
+ *
+ * This argument is optional, and when defined (and the status is FAILURE), it's passed "as-is"
+ * to the caller. It could be used to show custom error messages to the end user.
+ */
+ string failureMessage;
+};
+
+/**
+ * Status of the response to a SwitchUserRequest.
+ */
+enum SwitchUserStatus : int32_t {
+ /** The request succeeded and the HAL user was switched. */
+ SUCCESS = 1,
+ /** The request failed and the HAL user remained the same. */
+ FAILURE = 2,
+};
diff --git a/camera/common/1.0/default/HandleImporter.cpp b/camera/common/1.0/default/HandleImporter.cpp
index ac32c95..7792b31 100644
--- a/camera/common/1.0/default/HandleImporter.cpp
+++ b/camera/common/1.0/default/HandleImporter.cpp
@@ -182,9 +182,8 @@
}
Mutex::Autolock lock(mLock);
- if (mMapperV4 == nullptr && mMapperV3 == nullptr && mMapperV2 == nullptr) {
- ALOGE("%s: mMapperV4, mMapperV3 and mMapperV2 are all null!", __FUNCTION__);
- return;
+ if (!mInitialized) {
+ initializeLocked();
}
if (mMapperV4 != nullptr) {
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 9ff0d74..5f86742 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -81,8 +81,6 @@
return locked;
}
-buffer_handle_t sEmptyBuffer = nullptr;
-
} // Anonymous namespace
// Static instances
@@ -119,8 +117,8 @@
std::string make, model;
if (ret < 0) {
ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
- make = "Generic UVC webcam";
- model = "Generic UVC webcam";
+ mExifMake = "Generic UVC webcam";
+ mExifModel = "Generic UVC webcam";
} else {
// capability.card is UTF-8 encoded
char card[32];
@@ -134,11 +132,11 @@
}
}
if (j == 0 || card[j - 1] != '\0') {
- make = "Generic UVC webcam";
- model = "Generic UVC webcam";
+ mExifMake = "Generic UVC webcam";
+ mExifModel = "Generic UVC webcam";
} else {
- make = card;
- model = card;
+ mExifMake = card;
+ mExifModel = card;
}
}
@@ -147,7 +145,7 @@
ALOGE("%s: init OutputThread failed!", __FUNCTION__);
return true;
}
- mOutputThread->setExifMakeModel(make, model);
+ mOutputThread->setExifMakeModel(mExifMake, mExifModel);
status_t status = initDefaultRequests();
if (status != OK) {
@@ -161,7 +159,7 @@
ALOGE("%s: invalid request fmq", __FUNCTION__);
return true;
}
- mResultMetadataQueue = std::make_shared<RequestMetadataQueue>(
+ mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
kMetadataMsgQueueSize, false /* non blocking */);
if (!mResultMetadataQueue->isValid()) {
ALOGE("%s: invalid result fmq", __FUNCTION__);
@@ -183,7 +181,7 @@
}
void ExternalCameraDeviceSession::initOutputThread() {
- mOutputThread = new OutputThread(this, mCroppingType);
+ mOutputThread = new OutputThread(this, mCroppingType, mCameraCharacteristics);
}
void ExternalCameraDeviceSession::closeOutputThread() {
@@ -518,35 +516,9 @@
uint64_t bufId, buffer_handle_t buf,
/*out*/buffer_handle_t** outBufPtr,
bool allowEmptyBuf) {
-
- if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
- if (allowEmptyBuf) {
- *outBufPtr = &sEmptyBuffer;
- return Status::OK;
- } else {
- ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
- return Status::ILLEGAL_ARGUMENT;
- }
- }
-
- CirculatingBuffers& cbs = mCirculatingBuffers[streamId];
- if (cbs.count(bufId) == 0) {
- if (buf == nullptr) {
- ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
- return Status::ILLEGAL_ARGUMENT;
- }
- // Register a newly seen buffer
- buffer_handle_t importedBuf = buf;
- sHandleImporter.importBuffer(importedBuf);
- if (importedBuf == nullptr) {
- ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
- return Status::INTERNAL_ERROR;
- } else {
- cbs[bufId] = importedBuf;
- }
- }
- *outBufPtr = &cbs[bufId];
- return Status::OK;
+ return importBufferImpl(
+ mCirculatingBuffers, sHandleImporter, streamId,
+ bufId, buf, outBufPtr, allowEmptyBuf);
}
Status ExternalCameraDeviceSession::importRequestLockedImpl(
@@ -791,15 +763,32 @@
//TODO: refactor with processCaptureResult
Status ExternalCameraDeviceSession::processCaptureRequestError(
- const std::shared_ptr<HalRequest>& req) {
+ const std::shared_ptr<HalRequest>& req,
+ /*out*/std::vector<NotifyMsg>* outMsgs,
+ /*out*/std::vector<CaptureResult>* outResults) {
ATRACE_CALL();
// Return V4L2 buffer to V4L2 buffer queue
- enqueueV4l2Frame(req->frameIn);
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+ enqueueV4l2Frame(v4l2Frame);
- // NotifyShutter
- notifyShutter(req->frameNumber, req->shutterTs);
+ if (outMsgs == nullptr) {
+ notifyShutter(req->frameNumber, req->shutterTs);
+ notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ } else {
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = req->frameNumber;
+ shutter.msg.shutter.timestamp = req->shutterTs;
- notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = req->frameNumber;
+ error.msg.error.errorStreamId = -1;
+ error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+ outMsgs->push_back(shutter);
+ outMsgs->push_back(error);
+ }
// Fill output buffers
hidl_vec<CaptureResult> results;
@@ -826,16 +815,22 @@
mInflightFrames.erase(req->frameNumber);
}
- // Callback into framework
- invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
- freeReleaseFences(results);
+ if (outResults == nullptr) {
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ freeReleaseFences(results);
+ } else {
+ outResults->push_back(result);
+ }
return Status::OK;
}
Status ExternalCameraDeviceSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
ATRACE_CALL();
// Return V4L2 buffer to V4L2 buffer queue
- enqueueV4l2Frame(req->frameIn);
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(req->frameIn.get());
+ enqueueV4l2Frame(v4l2Frame);
// NotifyShutter
notifyShutter(req->frameNumber, req->shutterTs);
@@ -923,29 +918,10 @@
mProcessCaptureResultLock.unlock();
}
-void ExternalCameraDeviceSession::freeReleaseFences(hidl_vec<CaptureResult>& results) {
- for (auto& result : results) {
- if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
- native_handle_t* handle = const_cast<native_handle_t*>(
- result.inputBuffer.releaseFence.getNativeHandle());
- native_handle_close(handle);
- native_handle_delete(handle);
- }
- for (auto& buf : result.outputBuffers) {
- if (buf.releaseFence.getNativeHandle() != nullptr) {
- native_handle_t* handle = const_cast<native_handle_t*>(
- buf.releaseFence.getNativeHandle());
- native_handle_close(handle);
- native_handle_delete(handle);
- }
- }
- }
- return;
-}
-
ExternalCameraDeviceSession::OutputThread::OutputThread(
- wp<ExternalCameraDeviceSession> parent,
- CroppingType ct) : mParent(parent), mCroppingType(ct) {}
+ wp<OutputThreadInterface> parent, CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars) :
+ mParent(parent), mCroppingType(ct), mCameraCharacteristics(chars) {}
ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
@@ -955,88 +931,6 @@
mExifModel = model;
}
-uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout(
- const YCbCrLayout& layout) {
- intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
- intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
- if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
- // Interleaved format
- if (layout.cb > layout.cr) {
- return V4L2_PIX_FMT_NV21;
- } else {
- return V4L2_PIX_FMT_NV12;
- }
- } else if (layout.chromaStep == 1) {
- // Planar format
- if (layout.cb > layout.cr) {
- return V4L2_PIX_FMT_YVU420; // YV12
- } else {
- return V4L2_PIX_FMT_YUV420; // YU12
- }
- } else {
- return FLEX_YUV_GENERIC;
- }
-}
-
-int ExternalCameraDeviceSession::OutputThread::getCropRect(
- CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
- if (out == nullptr) {
- ALOGE("%s: out is null", __FUNCTION__);
- return -1;
- }
-
- uint32_t inW = inSize.width;
- uint32_t inH = inSize.height;
- uint32_t outW = outSize.width;
- uint32_t outH = outSize.height;
-
- // Handle special case where aspect ratio is close to input but scaled
- // dimension is slightly larger than input
- float arIn = ASPECT_RATIO(inSize);
- float arOut = ASPECT_RATIO(outSize);
- if (isAspectRatioClose(arIn, arOut)) {
- out->left = 0;
- out->top = 0;
- out->width = inW;
- out->height = inH;
- return 0;
- }
-
- if (ct == VERTICAL) {
- uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
- if (scaledOutH > inH) {
- ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
- __FUNCTION__, outW, outH, inW, inH);
- return -1;
- }
- scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
-
- out->left = 0;
- out->top = ((inH - scaledOutH) / 2) & ~0x1;
- out->width = inW;
- out->height = static_cast<int32_t>(scaledOutH);
- ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
- __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
- } else {
- uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
- if (scaledOutW > inW) {
- ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
- __FUNCTION__, outW, outH, inW, inH);
- return -1;
- }
- scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
-
- out->left = ((inW - scaledOutW) / 2) & ~0x1;
- out->top = 0;
- out->width = static_cast<int32_t>(scaledOutW);
- out->height = inH;
- ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
- __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
- }
-
- return 0;
-}
-
int ExternalCameraDeviceSession::OutputThread::cropAndScaleLocked(
sp<AllocatedFrame>& in, const Size& outSz, YCbCrLayout* out) {
Size inSz = {in->mWidth, in->mHeight};
@@ -1274,265 +1168,6 @@
return 0;
}
-int ExternalCameraDeviceSession::OutputThread::formatConvertLocked(
- const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
- int ret = 0;
- switch (format) {
- case V4L2_PIX_FMT_NV21:
- ret = libyuv::I420ToNV21(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cr),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: convert to NV21 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case V4L2_PIX_FMT_NV12:
- ret = libyuv::I420ToNV12(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cb),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: convert to NV12 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case V4L2_PIX_FMT_YVU420: // YV12
- case V4L2_PIX_FMT_YUV420: // YU12
- // TODO: maybe we can speed up here by somehow save this copy?
- ret = libyuv::I420Copy(
- static_cast<uint8_t*>(in.y),
- in.yStride,
- static_cast<uint8_t*>(in.cb),
- in.cStride,
- static_cast<uint8_t*>(in.cr),
- in.cStride,
- static_cast<uint8_t*>(out.y),
- out.yStride,
- static_cast<uint8_t*>(out.cb),
- out.cStride,
- static_cast<uint8_t*>(out.cr),
- out.cStride,
- sz.width,
- sz.height);
- if (ret != 0) {
- ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
- __FUNCTION__, ret);
- return ret;
- }
- break;
- case FLEX_YUV_GENERIC:
- // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
- ALOGE("%s: unsupported flexible yuv layout"
- " y %p cb %p cr %p y_str %d c_str %d c_step %d",
- __FUNCTION__, out.y, out.cb, out.cr,
- out.yStride, out.cStride, out.chromaStep);
- return -1;
- default:
- ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
- return -1;
- }
- return 0;
-}
-
-int ExternalCameraDeviceSession::OutputThread::encodeJpegYU12(
- const Size & inSz, const YCbCrLayout& inLayout,
- int jpegQuality, const void *app1Buffer, size_t app1Size,
- void *out, const size_t maxOutSize, size_t &actualCodeSize)
-{
- /* libjpeg is a C library so we use C-style "inheritance" by
- * putting libjpeg's jpeg_destination_mgr first in our custom
- * struct. This allows us to cast jpeg_destination_mgr* to
- * CustomJpegDestMgr* when we get it passed to us in a callback */
- struct CustomJpegDestMgr {
- struct jpeg_destination_mgr mgr;
- JOCTET *mBuffer;
- size_t mBufferSize;
- size_t mEncodedSize;
- bool mSuccess;
- } dmgr;
-
- jpeg_compress_struct cinfo = {};
- jpeg_error_mgr jerr;
-
- /* Initialize error handling with standard callbacks, but
- * then override output_message (to print to ALOG) and
- * error_exit to set a flag and print a message instead
- * of killing the whole process */
- cinfo.err = jpeg_std_error(&jerr);
-
- cinfo.err->output_message = [](j_common_ptr cinfo) {
- char buffer[JMSG_LENGTH_MAX];
-
- /* Create the message */
- (*cinfo->err->format_message)(cinfo, buffer);
- ALOGE("libjpeg error: %s", buffer);
- };
- cinfo.err->error_exit = [](j_common_ptr cinfo) {
- (*cinfo->err->output_message)(cinfo);
- if(cinfo->client_data) {
- auto & dmgr =
- *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
- dmgr.mSuccess = false;
- }
- };
- /* Now that we initialized some callbacks, let's create our compressor */
- jpeg_create_compress(&cinfo);
-
- /* Initialize our destination manager */
- dmgr.mBuffer = static_cast<JOCTET*>(out);
- dmgr.mBufferSize = maxOutSize;
- dmgr.mEncodedSize = 0;
- dmgr.mSuccess = true;
- cinfo.client_data = static_cast<void*>(&dmgr);
-
- /* These lambdas become C-style function pointers and as per C++11 spec
- * may not capture anything */
- dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
- auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
- dmgr.mgr.next_output_byte = dmgr.mBuffer;
- dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
- ALOGV("%s:%d jpeg start: %p [%zu]",
- __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
- };
-
- dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
- ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
- return 0;
- };
-
- dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
- auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
- dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
- ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
- };
- cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
-
- /* We are going to be using JPEG in raw data mode, so we are passing
- * straight subsampled planar YCbCr and it will not touch our pixel
- * data or do any scaling or anything */
- cinfo.image_width = inSz.width;
- cinfo.image_height = inSz.height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_YCbCr;
-
- /* Initialize defaults and then override what we want */
- jpeg_set_defaults(&cinfo);
-
- jpeg_set_quality(&cinfo, jpegQuality, 1);
- jpeg_set_colorspace(&cinfo, JCS_YCbCr);
- cinfo.raw_data_in = 1;
- cinfo.dct_method = JDCT_IFAST;
-
- /* Configure sampling factors. The sampling factor is JPEG subsampling 420
- * because the source format is YUV420. Note that libjpeg sampling factors
- * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
- * 1 V value for each 2 Y values */
- cinfo.comp_info[0].h_samp_factor = 2;
- cinfo.comp_info[0].v_samp_factor = 2;
- cinfo.comp_info[1].h_samp_factor = 1;
- cinfo.comp_info[1].v_samp_factor = 1;
- cinfo.comp_info[2].h_samp_factor = 1;
- cinfo.comp_info[2].v_samp_factor = 1;
-
- /* Let's not hardcode YUV420 in 6 places... 5 was enough */
- int maxVSampFactor = std::max( {
- cinfo.comp_info[0].v_samp_factor,
- cinfo.comp_info[1].v_samp_factor,
- cinfo.comp_info[2].v_samp_factor
- });
- int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
- cinfo.comp_info[1].v_samp_factor;
-
- /* Start the compressor */
- jpeg_start_compress(&cinfo, TRUE);
-
- /* Compute our macroblock height, so we can pad our input to be vertically
- * macroblock aligned.
- * TODO: Does it need to be horizontally MCU aligned too? */
-
- size_t mcuV = DCTSIZE*maxVSampFactor;
- size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
-
- /* libjpeg uses arrays of row pointers, which makes it really easy to pad
- * data vertically (unfortunately doesn't help horizontally) */
- std::vector<JSAMPROW> yLines (paddedHeight);
- std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
- std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
-
- uint8_t *py = static_cast<uint8_t*>(inLayout.y);
- uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
- uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
-
- for(uint32_t i = 0; i < paddedHeight; i++)
- {
- /* Once we are in the padding territory we still point to the last line
- * effectively replicating it several times ~ CLAMP_TO_EDGE */
- int li = std::min(i, inSz.height - 1);
- yLines[i] = static_cast<JSAMPROW>(py + li * inLayout.yStride);
- if(i < paddedHeight / cVSubSampling)
- {
- crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
- cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
- }
- }
-
- /* If APP1 data was passed in, use it */
- if(app1Buffer && app1Size)
- {
- jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
- static_cast<const JOCTET*>(app1Buffer), app1Size);
- }
-
- /* While we still have padded height left to go, keep giving it one
- * macroblock at a time. */
- while (cinfo.next_scanline < cinfo.image_height) {
- const uint32_t batchSize = DCTSIZE * maxVSampFactor;
- const uint32_t nl = cinfo.next_scanline;
- JSAMPARRAY planes[3]{ &yLines[nl],
- &cbLines[nl/cVSubSampling],
- &crLines[nl/cVSubSampling] };
-
- uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
-
- if (done != batchSize) {
- ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
- __FUNCTION__, done, batchSize, cinfo.next_scanline,
- cinfo.image_height);
- return -1;
- }
- }
-
- /* This will flush everything */
- jpeg_finish_compress(&cinfo);
-
- /* Grab the actual code size and set it */
- actualCodeSize = dmgr.mEncodedSize;
-
- return 0;
-}
-
/*
* TODO: There needs to be a mechanism to discover allocated buffer size
* in the HAL.
@@ -1555,25 +1190,9 @@
}
Size ExternalCameraDeviceSession::getMaxThumbResolution() const {
- Size thumbSize { 0, 0 };
- camera_metadata_ro_entry entry =
- mCameraCharacteristics.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
- for(uint32_t i = 0; i < entry.count; i += 2) {
- Size sz { static_cast<uint32_t>(entry.data.i32[i]),
- static_cast<uint32_t>(entry.data.i32[i+1]) };
- if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
- thumbSize = sz;
- }
- }
-
- if (thumbSize.width * thumbSize.height == 0) {
- ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
- }
-
- return thumbSize;
+ return getMaxThumbnailResolution(mCameraCharacteristics);
}
-
ssize_t ExternalCameraDeviceSession::getJpegBufferSize(
uint32_t width, uint32_t height) const {
// Constant from camera3.h
@@ -1616,7 +1235,7 @@
int ExternalCameraDeviceSession::OutputThread::createJpegLocked(
HalStreamBuffer &halBuf,
- const std::shared_ptr<HalRequest>& req)
+ const common::V1_0::helper::CameraMetadata& setting)
{
ATRACE_CALL();
int ret;
@@ -1645,17 +1264,17 @@
Size thumbSize;
bool outputThumbnail = true;
- if (req->setting.exists(ANDROID_JPEG_QUALITY)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_QUALITY);
+ if (setting.exists(ANDROID_JPEG_QUALITY)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_QUALITY);
jpegQuality = entry.data.u8[0];
} else {
return lfail("%s: ANDROID_JPEG_QUALITY not set",__FUNCTION__);
}
- if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
+ if (setting.exists(ANDROID_JPEG_THUMBNAIL_QUALITY)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_THUMBNAIL_QUALITY);
thumbQuality = entry.data.u8[0];
} else {
return lfail(
@@ -1663,9 +1282,9 @@
__FUNCTION__);
}
- if (req->setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
- camera_metadata_entry entry =
- req->setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
+ if (setting.exists(ANDROID_JPEG_THUMBNAIL_SIZE)) {
+ camera_metadata_ro_entry entry =
+ setting.find(ANDROID_JPEG_THUMBNAIL_SIZE);
thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
static_cast<uint32_t>(entry.data.i32[1])
};
@@ -1732,8 +1351,8 @@
/* Combine camera characteristics with request settings to form EXIF
* metadata */
- common::V1_0::helper::CameraMetadata meta(parent->mCameraCharacteristics);
- meta.append(req->setting);
+ common::V1_0::helper::CameraMetadata meta(mCameraCharacteristics);
+ meta.append(setting);
/* Generate EXIF object */
std::unique_ptr<ExifUtils> utils(ExifUtils::create());
@@ -1838,7 +1457,7 @@
// TODO: see if we can save some computation by converting to YV12 here
uint8_t* inData;
size_t inDataSize;
- if (req->frameIn->map(&inData, &inDataSize) != 0) {
+ if (req->frameIn->getData(&inData, &inDataSize) != 0) {
lk.unlock();
return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
}
@@ -1899,7 +1518,7 @@
// Gralloc lockYCbCr the buffer
switch (halBuf.format) {
case PixelFormat::BLOB: {
- int ret = createJpegLocked(halBuf, req);
+ int ret = createJpegLocked(halBuf, req->setting);
if(ret != 0) {
lk.unlock();
@@ -1949,8 +1568,8 @@
}
Size sz {halBuf.width, halBuf.height};
- ATRACE_BEGIN("formatConvertLocked");
- ret = formatConvertLocked(cropAndScaled, outLayout, sz, outputFourcc);
+ ATRACE_BEGIN("formatConvert");
+ ret = formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
ATRACE_END();
if (ret != 0) {
lk.unlock();
@@ -2055,6 +1674,14 @@
return Status::OK;
}
+void ExternalCameraDeviceSession::OutputThread::clearIntermediateBuffers() {
+ std::lock_guard<std::mutex> lk(mBufferLock);
+ mYu12Frame.clear();
+ mYu12ThumbFrame.clear();
+ mIntermediateBuffers.clear();
+ mBlobBufferSize = 0;
+}
+
Status ExternalCameraDeviceSession::OutputThread::submitRequest(
const std::shared_ptr<HalRequest>& req) {
std::unique_lock<std::mutex> lk(mRequestListLock);
@@ -2090,6 +1717,32 @@
}
}
+std::list<std::shared_ptr<HalRequest>>
+ExternalCameraDeviceSession::OutputThread::switchToOffline() {
+ ATRACE_CALL();
+ std::list<std::shared_ptr<HalRequest>> emptyList;
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return emptyList;
+ }
+
+ std::unique_lock<std::mutex> lk(mRequestListLock);
+ std::list<std::shared_ptr<HalRequest>> reqs = std::move(mRequestList);
+ mRequestList.clear();
+ if (mProcessingRequest) {
+ std::chrono::seconds timeout = std::chrono::seconds(kFlushWaitTimeoutSec);
+ auto st = mRequestDoneCond.wait_for(lk, timeout);
+ if (st == std::cv_status::timeout) {
+ ALOGE("%s: wait for inflight request finish timeout!", __FUNCTION__);
+ }
+ }
+ lk.unlock();
+ clearIntermediateBuffers();
+ ALOGV("%s: returning %zu request for offline processing", __FUNCTION__, reqs.size());
+ return reqs;
+}
+
void ExternalCameraDeviceSession::OutputThread::waitForNextRequest(
std::shared_ptr<HalRequest>* out) {
ATRACE_CALL();
@@ -2733,6 +2386,7 @@
return Status::INTERNAL_ERROR;
}
+ mBlobBufferSize = blobBufferSize;
status = mOutputThread->allocateIntermediateBuffers(v4lSize,
mMaxThumbResolution, config.streams, blobBufferSize);
if (status != Status::OK) {
@@ -2916,16 +2570,6 @@
status_t ExternalCameraDeviceSession::fillCaptureResult(
common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
- // android.control
- // For USB camera, we don't know the AE state. Set the state to converged to
- // indicate the frame should be good to use. Then apps don't have to wait the
- // AE state.
- const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
- UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
-
- const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
- UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
-
bool afTrigger = false;
{
std::lock_guard<std::mutex> lk(mAfTriggerLock);
@@ -2951,46 +2595,10 @@
}
UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
- // Set AWB state to converged to indicate the frame should be good to use.
- const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
- UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+ camera_metadata_ro_entry activeArraySize =
+ mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
- const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
- UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
-
- camera_metadata_ro_entry active_array_size =
- mCameraCharacteristics.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
-
- if (active_array_size.count == 0) {
- ALOGE("%s: cannot find active array size!", __FUNCTION__);
- return -EINVAL;
- }
-
- const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
- UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
-
- // This means pipeline latency of X frame intervals. The maximum number is 4.
- const uint8_t requestPipelineMaxDepth = 4;
- UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
-
- // android.scaler
- const int32_t crop_region[] = {
- active_array_size.data.i32[0], active_array_size.data.i32[1],
- active_array_size.data.i32[2], active_array_size.data.i32[3],
- };
- UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
-
- // android.sensor
- UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1);
-
- // android.statistics
- const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
- UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
-
- const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
- UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
-
- return OK;
+ return fillCaptureResultCommon(md, timestamp, activeArraySize);
}
#undef ARRAY_SIZE
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index e25deff..62a4c87 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -18,10 +18,23 @@
#include <log/log.h>
#include <cmath>
+#include <cstring>
#include <sys/mman.h>
#include <linux/videodev2.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <jpeglib.h>
+
#include "ExternalCameraUtils.h"
+namespace {
+
+buffer_handle_t sEmptyBuffer = nullptr;
+
+} // Anonymous namespace
+
namespace android {
namespace hardware {
namespace camera {
@@ -29,10 +42,13 @@
namespace V3_4 {
namespace implementation {
+Frame::Frame(uint32_t width, uint32_t height, uint32_t fourcc) :
+ mWidth(width), mHeight(height), mFourcc(fourcc) {}
+
V4L2Frame::V4L2Frame(
uint32_t w, uint32_t h, uint32_t fourcc,
int bufIdx, int fd, uint32_t dataSize, uint64_t offset) :
- mWidth(w), mHeight(h), mFourcc(fourcc),
+ Frame(w, h, fourcc),
mBufferIndex(bufIdx), mFd(fd), mDataSize(dataSize), mOffset(offset) {}
int V4L2Frame::map(uint8_t** data, size_t* dataSize) {
@@ -75,9 +91,13 @@
unmap();
}
+int V4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+ return map(outData, dataSize);
+}
+
AllocatedFrame::AllocatedFrame(
uint32_t w, uint32_t h) :
- mWidth(w), mHeight(h), mFourcc(V4L2_PIX_FMT_YUV420) {};
+ Frame(w, h, V4L2_PIX_FMT_YUV420) {};
AllocatedFrame::~AllocatedFrame() {}
@@ -106,6 +126,17 @@
return 0;
}
+int AllocatedFrame::getData(uint8_t** outData, size_t* dataSize) {
+ YCbCrLayout layout;
+ int ret = allocate(&layout);
+ if (ret != 0) {
+ return ret;
+ }
+ *outData = mData.data();
+ *dataSize = mData.size();
+ return 0;
+}
+
int AllocatedFrame::getLayout(YCbCrLayout* out) {
IMapper::Rect noCrop = {0, 0,
static_cast<int32_t>(mWidth),
@@ -150,8 +181,521 @@
return durationDenominator / static_cast<double>(durationNumerator);
}
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+ /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*inout*/HandleImporter& handleImporter,
+ int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) {
+ using ::android::hardware::camera::common::V1_0::Status;
+ if (buf == nullptr && bufId == BUFFER_ID_NO_BUFFER) {
+ if (allowEmptyBuf) {
+ *outBufPtr = &sEmptyBuffer;
+ return Status::OK;
+ } else {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ }
+
+ CirculatingBuffers& cbs = circulatingBuffers[streamId];
+ if (cbs.count(bufId) == 0) {
+ if (buf == nullptr) {
+ ALOGE("%s: bufferId %" PRIu64 " has null buffer handle!", __FUNCTION__, bufId);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ // Register a newly seen buffer
+ buffer_handle_t importedBuf = buf;
+ handleImporter.importBuffer(importedBuf);
+ if (importedBuf == nullptr) {
+ ALOGE("%s: output buffer for stream %d is invalid!", __FUNCTION__, streamId);
+ return Status::INTERNAL_ERROR;
+ } else {
+ cbs[bufId] = importedBuf;
+ }
+ }
+ *outBufPtr = &cbs[bufId];
+ return Status::OK;
+}
+
+uint32_t getFourCcFromLayout(const YCbCrLayout& layout) {
+ intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
+ intptr_t cr = reinterpret_cast<intptr_t>(layout.cr);
+ if (std::abs(cb - cr) == 1 && layout.chromaStep == 2) {
+ // Interleaved format
+ if (layout.cb > layout.cr) {
+ return V4L2_PIX_FMT_NV21;
+ } else {
+ return V4L2_PIX_FMT_NV12;
+ }
+ } else if (layout.chromaStep == 1) {
+ // Planar format
+ if (layout.cb > layout.cr) {
+ return V4L2_PIX_FMT_YVU420; // YV12
+ } else {
+ return V4L2_PIX_FMT_YUV420; // YU12
+ }
+ } else {
+ return FLEX_YUV_GENERIC;
+ }
+}
+
+int getCropRect(
+ CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out) {
+ if (out == nullptr) {
+ ALOGE("%s: out is null", __FUNCTION__);
+ return -1;
+ }
+
+ uint32_t inW = inSize.width;
+ uint32_t inH = inSize.height;
+ uint32_t outW = outSize.width;
+ uint32_t outH = outSize.height;
+
+ // Handle special case where aspect ratio is close to input but scaled
+ // dimension is slightly larger than input
+ float arIn = ASPECT_RATIO(inSize);
+ float arOut = ASPECT_RATIO(outSize);
+ if (isAspectRatioClose(arIn, arOut)) {
+ out->left = 0;
+ out->top = 0;
+ out->width = inW;
+ out->height = inH;
+ return 0;
+ }
+
+ if (ct == VERTICAL) {
+ uint64_t scaledOutH = static_cast<uint64_t>(outH) * inW / outW;
+ if (scaledOutH > inH) {
+ ALOGE("%s: Output size %dx%d cannot be vertically cropped from input size %dx%d",
+ __FUNCTION__, outW, outH, inW, inH);
+ return -1;
+ }
+ scaledOutH = scaledOutH & ~0x1; // make it multiple of 2
+
+ out->left = 0;
+ out->top = ((inH - scaledOutH) / 2) & ~0x1;
+ out->width = inW;
+ out->height = static_cast<int32_t>(scaledOutH);
+ ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledH %d",
+ __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutH));
+ } else {
+ uint64_t scaledOutW = static_cast<uint64_t>(outW) * inH / outH;
+ if (scaledOutW > inW) {
+ ALOGE("%s: Output size %dx%d cannot be horizontally cropped from input size %dx%d",
+ __FUNCTION__, outW, outH, inW, inH);
+ return -1;
+ }
+ scaledOutW = scaledOutW & ~0x1; // make it multiple of 2
+
+ out->left = ((inW - scaledOutW) / 2) & ~0x1;
+ out->top = 0;
+ out->width = static_cast<int32_t>(scaledOutW);
+ out->height = inH;
+ ALOGV("%s: crop %dx%d to %dx%d: top %d, scaledW %d",
+ __FUNCTION__, inW, inH, outW, outH, out->top, static_cast<int32_t>(scaledOutW));
+ }
+
+ return 0;
+}
+
+int formatConvert(
+ const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format) {
+ int ret = 0;
+ switch (format) {
+ case V4L2_PIX_FMT_NV21:
+ ret = libyuv::I420ToNV21(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cr),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: convert to NV21 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case V4L2_PIX_FMT_NV12:
+ ret = libyuv::I420ToNV12(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cb),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: convert to NV12 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case V4L2_PIX_FMT_YVU420: // YV12
+ case V4L2_PIX_FMT_YUV420: // YU12
+ // TODO: maybe we can speed up here by somehow save this copy?
+ ret = libyuv::I420Copy(
+ static_cast<uint8_t*>(in.y),
+ in.yStride,
+ static_cast<uint8_t*>(in.cb),
+ in.cStride,
+ static_cast<uint8_t*>(in.cr),
+ in.cStride,
+ static_cast<uint8_t*>(out.y),
+ out.yStride,
+ static_cast<uint8_t*>(out.cb),
+ out.cStride,
+ static_cast<uint8_t*>(out.cr),
+ out.cStride,
+ sz.width,
+ sz.height);
+ if (ret != 0) {
+ ALOGE("%s: copy to YV12 or YU12 buffer failed! ret %d",
+ __FUNCTION__, ret);
+ return ret;
+ }
+ break;
+ case FLEX_YUV_GENERIC:
+ // TODO: b/72261744 write to arbitrary flexible YUV layout. Slow.
+ ALOGE("%s: unsupported flexible yuv layout"
+ " y %p cb %p cr %p y_str %d c_str %d c_step %d",
+ __FUNCTION__, out.y, out.cb, out.cr,
+ out.yStride, out.cStride, out.chromaStep);
+ return -1;
+ default:
+ ALOGE("%s: unknown YUV format 0x%x!", __FUNCTION__, format);
+ return -1;
+ }
+ return 0;
+}
+
+int encodeJpegYU12(
+ const Size & inSz, const YCbCrLayout& inLayout,
+ int jpegQuality, const void *app1Buffer, size_t app1Size,
+ void *out, const size_t maxOutSize, size_t &actualCodeSize)
+{
+ /* libjpeg is a C library so we use C-style "inheritance" by
+ * putting libjpeg's jpeg_destination_mgr first in our custom
+ * struct. This allows us to cast jpeg_destination_mgr* to
+ * CustomJpegDestMgr* when we get it passed to us in a callback */
+ struct CustomJpegDestMgr {
+ struct jpeg_destination_mgr mgr;
+ JOCTET *mBuffer;
+ size_t mBufferSize;
+ size_t mEncodedSize;
+ bool mSuccess;
+ } dmgr;
+
+ jpeg_compress_struct cinfo = {};
+ jpeg_error_mgr jerr;
+
+ /* Initialize error handling with standard callbacks, but
+ * then override output_message (to print to ALOG) and
+ * error_exit to set a flag and print a message instead
+ * of killing the whole process */
+ cinfo.err = jpeg_std_error(&jerr);
+
+ cinfo.err->output_message = [](j_common_ptr cinfo) {
+ char buffer[JMSG_LENGTH_MAX];
+
+ /* Create the message */
+ (*cinfo->err->format_message)(cinfo, buffer);
+ ALOGE("libjpeg error: %s", buffer);
+ };
+ cinfo.err->error_exit = [](j_common_ptr cinfo) {
+ (*cinfo->err->output_message)(cinfo);
+ if(cinfo->client_data) {
+ auto & dmgr =
+ *reinterpret_cast<CustomJpegDestMgr*>(cinfo->client_data);
+ dmgr.mSuccess = false;
+ }
+ };
+ /* Now that we initialized some callbacks, let's create our compressor */
+ jpeg_create_compress(&cinfo);
+
+ /* Initialize our destination manager */
+ dmgr.mBuffer = static_cast<JOCTET*>(out);
+ dmgr.mBufferSize = maxOutSize;
+ dmgr.mEncodedSize = 0;
+ dmgr.mSuccess = true;
+ cinfo.client_data = static_cast<void*>(&dmgr);
+
+ /* These lambdas become C-style function pointers and as per C++11 spec
+ * may not capture anything */
+ dmgr.mgr.init_destination = [](j_compress_ptr cinfo) {
+ auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+ dmgr.mgr.next_output_byte = dmgr.mBuffer;
+ dmgr.mgr.free_in_buffer = dmgr.mBufferSize;
+ ALOGV("%s:%d jpeg start: %p [%zu]",
+ __FUNCTION__, __LINE__, dmgr.mBuffer, dmgr.mBufferSize);
+ };
+
+ dmgr.mgr.empty_output_buffer = [](j_compress_ptr cinfo __unused) {
+ ALOGV("%s:%d Out of buffer", __FUNCTION__, __LINE__);
+ return 0;
+ };
+
+ dmgr.mgr.term_destination = [](j_compress_ptr cinfo) {
+ auto & dmgr = reinterpret_cast<CustomJpegDestMgr&>(*cinfo->dest);
+ dmgr.mEncodedSize = dmgr.mBufferSize - dmgr.mgr.free_in_buffer;
+ ALOGV("%s:%d Done with jpeg: %zu", __FUNCTION__, __LINE__, dmgr.mEncodedSize);
+ };
+ cinfo.dest = reinterpret_cast<struct jpeg_destination_mgr*>(&dmgr);
+
+ /* We are going to be using JPEG in raw data mode, so we are passing
+ * straight subsampled planar YCbCr and it will not touch our pixel
+ * data or do any scaling or anything */
+ cinfo.image_width = inSz.width;
+ cinfo.image_height = inSz.height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_YCbCr;
+
+ /* Initialize defaults and then override what we want */
+ jpeg_set_defaults(&cinfo);
+
+ jpeg_set_quality(&cinfo, jpegQuality, 1);
+ jpeg_set_colorspace(&cinfo, JCS_YCbCr);
+ cinfo.raw_data_in = 1;
+ cinfo.dct_method = JDCT_IFAST;
+
+ /* Configure sampling factors. The sampling factor is JPEG subsampling 420
+ * because the source format is YUV420. Note that libjpeg sampling factors
+ * are... a little weird. Sampling of Y=2,U=1,V=1 means there is 1 U and
+ * 1 V value for each 2 Y values */
+ cinfo.comp_info[0].h_samp_factor = 2;
+ cinfo.comp_info[0].v_samp_factor = 2;
+ cinfo.comp_info[1].h_samp_factor = 1;
+ cinfo.comp_info[1].v_samp_factor = 1;
+ cinfo.comp_info[2].h_samp_factor = 1;
+ cinfo.comp_info[2].v_samp_factor = 1;
+
+ /* Let's not hardcode YUV420 in 6 places... 5 was enough */
+ int maxVSampFactor = std::max( {
+ cinfo.comp_info[0].v_samp_factor,
+ cinfo.comp_info[1].v_samp_factor,
+ cinfo.comp_info[2].v_samp_factor
+ });
+ int cVSubSampling = cinfo.comp_info[0].v_samp_factor /
+ cinfo.comp_info[1].v_samp_factor;
+
+ /* Start the compressor */
+ jpeg_start_compress(&cinfo, TRUE);
+
+ /* Compute our macroblock height, so we can pad our input to be vertically
+ * macroblock aligned.
+ * TODO: Does it need to be horizontally MCU aligned too? */
+
+ size_t mcuV = DCTSIZE*maxVSampFactor;
+ size_t paddedHeight = mcuV * ((inSz.height + mcuV - 1) / mcuV);
+
+ /* libjpeg uses arrays of row pointers, which makes it really easy to pad
+ * data vertically (unfortunately doesn't help horizontally) */
+ std::vector<JSAMPROW> yLines (paddedHeight);
+ std::vector<JSAMPROW> cbLines(paddedHeight/cVSubSampling);
+ std::vector<JSAMPROW> crLines(paddedHeight/cVSubSampling);
+
+ uint8_t *py = static_cast<uint8_t*>(inLayout.y);
+ uint8_t *pcr = static_cast<uint8_t*>(inLayout.cr);
+ uint8_t *pcb = static_cast<uint8_t*>(inLayout.cb);
+
+ for(uint32_t i = 0; i < paddedHeight; i++)
+ {
+ /* Once we are in the padding territory we still point to the last line
+ * effectively replicating it several times ~ CLAMP_TO_EDGE */
+ int li = std::min(i, inSz.height - 1);
+ yLines[i] = static_cast<JSAMPROW>(py + li * inLayout.yStride);
+ if(i < paddedHeight / cVSubSampling)
+ {
+ li = std::min(i, (inSz.height - 1) / cVSubSampling);
+ crLines[i] = static_cast<JSAMPROW>(pcr + li * inLayout.cStride);
+ cbLines[i] = static_cast<JSAMPROW>(pcb + li * inLayout.cStride);
+ }
+ }
+
+ /* If APP1 data was passed in, use it */
+ if(app1Buffer && app1Size)
+ {
+ jpeg_write_marker(&cinfo, JPEG_APP0 + 1,
+ static_cast<const JOCTET*>(app1Buffer), app1Size);
+ }
+
+ /* While we still have padded height left to go, keep giving it one
+ * macroblock at a time. */
+ while (cinfo.next_scanline < cinfo.image_height) {
+ const uint32_t batchSize = DCTSIZE * maxVSampFactor;
+ const uint32_t nl = cinfo.next_scanline;
+ JSAMPARRAY planes[3]{ &yLines[nl],
+ &cbLines[nl/cVSubSampling],
+ &crLines[nl/cVSubSampling] };
+
+ uint32_t done = jpeg_write_raw_data(&cinfo, planes, batchSize);
+
+ if (done != batchSize) {
+ ALOGE("%s: compressed %u lines, expected %u (total %u/%u)",
+ __FUNCTION__, done, batchSize, cinfo.next_scanline,
+ cinfo.image_height);
+ return -1;
+ }
+ }
+
+ /* This will flush everything */
+ jpeg_finish_compress(&cinfo);
+
+ /* Grab the actual code size and set it */
+ actualCodeSize = dmgr.mEncodedSize;
+
+ return 0;
+}
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata& chars) {
+ Size thumbSize { 0, 0 };
+ camera_metadata_ro_entry entry =
+ chars.find(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
+ for(uint32_t i = 0; i < entry.count; i += 2) {
+ Size sz { static_cast<uint32_t>(entry.data.i32[i]),
+ static_cast<uint32_t>(entry.data.i32[i+1]) };
+ if(sz.width * sz.height > thumbSize.width * thumbSize.height) {
+ thumbSize = sz;
+ }
+ }
+
+ if (thumbSize.width * thumbSize.height == 0) {
+ ALOGW("%s: non-zero thumbnail size not available", __FUNCTION__);
+ }
+
+ return thumbSize;
+}
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>& results) {
+ for (auto& result : results) {
+ if (result.inputBuffer.releaseFence.getNativeHandle() != nullptr) {
+ native_handle_t* handle = const_cast<native_handle_t*>(
+ result.inputBuffer.releaseFence.getNativeHandle());
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ for (auto& buf : result.outputBuffers) {
+ if (buf.releaseFence.getNativeHandle() != nullptr) {
+ native_handle_t* handle = const_cast<native_handle_t*>(
+ buf.releaseFence.getNativeHandle());
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ }
+ }
+ return;
+}
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+#define UPDATE(md, tag, data, size) \
+do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+} while (0)
+
+status_t fillCaptureResultCommon(
+ common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp,
+ camera_metadata_ro_entry& activeArraySize) {
+ if (activeArraySize.count < 4) {
+ ALOGE("%s: cannot find active array size!", __FUNCTION__);
+ return -EINVAL;
+ }
+ // android.control
+ // For USB camera, we don't know the AE state. Set the state to converged to
+ // indicate the frame should be good to use. Then apps don't have to wait the
+ // AE state.
+ const uint8_t aeState = ANDROID_CONTROL_AE_STATE_CONVERGED;
+ UPDATE(md, ANDROID_CONTROL_AE_STATE, &aeState, 1);
+
+ const uint8_t ae_lock = ANDROID_CONTROL_AE_LOCK_OFF;
+ UPDATE(md, ANDROID_CONTROL_AE_LOCK, &ae_lock, 1);
+
+ // Set AWB state to converged to indicate the frame should be good to use.
+ const uint8_t awbState = ANDROID_CONTROL_AWB_STATE_CONVERGED;
+ UPDATE(md, ANDROID_CONTROL_AWB_STATE, &awbState, 1);
+
+ const uint8_t awbLock = ANDROID_CONTROL_AWB_LOCK_OFF;
+ UPDATE(md, ANDROID_CONTROL_AWB_LOCK, &awbLock, 1);
+
+ const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
+ UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+
+ // This means pipeline latency of X frame intervals. The maximum number is 4.
+ const uint8_t requestPipelineMaxDepth = 4;
+ UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
+ // android.scaler
+ const int32_t crop_region[] = {
+ activeArraySize.data.i32[0], activeArraySize.data.i32[1],
+ activeArraySize.data.i32[2], activeArraySize.data.i32[3],
+ };
+ UPDATE(md, ANDROID_SCALER_CROP_REGION, crop_region, ARRAY_SIZE(crop_region));
+
+ // android.sensor
+ UPDATE(md, ANDROID_SENSOR_TIMESTAMP, ×tamp, 1);
+
+ // android.statistics
+ const uint8_t lensShadingMapMode = ANDROID_STATISTICS_LENS_SHADING_MAP_MODE_OFF;
+ UPDATE(md, ANDROID_STATISTICS_LENS_SHADING_MAP_MODE, &lensShadingMapMode, 1);
+
+ const uint8_t sceneFlicker = ANDROID_STATISTICS_SCENE_FLICKER_NONE;
+ UPDATE(md, ANDROID_STATISTICS_SCENE_FLICKER, &sceneFlicker, 1);
+
+ return OK;
+}
+
+#undef ARRAY_SIZE
+#undef UPDATE
+
} // namespace implementation
} // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+AllocatedV4L2Frame::AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn) :
+ Frame(frameIn->mWidth, frameIn->mHeight, frameIn->mFourcc) {
+ uint8_t* dataIn;
+ size_t dataSize;
+ if (frameIn->getData(&dataIn, &dataSize) != 0) {
+ ALOGE("%s: map input V4L2 frame failed!", __FUNCTION__);
+ return;
+ }
+
+ mData.resize(dataSize);
+ std::memcpy(mData.data(), dataIn, dataSize);
+}
+
+int AllocatedV4L2Frame::getData(uint8_t** outData, size_t* dataSize) {
+ if (outData == nullptr || dataSize == nullptr) {
+ ALOGE("%s: outData(%p)/dataSize(%p) must not be null", __FUNCTION__, outData, dataSize);
+ return -1;
+ }
+
+ *outData = mData.data();
+ *dataSize = mData.size();
+ return 0;
+}
+
+AllocatedV4L2Frame::~AllocatedV4L2Frame() {}
+
+} // namespace implementation
+} // namespace V3_6
} // namespace device
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 71b7c17..180f0c1 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
#include <android/hardware/camera/device/3.2/ICameraDevice.h>
#include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
@@ -84,7 +84,8 @@
using ::android::Mutex;
using ::android::base::unique_fd;
-struct ExternalCameraDeviceSession : public virtual RefBase {
+struct ExternalCameraDeviceSession : public virtual RefBase,
+ public virtual OutputThreadInterface {
ExternalCameraDeviceSession(const sp<ICameraDeviceCallback>&,
const ExternalCameraConfig& cfg,
@@ -110,6 +111,82 @@
static const int kMaxStallStream = 1;
static const uint32_t kMaxBytesPerPixel = 2;
+ class OutputThread : public android::Thread {
+ public:
+ OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+ const common::V1_0::helper::CameraMetadata&);
+ virtual ~OutputThread();
+
+ Status allocateIntermediateBuffers(
+ const Size& v4lSize, const Size& thumbSize,
+ const hidl_vec<Stream>& streams,
+ uint32_t blobBufferSize);
+ Status submitRequest(const std::shared_ptr<HalRequest>&);
+ void flush();
+ void dump(int fd);
+ virtual bool threadLoop() override;
+
+ void setExifMakeModel(const std::string& make, const std::string& model);
+
+ // The remaining request list is returned for offline processing
+ std::list<std::shared_ptr<HalRequest>> switchToOffline();
+
+ protected:
+ // Methods to request output buffer in parallel
+ // No-op for device@3.4. Implemented in device@3.5
+ virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
+ virtual int waitForBufferRequestDone(
+ /*out*/std::vector<HalStreamBuffer>*) { return 0; }
+
+ static const int kFlushWaitTimeoutSec = 3; // 3 sec
+ static const int kReqWaitTimeoutMs = 33; // 33ms
+ static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec
+
+ void waitForNextRequest(std::shared_ptr<HalRequest>* out);
+ void signalRequestDone();
+
+ int cropAndScaleLocked(
+ sp<AllocatedFrame>& in, const Size& outSize,
+ YCbCrLayout* out);
+
+ int cropAndScaleThumbLocked(
+ sp<AllocatedFrame>& in, const Size& outSize,
+ YCbCrLayout* out);
+
+ int createJpegLocked(HalStreamBuffer &halBuf,
+ const common::V1_0::helper::CameraMetadata& settings);
+
+ void clearIntermediateBuffers();
+
+ const wp<OutputThreadInterface> mParent;
+ const CroppingType mCroppingType;
+ const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
+
+ mutable std::mutex mRequestListLock; // Protect acccess to mRequestList,
+ // mProcessingRequest and mProcessingFrameNumer
+ std::condition_variable mRequestCond; // signaled when a new request is submitted
+ std::condition_variable mRequestDoneCond; // signaled when a request is done processing
+ std::list<std::shared_ptr<HalRequest>> mRequestList;
+ bool mProcessingRequest = false;
+ uint32_t mProcessingFrameNumer = 0;
+
+ // V4L2 frameIn
+ // (MJPG decode)-> mYu12Frame
+ // (Scale)-> mScaledYu12Frames
+ // (Format convert) -> output gralloc frames
+ mutable std::mutex mBufferLock; // Protect access to intermediate buffers
+ sp<AllocatedFrame> mYu12Frame;
+ sp<AllocatedFrame> mYu12ThumbFrame;
+ std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
+ std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
+ YCbCrLayout mYu12FrameLayout;
+ YCbCrLayout mYu12ThumbFrameLayout;
+ uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
+
+ std::string mExifMake;
+ std::string mExifModel;
+ };
+
protected:
// Methods from ::android::hardware::camera::device::V3_2::ICameraDeviceSession follow
@@ -150,27 +227,22 @@
ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb);
protected:
- struct HalStreamBuffer {
- int32_t streamId;
- uint64_t bufferId;
- uint32_t width;
- uint32_t height;
- PixelFormat format;
- V3_2::BufferUsageFlags usage;
- buffer_handle_t* bufPtr;
- int acquireFence;
- bool fenceTimeout;
- };
+ // Methods from OutputThreadInterface
+ virtual Status importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) override;
- struct HalRequest {
- uint32_t frameNumber;
- common::V1_0::helper::CameraMetadata setting;
- sp<V4L2Frame> frameIn;
- nsecs_t shutterTs;
- std::vector<HalStreamBuffer> buffers;
- };
+ virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
- static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+ virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+ // End of OutputThreadInterface methods
Status constructDefaultRequestSettingsRaw(RequestTemplate type,
V3_2::CameraMetadata *outMetadata);
@@ -219,11 +291,6 @@
// Optional argument for ICameraDeviceSession@3.5 impl
bool allowEmptyBuf = false);
- Status importBuffer(int32_t streamId,
- uint64_t bufId, buffer_handle_t buf,
- /*out*/buffer_handle_t** outBufPtr,
- bool allowEmptyBuf);
-
Status importBufferLocked(int32_t streamId,
uint64_t bufId, buffer_handle_t buf,
/*out*/buffer_handle_t** outBufPtr,
@@ -236,106 +303,15 @@
Status processOneCaptureRequest(const CaptureRequest& request);
- Status processCaptureResult(std::shared_ptr<HalRequest>&);
- Status processCaptureRequestError(const std::shared_ptr<HalRequest>&);
void notifyShutter(uint32_t frameNumber, nsecs_t shutterTs);
- void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec);
void invokeProcessCaptureResultCallback(
hidl_vec<CaptureResult> &results, bool tryWriteFmq);
- static void freeReleaseFences(hidl_vec<CaptureResult>&);
Size getMaxJpegResolution() const;
Size getMaxThumbResolution() const;
- ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
int waitForV4L2BufferReturnLocked(std::unique_lock<std::mutex>& lk);
- class OutputThread : public android::Thread {
- public:
- OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType);
- virtual ~OutputThread();
-
- Status allocateIntermediateBuffers(
- const Size& v4lSize, const Size& thumbSize,
- const hidl_vec<Stream>& streams,
- uint32_t blobBufferSize);
- Status submitRequest(const std::shared_ptr<HalRequest>&);
- void flush();
- void dump(int fd);
- virtual bool threadLoop() override;
-
- void setExifMakeModel(const std::string& make, const std::string& model);
-
- protected:
- // Methods to request output buffer in parallel
- // No-op for device@3.4. Implemented in device@3.5
- virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) { return 0; }
- virtual int waitForBufferRequestDone(
- /*out*/std::vector<HalStreamBuffer>*) { return 0; }
-
- static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
- static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
- static_cast<uint32_t>('X') << 24;
- // returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
- static uint32_t getFourCcFromLayout(const YCbCrLayout&);
- static int getCropRect(
- CroppingType ct, const Size& inSize, const Size& outSize, IMapper::Rect* out);
-
- static const int kFlushWaitTimeoutSec = 3; // 3 sec
- static const int kReqWaitTimeoutMs = 33; // 33ms
- static const int kReqWaitTimesMax = 90; // 33ms * 90 ~= 3 sec
-
- void waitForNextRequest(std::shared_ptr<HalRequest>* out);
- void signalRequestDone();
-
- int cropAndScaleLocked(
- sp<AllocatedFrame>& in, const Size& outSize,
- YCbCrLayout* out);
-
- int cropAndScaleThumbLocked(
- sp<AllocatedFrame>& in, const Size& outSize,
- YCbCrLayout* out);
-
- int formatConvertLocked(const YCbCrLayout& in, const YCbCrLayout& out,
- Size sz, uint32_t format);
-
- static int encodeJpegYU12(const Size &inSz,
- const YCbCrLayout& inLayout, int jpegQuality,
- const void *app1Buffer, size_t app1Size,
- void *out, size_t maxOutSize,
- size_t &actualCodeSize);
-
- int createJpegLocked(HalStreamBuffer &halBuf, const std::shared_ptr<HalRequest>& req);
-
- const wp<ExternalCameraDeviceSession> mParent;
- const CroppingType mCroppingType;
-
- mutable std::mutex mRequestListLock; // Protect acccess to mRequestList,
- // mProcessingRequest and mProcessingFrameNumer
- std::condition_variable mRequestCond; // signaled when a new request is submitted
- std::condition_variable mRequestDoneCond; // signaled when a request is done processing
- std::list<std::shared_ptr<HalRequest>> mRequestList;
- bool mProcessingRequest = false;
- uint32_t mProcessingFrameNumer = 0;
-
- // V4L2 frameIn
- // (MJPG decode)-> mYu12Frame
- // (Scale)-> mScaledYu12Frames
- // (Format convert) -> output gralloc frames
- mutable std::mutex mBufferLock; // Protect access to intermediate buffers
- sp<AllocatedFrame> mYu12Frame;
- sp<AllocatedFrame> mYu12ThumbFrame;
- std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mIntermediateBuffers;
- std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
- YCbCrLayout mYu12FrameLayout;
- YCbCrLayout mYu12ThumbFrameLayout;
- uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
-
- std::string mExifMake;
- std::string mExifModel;
- };
-
// Protect (most of) HIDL interface methods from synchronized-entering
mutable Mutex mInterfaceLock;
@@ -345,7 +321,7 @@
const common::V1_0::helper::CameraMetadata mCameraCharacteristics;
const std::vector<SupportedV4L2Format> mSupportedFormats;
const CroppingType mCroppingType;
- const std::string& mCameraId;
+ const std::string mCameraId;
// Not protected by mLock, this is almost a const.
// Setup in constructor, reset in close() after OutputThread is joined
@@ -381,12 +357,6 @@
std::mutex mInflightFramesLock; // protect mInflightFrames
std::unordered_set<uint32_t> mInflightFrames;
- // buffers currently circulating between HAL and camera service
- // key: bufferId sent via HIDL interface
- // value: imported buffer_handle_t
- // Buffer will be imported during processCaptureRequest and will be freed
- // when the its stream is deleted or camera device session is closed
- typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
// Stream ID -> circulating buffers map
std::map<int, CirculatingBuffers> mCirculatingBuffers;
// Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
@@ -395,6 +365,8 @@
std::mutex mAfTriggerLock; // protect mAfTrigger
bool mAfTrigger = false;
+ uint32_t mBlobBufferSize = 0;
+
static HandleImporter sHandleImporter;
/* Beginning of members not changed after initialize() */
@@ -410,6 +382,9 @@
const Size mMaxThumbResolution;
const Size mMaxJpegResolution;
+
+ std::string mExifMake;
+ std::string mExifModel;
/* End of members not changed after initialize() */
private:
@@ -484,4 +459,4 @@
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICE3SESSION_H
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
index 341c622..74f75eb 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h
@@ -17,16 +17,27 @@
#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_4_EXTCAMUTIL_H
+#include <android/hardware/camera/common/1.0/types.h>
+#include <android/hardware/camera/device/3.2/types.h>
+#include <android/hardware/graphics/common/1.0/types.h>
#include <android/hardware/graphics/mapper/2.0/IMapper.h>
#include <inttypes.h>
#include <mutex>
+#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "tinyxml2.h" // XML parsing
#include "utils/LightRefBase.h"
+#include "utils/Timers.h"
+#include <CameraMetadata.h>
+#include <HandleImporter.h>
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+
+using ::android::hardware::graphics::mapper::V2_0::IMapper;
+using ::android::hardware::graphics::mapper::V2_0::YCbCrLayout;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
namespace android {
namespace hardware {
@@ -113,16 +124,28 @@
std::vector<FrameRate> frameRates;
};
+// A Base class with basic information about a frame
+struct Frame : public VirtualLightRefBase {
+public:
+ Frame(uint32_t width, uint32_t height, uint32_t fourcc);
+ const uint32_t mWidth;
+ const uint32_t mHeight;
+ const uint32_t mFourcc;
+
+ // getData might involve map/allocation
+ virtual int getData(uint8_t** outData, size_t* dataSize) = 0;
+};
+
// A class provide access to a dequeued V4L2 frame buffer (mostly in MJPG format)
// Also contains necessary information to enqueue the buffer back to V4L2 buffer queue
-class V4L2Frame : public virtual VirtualLightRefBase {
+class V4L2Frame : public Frame {
public:
V4L2Frame(uint32_t w, uint32_t h, uint32_t fourcc, int bufIdx, int fd,
uint32_t dataSize, uint64_t offset);
~V4L2Frame() override;
- const uint32_t mWidth;
- const uint32_t mHeight;
- const uint32_t mFourcc;
+
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
const int mBufferIndex; // for later enqueue
int map(uint8_t** data, size_t* dataSize);
int unmap();
@@ -137,13 +160,13 @@
// A RAII class representing a CPU allocated YUV frame used as intermeidate buffers
// when generating output images.
-class AllocatedFrame : public virtual VirtualLightRefBase {
+class AllocatedFrame : public Frame {
public:
- AllocatedFrame(uint32_t w, uint32_t h); // TODO: use Size?
+ AllocatedFrame(uint32_t w, uint32_t h); // only support V4L2_PIX_FMT_YUV420 for now
~AllocatedFrame() override;
- const uint32_t mWidth;
- const uint32_t mHeight;
- const uint32_t mFourcc; // Only support YU12 format for now
+
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+
int allocate(YCbCrLayout* out = nullptr);
int getLayout(YCbCrLayout* out);
int getCroppedLayout(const IMapper::Rect&, YCbCrLayout* out); // return non-zero for bad input
@@ -165,8 +188,110 @@
bool isAspectRatioClose(float ar1, float ar2);
+struct HalStreamBuffer {
+ int32_t streamId;
+ uint64_t bufferId;
+ uint32_t width;
+ uint32_t height;
+ ::android::hardware::graphics::common::V1_0::PixelFormat format;
+ ::android::hardware::camera::device::V3_2::BufferUsageFlags usage;
+ buffer_handle_t* bufPtr;
+ int acquireFence;
+ bool fenceTimeout;
+};
+
+struct HalRequest {
+ uint32_t frameNumber;
+ common::V1_0::helper::CameraMetadata setting;
+ sp<Frame> frameIn;
+ nsecs_t shutterTs;
+ std::vector<HalStreamBuffer> buffers;
+};
+
+static const uint64_t BUFFER_ID_NO_BUFFER = 0;
+
+// buffers currently circulating between HAL and camera service
+// key: bufferId sent via HIDL interface
+// value: imported buffer_handle_t
+// Buffer will be imported during processCaptureRequest (or requestStreamBuffer
+// in the case of HAL buffer manager is enabled) and will be freed
+// when the stream is deleted or camera device session is closed
+typedef std::unordered_map<uint64_t, buffer_handle_t> CirculatingBuffers;
+
+::android::hardware::camera::common::V1_0::Status importBufferImpl(
+ /*inout*/std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*inout*/HandleImporter& handleImporter,
+ int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf);
+
+static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
+ static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
+ static_cast<uint32_t>('X') << 24;
+
+// returns FLEX_YUV_GENERIC for formats other than YV12/YU12/NV12/NV21
+uint32_t getFourCcFromLayout(const YCbCrLayout&);
+
+using ::android::hardware::camera::external::common::Size;
+int getCropRect(CroppingType ct, const Size& inSize,
+ const Size& outSize, IMapper::Rect* out);
+
+int formatConvert(const YCbCrLayout& in, const YCbCrLayout& out, Size sz, uint32_t format);
+
+int encodeJpegYU12(const Size &inSz,
+ const YCbCrLayout& inLayout, int jpegQuality,
+ const void *app1Buffer, size_t app1Size,
+ void *out, size_t maxOutSize,
+ size_t &actualCodeSize);
+
+Size getMaxThumbnailResolution(const common::V1_0::helper::CameraMetadata&);
+
+void freeReleaseFences(hidl_vec<V3_2::CaptureResult>&);
+
+status_t fillCaptureResultCommon(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp,
+ camera_metadata_ro_entry& activeArraySize);
+
+// Interface for OutputThread calling back to parent
+struct OutputThreadInterface : public virtual RefBase {
+ virtual ::android::hardware::camera::common::V1_0::Status importBuffer(
+ int32_t streamId, uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr, bool allowEmptyBuf) = 0;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) = 0;
+
+ // Callbacks are fired within the method if msgs/results are nullptr.
+ // Otherwise the callbacks will be returned and caller is responsible to
+ // fire the callback later
+ virtual ::android::hardware::camera::common::V1_0::Status processCaptureRequestError(
+ const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<V3_2::NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<V3_2::CaptureResult>* results = nullptr) = 0;
+
+ virtual ::android::hardware::camera::common::V1_0::Status processCaptureResult(
+ std::shared_ptr<HalRequest>&) = 0;
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const = 0;
+};
+
} // namespace implementation
} // namespace V3_4
+
+namespace V3_6 {
+namespace implementation {
+
+// A CPU copy of a mapped V4L2Frame. Will map the input V4L2 frame.
+class AllocatedV4L2Frame : public V3_4::implementation::Frame {
+public:
+ AllocatedV4L2Frame(sp<V3_4::implementation::V4L2Frame> frameIn);
+ ~AllocatedV4L2Frame() override;
+ virtual int getData(uint8_t** outData, size_t* dataSize) override;
+private:
+ std::vector<uint8_t> mData;
+};
+
+} // namespace implementation
+} // namespace V3_6
} // namespace device
} // namespace camera
} // namespace hardware
diff --git a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
index 00c1d0d..287ac32 100644
--- a/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.5/default/ExternalCameraDeviceSession.cpp
@@ -80,7 +80,7 @@
ExternalCameraDeviceSession::BufferRequestThread::BufferRequestThread(
- wp<ExternalCameraDeviceSession> parent,
+ wp<OutputThreadInterface> parent,
sp<V3_5::ICameraDeviceCallback> callbacks) :
mParent(parent),
mCallbacks(callbacks) {}
@@ -254,7 +254,8 @@
mBufferRequestThread = new BufferRequestThread(this, mCallback_3_5);
mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
}
- mOutputThread = new OutputThread(this, mCroppingType, mBufferRequestThread);
+ mOutputThread = new OutputThread(
+ this, mCroppingType, mCameraCharacteristics, mBufferRequestThread);
}
void ExternalCameraDeviceSession::closeOutputThreadImpl() {
@@ -271,10 +272,11 @@
}
ExternalCameraDeviceSession::OutputThread::OutputThread(
- wp<ExternalCameraDeviceSession> parent,
+ wp<OutputThreadInterface> parent,
CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars,
sp<BufferRequestThread> bufReqThread) :
- V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct),
+ V3_4::implementation::ExternalCameraDeviceSession::OutputThread(parent, ct, chars),
mBufferRequestThread(bufReqThread) {}
ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
diff --git a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
index 281f93a..e89ef45 100644
--- a/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
@@ -72,6 +72,7 @@
using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::HalStreamBuffer;
struct ExternalCameraDeviceSession : public V3_4::implementation::ExternalCameraDeviceSession {
@@ -97,6 +98,62 @@
config, supportedFormats, devCfg);
}
+ class BufferRequestThread : public android::Thread {
+ public:
+ BufferRequestThread(
+ wp<OutputThreadInterface> parent,
+ sp<V3_5::ICameraDeviceCallback> callbacks);
+
+ int requestBufferStart(const std::vector<HalStreamBuffer>&);
+ int waitForBufferRequestDone(
+ /*out*/std::vector<HalStreamBuffer>*);
+
+ virtual bool threadLoop() override;
+
+ private:
+ void waitForNextRequest();
+
+ const wp<OutputThreadInterface> mParent;
+ const sp<V3_5::ICameraDeviceCallback> mCallbacks;
+
+ std::mutex mLock;
+ bool mRequestingBuffer = false;
+
+ std::vector<HalStreamBuffer> mBufferReqs;
+ std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
+ // mHalBufferReqs is not under mLock protection during the HIDL transaction
+ hidl_vec<BufferRequest> mHalBufferReqs;
+
+ // request buffers takes much less time in steady state, but can take much longer
+ // when requesting 1st buffer from a stream.
+ // TODO: consider a separate timeout for new vs. steady state?
+ // TODO: or make sure framework is warming up the pipeline during configure new stream?
+ static const int kReqProcTimeoutMs = 66;
+
+ static const int kReqWaitTimeoutMs = 33;
+ static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec
+ std::condition_variable mRequestCond; // signaled when a new buffer request incoming
+ std::condition_variable mRequestDoneCond; // signaled when a request is done
+ };
+
+ class OutputThread :
+ public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
+ public:
+ // TODO: pass buffer request thread to OutputThread ctor
+ OutputThread(wp<OutputThreadInterface> parent, CroppingType,
+ const common::V1_0::helper::CameraMetadata&,
+ sp<BufferRequestThread> bufReqThread);
+ virtual ~OutputThread();
+
+ protected:
+ // Methods to request output buffer in parallel
+ virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
+ virtual int waitForBufferRequestDone(
+ /*out*/std::vector<HalStreamBuffer>*) override;
+
+ const sp<BufferRequestThread> mBufferRequestThread;
+ };
+
protected:
// Methods from v3.4 and earlier will trampoline to inherited implementation
Return<void> configureStreams_3_5(
@@ -120,63 +177,8 @@
hidl_vec<buffer_handle_t*>& allBufPtrs,
hidl_vec<int>& allFences) override;
- class BufferRequestThread : public android::Thread {
- public:
- BufferRequestThread(
- wp<ExternalCameraDeviceSession> parent,
- sp<V3_5::ICameraDeviceCallback> callbacks);
-
- int requestBufferStart(const std::vector<HalStreamBuffer>&);
- int waitForBufferRequestDone(
- /*out*/std::vector<HalStreamBuffer>*);
-
- virtual bool threadLoop() override;
-
- private:
- void waitForNextRequest();
-
- const wp<ExternalCameraDeviceSession> mParent;
- const sp<V3_5::ICameraDeviceCallback> mCallbacks;
-
- std::mutex mLock;
- bool mRequestingBuffer = false;
-
- std::vector<HalStreamBuffer> mBufferReqs;
- std::vector<HalStreamBuffer> mPendingReturnBufferReqs;
- // mHalBufferReqs is not under mLock protection during the HIDL transaction
- hidl_vec<BufferRequest> mHalBufferReqs;
-
- // request buffers takes much less time in steady state, but can take much longer
- // when requesting 1st buffer from a stream.
- // TODO: consider a separate timeout for new vs. steady state?
- // TODO: or make sure framework is warming up the pipeline during configure new stream?
- static const int kReqProcTimeoutMs = 66;
-
- static const int kReqWaitTimeoutMs = 33;
- static const int kReqWaitTimesWarn = 90; // 33ms * 90 ~= 3 sec
- std::condition_variable mRequestCond; // signaled when a new buffer request incoming
- std::condition_variable mRequestDoneCond; // signaled when a request is done
- };
-
sp<BufferRequestThread> mBufferRequestThread;
- class OutputThread :
- public V3_4::implementation::ExternalCameraDeviceSession::OutputThread {
- public:
- // TODO: pass buffer request thread to OutputThread ctor
- OutputThread(wp<ExternalCameraDeviceSession> parent, CroppingType,
- sp<BufferRequestThread> bufReqThread);
- virtual ~OutputThread();
-
- protected:
- // Methods to request output buffer in parallel
- virtual int requestBufferStart(const std::vector<HalStreamBuffer>&) override;
- virtual int waitForBufferRequestDone(
- /*out*/std::vector<HalStreamBuffer>*) override;
-
- const sp<BufferRequestThread> mBufferRequestThread;
- };
-
sp<V3_5::ICameraDeviceCallback> mCallback_3_5;
bool mSupportBufMgr;
@@ -270,4 +272,4 @@
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICE3SESSION_H
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/Android.bp b/camera/device/3.6/default/Android.bp
index ce51185..a2ddebd 100644
--- a/camera/device/3.6/default/Android.bp
+++ b/camera/device/3.6/default/Android.bp
@@ -28,6 +28,7 @@
srcs: [
"ExternalCameraDevice.cpp",
"ExternalCameraDeviceSession.cpp",
+ "ExternalCameraOfflineSession.cpp",
],
shared_libs: [
"libhidlbase",
diff --git a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
index e14ae99..60a1a10 100644
--- a/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.6/default/ExternalCameraDeviceSession.cpp
@@ -73,12 +73,8 @@
Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
- outStreams.streams.resize(outStreams_v33.streams.size());
- for (size_t i = 0; i < outStreams.streams.size(); i++) {
- outStreams.streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
- // TODO: implement it later
- outStreams.streams[i].supportOffline = false;
- }
+ fillOutputStream3_6(outStreams_v33, &outStreams);
+
_hidl_cb(status, outStreams);
return Void();
}
@@ -86,12 +82,275 @@
Return<void> ExternalCameraDeviceSession::switchToOffline(
const hidl_vec<int32_t>& streamsToKeep,
ICameraDeviceSession::switchToOffline_cb _hidl_cb) {
- // TODO: implement this
- (void) streamsToKeep;
- (void) _hidl_cb;
+ std::vector<NotifyMsg> msgs;
+ std::vector<CaptureResult> results;
+ CameraOfflineSessionInfo info;
+ sp<ICameraOfflineSession> session;
+
+ Status st = switchToOffline(streamsToKeep, &msgs, &results, &info, &session);
+
+ mCallback->notify(msgs);
+ hidl_vec<CaptureResult> hidlResults(std::move(results));
+ invokeProcessCaptureResultCallback(hidlResults, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(hidlResults);
+
+ _hidl_cb(st, info, session);
return Void();
}
+void ExternalCameraDeviceSession::fillOutputStream3_6(
+ const V3_3::HalStreamConfiguration& outStreams_v33,
+ /*out*/V3_6::HalStreamConfiguration* outStreams_v36) {
+ if (outStreams_v36 == nullptr) {
+ ALOGE("%s: outStreams_v36 must not be null!", __FUNCTION__);
+ return;
+ }
+ Mutex::Autolock _l(mLock);
+ outStreams_v36->streams.resize(outStreams_v33.streams.size());
+ for (size_t i = 0; i < outStreams_v36->streams.size(); i++) {
+ outStreams_v36->streams[i].v3_4.v3_3 = outStreams_v33.streams[i];
+ outStreams_v36->streams[i].supportOffline =
+ supportOfflineLocked(outStreams_v33.streams[i].v3_2.id);
+ }
+}
+
+bool ExternalCameraDeviceSession::supportOfflineLocked(int32_t streamId) {
+ const Stream& stream = mStreamMap[streamId];
+ if (stream.format == PixelFormat::BLOB &&
+ stream.dataSpace == static_cast<int32_t>(Dataspace::V0_JFIF)) {
+ return true;
+ }
+ // TODO: support YUV output stream?
+ return false;
+}
+
+bool ExternalCameraDeviceSession::canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+ std::shared_ptr<V3_4::implementation::HalRequest> halReq) {
+ for (const auto& buffer : halReq->buffers) {
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ return false;
+ }
+ }
+ }
+ // Only drop a request completely if it has no offline output
+ return true;
+}
+
+void ExternalCameraDeviceSession::fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*out*/CameraOfflineSessionInfo* info) {
+ if (info == nullptr) {
+ ALOGE("%s: output info must not be null!", __FUNCTION__);
+ return;
+ }
+
+ info->offlineStreams.resize(offlineStreams.size());
+ info->offlineRequests.resize(offlineReqs.size());
+
+ // Fill in offline reqs and count outstanding buffers
+ for (size_t i = 0; i < offlineReqs.size(); i++) {
+ info->offlineRequests[i].frameNumber = offlineReqs[i]->frameNumber;
+ info->offlineRequests[i].pendingStreams.resize(offlineReqs[i]->buffers.size());
+ for (size_t bIdx = 0; bIdx < offlineReqs[i]->buffers.size(); bIdx++) {
+ int32_t streamId = offlineReqs[i]->buffers[bIdx].streamId;
+ info->offlineRequests[i].pendingStreams[bIdx] = streamId;
+ }
+ }
+
+ for (size_t i = 0; i < offlineStreams.size(); i++) {
+ int32_t streamId = offlineStreams[i];
+ info->offlineStreams[i].id = streamId;
+ // outstanding buffers are 0 since we are doing hal buffer management and
+ // offline session will ask for those buffers later
+ info->offlineStreams[i].numOutstandingBuffers = 0;
+ const CirculatingBuffers& bufIdMap = circulatingBuffers.at(streamId);
+ info->offlineStreams[i].circulatingBufferIds.resize(bufIdMap.size());
+ size_t bIdx = 0;
+ for (const auto& pair : bufIdMap) {
+ // Fill in bufferId
+ info->offlineStreams[i].circulatingBufferIds[bIdx++] = pair.first;
+ }
+
+ }
+}
+
+Status ExternalCameraDeviceSession::switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+ /*out*/std::vector<NotifyMsg>* msgs,
+ /*out*/std::vector<CaptureResult>* results,
+ /*out*/CameraOfflineSessionInfo* info,
+ /*out*/sp<ICameraOfflineSession>* session) {
+ ATRACE_CALL();
+ if (offlineStreams.size() > 1) {
+ ALOGE("%s: more than one offline stream is not supported", __FUNCTION__);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ if (msgs == nullptr || results == nullptr || info == nullptr || session == nullptr) {
+ ALOGE("%s: output arguments (%p, %p, %p, %p) must not be null", __FUNCTION__,
+ msgs, results, info, session);
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ msgs->clear();
+ results->clear();
+
+ Mutex::Autolock _il(mInterfaceLock);
+ Status status = initStatus();
+ if (status != Status::OK) {
+ return status;
+ }
+
+ Mutex::Autolock _l(mLock);
+ for (auto streamId : offlineStreams) {
+ if (!supportOfflineLocked(streamId)) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+ }
+
+ // pause output thread and get all remaining inflight requests
+ auto remainingReqs = mOutputThread->switchToOffline();
+ std::vector<std::shared_ptr<V3_4::implementation::HalRequest>> halReqs;
+
+ // Send out buffer/request error for remaining requests and filter requests
+ // to be handled in offline mode
+ for (auto& halReq : remainingReqs) {
+ bool dropReq = canDropRequest(offlineStreams, halReq);
+ if (dropReq) {
+ // Request is dropped completely. Just send request error and
+ // there is no need to send the request to offline session
+ processCaptureRequestError(halReq, msgs, results);
+ continue;
+ }
+
+ // All requests reach here must have at least one offline stream output
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = halReq->frameNumber;
+ shutter.msg.shutter.timestamp = halReq->shutterTs;
+ msgs->push_back(shutter);
+
+ std::vector<V3_4::implementation::HalStreamBuffer> offlineBuffers;
+ for (const auto& buffer : halReq->buffers) {
+ bool dropBuffer = true;
+ for (auto offlineStreamId : offlineStreams) {
+ if (buffer.streamId == offlineStreamId) {
+ dropBuffer = false;
+ break;
+ }
+ }
+ if (dropBuffer) {
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = halReq->frameNumber;
+ error.msg.error.errorStreamId = buffer.streamId;
+ error.msg.error.errorCode = ErrorCode::ERROR_BUFFER;
+ msgs->push_back(error);
+
+ CaptureResult result;
+ result.frameNumber = halReq->frameNumber;
+ result.partialResult = 0; // buffer only result
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(1);
+ result.outputBuffers[0].streamId = buffer.streamId;
+ result.outputBuffers[0].bufferId = buffer.bufferId;
+ result.outputBuffers[0].status = BufferStatus::ERROR;
+ if (buffer.acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = buffer.acquireFence;
+ result.outputBuffers[0].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ results->push_back(result);
+ } else {
+ offlineBuffers.push_back(buffer);
+ }
+ }
+ halReq->buffers = offlineBuffers;
+ halReqs.push_back(halReq);
+ }
+
+ // convert hal requests to offline request
+ std::deque<std::shared_ptr<HalRequest>> offlineReqs(halReqs.size());
+ for (auto& v4lReq : halReqs) {
+ std::shared_ptr<HalRequest> halReq = std::make_shared<HalRequest>();
+ halReq->frameNumber = v4lReq->frameNumber;
+ halReq->setting = v4lReq->setting;
+ halReq->shutterTs = v4lReq->shutterTs;
+ halReq->buffers = v4lReq->buffers;
+ sp<V3_4::implementation::V4L2Frame> v4l2Frame =
+ static_cast<V3_4::implementation::V4L2Frame*>(v4lReq->frameIn.get());
+ halReq->frameIn = new AllocatedV4L2Frame(v4l2Frame);
+ offlineReqs.push_back(halReq);
+ // enqueue V4L2 frame
+ enqueueV4l2Frame(v4l2Frame);
+ }
+
+ // Collect buffer caches/streams
+ hidl_vec<Stream> streamInfos;
+ streamInfos.resize(offlineStreams.size());
+ std::map<int, CirculatingBuffers> circulatingBuffers;
+ {
+ Mutex::Autolock _l(mCbsLock);
+ size_t idx = 0;
+ for(auto streamId : offlineStreams) {
+ circulatingBuffers[streamId] = mCirculatingBuffers.at(streamId);
+ mCirculatingBuffers.erase(streamId);
+ streamInfos[idx++] = mStreamMap.at(streamId);
+ mStreamMap.erase(streamId);
+ }
+ }
+
+ fillOfflineSessionInfo(offlineStreams, offlineReqs, circulatingBuffers, info);
+
+ // create the offline session object
+ bool afTrigger;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ }
+ sp<ExternalCameraOfflineSession> sessionImpl = new ExternalCameraOfflineSession(
+ mCroppingType, mCameraCharacteristics, mCameraId,
+ mExifMake, mExifModel, mBlobBufferSize, afTrigger,
+ streamInfos, offlineReqs, circulatingBuffers);
+
+ bool initFailed = sessionImpl->initialize();
+ if (initFailed) {
+ ALOGE("%s: offline session initialize failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ // cleanup stream and buffer caches
+ {
+ Mutex::Autolock _l(mCbsLock);
+ for(auto pair : mStreamMap) {
+ cleanupBuffersLocked(/*Stream ID*/pair.first);
+ }
+ mCirculatingBuffers.clear();
+ }
+ mStreamMap.clear();
+
+ // update inflight records
+ {
+ std::lock_guard<std::mutex> lk(mInflightFramesLock);
+ mInflightFrames.clear();
+ }
+
+ // stop v4l2 streaming
+ if (v4l2StreamOffLocked() !=0) {
+ ALOGE("%s: stop V4L2 streaming failed!", __FUNCTION__);
+ return Status::INTERNAL_ERROR;
+ }
+
+ // No need to return session if there is no offline requests left
+ if (offlineReqs.size() != 0) {
+ *session = sessionImpl->getInterface();
+ } else {
+ *session = nullptr;
+ }
+ return Status::OK;
+}
+
} // namespace implementation
} // namespace V3_6
} // namespace device
diff --git a/camera/device/3.6/default/ExternalCameraOfflineSession.cpp b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
new file mode 100644
index 0000000..e606fda
--- /dev/null
+++ b/camera/device/3.6/default/ExternalCameraOfflineSession.cpp
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ExtCamOfflnSsn@3.6"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+#include <android/log.h>
+
+#include <linux/videodev2.h>
+#include <sync/sync.h>
+
+#define HAVE_JPEG // required for libyuv.h to export MJPEG decode APIs
+#include <libyuv.h>
+
+#include <utils/Trace.h>
+#include "ExternalCameraOfflineSession.h"
+
+namespace {
+
+// Size of request/result metadata fast message queue. Change to 0 to always use hwbinder buffer.
+static constexpr size_t kMetadataMsgQueueSize = 1 << 18 /* 256kB */;
+
+} // anonymous namespace
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+// static instance
+HandleImporter ExternalCameraOfflineSession::sHandleImporter;
+
+using V3_5::implementation::ExternalCameraDeviceSession;
+
+ExternalCameraOfflineSession::ExternalCameraOfflineSession(
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ const std::string& exifMake,
+ const std::string& exifModel,
+ const uint32_t blobBufferSize,
+ const bool afTrigger,
+ const hidl_vec<Stream>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers) :
+ mCroppingType(croppingType), mChars(chars), mCameraId(cameraId),
+ mExifMake(exifMake), mExifModel(exifModel), mBlobBufferSize(blobBufferSize),
+ mAfTrigger(afTrigger), mOfflineStreams(offlineStreams), mOfflineReqs(offlineReqs),
+ mCirculatingBuffers(circulatingBuffers) {}
+
+ExternalCameraOfflineSession::~ExternalCameraOfflineSession() {
+ close();
+}
+
+bool ExternalCameraOfflineSession::initialize() {
+ mResultMetadataQueue = std::make_shared<ResultMetadataQueue>(
+ kMetadataMsgQueueSize, false /* non blocking */);
+ if (!mResultMetadataQueue->isValid()) {
+ ALOGE("%s: invalid result fmq", __FUNCTION__);
+ return true;
+ }
+ return false;
+}
+
+void ExternalCameraOfflineSession::initOutputThread() {
+ if (mOutputThread != nullptr) {
+ ALOGE("%s: OutputThread already exist!", __FUNCTION__);
+ return;
+ }
+
+ mBufferRequestThread = new ExternalCameraDeviceSession::BufferRequestThread(
+ this, mCallback);
+ mBufferRequestThread->run("ExtCamBufReq", PRIORITY_DISPLAY);
+
+ mOutputThread = new OutputThread(this, mCroppingType, mChars,
+ mBufferRequestThread, mOfflineReqs);
+
+ mOutputThread->setExifMakeModel(mExifMake, mExifModel);
+
+ Size inputSize = { mOfflineReqs[0]->frameIn->mWidth, mOfflineReqs[0]->frameIn->mHeight};
+ Size maxThumbSize = V3_4::implementation::getMaxThumbnailResolution(mChars);
+ mOutputThread->allocateIntermediateBuffers(
+ inputSize, maxThumbSize, mOfflineStreams, mBlobBufferSize);
+
+ mOutputThread->run("ExtCamOfflnOut", PRIORITY_DISPLAY);
+}
+
+bool ExternalCameraOfflineSession::OutputThread::threadLoop() {
+ auto parent = mParent.promote();
+ if (parent == nullptr) {
+ ALOGE("%s: session has been disconnected!", __FUNCTION__);
+ return false;
+ }
+
+ if (mOfflineReqs.empty()) {
+ ALOGI("%s: all offline requests are processed. Stopping.", __FUNCTION__);
+ return false;
+ }
+
+ std::shared_ptr<HalRequest> req = mOfflineReqs.front();
+ mOfflineReqs.pop_front();
+
+ auto onDeviceError = [&](auto... args) {
+ ALOGE(args...);
+ parent->notifyError(
+ req->frameNumber, /*stream*/-1, ErrorCode::ERROR_DEVICE);
+ signalRequestDone();
+ return false;
+ };
+
+ if (req->frameIn->mFourcc != V4L2_PIX_FMT_MJPEG && req->frameIn->mFourcc != V4L2_PIX_FMT_Z16) {
+ return onDeviceError("%s: do not support V4L2 format %c%c%c%c", __FUNCTION__,
+ req->frameIn->mFourcc & 0xFF,
+ (req->frameIn->mFourcc >> 8) & 0xFF,
+ (req->frameIn->mFourcc >> 16) & 0xFF,
+ (req->frameIn->mFourcc >> 24) & 0xFF);
+ }
+
+ int res = requestBufferStart(req->buffers);
+ if (res != 0) {
+ ALOGE("%s: send BufferRequest failed! res %d", __FUNCTION__, res);
+ return onDeviceError("%s: failed to send buffer request!", __FUNCTION__);
+ }
+
+ std::unique_lock<std::mutex> lk(mBufferLock);
+ // Convert input V4L2 frame to YU12 of the same size
+ // TODO: see if we can save some computation by converting to YV12 here
+ uint8_t* inData;
+ size_t inDataSize;
+ if (req->frameIn->getData(&inData, &inDataSize) != 0) {
+ lk.unlock();
+ return onDeviceError("%s: V4L2 buffer map failed", __FUNCTION__);
+ }
+
+ // TODO: in some special case maybe we can decode jpg directly to gralloc output?
+ if (req->frameIn->mFourcc == V4L2_PIX_FMT_MJPEG) {
+ ATRACE_BEGIN("MJPGtoI420");
+ int res = libyuv::MJPGToI420(
+ inData, inDataSize, static_cast<uint8_t*>(mYu12FrameLayout.y), mYu12FrameLayout.yStride,
+ static_cast<uint8_t*>(mYu12FrameLayout.cb), mYu12FrameLayout.cStride,
+ static_cast<uint8_t*>(mYu12FrameLayout.cr), mYu12FrameLayout.cStride,
+ mYu12Frame->mWidth, mYu12Frame->mHeight, mYu12Frame->mWidth, mYu12Frame->mHeight);
+ ATRACE_END();
+
+ if (res != 0) {
+ // For some webcam, the first few V4L2 frames might be malformed...
+ ALOGE("%s: Convert V4L2 frame to YU12 failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ Status st = parent->processCaptureRequestError(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture request error!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+ }
+ }
+
+ ATRACE_BEGIN("Wait for BufferRequest done");
+ res = waitForBufferRequestDone(&req->buffers);
+ ATRACE_END();
+
+ if (res != 0) {
+ ALOGE("%s: wait for BufferRequest done failed! res %d", __FUNCTION__, res);
+ lk.unlock();
+ return onDeviceError("%s: failed to process buffer request error!", __FUNCTION__);
+ }
+
+ ALOGV("%s processing new request", __FUNCTION__);
+ const int kSyncWaitTimeoutMs = 500;
+ for (auto& halBuf : req->buffers) {
+ if (*(halBuf.bufPtr) == nullptr) {
+ ALOGW("%s: buffer for stream %d missing", __FUNCTION__, halBuf.streamId);
+ halBuf.fenceTimeout = true;
+ } else if (halBuf.acquireFence >= 0) {
+ int ret = sync_wait(halBuf.acquireFence, kSyncWaitTimeoutMs);
+ if (ret) {
+ halBuf.fenceTimeout = true;
+ } else {
+ ::close(halBuf.acquireFence);
+ halBuf.acquireFence = -1;
+ }
+ }
+
+ if (halBuf.fenceTimeout) {
+ continue;
+ }
+
+ // Gralloc lockYCbCr the buffer
+ switch (halBuf.format) {
+ case PixelFormat::BLOB: {
+ int ret = createJpegLocked(halBuf, req->setting);
+
+ if(ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: createJpegLocked failed with %d",
+ __FUNCTION__, ret);
+ }
+ } break;
+ case PixelFormat::Y16: {
+ void* outLayout = sHandleImporter.lock(*(halBuf.bufPtr), halBuf.usage, inDataSize);
+
+ std::memcpy(outLayout, inData, inDataSize);
+
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ case PixelFormat::YCBCR_420_888:
+ case PixelFormat::YV12: {
+ IMapper::Rect outRect {0, 0,
+ static_cast<int32_t>(halBuf.width),
+ static_cast<int32_t>(halBuf.height)};
+ YCbCrLayout outLayout = sHandleImporter.lockYCbCr(
+ *(halBuf.bufPtr), halBuf.usage, outRect);
+ ALOGV("%s: outLayout y %p cb %p cr %p y_str %d c_str %d c_step %d",
+ __FUNCTION__, outLayout.y, outLayout.cb, outLayout.cr,
+ outLayout.yStride, outLayout.cStride, outLayout.chromaStep);
+
+ // Convert to output buffer size/format
+ uint32_t outputFourcc = V3_4::implementation::getFourCcFromLayout(outLayout);
+ ALOGV("%s: converting to format %c%c%c%c", __FUNCTION__,
+ outputFourcc & 0xFF,
+ (outputFourcc >> 8) & 0xFF,
+ (outputFourcc >> 16) & 0xFF,
+ (outputFourcc >> 24) & 0xFF);
+
+ YCbCrLayout cropAndScaled;
+ ATRACE_BEGIN("cropAndScaleLocked");
+ int ret = cropAndScaleLocked(
+ mYu12Frame,
+ Size { halBuf.width, halBuf.height },
+ &cropAndScaled);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: crop and scale failed!", __FUNCTION__);
+ }
+
+ Size sz {halBuf.width, halBuf.height};
+ ATRACE_BEGIN("formatConvert");
+ ret = V3_4::implementation::formatConvert(cropAndScaled, outLayout, sz, outputFourcc);
+ ATRACE_END();
+ if (ret != 0) {
+ lk.unlock();
+ return onDeviceError("%s: format coversion failed!", __FUNCTION__);
+ }
+ int relFence = sHandleImporter.unlock(*(halBuf.bufPtr));
+ if (relFence >= 0) {
+ halBuf.acquireFence = relFence;
+ }
+ } break;
+ default:
+ lk.unlock();
+ return onDeviceError("%s: unknown output format %x", __FUNCTION__, halBuf.format);
+ }
+ } // for each buffer
+ mScaledYu12Frames.clear();
+
+ // Don't hold the lock while calling back to parent
+ lk.unlock();
+ Status st = parent->processCaptureResult(req);
+ if (st != Status::OK) {
+ return onDeviceError("%s: failed to process capture result!", __FUNCTION__);
+ }
+ signalRequestDone();
+ return true;
+}
+
+Status ExternalCameraOfflineSession::importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) {
+ Mutex::Autolock _l(mCbsLock);
+ return V3_4::implementation::importBufferImpl(
+ mCirculatingBuffers, sHandleImporter, streamId,
+ bufId, buf, outBufPtr, allowEmptyBuf);
+ return Status::OK;
+};
+
+#define UPDATE(md, tag, data, size) \
+do { \
+ if ((md).update((tag), (data), (size))) { \
+ ALOGE("Update " #tag " failed!"); \
+ return BAD_VALUE; \
+ } \
+} while (0)
+
+status_t ExternalCameraOfflineSession::fillCaptureResult(
+ common::V1_0::helper::CameraMetadata &md, nsecs_t timestamp) {
+ bool afTrigger = false;
+ {
+ std::lock_guard<std::mutex> lk(mAfTriggerLock);
+ afTrigger = mAfTrigger;
+ if (md.exists(ANDROID_CONTROL_AF_TRIGGER)) {
+ camera_metadata_entry entry = md.find(ANDROID_CONTROL_AF_TRIGGER);
+ if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_START) {
+ mAfTrigger = afTrigger = true;
+ } else if (entry.data.u8[0] == ANDROID_CONTROL_AF_TRIGGER_CANCEL) {
+ mAfTrigger = afTrigger = false;
+ }
+ }
+ }
+
+ // For USB camera, the USB camera handles everything and we don't have control
+ // over AF. We only simply fake the AF metadata based on the request
+ // received here.
+ uint8_t afState;
+ if (afTrigger) {
+ afState = ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED;
+ } else {
+ afState = ANDROID_CONTROL_AF_STATE_INACTIVE;
+ }
+ UPDATE(md, ANDROID_CONTROL_AF_STATE, &afState, 1);
+
+ camera_metadata_ro_entry activeArraySize =
+ mChars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
+
+ return V3_4::implementation::fillCaptureResultCommon(md, timestamp, activeArraySize);
+}
+
+#undef UPDATE
+
+Status ExternalCameraOfflineSession::processCaptureResult(std::shared_ptr<HalRequest>& req) {
+ ATRACE_CALL();
+ // Fill output buffers
+ hidl_vec<CaptureResult> results;
+ results.resize(1);
+ CaptureResult& result = results[0];
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ if (req->buffers[i].fenceTimeout) {
+ result.outputBuffers[i].status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ notifyError(req->frameNumber, req->buffers[i].streamId, ErrorCode::ERROR_BUFFER);
+ } else {
+ result.outputBuffers[i].status = BufferStatus::OK;
+ // TODO: refactor
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ }
+ }
+
+ // Fill capture result metadata
+ fillCaptureResult(req->setting, req->shutterTs);
+ const camera_metadata_t *rawResult = req->setting.getAndLock();
+ V3_2::implementation::convertToHidl(rawResult, &result.result);
+ req->setting.unlock(rawResult);
+
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(results);
+ return Status::OK;
+};
+
+void ExternalCameraOfflineSession::invokeProcessCaptureResultCallback(
+ hidl_vec<CaptureResult> &results, bool tryWriteFmq) {
+ if (mProcessCaptureResultLock.tryLock() != OK) {
+ const nsecs_t NS_TO_SECOND = 1000000000;
+ ALOGV("%s: previous call is not finished! waiting 1s...", __FUNCTION__);
+ if (mProcessCaptureResultLock.timedLock(/* 1s */NS_TO_SECOND) != OK) {
+ ALOGE("%s: cannot acquire lock in 1s, cannot proceed",
+ __FUNCTION__);
+ return;
+ }
+ }
+ if (tryWriteFmq && mResultMetadataQueue->availableToWrite() > 0) {
+ for (CaptureResult &result : results) {
+ if (result.result.size() > 0) {
+ if (mResultMetadataQueue->write(result.result.data(), result.result.size())) {
+ result.fmqResultSize = result.result.size();
+ result.result.resize(0);
+ } else {
+ ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+ result.fmqResultSize = 0;
+ }
+ } else {
+ result.fmqResultSize = 0;
+ }
+ }
+ }
+ auto status = mCallback->processCaptureResult(results);
+ if (!status.isOk()) {
+ ALOGE("%s: processCaptureResult ERROR : %s", __FUNCTION__,
+ status.description().c_str());
+ }
+
+ mProcessCaptureResultLock.unlock();
+}
+
+Status ExternalCameraOfflineSession::processCaptureRequestError(
+ const std::shared_ptr<HalRequest>& req,
+ /*out*/std::vector<NotifyMsg>* outMsgs,
+ /*out*/std::vector<CaptureResult>* outResults) {
+ ATRACE_CALL();
+
+ if (outMsgs == nullptr) {
+ notifyError(/*frameNum*/req->frameNumber, /*stream*/-1, ErrorCode::ERROR_REQUEST);
+ } else {
+ NotifyMsg shutter;
+ shutter.type = MsgType::SHUTTER;
+ shutter.msg.shutter.frameNumber = req->frameNumber;
+ shutter.msg.shutter.timestamp = req->shutterTs;
+
+ NotifyMsg error;
+ error.type = MsgType::ERROR;
+ error.msg.error.frameNumber = req->frameNumber;
+ error.msg.error.errorStreamId = -1;
+ error.msg.error.errorCode = ErrorCode::ERROR_REQUEST;
+ outMsgs->push_back(shutter);
+ outMsgs->push_back(error);
+ }
+
+ // Fill output buffers
+ hidl_vec<CaptureResult> results;
+ results.resize(1);
+ CaptureResult& result = results[0];
+ result.frameNumber = req->frameNumber;
+ result.partialResult = 1;
+ result.inputBuffer.streamId = -1;
+ result.outputBuffers.resize(req->buffers.size());
+ for (size_t i = 0; i < req->buffers.size(); i++) {
+ result.outputBuffers[i].streamId = req->buffers[i].streamId;
+ result.outputBuffers[i].bufferId = req->buffers[i].bufferId;
+ result.outputBuffers[i].status = BufferStatus::ERROR;
+ if (req->buffers[i].acquireFence >= 0) {
+ native_handle_t* handle = native_handle_create(/*numFds*/1, /*numInts*/0);
+ handle->data[0] = req->buffers[i].acquireFence;
+ result.outputBuffers[i].releaseFence.setTo(handle, /*shouldOwn*/false);
+ }
+ }
+
+ if (outResults == nullptr) {
+ // Callback into framework
+ invokeProcessCaptureResultCallback(results, /* tryWriteFmq */true);
+ V3_4::implementation::freeReleaseFences(results);
+ } else {
+ outResults->push_back(result);
+ }
+ return Status::OK;
+};
+
+ssize_t ExternalCameraOfflineSession::getJpegBufferSize(
+ uint32_t /*width*/, uint32_t /*height*/) const {
+ // Empty implementation here as the jpeg buffer size is passed in by ctor
+ return 0;
+};
+
+void ExternalCameraOfflineSession::notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) {
+ NotifyMsg msg;
+ msg.type = MsgType::ERROR;
+ msg.msg.error.frameNumber = frameNumber;
+ msg.msg.error.errorStreamId = streamId;
+ msg.msg.error.errorCode = ec;
+ mCallback->notify({msg});
+};
+
+Return<void> ExternalCameraOfflineSession::setCallback(const sp<ICameraDeviceCallback>& cb) {
+ Mutex::Autolock _il(mInterfaceLock);
+ if (mCallback != nullptr && cb != nullptr) {
+ ALOGE("%s: callback must not be set twice!", __FUNCTION__);
+ return Void();
+ }
+ mCallback = cb;
+
+ initOutputThread();
+
+ if (mOutputThread == nullptr) {
+ ALOGE("%s: init OutputThread failed!", __FUNCTION__);
+ }
+ return Void();
+}
+
+Return<void> ExternalCameraOfflineSession::getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) {
+ Mutex::Autolock _il(mInterfaceLock);
+ _hidl_cb(*mResultMetadataQueue->getDesc());
+ return Void();
+}
+
+void ExternalCameraOfflineSession::cleanupBuffersLocked(int id) {
+ for (auto& pair : mCirculatingBuffers.at(id)) {
+ sHandleImporter.freeBuffer(pair.second);
+ }
+ mCirculatingBuffers[id].clear();
+ mCirculatingBuffers.erase(id);
+}
+
+Return<void> ExternalCameraOfflineSession::close() {
+ Mutex::Autolock _il(mInterfaceLock);
+ {
+ Mutex::Autolock _l(mLock);
+ if (mClosed) {
+ ALOGW("%s: offline session already closed!", __FUNCTION__);
+ return Void();
+ }
+ }
+ if (mBufferRequestThread) {
+ mBufferRequestThread->requestExit();
+ mBufferRequestThread->join();
+ mBufferRequestThread.clear();
+ }
+ if (mOutputThread) {
+ mOutputThread->flush();
+ mOutputThread->requestExit();
+ mOutputThread->join();
+ mOutputThread.clear();
+ }
+
+ Mutex::Autolock _l(mLock);
+ // free all buffers
+ {
+ Mutex::Autolock _cbl(mCbsLock);
+ for(auto stream : mOfflineStreams) {
+ cleanupBuffersLocked(stream.id);
+ }
+ }
+ mCallback.clear();
+ mClosed = true;
+ return Void();
+}
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
index 0e57c4c..db0d9a5 100644
--- a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraDeviceSession.h
@@ -14,12 +14,13 @@
* limitations under the License.
*/
-#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H
-#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include "ExternalCameraOfflineSession.h"
namespace android {
namespace hardware {
@@ -37,6 +38,7 @@
using ::android::hardware::camera::device::V3_2::Stream;
using ::android::hardware::camera::device::V3_5::StreamConfiguration;
using ::android::hardware::camera::device::V3_6::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
using ::android::hardware::camera::common::V1_0::Status;
using ::android::hardware::camera::external::common::ExternalCameraConfig;
using ::android::hardware::graphics::common::V1_0::PixelFormat;
@@ -69,13 +71,6 @@
return new TrampolineSessionInterface_3_6(this);
}
- static Status isStreamCombinationSupported(const V3_2::StreamConfiguration& config,
- const std::vector<SupportedV4L2Format>& supportedFormats,
- const ExternalCameraConfig& devCfg) {
- return V3_4::implementation::ExternalCameraDeviceSession::isStreamCombinationSupported(
- config, supportedFormats, devCfg);
- }
-
protected:
// Methods from v3.5 and earlier will trampoline to inherited implementation
Return<void> configureStreams_3_6(
@@ -86,6 +81,28 @@
const hidl_vec<int32_t>& streamsToKeep,
ICameraDeviceSession::switchToOffline_cb _hidl_cb);
+ void fillOutputStream3_6(const V3_3::HalStreamConfiguration& outStreams_v33,
+ /*out*/V3_6::HalStreamConfiguration* outStreams_v36);
+ bool supportOfflineLocked(int32_t streamId);
+
+ // Main body of switchToOffline. This method does not invoke any callbacks
+ // but instead returns the necessary callbacks in output arguments so callers
+ // can callback later without holding any locks
+ Status switchToOffline(const hidl_vec<int32_t>& offlineStreams,
+ /*out*/std::vector<NotifyMsg>* msgs,
+ /*out*/std::vector<CaptureResult>* results,
+ /*out*/CameraOfflineSessionInfo* info,
+ /*out*/sp<ICameraOfflineSession>* session);
+
+ // Whether a request can be completely dropped when switching to offline
+ bool canDropRequest(const hidl_vec<int32_t>& offlineStreams,
+ std::shared_ptr<V3_4::implementation::HalRequest> halReq);
+
+ void fillOfflineSessionInfo(const hidl_vec<int32_t>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers,
+ /*out*/CameraOfflineSessionInfo* info);
+
private:
struct TrampolineSessionInterface_3_6 : public ICameraDeviceSession {
@@ -188,4 +205,4 @@
} // namespace hardware
} // namespace android
-#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICE3SESSION_H
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERADEVICESESSION_H
diff --git a/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
new file mode 100644
index 0000000..230b67c
--- /dev/null
+++ b/camera/device/3.6/default/include/ext_device_v3_6_impl/ExternalCameraOfflineSession.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraOfflineSession.h>
+#include <android/hardware/camera/common/1.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hidl/MQDescriptor.h>
+#include <deque>
+#include <../../3.4/default/include/ext_device_v3_4_impl/ExternalCameraUtils.h>
+#include <../../3.5/default/include/ext_device_v3_5_impl/ExternalCameraDeviceSession.h>
+#include <HandleImporter.h>
+#include <Exif.h>
+#include <android-base/unique_fd.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_6 {
+namespace implementation {
+
+using ::android::hardware::camera::device::V3_2::BufferCache;
+using ::android::hardware::camera::device::V3_5::BufferRequest;
+using ::android::hardware::camera::device::V3_5::BufferRequestStatus;
+using ::android::hardware::camera::device::V3_2::BufferStatus;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_2::CaptureResult;
+using ::android::hardware::camera::device::V3_2::ErrorCode;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::device::V3_2::MsgType;
+using ::android::hardware::camera::device::V3_2::NotifyMsg;
+using ::android::hardware::camera::device::V3_2::RequestTemplate;
+using ::android::hardware::camera::device::V3_2::Stream;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_2::StreamConfigurationMode;
+using ::android::hardware::camera::device::V3_2::StreamRotation;
+using ::android::hardware::camera::device::V3_2::StreamType;
+using ::android::hardware::camera::device::V3_2::DataspaceFlags;
+using ::android::hardware::camera::device::V3_2::CameraBlob;
+using ::android::hardware::camera::device::V3_2::CameraBlobId;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_6::ICameraOfflineSession;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::camera::common::V1_0::helper::ExifUtils;
+using ::android::hardware::camera::external::common::ExternalCameraConfig;
+using ::android::hardware::camera::external::common::Size;
+using ::android::hardware::camera::external::common::SizeHasher;
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::Dataspace;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+using ::android::base::unique_fd;
+
+using ::android::hardware::camera::device::V3_4::implementation::SupportedV4L2Format;
+using ::android::hardware::camera::device::V3_4::implementation::CroppingType;
+using ::android::hardware::camera::device::V3_4::implementation::CirculatingBuffers;
+using ::android::hardware::camera::device::V3_4::implementation::HalRequest;
+using ::android::hardware::camera::device::V3_4::implementation::OutputThreadInterface;
+
+struct ExternalCameraOfflineSession : public virtual RefBase,
+ public virtual OutputThreadInterface {
+
+ ExternalCameraOfflineSession(
+ const CroppingType& croppingType,
+ const common::V1_0::helper::CameraMetadata& chars,
+ const std::string& cameraId,
+ const std::string& exifMake,
+ const std::string& exifModel,
+ uint32_t blobBufferSize,
+ bool afTrigger,
+ const hidl_vec<Stream>& offlineStreams,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs,
+ const std::map<int, CirculatingBuffers>& circulatingBuffers);
+
+ bool initialize();
+
+ virtual ~ExternalCameraOfflineSession();
+
+ // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+ // dealing with minor version revs and simultaneous implementation and interface inheritance
+ virtual sp<V3_6::ICameraOfflineSession> getInterface() {
+ return new TrampolineSessionInterface_3_6(this);
+ }
+
+protected:
+
+ // Methods from OutputThreadInterface
+ virtual Status importBuffer(int32_t streamId,
+ uint64_t bufId, buffer_handle_t buf,
+ /*out*/buffer_handle_t** outBufPtr,
+ bool allowEmptyBuf) override;
+
+ virtual Status processCaptureResult(std::shared_ptr<HalRequest>&) override;
+
+ virtual Status processCaptureRequestError(const std::shared_ptr<HalRequest>&,
+ /*out*/std::vector<NotifyMsg>* msgs = nullptr,
+ /*out*/std::vector<CaptureResult>* results = nullptr) override;
+
+ virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const override;
+
+ virtual void notifyError(uint32_t frameNumber, int32_t streamId, ErrorCode ec) override;
+ // End of OutputThreadInterface methods
+
+ class OutputThread : public V3_5::implementation::ExternalCameraDeviceSession::OutputThread {
+ public:
+ OutputThread(
+ wp<OutputThreadInterface> parent, CroppingType ct,
+ const common::V1_0::helper::CameraMetadata& chars,
+ sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> bufReqThread,
+ std::deque<std::shared_ptr<HalRequest>>& offlineReqs) :
+ V3_5::implementation::ExternalCameraDeviceSession::OutputThread(
+ parent, ct, chars, bufReqThread),
+ mOfflineReqs(offlineReqs) {}
+
+ virtual bool threadLoop() override;
+
+ protected:
+ std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+ }; // OutputThread
+
+
+ Return<void> setCallback(const sp<ICameraDeviceCallback>& cb);
+
+ Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb);
+
+ Return<void> close();
+
+ void initOutputThread();
+
+ void invokeProcessCaptureResultCallback(
+ hidl_vec<CaptureResult> &results, bool tryWriteFmq);
+
+ status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
+
+ void cleanupBuffersLocked(int id);
+
+ // Protect (most of) HIDL interface methods from synchronized-entering
+ mutable Mutex mInterfaceLock;
+
+ mutable Mutex mLock; // Protect all data members except otherwise noted
+
+ bool mClosed = false;
+ const CroppingType mCroppingType;
+ const common::V1_0::helper::CameraMetadata mChars;
+ const std::string mCameraId;
+ const std::string mExifMake;
+ const std::string mExifModel;
+ const uint32_t mBlobBufferSize;
+
+ std::mutex mAfTriggerLock; // protect mAfTrigger
+ bool mAfTrigger;
+
+ const hidl_vec<Stream> mOfflineStreams;
+ std::deque<std::shared_ptr<HalRequest>> mOfflineReqs;
+
+ // Protect mCirculatingBuffers, must not lock mLock after acquiring this lock
+ mutable Mutex mCbsLock;
+ std::map<int, CirculatingBuffers> mCirculatingBuffers;
+
+ static HandleImporter sHandleImporter;
+
+ using ResultMetadataQueue = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+ std::shared_ptr<ResultMetadataQueue> mResultMetadataQueue;
+
+ // Protect against invokeProcessCaptureResultCallback()
+ Mutex mProcessCaptureResultLock;
+
+ sp<ICameraDeviceCallback> mCallback;
+
+ sp<V3_5::implementation::ExternalCameraDeviceSession::BufferRequestThread> mBufferRequestThread;
+ sp<OutputThread> mOutputThread;
+private:
+
+ struct TrampolineSessionInterface_3_6 : public ICameraOfflineSession {
+ TrampolineSessionInterface_3_6(sp<ExternalCameraOfflineSession> parent) :
+ mParent(parent) {}
+
+ virtual Return<void> setCallback(const sp<ICameraDeviceCallback>& cb) override {
+ return mParent->setCallback(cb);
+ }
+
+ virtual Return<void> getCaptureResultMetadataQueue(
+ V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override {
+ return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+ }
+
+ virtual Return<void> close() override {
+ return mParent->close();
+ }
+
+ private:
+ sp<ExternalCameraOfflineSession> mParent;
+ };
+};
+
+} // namespace implementation
+} // namespace V3_6
+} // namespace device
+} // namespace camera
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_6_EXTCAMERAOFFLINESESSION_H
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index 15f5c9a..4b9d6f1 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -38,7 +38,8 @@
"android.hardware.camera.device@3.3",
"android.hardware.camera.device@3.4",
"android.hardware.camera.device@3.5",
- "android.hardware.camera.metadata@3.4",
+ "android.hardware.camera.device@3.6",
+ "android.hardware.camera.metadata@3.4",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index b4092ca..e3e53dd 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -37,6 +37,7 @@
#include <android/hardware/camera/device/3.5/ICameraDevice.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.6/ICameraDeviceSession.h>
#include <android/hardware/camera/metadata/3.4/types.h>
#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
@@ -133,6 +134,8 @@
const uint32_t kMaxPreviewWidth = 1920;
const uint32_t kMaxPreviewHeight = 1080;
+const uint32_t kMaxStillWidth = 2048;
+const uint32_t kMaxStillHeight = 1536;
const uint32_t kMaxVideoWidth = 4096;
const uint32_t kMaxVideoHeight = 2160;
const int64_t kStreamBufferTimeoutSec = 3;
@@ -162,11 +165,13 @@
namespace {
// "device@<version>/legacy/<id>"
const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
+ const int CAMERA_DEVICE_API_VERSION_3_6 = 0x306;
const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305;
const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304;
const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+ const char *kHAL3_6 = "3.6";
const char *kHAL3_5 = "3.5";
const char *kHAL3_4 = "3.4";
const char *kHAL3_3 = "3.3";
@@ -202,7 +207,9 @@
return -1;
}
- if (version.compare(kHAL3_5) == 0) {
+ if (version.compare(kHAL3_6) == 0) {
+ return CAMERA_DEVICE_API_VERSION_3_6;
+ } else if (version.compare(kHAL3_5) == 0) {
return CAMERA_DEVICE_API_VERSION_3_5;
} else if (version.compare(kHAL3_4) == 0) {
return CAMERA_DEVICE_API_VERSION_3_4;
@@ -717,7 +724,8 @@
void castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
- sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/);
+ sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
+ sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/);
void castDevice(const sp<device::V3_2::ICameraDevice> &device, int32_t deviceVersion,
sp<device::V3_5::ICameraDevice> *device3_5/*out*/);
void createStreamConfiguration(const ::android::hardware::hidl_vec<V3_2::Stream>& streams3_2,
@@ -727,6 +735,17 @@
::android::hardware::camera::device::V3_5::StreamConfiguration *config3_5,
uint32_t jpegBufferSize = 0);
+ void configureOfflineStillStream(const std::string &name, int32_t deviceVersion,
+ sp<ICameraProvider> provider,
+ const AvailableStream *threshold,
+ sp<device::V3_6::ICameraDeviceSession> *session/*out*/,
+ V3_2::Stream *stream /*out*/,
+ device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/,
+ bool *supportsPartialResults /*out*/,
+ uint32_t *partialResultCount /*out*/,
+ sp<DeviceCb> *outCb /*out*/,
+ uint32_t *jpegBufferSize /*out*/,
+ bool *useHalBufManager /*out*/);
void configurePreviewStreams3_4(const std::string &name, int32_t deviceVersion,
sp<ICameraProvider> provider,
const AvailableStream *previewThreshold,
@@ -792,6 +811,7 @@
uint32_t* outBufSize);
static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
static Status isLogicalMultiCamera(const camera_metadata_t *staticMeta);
+ static Status isOfflineSessionSupported(const camera_metadata_t *staticMeta);
static Status getPhysicalCameraIds(const camera_metadata_t *staticMeta,
std::unordered_set<std::string> *physicalIds/*out*/);
static Status getSupportedKeys(camera_metadata_t *staticMeta,
@@ -818,6 +838,9 @@
CameraParameters &cameraParams, const char *mode) ;
static Status isMonochromeCamera(const camera_metadata_t *staticMeta);
+ // Used by switchToOffline where a new result queue is created for offline reqs
+ void updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue);
+
protected:
// In-flight queue for tracking completion of capture requests.
@@ -1442,7 +1465,13 @@
hidl_vec<StreamBuffer> tmpRetBuffers(bufReq.numBuffersRequested);
for (size_t j = 0; j < bufReq.numBuffersRequested; j++) {
hidl_handle buffer_handle;
- mParent->allocateGraphicBuffer(stream.v3_2.width, stream.v3_2.height,
+ uint32_t w = stream.v3_2.width;
+ uint32_t h = stream.v3_2.height;
+ if (stream.v3_2.format == PixelFormat::BLOB) {
+ w = stream.bufferSize;
+ h = 1;
+ }
+ mParent->allocateGraphicBuffer(w, h,
android_convertGralloc1To0Usage(
halStream.producerUsage, halStream.consumerUsage),
halStream.overrideFormat, &buffer_handle);
@@ -1706,6 +1735,7 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_3:
@@ -1748,6 +1778,7 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2489,6 +2520,7 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2568,6 +2600,7 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2694,6 +2727,7 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2759,6 +2793,7 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2788,8 +2823,12 @@
sp<device::V3_3::ICameraDeviceSession> sessionV3_3;
sp<device::V3_4::ICameraDeviceSession> sessionV3_4;
sp<device::V3_5::ICameraDeviceSession> sessionV3_5;
- castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4, &sessionV3_5);
- if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
+ sp<device::V3_6::ICameraDeviceSession> sessionV3_6;
+ castSession(session, deviceVersion, &sessionV3_3,
+ &sessionV3_4, &sessionV3_5, &sessionV3_6);
+ if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_6) {
+ ASSERT_TRUE(sessionV3_6.get() != nullptr);
+ } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
ASSERT_TRUE(sessionV3_5.get() != nullptr);
} else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
ASSERT_TRUE(sessionV3_4.get() != nullptr);
@@ -2851,6 +2890,7 @@
for (const auto& name : cameraDeviceNames) {
int deviceVersion = getCameraDeviceVersion(name, mProviderType);
switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_3:
@@ -2949,11 +2989,12 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
openEmptyDeviceSession(name, mProvider,
&session /*out*/, &staticMeta /*out*/, &cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
outputStreams.clear();
@@ -3057,11 +3098,12 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
outputStreams.clear();
@@ -3254,11 +3296,12 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
Status rc = isZSLModeAvailable(staticMeta);
@@ -3421,8 +3464,9 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
ASSERT_NE(session3_4, nullptr);
} else {
@@ -3543,11 +3587,12 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
// Check if camera support depth only
@@ -3660,11 +3705,12 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
Status rc = isConstrainedModeAvailable(staticMeta);
@@ -3871,11 +3917,12 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
sp<device::V3_2::ICameraDevice> cameraDevice;
sp<device::V3_5::ICameraDevice> cameraDevice3_5;
openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMeta /*out*/,
&cameraDevice /*out*/);
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
castDevice(cameraDevice, deviceVersion, &cameraDevice3_5);
// Check if camera support depth only
@@ -4613,6 +4660,207 @@
}
}
+// Verify camera offline session behavior
+TEST_P(CameraHidlTest, switchToOffline) {
+ hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+ AvailableStream threshold = {kMaxStillWidth, kMaxStillHeight,
+ static_cast<int32_t>(PixelFormat::BLOB)};
+ uint64_t bufferId = 1;
+ uint32_t frameNumber = 1;
+ ::android::hardware::hidl_vec<uint8_t> settings;
+
+ for (const auto& name : cameraDeviceNames) {
+ int deviceVersion = getCameraDeviceVersion(name, mProviderType);
+ if (deviceVersion == CAMERA_DEVICE_API_VERSION_1_0) {
+ continue;
+ } else if (deviceVersion <= 0) {
+ ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
+ ADD_FAILURE();
+ return;
+ }
+
+ camera_metadata_t* staticMetaBuffer;
+ {
+ Return<void> ret;
+ sp<ICameraDeviceSession> session;
+ openEmptyDeviceSession(name, mProvider, &session /*out*/, &staticMetaBuffer /*out*/);
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata staticMeta(
+ staticMetaBuffer);
+
+ if (isOfflineSessionSupported(staticMetaBuffer) != Status::OK) {
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+
+ bool supportsPartialResults = false;
+ uint32_t partialResultCount = 0;
+ V3_2::Stream stream;
+ V3_6::HalStreamConfiguration halStreamConfig;
+ sp<V3_6::ICameraDeviceSession> session;
+ sp<DeviceCb> cb;
+ uint32_t jpegBufferSize;
+ bool useHalBufManager;
+ configureOfflineStillStream(name, deviceVersion, mProvider, &threshold,
+ &session /*out*/, &stream /*out*/, &halStreamConfig /*out*/,
+ &supportsPartialResults /*out*/, &partialResultCount /*out*/, &cb /*out*/,
+ &jpegBufferSize /*out*/, &useHalBufManager /*out*/);
+
+ auto ret = session->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE,
+ [&](auto status, const auto& req) {
+ ASSERT_EQ(Status::OK, status);
+ settings = req; });
+ ASSERT_TRUE(ret.isOk());
+
+ std::shared_ptr<ResultMetadataQueue> resultQueue;
+ auto resultQueueRet =
+ session->getCaptureResultMetadataQueue(
+ [&resultQueue](const auto& descriptor) {
+ resultQueue = std::make_shared<ResultMetadataQueue>(
+ descriptor);
+ if (!resultQueue->isValid() ||
+ resultQueue->availableToWrite() <= 0) {
+ ALOGE("%s: HAL returns empty result metadata fmq,"
+ " not use it", __func__);
+ resultQueue = nullptr;
+ // Don't use the queue onwards.
+ }
+ });
+ ASSERT_TRUE(resultQueueRet.isOk());
+
+ ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta;
+ StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, nullptr};
+ hidl_handle buffers[kBurstFrameCount];
+ StreamBuffer outputBuffers[kBurstFrameCount];
+ CaptureRequest requests[kBurstFrameCount];
+ InFlightRequest inflightReqs[kBurstFrameCount];
+ hidl_vec<uint8_t> requestSettings[kBurstFrameCount];
+ auto halStreamConfig3_2 = halStreamConfig.streams[0].v3_4.v3_3.v3_2;
+ for (uint32_t i = 0; i < kBurstFrameCount; i++) {
+ std::unique_lock<std::mutex> l(mLock);
+
+ if (useHalBufManager) {
+ outputBuffers[i] = {halStreamConfig3_2.id, /*bufferId*/ 0,
+ buffers[i], BufferStatus::OK, nullptr, nullptr};
+ } else {
+ // jpeg buffer (w,h) = (blobLen, 1)
+ allocateGraphicBuffer(jpegBufferSize, /*height*/1,
+ android_convertGralloc1To0Usage(halStreamConfig3_2.producerUsage,
+ halStreamConfig3_2.consumerUsage),
+ halStreamConfig3_2.overrideFormat, &buffers[i]);
+ outputBuffers[i] = {halStreamConfig3_2.id, bufferId + i,
+ buffers[i], BufferStatus::OK, nullptr, nullptr};
+ }
+
+ requestMeta.clear();
+ requestMeta.append(reinterpret_cast<camera_metadata_t *> (settings.data()));
+
+ camera_metadata_t *metaBuffer = requestMeta.release();
+ requestSettings[i].setToExternal(reinterpret_cast<uint8_t *> (metaBuffer),
+ get_camera_metadata_size(metaBuffer), true);
+
+ requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i],
+ emptyInputBuffer, {outputBuffers[i]}};
+
+ inflightReqs[i] = {1, false, supportsPartialResults, partialResultCount,
+ resultQueue};
+ mInflightMap.add(frameNumber + i, &inflightReqs[i]);
+ }
+
+ Status status = Status::INTERNAL_ERROR;
+ uint32_t numRequestProcessed = 0;
+ hidl_vec<BufferCache> cachesToRemove;
+ hidl_vec<CaptureRequest> burstRequest;
+ burstRequest.setToExternal(requests, kBurstFrameCount);
+ Return<void> returnStatus = session->processCaptureRequest(burstRequest, cachesToRemove,
+ [&status, &numRequestProcessed] (auto s, uint32_t n) {
+ status = s;
+ numRequestProcessed = n;
+ });
+ ASSERT_TRUE(returnStatus.isOk());
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_EQ(numRequestProcessed, kBurstFrameCount);
+
+ hidl_vec<int32_t> offlineStreamIds = {halStreamConfig3_2.id};
+ V3_6::CameraOfflineSessionInfo offlineSessionInfo;
+ sp<device::V3_6::ICameraOfflineSession> offlineSession;
+ returnStatus = session->switchToOffline(offlineStreamIds,
+ [&status, &offlineSessionInfo, &offlineSession] (auto stat, auto info,
+ auto offSession) {
+ status = stat;
+ offlineSessionInfo = info;
+ offlineSession = offSession;
+ });
+ ASSERT_TRUE(returnStatus.isOk());
+
+ if (!halStreamConfig.streams[0].supportOffline) {
+ ASSERT_EQ(status, Status::ILLEGAL_ARGUMENT);
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ ASSERT_EQ(status, Status::OK);
+ // Hal might be unable to find any requests qualified for offline mode.
+ if (offlineSession == nullptr) {
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ ASSERT_EQ(offlineSessionInfo.offlineStreams.size(), 1u);
+ ASSERT_EQ(offlineSessionInfo.offlineStreams[0].id, halStreamConfig3_2.id);
+ ASSERT_NE(offlineSessionInfo.offlineRequests.size(), 0u);
+
+ // close device session to make sure offline session does not rely on it
+ ret = session->close();
+ ASSERT_TRUE(ret.isOk());
+
+ std::shared_ptr<ResultMetadataQueue> offlineResultQueue;
+ auto offlineResultQueueRet =
+ offlineSession->getCaptureResultMetadataQueue(
+ [&offlineResultQueue](const auto& descriptor) {
+ offlineResultQueue = std::make_shared<ResultMetadataQueue>(
+ descriptor);
+ if (!offlineResultQueue->isValid() ||
+ offlineResultQueue->availableToWrite() <= 0) {
+ ALOGE("%s: offline session returns empty result metadata fmq,"
+ " not use it", __func__);
+ offlineResultQueue = nullptr;
+ // Don't use the queue onwards.
+ }
+ });
+ ASSERT_TRUE(offlineResultQueueRet.isOk());
+
+ updateInflightResultQueue(offlineResultQueue);
+
+ ret = offlineSession->setCallback(cb);
+ ASSERT_TRUE(ret.isOk());
+
+ for (size_t i = 0; i < kBurstFrameCount; i++) {
+ std::unique_lock<std::mutex> l(mLock);
+ while (!inflightReqs[i].errorCodeValid && ((0 < inflightReqs[i].numBuffersLeft) ||
+ (!inflightReqs[i].haveResultMetadata))) {
+ auto timeout = std::chrono::system_clock::now() +
+ std::chrono::seconds(kStreamBufferTimeoutSec);
+ ASSERT_NE(std::cv_status::timeout, mResultCondition.wait_until(l, timeout));
+ }
+
+ ASSERT_FALSE(inflightReqs[i].errorCodeValid);
+ ASSERT_NE(inflightReqs[i].resultOutputBuffers.size(), 0u);
+ ASSERT_EQ(stream.id, inflightReqs[i].resultOutputBuffers[0].streamId);
+ ASSERT_FALSE(inflightReqs[i].collectedResult.isEmpty());
+ }
+
+
+ ret = offlineSession->close();
+ ASSERT_TRUE(ret.isOk());
+ }
+}
+
// Check whether an invalid capture request with missing output buffers
// will be reported correctly.
TEST_P(CameraHidlTest, processCaptureRequestInvalidBuffer) {
@@ -4972,6 +5220,30 @@
return ret;
}
+// Check if the camera device has logical multi-camera capability.
+Status CameraHidlTest::isOfflineSessionSupported(const camera_metadata_t *staticMeta) {
+ Status ret = Status::METHOD_NOT_SUPPORTED;
+ if (nullptr == staticMeta) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ camera_metadata_ro_entry entry;
+ int rc = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
+ if (0 != rc) {
+ return Status::ILLEGAL_ARGUMENT;
+ }
+
+ for (size_t i = 0; i < entry.count; i++) {
+ if (ANDROID_REQUEST_AVAILABLE_CAPABILITIES_OFFLINE_PROCESSING == entry.data.u8[i]) {
+ ret = Status::OK;
+ break;
+ }
+ }
+
+ return ret;
+}
+
// Generate a list of physical camera ids backing a logical multi-camera.
Status CameraHidlTest::getPhysicalCameraIds(const camera_metadata_t *staticMeta,
std::unordered_set<std::string> *physicalIds) {
@@ -5330,7 +5602,8 @@
*outCb = cb;
sp<device::V3_3::ICameraDeviceSession> session3_3;
- castSession(session, deviceVersion, &session3_3, session3_4, session3_5);
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
+ castSession(session, deviceVersion, &session3_3, session3_4, session3_5, &session3_6);
ASSERT_NE(nullptr, (*session3_4).get());
*useHalBufManager = false;
@@ -5423,6 +5696,142 @@
ASSERT_TRUE(ret.isOk());
}
+// Configure preview stream with possible offline session support
+void CameraHidlTest::configureOfflineStillStream(const std::string &name,
+ int32_t deviceVersion,
+ sp<ICameraProvider> provider,
+ const AvailableStream *threshold,
+ sp<device::V3_6::ICameraDeviceSession> *session/*out*/,
+ V3_2::Stream *stream /*out*/,
+ device::V3_6::HalStreamConfiguration *halStreamConfig /*out*/,
+ bool *supportsPartialResults /*out*/,
+ uint32_t *partialResultCount /*out*/,
+ sp<DeviceCb> *outCb /*out*/,
+ uint32_t *jpegBufferSize /*out*/,
+ bool *useHalBufManager /*out*/) {
+ ASSERT_NE(nullptr, session);
+ ASSERT_NE(nullptr, halStreamConfig);
+ ASSERT_NE(nullptr, stream);
+ ASSERT_NE(nullptr, supportsPartialResults);
+ ASSERT_NE(nullptr, partialResultCount);
+ ASSERT_NE(nullptr, outCb);
+ ASSERT_NE(nullptr, jpegBufferSize);
+ ASSERT_NE(nullptr, useHalBufManager);
+
+ std::vector<AvailableStream> outputStreams;
+ ::android::sp<ICameraDevice> cameraDevice;
+ ALOGI("configureStreams: Testing camera device %s", name.c_str());
+ Return<void> ret;
+ ret = provider->getCameraDeviceInterface_V3_x(
+ name,
+ [&](auto status, const auto& device) {
+ ALOGI("getCameraDeviceInterface_V3_x returns status:%d",
+ (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(device, nullptr);
+ cameraDevice = device;
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ camera_metadata_t *staticMeta;
+ ret = cameraDevice->getCameraCharacteristics([&] (Status s,
+ CameraMetadata metadata) {
+ ASSERT_EQ(Status::OK, s);
+ staticMeta = clone_camera_metadata(
+ reinterpret_cast<const camera_metadata_t*>(metadata.data()));
+ ASSERT_NE(nullptr, staticMeta);
+ });
+ ASSERT_TRUE(ret.isOk());
+
+ camera_metadata_ro_entry entry;
+ auto status = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_REQUEST_PARTIAL_RESULT_COUNT, &entry);
+ if ((0 == status) && (entry.count > 0)) {
+ *partialResultCount = entry.data.i32[0];
+ *supportsPartialResults = (*partialResultCount > 1);
+ }
+
+ *useHalBufManager = false;
+ status = find_camera_metadata_ro_entry(staticMeta,
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION, &entry);
+ if ((0 == status) && (entry.count == 1)) {
+ *useHalBufManager = (entry.data.u8[0] ==
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5);
+ }
+
+ auto st = getJpegBufferSize(staticMeta, jpegBufferSize);
+ ASSERT_EQ(st, Status::OK);
+
+ sp<DeviceCb> cb = new DeviceCb(this, deviceVersion, staticMeta);
+ ret = cameraDevice->open(cb, [&session](auto status, const auto& newSession) {
+ ALOGI("device::open returns status:%d", (int)status);
+ ASSERT_EQ(Status::OK, status);
+ ASSERT_NE(newSession, nullptr);
+ auto castResult = device::V3_6::ICameraDeviceSession::castFrom(newSession);
+ ASSERT_TRUE(castResult.isOk());
+ *session = castResult;
+ });
+ ASSERT_TRUE(ret.isOk());
+ *outCb = cb;
+
+ outputStreams.clear();
+ auto rc = getAvailableOutputStreams(staticMeta,
+ outputStreams, threshold);
+ size_t idx = 0;
+ int currLargest = outputStreams[0].width * outputStreams[0].height;
+ for (size_t i = 0; i < outputStreams.size(); i++) {
+ int area = outputStreams[i].width * outputStreams[i].height;
+ if (area > currLargest) {
+ idx = i;
+ currLargest = area;
+ }
+ }
+ free_camera_metadata(staticMeta);
+ ASSERT_EQ(Status::OK, rc);
+ ASSERT_FALSE(outputStreams.empty());
+
+ V3_2::DataspaceFlags dataspaceFlag = 0;
+ switch (static_cast<PixelFormat>(outputStreams[idx].format)) {
+ case PixelFormat::BLOB:
+ dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::V0_JFIF);
+ break;
+ case PixelFormat::Y16:
+ dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::DEPTH);
+ break;
+ default:
+ dataspaceFlag = static_cast<V3_2::DataspaceFlags>(Dataspace::UNKNOWN);
+ }
+
+ ::android::hardware::hidl_vec<V3_4::Stream> streams3_4(/*size*/1);
+ V3_4::Stream stream3_4 = {{ 0 /*streamId*/, StreamType::OUTPUT,
+ static_cast<uint32_t> (outputStreams[idx].width),
+ static_cast<uint32_t> (outputStreams[idx].height),
+ static_cast<PixelFormat> (outputStreams[idx].format),
+ GRALLOC1_CONSUMER_USAGE_CPU_READ, dataspaceFlag, StreamRotation::ROTATION_0},
+ nullptr /*physicalId*/, /*bufferSize*/ *jpegBufferSize};
+ streams3_4[0] = stream3_4;
+
+ ::android::hardware::camera::device::V3_4::StreamConfiguration config3_4;
+ ::android::hardware::camera::device::V3_5::StreamConfiguration config3_5;
+ config3_4 = {streams3_4, StreamConfigurationMode::NORMAL_MODE, {}};
+
+ config3_5.v3_4 = config3_4;
+ config3_5.streamConfigCounter = 0;
+ ret = (*session)->configureStreams_3_6(config3_5,
+ [&] (Status s, device::V3_6::HalStreamConfiguration halConfig) {
+ ASSERT_EQ(Status::OK, s);
+ *halStreamConfig = halConfig;
+
+ if (*useHalBufManager) {
+ hidl_vec<V3_2::HalStream> halStreams3_2(1);
+ halStreams3_2[0] = halConfig.streams[0].v3_4.v3_3.v3_2;
+ cb->setCurrentStreamConfig(streams3_4, halStreams3_2);
+ }
+ });
+ *stream = streams3_4[0].v3_2;
+ ASSERT_TRUE(ret.isOk());
+}
+
bool CameraHidlTest::isDepthOnly(camera_metadata_t* staticMeta) {
camera_metadata_ro_entry scalarEntry;
camera_metadata_ro_entry depthEntry;
@@ -5454,6 +5863,14 @@
return false;
}
+void CameraHidlTest::updateInflightResultQueue(std::shared_ptr<ResultMetadataQueue> resultQueue) {
+ std::unique_lock<std::mutex> l(mLock);
+ for (size_t i = 0; i < mInflightMap.size(); i++) {
+ auto& req = mInflightMap.editValueAt(i);
+ req->resultQueue = resultQueue;
+ }
+}
+
// Open a device session and configure a preview stream.
void CameraHidlTest::configurePreviewStream(const std::string &name, int32_t deviceVersion,
sp<ICameraProvider> provider,
@@ -5522,7 +5939,8 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
- castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
+ castSession(*session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
*useHalBufManager = false;
status = find_camera_metadata_ro_entry(staticMeta,
@@ -5657,12 +6075,20 @@
void CameraHidlTest::castSession(const sp<ICameraDeviceSession> &session, int32_t deviceVersion,
sp<device::V3_3::ICameraDeviceSession> *session3_3 /*out*/,
sp<device::V3_4::ICameraDeviceSession> *session3_4 /*out*/,
- sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/) {
+ sp<device::V3_5::ICameraDeviceSession> *session3_5 /*out*/,
+ sp<device::V3_6::ICameraDeviceSession> *session3_6 /*out*/) {
ASSERT_NE(nullptr, session3_3);
ASSERT_NE(nullptr, session3_4);
ASSERT_NE(nullptr, session3_5);
+ ASSERT_NE(nullptr, session3_6);
switch (deviceVersion) {
+ case CAMERA_DEVICE_API_VERSION_3_6: {
+ auto castResult = device::V3_6::ICameraDeviceSession::castFrom(session);
+ ASSERT_TRUE(castResult.isOk());
+ *session3_6 = castResult;
+ }
+ [[fallthrough]];
case CAMERA_DEVICE_API_VERSION_3_5: {
auto castResult = device::V3_5::ICameraDeviceSession::castFrom(session);
ASSERT_TRUE(castResult.isOk());
@@ -6261,7 +6687,8 @@
sp<device::V3_3::ICameraDeviceSession> session3_3;
sp<device::V3_4::ICameraDeviceSession> session3_4;
sp<device::V3_5::ICameraDeviceSession> session3_5;
- castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5);
+ sp<device::V3_6::ICameraDeviceSession> session3_6;
+ castSession(session, deviceVersion, &session3_3, &session3_4, &session3_5, &session3_6);
ASSERT_NE(nullptr, session3_5.get());
hidl_vec<int32_t> streamIds(1);
diff --git a/camera/provider/2.5/default/Android.bp b/camera/provider/2.5/default/Android.bp
index 4563362..9ddf651 100644
--- a/camera/provider/2.5/default/Android.bp
+++ b/camera/provider/2.5/default/Android.bp
@@ -52,6 +52,8 @@
"android.hardware.camera.provider@2.4-external",
"android.hardware.camera.provider@2.5",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
"camera.device@3.3-impl",
@@ -72,7 +74,8 @@
],
header_libs: [
"camera.device@3.4-external-impl_headers",
- "camera.device@3.5-external-impl_headers"
+ "camera.device@3.5-external-impl_headers",
+ "camera.device@3.6-external-impl_headers"
],
export_include_dirs: ["."],
}
@@ -165,7 +168,10 @@
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.5-external",
"android.hardware.graphics.mapper@2.0",
+ "android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"libbinder",
+ "libcamera_metadata",
"libhidlbase",
"liblog",
"libtinyxml2",
@@ -179,5 +185,6 @@
"camera.device@3.4-impl_headers",
"camera.device@3.5-external-impl_headers",
"camera.device@3.5-impl_headers",
+ "camera.device@3.6-external-impl_headers",
],
}
diff --git a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
index 7e5a61a..1b5797b 100644
--- a/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
+++ b/cas/1.1/vts/functional/VtsHalCasV1_1TargetTest.cpp
@@ -16,8 +16,6 @@
#define LOG_TAG "mediacas_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
#include <android-base/logging.h>
#include <android/hardware/cas/1.0/IDescramblerBase.h>
#include <android/hardware/cas/1.0/types.h>
diff --git a/current.txt b/current.txt
index f1c588d..bb48cd3 100644
--- a/current.txt
+++ b/current.txt
@@ -600,6 +600,8 @@
a785a57447a81e9c130eef6904c3a5c256076c6a04588c40620ebd6fa2660d77 android.hardware.radio@1.2::types
1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
+ff5dd821c2c7a9c78607159c4d788960b725487263c49d956ca5fa3d37008b45 android.hardware.wifi@1.2::IWifiStaIface
+5751f230e86a36111e7c5b995577cbf89d8df76c8e6c7641199198f3db3a93f7 android.hardware.wifi@1.3::IWifiStaIface
# HALs released in Android R
e966a3437d6a98d9d9e14e9d672088771716031900c0deb55a0946c751a03a44 android.hardware.audio@6.0::types
@@ -634,6 +636,8 @@
40ab2c6866c18d32baf6e49e3053949e79601f56963a791e93e68b9ee18f718d android.hardware.bluetooth@1.1::IBluetoothHciCallbacks
07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
+e88840e0558439cb54837514ddccd43877094951758f367e9c638084eb7455a6 android.hardware.camera.provider@2.6::ICameraProvider
+8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
9811f867def49b420d8c707f7e38d3bdd64f835244e1d2a5e9762ab9835672dc android.hardware.cas@1.2::ICasListener
f18695dd36ee205640b8326a17453858a7b4596653aaa6ef0016b0aef1bd4dac android.hardware.cas@1.2::IMediaCasService
@@ -671,20 +675,20 @@
3646950b10f7cacdafca13609b0e18496cea942f3bdfe920494661856eff48bb android.hardware.neuralnetworks@1.3::types
3e01d4446cd69fd1c48f8572efd97487bc179564b32bd795800b97bbe10be37b android.hardware.wifi@1.4::IWifi
c67aaf26a7a40d14ea61e70e20afacbd0bb906df1704d585ac8599fbb69dd44b android.hardware.wifi.hostapd@1.2::IHostapd
-11f6448d15336361180391c8ebcdfd2d7cf77b3782d577e594d583aadc9c2877 android.hardware.wifi.hostapd@1.2::types
+2b5a7ea572b736030c64a3b4043af244425477c4672301780fe15aba5ed393d9 android.hardware.wifi.hostapd@1.2::types
a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardware.wifi.supplicant@1.3::ISupplicant
8aed0a8e03e7a67bfdfb78ad7529a9ae95bea36e6060473b204c89d772522126 android.hardware.wifi.supplicant@1.3::ISupplicantStaIface
def77c7db95d374f11a111bfc4ed60f92451303642a43276c4e291988fcee625 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
62cf050c593c1ec34b49178b5bdde72dd9b80d9bad3eb184e4f0cd564d28678c android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types
-50e22cd55ad5499e68e81541bbc67bd10e59c1b9f3ff8cc7ba70dcb0d2918381 android.hardware.radio@1.5::types
-8cc3306e8cd755d04521d1611b217b9d13a2a76d2af57cbea8f875333b3363f7 android.hardware.radio@1.5::IRadio
+e1d34b83188a8ef3c507ec53c0ebcf714863c746da7f4a05460453f7c4c09389 android.hardware.radio@1.5::types
+8062d0a1a03594dd8b448adcf6f08856b5720f7e33f9b785a21d3ef74a4f211d android.hardware.radio@1.5::IRadio
e96ae1c3a9c0689002ec2318e9c587f4f607c16a75a3cd38788b77eb91072021 android.hardware.radio@1.5::IRadioIndication
-7b77721a7716e163f5cc5f2830ed5616b953fcf0e5406f69de0fde5ce95e4184 android.hardware.radio@1.5::IRadioResponse
-2fd107f3de1b7e36825e241a88dfae8edf3a77c166cb746f00ddf6440ab78db1 android.hardware.radio.config@1.3::types
+7f2439b48bda2961c6d629d0415eee66d519142cf9537f05e9d285153c70ca85 android.hardware.radio@1.5::IRadioResponse
+dcc8872337f0135e81970e1d8d5fd7139160dc80e9be76f0ae05290fa7e472b8 android.hardware.radio.config@1.3::types
a2977755bc5f1ef47f04b7f2400632efda6218e1515dba847da487145cfabc4f android.hardware.radio.config@1.3::IRadioConfig
742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
0006ab8e8b0910cbd3bbb08d5f17d5fac7d65a2bdad5f2334e4851db9d1e6fa8 android.hardware.radio.config@1.3::IRadioConfigResponse
-51d1c8d285e0456da2a3fdfbf4700c6277165d5e83219894d651c8ea0e39aa8b android.hardware.soundtrigger@2.3::types
+4a6517ea4ad807855428b0101d8e1a486497bd88ab4300ba3b2be43d46d32580 android.hardware.soundtrigger@2.3::types
12d7533ff0754f45bf59ab300799074570a99a676545652c2c23abc73cb4515d android.hardware.soundtrigger@2.3::ISoundTriggerHw
7746fda1fbf9c7c132bae701cc5a161309e4f5e7f3e8065811045975ee86196d android.hardware.usb.gadget@1.1::IUsbGadget
diff --git a/drm/1.3/vts/OWNERS b/drm/1.3/vts/OWNERS
new file mode 100644
index 0000000..3a0672e
--- /dev/null
+++ b/drm/1.3/vts/OWNERS
@@ -0,0 +1,9 @@
+conglin@google.com
+edwinwong@google.com
+fredgc@google.com
+jtinker@google.com
+juce@google.com
+kylealexander@google.com
+rfrias@google.com
+robertshih@google.com
+sigquit@google.com
diff --git a/drm/1.3/vts/functional/Android.bp b/drm/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..4be1575
--- /dev/null
+++ b/drm/1.3/vts/functional/Android.bp
@@ -0,0 +1,78 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+ name: "android.hardware.drm@1.3-vts",
+ defaults: ["VtsHalTargetTestDefaults"],
+ local_include_dirs: [
+ "include",
+ ],
+ srcs: [
+ "drm_hal_test.cpp",
+ ],
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ "android.hardware.drm@1.3",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libnativehelper",
+ ],
+ static_libs: [
+ "android.hardware.drm@1.0-helper",
+ "libcrypto_static",
+ "libdrmvtshelper",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+}
+
+cc_test {
+ name: "VtsHalDrmV1_3TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ include_dirs: ["hardware/interfaces/drm/1.0/vts/functional"],
+ srcs: [
+ "drm_hal_test_main.cpp",
+ ],
+ whole_static_libs: [
+ "android.hardware.drm@1.0-vts",
+ "android.hardware.drm@1.1-vts",
+ "android.hardware.drm@1.2-vts",
+ "android.hardware.drm@1.3-vts",
+ ],
+ shared_libs: [
+ "android.hardware.drm@1.0",
+ "android.hardware.drm@1.1",
+ "android.hardware.drm@1.2",
+ "android.hardware.drm@1.3",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libhidlmemory",
+ "libnativehelper",
+ ],
+ static_libs: [
+ "android.hardware.drm@1.0-helper",
+ "libcrypto_static",
+ "libdrmvtshelper",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
+}
diff --git a/drm/1.3/vts/functional/drm_hal_test.cpp b/drm/1.3/vts/functional/drm_hal_test.cpp
new file mode 100644
index 0000000..738f5b2
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+TEST_P(DrmHalTestV1_3, SchemeSupported) {
+ EXPECT_TRUE(drmFactory_->isCryptoSchemeSupported(GetParam().scheme_));
+}
+
+TEST_P(DrmHalTestV1_3, SignRsaNotAllowed) {
+ hidl_array<uint8_t, 16> kWidevineUUID ({
+ 0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
+ 0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
+ });
+
+ if (!drmFactory_->isCryptoSchemeSupported(kWidevineUUID)) {
+ GTEST_SKIP() << "Widevine only test";
+ }
+
+ // signRSA
+ const hidl_vec<uint8_t>& sessionId{};
+ const hidl_string& algorithm{};
+ const hidl_vec<uint8_t>& message{};
+ const hidl_vec<uint8_t>& wrappedKey{};
+ auto res = drmPlugin_->signRSA(
+ sessionId, algorithm, message, wrappedKey,
+ [&](StatusV1_0 status, const hidl_vec<uint8_t>& signature) {
+ EXPECT_EQ(status, StatusV1_0::ERROR_DRM_UNKNOWN);
+ EXPECT_EQ(signature.size(), 0);
+ }
+ );
+ EXPECT_TRUE(res.isOk());
+}
+
+} // namespace vts
+} // namespace V1_3
+} // namespace drm
+} // namespace hardware
+} // namespace android
diff --git a/drm/1.3/vts/functional/drm_hal_test_main.cpp b/drm/1.3/vts/functional/drm_hal_test_main.cpp
new file mode 100644
index 0000000..02b45ea
--- /dev/null
+++ b/drm/1.3/vts/functional/drm_hal_test_main.cpp
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Instantiate the set of test cases for each vendor module
+ */
+
+#define LOG_TAG "drm_hal_test@1.3"
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "android/hardware/drm/1.0/vts/drm_hal_clearkey_test.h" // V1_0 tests
+#include "android/hardware/drm/1.0/vts/drm_hal_vendor_test.h" // V1_0 tests
+#include "android/hardware/drm/1.1/vts/drm_hal_clearkey_test.h" // V1_1 tests
+#include "android/hardware/drm/1.2/vts/drm_hal_common.h" // V1_2 tests
+#include "android/hardware/drm/1.3/vts/drm_hal_test.h" // V1_3 tests
+
+using drm_vts::DrmHalTestParam;
+using drm_vts::PrintParamInstanceToString;
+
+using android::hardware::drm::V1_0::vts::DrmHalVendorFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalVendorDecryptTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyFactoryTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyPluginTest;
+using android::hardware::drm::V1_0::vts::DrmHalClearkeyDecryptTest;
+using android::hardware::drm::V1_1::vts::DrmHalClearkeyTest;
+using android::hardware::drm::V1_2::vts::DrmHalTest;
+using android::hardware::drm::V1_2::vts::DrmHalClearkeyTestV1_2;
+using android::hardware::drm::V1_3::vts::DrmHalTestV1_3;
+
+static const std::vector<DrmHalTestParam> kAllInstances = [] {
+ using ::android::hardware::drm::V1_3::ICryptoFactory;
+ using ::android::hardware::drm::V1_3::IDrmFactory;
+
+ std::vector<std::string> drmInstances =
+ android::hardware::getAllHalInstanceNames(IDrmFactory::descriptor);
+ std::vector<std::string> cryptoInstances =
+ android::hardware::getAllHalInstanceNames(ICryptoFactory::descriptor);
+ std::set<std::string> allInstances;
+ allInstances.insert(drmInstances.begin(), drmInstances.end());
+ allInstances.insert(cryptoInstances.begin(), cryptoInstances.end());
+
+ std::vector<DrmHalTestParam> allInstanceUuidCombos;
+ for (const auto &instance : allInstances) {
+ auto drmFactory = IDrmFactory::getService(instance);
+ if (drmFactory == nullptr) {
+ continue;
+ }
+ drmFactory->getSupportedCryptoSchemes(
+ [&](const hidl_vec<hidl_array<uint8_t, 16>>& schemes) {
+ for (const auto &scheme : schemes) {
+ allInstanceUuidCombos.push_back(DrmHalTestParam(instance, scheme));
+ }
+ });
+ }
+ return allInstanceUuidCombos;
+}();
+
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorFactoryTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorPluginTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_CASE_P(PerInstanceUuidV1_0, DrmHalVendorDecryptTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyFactoryTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyPluginTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_0, DrmHalClearkeyDecryptTest,
+ testing::ValuesIn(kAllInstances),
+ drm_vts::PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_1, DrmHalClearkeyTest,
+ testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalTest,
+ testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_2, DrmHalClearkeyTestV1_2,
+ testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+
+INSTANTIATE_TEST_SUITE_P(PerInstanceUuidV1_3, DrmHalTestV1_3,
+ testing::ValuesIn(kAllInstances),
+ PrintParamInstanceToString);
+
+int main(int argc, char** argv) {
+#if defined(__LP64__)
+ const char* kModulePath = "/data/local/tmp/64/lib";
+#else
+ const char* kModulePath = "/data/local/tmp/32/lib";
+#endif
+ DrmHalTest::gVendorModules = new drm_vts::VendorModules(kModulePath);
+ if (DrmHalTest::gVendorModules->getPathList().size() == 0) {
+ std::cerr << "WARNING: No vendor modules found in " << kModulePath <<
+ ", all vendor tests will be skipped" << std::endl;
+ }
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ ALOGI("Test result = %d", status);
+ return status;
+}
diff --git a/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
new file mode 100644
index 0000000..d8f5277
--- /dev/null
+++ b/drm/1.3/vts/functional/include/android/hardware/drm/1.3/vts/drm_hal_test.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DRM_HAL_TEST_V1_3_H
+#define DRM_HAL_TEST_V1_3_H
+
+#include <android/hardware/drm/1.3/ICryptoFactory.h>
+#include <android/hardware/drm/1.3/IDrmFactory.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
+#include <hidl/ServiceManagement.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "drm_hal_vendor_module_api.h"
+#include "drm_vts_helper.h"
+#include "vendor_modules.h"
+#include "VtsHalHidlTargetCallbackBase.h"
+
+namespace android {
+namespace hardware {
+namespace drm {
+namespace V1_3 {
+namespace vts {
+
+using android::hardware::hidl_array;
+using android::hardware::hidl_string;
+
+using drm_vts::DrmHalTestParam;
+
+using IDrmFactoryV1_3 = android::hardware::drm::V1_3::IDrmFactory;
+using IDrmPluginV1_0 = android::hardware::drm::V1_0::IDrmPlugin;
+using StatusV1_0 = android::hardware::drm::V1_0::Status;
+
+class DrmHalTestV1_3 : public ::testing::TestWithParam<DrmHalTestParam> {
+public:
+ DrmHalTestV1_3()
+ : drmFactory_(IDrmFactoryV1_3::getService(GetParam().instance_)) {}
+
+ virtual void SetUp() override {
+ ASSERT_NE(drmFactory_, nullptr);
+
+ // create plugin
+ hidl_string packageName("android.hardware.drm.V1_3.vts");
+ auto res = drmFactory_->createPlugin(
+ GetParam().scheme_, packageName,
+ [&](StatusV1_0 status, const sp<IDrmPluginV1_0>& pluginV1_0) {
+ EXPECT_EQ(StatusV1_0::OK, status);
+ drmPlugin_ = pluginV1_0;
+ });
+ EXPECT_TRUE(res.isOk());
+ ASSERT_NE(drmPlugin_, nullptr);
+ }
+
+ virtual void TearDown() override {}
+
+protected:
+ sp<IDrmFactoryV1_3> drmFactory_;
+ sp<IDrmPluginV1_0> drmPlugin_;
+};
+
+} // namespace vts
+} // namespace V1_3
+} // namespace drm
+} // namespace hardware
+} // namespace android
+
+#endif // DRM_HAL_TEST_V1_3_H
diff --git a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
index 6183a1a..c04b4d0 100644
--- a/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
+++ b/gnss/1.0/vts/functional/VtsHalGnssV1_0TargetTest.cpp
@@ -26,6 +26,8 @@
#include <condition_variable>
#include <mutex>
+#include <cutils/properties.h>
+
using android::hardware::Return;
using android::hardware::Void;
@@ -37,6 +39,12 @@
using android::hardware::gnss::V1_0::IGnssMeasurement;
using android::sp;
+static bool IsAutomotiveDevice() {
+ char buffer[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.hardware.type", buffer, "");
+ return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
#define TIMEOUT_SEC 2 // for basic commands/responses
// for command line argument on how strictly to run the test
@@ -473,9 +481,9 @@
auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
ASSERT_TRUE(gnssDebug.isOk());
- if (info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
- sp<IGnssDebug> iGnssDebug = gnssDebug;
- EXPECT_NE(iGnssDebug, nullptr);
+ if (!IsAutomotiveDevice() && info_called_count_ > 0 && last_info_.yearOfHw >= 2017) {
+ sp<IGnssDebug> iGnssDebug = gnssDebug;
+ EXPECT_NE(iGnssDebug, nullptr);
}
}
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index e0d8b54..8530ffb 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -19,6 +19,7 @@
#include <gnss_hal_test.h>
#include <android/hardware/gnss/1.1/IGnssConfiguration.h>
+#include <cutils/properties.h>
#include <gtest/gtest.h>
using android::hardware::hidl_vec;
@@ -32,6 +33,12 @@
using android::hardware::gnss::V1_1::IGnssConfiguration;
using android::hardware::gnss::V1_1::IGnssMeasurement;
+static bool IsAutomotiveDevice() {
+ char buffer[PROPERTY_VALUE_MAX] = {0};
+ property_get("ro.hardware.type", buffer, "");
+ return strncmp(buffer, "automotive", PROPERTY_VALUE_MAX) == 0;
+}
+
/*
* SetupTeardownCreateCleanup:
* Requests the gnss HAL then calls cleanup
@@ -524,7 +531,8 @@
TEST_P(GnssHalTest, GnssDebugValuesSanityTest) {
auto gnssDebug = gnss_hal_->getExtensionGnssDebug();
ASSERT_TRUE(gnssDebug.isOk());
- if (gnss_cb_->info_cbq_.calledCount() > 0 && gnss_cb_->last_info_.yearOfHw >= 2017) {
+ if (!IsAutomotiveDevice() && gnss_cb_->info_cbq_.calledCount() > 0 &&
+ gnss_cb_->last_info_.yearOfHw >= 2017) {
sp<IGnssDebug> iGnssDebug = gnssDebug;
EXPECT_NE(iGnssDebug, nullptr);
diff --git a/graphics/composer/2.1/utils/vts/Android.bp b/graphics/composer/2.1/utils/vts/Android.bp
index cdc0f35..3b0911f 100644
--- a/graphics/composer/2.1/utils/vts/Android.bp
+++ b/graphics/composer/2.1/utils/vts/Android.bp
@@ -23,14 +23,13 @@
"TestCommandReader.cpp",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
"android.hardware.graphics.mapper@4.0-vts",
+ "libgtest",
],
export_static_lib_headers: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.mapper@2.0-vts",
"android.hardware.graphics.mapper@3.0-vts",
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index a8e1480..4b6b7c8 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
#include <composer-vts/2.1/ComposerVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -25,11 +23,6 @@
namespace V2_1 {
namespace vts {
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
- : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
Composer::Composer(const sp<IComposer>& composer) : mComposer(composer) {
// ASSERT_* can only be used in functions returning void.
[this] {
diff --git a/graphics/composer/2.2/utils/vts/Android.bp b/graphics/composer/2.2/utils/vts/Android.bp
index 5432882..a8bb1a2 100644
--- a/graphics/composer/2.2/utils/vts/Android.bp
+++ b/graphics/composer/2.2/utils/vts/Android.bp
@@ -26,11 +26,11 @@
"libui",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.mapper@2.1-vts",
"libarect",
+ "libgtest",
"libmath",
"libnativewindow",
"librenderengine",
@@ -40,7 +40,6 @@
"android.hardware.graphics.mapper@4.0-vts",
],
export_static_lib_headers: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1-vts",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.mapper@2.1-vts",
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index 93b67f0..a526137 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -16,7 +16,6 @@
#include <composer-vts/2.2/ComposerVts.h>
-#include <VtsHalHidlTargetTestBase.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <hidl/HidlTransportUtils.h>
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 5d22305..6bc2732 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -22,7 +22,6 @@
#include <unordered_set>
#include <vector>
-#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/graphics/composer/2.2/IComposer.h>
#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
index 7519a64..d5eedf1 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -142,7 +142,7 @@
const native_handle_t* mBufferHandle = nullptr;
};
-class ReadbackHelper : public ::testing::VtsHalHidlTargetTestBase {
+class ReadbackHelper {
public:
static std::string getColorModeString(ColorMode mode);
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
index b936cab..4eb4bb7 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/RenderEngineVts.h
@@ -24,8 +24,6 @@
#include <ui/Rect.h>
#include <ui/Region.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index f987516..e38af00 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -19,7 +19,7 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
"VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
- "VtsHalGraphicsComposerV2_2TargetTest.cpp"
+ "VtsHalGraphicsComposerV2_2TargetTest.cpp",
],
// TODO(b/64437680): Assume these libs are always available on the device.
@@ -51,12 +51,16 @@
"android.hardware.graphics.mapper@3.0-vts",
"android.hardware.graphics.mapper@4.0",
"android.hardware.graphics.mapper@4.0-vts",
- "librenderengine"
+ "libgtest",
+ "librenderengine",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
"android.hardware.graphics.composer@2.2-command-buffer",
],
disable_framework: true,
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 044bd96..cb43e64 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -932,7 +932,7 @@
class GraphicsBlendModeCompositionTest
: public GraphicsCompositionTestBase,
- public testing::WithParamInterface<std::tuple<string, string>> {
+ public testing::WithParamInterface<std::tuple<std::string, std::string>> {
public:
void SetUp() override {
SetUpBase(std::get<0>(GetParam()));
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
index f65a9c4..3d81e8f 100644
--- a/graphics/composer/2.3/utils/vts/Android.bp
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -23,6 +23,7 @@
static_libs: [
"android.hardware.graphics.composer@2.2-vts",
"android.hardware.graphics.composer@2.3",
+ "libgtest",
],
export_static_lib_headers: [
"android.hardware.graphics.composer@2.2-vts",
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
index d4f5b3a..d73a3b0 100644
--- a/graphics/composer/2.3/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
#include <composer-vts/2.3/ComposerVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -27,11 +25,6 @@
using V2_1::Error;
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
- : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
Composer::Composer(const sp<IComposer>& composer)
: V2_2::vts::Composer(composer), mComposer(composer) {}
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
index e5ac842..dae9ab4 100644
--- a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -19,7 +19,6 @@
#include <memory>
#include <vector>
-#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/graphics/composer/2.3/IComposer.h>
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
#include <composer-vts/2.2/ComposerVts.h>
diff --git a/graphics/composer/2.4/utils/vts/Android.bp b/graphics/composer/2.4/utils/vts/Android.bp
index 673c15e..e42223d 100644
--- a/graphics/composer/2.4/utils/vts/Android.bp
+++ b/graphics/composer/2.4/utils/vts/Android.bp
@@ -22,12 +22,12 @@
"GraphicsComposerCallback.cpp",
],
static_libs: [
- "VtsHalHidlTargetTestBase",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
"android.hardware.graphics.composer@2.3-vts",
"android.hardware.graphics.composer@2.3",
"android.hardware.graphics.composer@2.4",
+ "libgtest",
],
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
diff --git a/graphics/composer/2.4/utils/vts/ComposerVts.cpp b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
index 8cdc452..c5f3b5e 100644
--- a/graphics/composer/2.4/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.4/utils/vts/ComposerVts.cpp
@@ -16,8 +16,6 @@
#include <composer-vts/2.4/ComposerVts.h>
-#include <VtsHalHidlTargetTestBase.h>
-
namespace android {
namespace hardware {
namespace graphics {
@@ -27,11 +25,6 @@
using V2_4::Error;
-Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
-
-Composer::Composer(const std::string& name)
- : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
-
Composer::Composer(const sp<IComposer>& composer)
: V2_3::vts::Composer(composer), mComposer(composer) {}
diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
index 3dd8e50..fd59eb9 100644
--- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
+++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/ComposerVts.h
@@ -19,7 +19,6 @@
#include <memory>
#include <vector>
-#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/graphics/composer/2.4/IComposer.h>
#include <android/hardware/graphics/composer/2.4/IComposerClient.h>
#include <composer-vts/2.3/ComposerVts.h>
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index f6b46ff..a7c3fd7 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -42,6 +42,8 @@
namespace vts {
namespace {
+using namespace std::chrono_literals;
+
using common::V1_0::BufferUsage;
using common::V1_1::RenderIntent;
using common::V1_2::ColorMode;
@@ -526,7 +528,7 @@
EXPECT_EQ(Error::UNSUPPORTED,
mComposerClient->setAutoLowLatencyMode(mPrimaryDisplay, false));
GTEST_SUCCEED() << "Auto Low Latency Mode is not supported on display "
- << to_string(display) << ", skipping test";
+ << std::to_string(display) << ", skipping test";
return;
}
@@ -580,7 +582,7 @@
if (!contentTypeSupport) {
EXPECT_EQ(Error::UNSUPPORTED, mComposerClient->setContentType(display, contentType));
GTEST_SUCCEED() << contentTypeStr << " content type is not supported on display "
- << to_string(display) << ", skipping test";
+ << std::to_string(display) << ", skipping test";
return;
}
@@ -626,7 +628,7 @@
testing::ValuesIn(android::hardware::getAllHalInstanceNames(IComposer::descriptor)),
android::hardware::PrintInstanceNameToString);
-TEST_F(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
+TEST_P(GraphicsComposerHidlCommandTest, getLayerGenericMetadataKeys) {
std::vector<IComposerClient::LayerGenericMetadataKey> keys;
mComposerClient->getLayerGenericMetadataKeys(&keys);
diff --git a/health/2.1/README.md b/health/2.1/README.md
index bfcf13b..8390570 100644
--- a/health/2.1/README.md
+++ b/health/2.1/README.md
@@ -24,6 +24,9 @@
```mk
# Install default passthrough implementation to vendor.
PRODUCT_PACKAGES += android.hardware.health@2.1-impl
+
+ # For non-A/B devices, install default passthrough implementation to recovery.
+ PRODUCT_PACKAGES += android.hardware.health@2.1-impl.recovery
```
You are done. Otherwise, go to the next step.
@@ -42,6 +45,8 @@
implementation, See
[Upgrading from Health HAL 2.0](#update-from-2-0).
+ 1. [Install the implementation](#install).
+
1. [Update necessary SELinux permissions](#selinux).
1. [Fix `/charger` symlink](#charger-symlink).
@@ -95,15 +100,22 @@
`HealthImpl::getHealthInfo` or `HealthImpl::getHealthInfo_2_1` because they call
`getDiskStats` and `getStorageInfo` to retrieve storage information.
+# Install the implementation {#install}
+
+In `device.mk`:
+
+```mk
+# Install the passthrough implementation to vendor.
+PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>
+
+# For non-A/B devices, also install the passthrough implementation to recovery.
+PRODUCT_PACKAGES += android.hardware.health@2.1-impl-<device>.recovery
+```
+
# Update necessary SELinux permissions {#selinux}
For example (replace `<device>` with the device name):
```
-# device/<manufacturer>/<device>/sepolicy/vendor/file_contexts
-# Required for charger to open passthrough implementation. Replace <device> with the proper device
-# name. File name must be consistent with `stem` of the implementation module.
-/vendor/lib(64)?/hw/android\.hardware\.health@2\.0-impl-2\.1-<device>\.so u:object_r:same_process_hal_file:s0
-
# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
# Add device specific permissions to hal_health_default domain, especially
# if a device-specific libhealthd is used and/or device-specific storage related
diff --git a/health/2.1/default/android.hardware.health@2.1-service.rc b/health/2.1/default/android.hardware.health@2.1-service.rc
index 917f1c2..b6d9e3b 100644
--- a/health/2.1/default/android.hardware.health@2.1-service.rc
+++ b/health/2.1/default/android.hardware.health@2.1-service.rc
@@ -1,5 +1,5 @@
service health-hal-2-1 /vendor/bin/hw/android.hardware.health@2.1-service
- class hal
+ class hal charger
user system
group system
capabilities WAKE_ALARM
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
index a973923..d4351ec 100644
--- a/neuralnetworks/1.3/types.t
+++ b/neuralnetworks/1.3/types.t
@@ -553,6 +553,19 @@
};
/**
+ * Optional timeout duration measured in nanoseconds.
+ */
+safe_union OptionalTimeoutDuration {
+ /** No time point provided. */
+ Monostate none;
+
+ /**
+ * Timeout duration measured in nanoseconds.
+ */
+ uint64_t nanoseconds;
+};
+
+/**
* Return status of a function.
*/
enum ErrorStatus : @1.0::ErrorStatus {
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index bc40500..2ec92e5 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -18,10 +18,8 @@
import @1.0::CdmaSmsMessage;
import @1.2::DataRequestReason;
-import @1.4::DataProfileInfo;
import @1.4::IRadio;
import @1.5::AccessNetwork;
-import @1.5::BarringInfo;
import @1.5::DataProfileInfo;
import @1.5::IndicationFilter;
import @1.5::LinkAddress;
@@ -118,13 +116,13 @@
vec<RadioAccessSpecifier> specifiers);
/**
- * Starts a network scan
+ * Starts a network scan.
*
* @param serial Serial number of request.
* @param request Defines the radio networks/bands/channels which need to be scanned.
*
- * Same API as @1.4::IRadio.startNetworkScan_1_4, except using
- * 1.5 version of NetworkScanRequest
+ * Same API as @1.4::IRadio.startNetworkScan_1_4, except using the
+ * 1.5 NetworkScanRequest as the input param.
*/
oneway startNetworkScan_1_5(int32_t serial, NetworkScanRequest request);
@@ -166,14 +164,14 @@
* Response function is IRadioResponse.setupDataCallResponse_1_5()
*
* Note this API is the same as the 1.4 version except using the
- * 1.5 AccessNetwork, DataProfileInto, and link addresses as the input param.
+ * 1.5 AccessNetwork, DataProfileInto, and LinkAddress as the input param.
*/
oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork,
DataProfileInfo dataProfileInfo, bool roamingAllowed,
DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
/**
- * Set an apn to initial attach network
+ * Set an APN to initial attach network.
*
* @param serial Serial number of request.
* @param dataProfileInfo data profile containing APN settings
@@ -189,7 +187,7 @@
* Send data profiles of the current carrier to the modem.
*
* @param serial Serial number of request.
- * @param profiles Array of DataProfile to set.
+ * @param profiles Array of DataProfileInfo to set.
*
* Response callback is IRadioResponse.setDataProfileResponse_1_5()
*
@@ -230,7 +228,7 @@
*
* Prevents the reporting of specified unsolicited indications from the radio. This is used
* for power saving in instances when those indications are not needed. If unset, defaults to
- * @1.2::IndicationFilter:ALL.
+ * @1.5::IndicationFilter:ALL.
*
* @param serial Serial number of request.
* @param indicationFilter 32-bit bitmap of IndicationFilter. Bits set to 1 indicate the
@@ -250,7 +248,7 @@
oneway getBarringInfo(int32_t serial);
/**
- * Request current voice registration state
+ * Request current voice registration state.
*
* @param serial Serial number of request.
*
@@ -259,7 +257,7 @@
oneway getVoiceRegistrationState_1_5(int32_t serial);
/**
- * Request current data registration state
+ * Request current data registration state.
*
* @param serial Serial number of request.
*
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 6a2187f..aa8b526 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -21,10 +21,9 @@
import @1.4::IRadioResponse;
import @1.5::BarringInfo;
import @1.5::CellInfo;
+import @1.5::PersoSubstate;
import @1.5::RegStateResult;
import @1.5::SetupDataCallResult;
-import @1.4::SetupDataCallResult;
-import @1.5::PersoSubstate;
/**
* Interface declaring response functions to solicited radio requests.
@@ -177,6 +176,7 @@
oneway getBarringInfoResponse(RadioResponseInfo info, vec<BarringInfo> barringInfos);
/**
+ * @param info Response info struct containing response type, serial no. and error
* @param voiceRegResponse Current Voice registration response as defined by RegStateResult
* in types.hal
*
@@ -215,7 +215,6 @@
*/
oneway getCellInfoListResponse_1_5(RadioResponseInfo info, vec<CellInfo> cellInfo);
-
/**
* @param info Response info struct containing response type, serial no. and error
*
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index cf195cc..448e5c8 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -19,19 +19,15 @@
import @1.0::ApnAuthType;
import @1.0::DataProfileId;
import @1.0::DataProfileInfoType;
-import @1.0::CdmaSignalStrength;
-import @1.0::EvdoSignalStrength;
import @1.0::GsmSignalStrength;
import @1.0::LteSignalStrength;
import @1.0::PersoSubstate;
-import @1.0::RadioAccessFamily;
import @1.0::RadioError;
import @1.0::RegState;
import @1.0::TimeStampType;
import @1.1::EutranBands;
import @1.1::GeranBands;
import @1.1::RadioAccessNetworks;
-import @1.1::RadioAccessSpecifier;
import @1.1::ScanStatus;
import @1.1::ScanType;
import @1.1::UtranBands;
@@ -43,7 +39,6 @@
import @1.2::CellIdentityLte;
import @1.2::CellInfoCdma;
import @1.2::IndicationFilter;
-import @1.2::NetworkScanRequest;
import @1.2::TdscdmaSignalStrength;
import @1.2::WcdmaSignalStrength;
import @1.4::AccessNetwork;
@@ -51,11 +46,11 @@
import @1.4::CellIdentityNr;
import @1.4::DataCallFailCause;
import @1.4::DataConnActiveStatus;
-import @1.4::DataProfileInfo;
import @1.4::LteVopsInfo;
import @1.4::NrIndicators;
import @1.4::NrSignalStrength;
import @1.4::PdpProtocolType;
+import @1.4::RadioAccessFamily;
import @1.4::RadioTechnology;
import android.hidl.safe_union@1.0::Monostate;
@@ -131,7 +126,7 @@
/** Signal Measurement Type */
SignalMeasurementType signalMeasurement;
- /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis */
+ /** A hysteresis time in milliseconds to prevent flapping. A value of 0 disables hysteresis. */
int32_t hysteresisMs;
/**
@@ -175,7 +170,7 @@
};
/**
- * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands
+ * Overwritten from @1.1::RadioAccessSpecifier to add NGRAN and NgranBands.
*/
struct RadioAccessSpecifier {
/**
@@ -264,8 +259,7 @@
};
/**
- * Overwritten from @1.2::NetworkScanRequest to update
- * RadioAccessSpecifier to 1.5 version
+ * Overwritten from @1.2::NetworkScanRequest to update RadioAccessSpecifier to 1.5 version.
*/
struct NetworkScanRequest {
ScanType type;
@@ -328,11 +322,10 @@
};
/**
- * Extended from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with
+ * Overwritten from @1.4::DataProfileInfo to update ApnTypes to 1.5 version and replace mtu with
* mtuV4 and mtuV6. In the future, this must be extended instead of overwritten.
*/
struct DataProfileInfo {
-
/** ID of the data profile. */
DataProfileId profileId;
@@ -445,8 +438,8 @@
};
/**
- * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5
- * version. In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by
+ * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5 version.
+ * In 1.5 the type of addresses changes to vector of LinkAddress, and mtu is replaced by
* mtuV4 and mtuV6.
*/
struct SetupDataCallResult {
@@ -687,7 +680,7 @@
} ratSpecificInfo;
};
-/** A union representing the CellIdentity of a single cell */
+/** A union representing the CellIdentity of a single cell. */
safe_union CellIdentity {
Monostate noinit;
@@ -699,125 +692,116 @@
CellIdentityNr nr;
};
-/**
- * Combined list of barring services for UTRAN, EUTRAN, and NGRAN.
- *
- * Barring information is defined in:
- * -UTRAN - 3gpp 25.331 Sec 10.2.48.8.6.
- * -EUTRAN - 3gpp 36.331 Sec 6.3.1 SystemInformationBlockType2
- * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3]
- */
-enum BarringServiceType : int32_t {
- /** Applicabe to UTRAN */
- /** Barring for all CS services, including registration */
- CS_SERVICE,
- /** Barring for all PS services, including registration */
- PS_SERVICE,
- /** Barring for mobile-originated circuit-switched voice calls */
- CS_VOICE,
-
- /** Applicable to EUTRAN, NGRAN */
- /** Barring for mobile-originated signalling for any purpose */
- MO_SIGNALLING,
- /** Barring for mobile-originated internet or other interactive data */
- MO_DATA,
- /** Barring for circuit-switched fallback calling */
- CS_FALLBACK,
- /** Barring for IMS voice calling */
- MMTEL_VOICE,
- /** Barring for IMS video calling */
- MMTEL_VIDEO,
-
- /** Applicable to UTRAN, EUTRAN, NGRAN */
- /** Barring for emergency services, either CS or emergency MMTEL */
- EMERGENCY,
- /** Barring for short message services */
- SMS,
-
- /** Operator-specific barring codes; applicable to NGRAN */
- OPERATOR_1 = 1001,
- OPERATOR_2 = 1002,
- OPERATOR_3 = 1003,
- OPERATOR_4 = 1004,
- OPERATOR_5 = 1005,
- OPERATOR_6 = 1006,
- OPERATOR_7 = 1007,
- OPERATOR_8 = 1008,
- OPERATOR_9 = 1009,
- OPERATOR_10 = 1010,
- OPERATOR_11 = 1011,
- OPERATOR_12 = 1012,
- OPERATOR_13 = 1013,
- OPERATOR_14 = 1014,
- OPERATOR_15 = 1015,
- OPERATOR_16 = 1016,
- OPERATOR_17 = 1017,
- OPERATOR_18 = 1018,
- OPERATOR_19 = 1019,
- OPERATOR_20 = 1020,
- OPERATOR_21 = 1021,
- OPERATOR_22 = 1022,
- OPERATOR_23 = 1023,
- OPERATOR_24 = 1024,
- OPERATOR_25 = 1025,
- OPERATOR_26 = 1026,
- OPERATOR_27 = 1027,
- OPERATOR_28 = 1028,
- OPERATOR_29 = 1029,
- OPERATOR_30 = 1030,
- OPERATOR_31 = 1031,
- OPERATOR_32 = 1032,
-};
-
-enum BarringType : int32_t {
- /** Device is not barred for the given service */
- NONE,
- /** Device may be barred based on time and probability factors */
- CONDITIONAL,
- /* Device is unconditionally barred */
- UNCONDITIONAL,
-};
-
-struct ConditionalBarringInfo {
- /** The barring factor as a percentage 0-100 */
- int32_t barringFactor;
-
- /** The number of seconds between re-evaluations of barring */
- int32_t barringTimeSeconds;
-
- /**
- * Indicates whether barring is currently being applied.
- *
- * <p>True if the UE applies barring to a conditionally barred
- * service based on the conditional barring parameters.
- *
- * <p>False if the service is conditionally barred but barring
- * is not currently applied, which could be due to either the
- * barring criteria not having been evaluated (if the UE has not
- * attempted to use the service) or due to the criteria being
- * evaluated and the UE being permitted to use the service
- * despite conditional barring.
- */
- bool isBarred;
-};
-
-safe_union BarringTypeSpecificInfo {
- /** Barring type is either none or unconditional */
- Monostate noinit;
-
- /** Must be included if barring is conditional */
- ConditionalBarringInfo conditionalBarringInfo;
-};
-
struct BarringInfo {
- /** Barring service */
- BarringServiceType service;
+ /**
+ * Combined list of barring services for UTRAN, EUTRAN, and NGRAN.
+ *
+ * Barring information is defined in:
+ * -UTRAN - 3gpp 25.331 Sec 10.2.48.8.6.
+ * -EUTRAN - 3gpp 36.331 Sec 6.3.1 SystemInformationBlockType2
+ * -NGRAN - 3gpp 38.331 Sec 6.3.2 UAC-BarringInfo and 22.261 Sec 6.22.2.[2-3]
+ */
+ enum ServiceType : int32_t {
+ /** Applicable to UTRAN */
+ /** Barring for all CS services, including registration */
+ CS_SERVICE,
+ /** Barring for all PS services, including registration */
+ PS_SERVICE,
+ /** Barring for mobile-originated circuit-switched voice calls */
+ CS_VOICE,
+
+ /** Applicable to EUTRAN, NGRAN */
+ /** Barring for mobile-originated signalling for any purpose */
+ MO_SIGNALLING,
+ /** Barring for mobile-originated internet or other interactive data */
+ MO_DATA,
+ /** Barring for circuit-switched fallback calling */
+ CS_FALLBACK,
+ /** Barring for IMS voice calling */
+ MMTEL_VOICE,
+ /** Barring for IMS video calling */
+ MMTEL_VIDEO,
+
+ /** Applicable to UTRAN, EUTRAN, NGRAN */
+ /** Barring for emergency services, either CS or emergency MMTEL */
+ EMERGENCY,
+ /** Barring for short message services */
+ SMS,
+
+ /** Operator-specific barring codes; applicable to NGRAN */
+ OPERATOR_1 = 1001,
+ OPERATOR_2 = 1002,
+ OPERATOR_3 = 1003,
+ OPERATOR_4 = 1004,
+ OPERATOR_5 = 1005,
+ OPERATOR_6 = 1006,
+ OPERATOR_7 = 1007,
+ OPERATOR_8 = 1008,
+ OPERATOR_9 = 1009,
+ OPERATOR_10 = 1010,
+ OPERATOR_11 = 1011,
+ OPERATOR_12 = 1012,
+ OPERATOR_13 = 1013,
+ OPERATOR_14 = 1014,
+ OPERATOR_15 = 1015,
+ OPERATOR_16 = 1016,
+ OPERATOR_17 = 1017,
+ OPERATOR_18 = 1018,
+ OPERATOR_19 = 1019,
+ OPERATOR_20 = 1020,
+ OPERATOR_21 = 1021,
+ OPERATOR_22 = 1022,
+ OPERATOR_23 = 1023,
+ OPERATOR_24 = 1024,
+ OPERATOR_25 = 1025,
+ OPERATOR_26 = 1026,
+ OPERATOR_27 = 1027,
+ OPERATOR_28 = 1028,
+ OPERATOR_29 = 1029,
+ OPERATOR_30 = 1030,
+ OPERATOR_31 = 1031,
+ OPERATOR_32 = 1032,
+ } serviceType;
/** The type of barring applied to the service */
- BarringType type;
+ enum BarringType : int32_t {
+ /** Device is not barred for the given service */
+ NONE,
+ /** Device may be barred based on time and probability factors */
+ CONDITIONAL,
+ /* Device is unconditionally barred */
+ UNCONDITIONAL,
+ } barringType;
/** Type-specific barring info if applicable */
- BarringTypeSpecificInfo typeSpecificInfo;
+ safe_union BarringTypeSpecificInfo {
+ /** Barring type is either none or unconditional */
+ Monostate noinit;
+
+ /** Must be included if barring is conditional */
+ struct Conditional {
+ /** The barring factor as a percentage 0-100 */
+ int32_t factor;
+
+ /** The number of seconds between re-evaluations of barring */
+ int32_t timeSeconds;
+
+ /**
+ * Indicates whether barring is currently being applied.
+ *
+ * <p>True if the UE applies barring to a conditionally barred
+ * service based on the conditional barring parameters.
+ *
+ * <p>False if the service is conditionally barred but barring
+ * is not currently applied, which could be due to either the
+ * barring criteria not having been evaluated (if the UE has not
+ * attempted to use the service) or due to the criteria being
+ * evaluated and the UE being permitted to use the service
+ * despite conditional barring.
+ */
+ bool isBarred;
+ } conditional;
+ } barringTypeSpecificInfo;
};
enum IndicationFilter : @1.2::IndicationFilter {
@@ -963,14 +947,14 @@
string registeredPlmn;
/**
- * Access-technology-specific registration information, such as for Cdma2000.
+ * Access-technology-specific registration information, such as for CDMA2000.
*/
safe_union AccessTechnologySpecificInfo {
Monostate noinit;
struct Cdma2000RegistrationInfo {
/**
- * concurrent services support indicator. if registered on a CDMA system.
+ * Concurrent services support indicator. if registered on a CDMA system.
* false - Concurrent services not supported,
* true - Concurrent services supported
*/
@@ -999,10 +983,10 @@
struct EutranRegistrationInfo {
/**
* Network capabilities for voice over PS services. This info is valid only on LTE
- * network and must be present when device is camped on LTE. vopsInfo must be empty when
+ * network and must be present when device is camped on LTE. VopsInfo must be empty when
* device is camped only on 2G/3G.
*/
- LteVopsInfo lteVopsInfo; // LTE network capability
+ LteVopsInfo lteVopsInfo;
/**
* The parameters of NR 5G Non-Standalone. This value is only valid on E-UTRAN,
@@ -1032,17 +1016,20 @@
};
/**
- * Additional personalization categories in addition to those specified in 3GPP TS 22.022 and 3GPP2 C.S0068-0.
+ * Additional personalization categories in addition to those specified in 3GPP TS 22.022 and
+ * 3GPP2 C.S0068-0.
*/
enum PersoSubstate : @1.0::PersoSubstate {
SIM_SPN,
SIM_SPN_PUK,
- SIM_SP_EHPLMN, // Equivalent Home PLMN
+ /** Equivalent Home PLMN */
+ SIM_SP_EHPLMN,
SIM_SP_EHPLMN_PUK,
SIM_ICCID,
SIM_ICCID_PUK,
SIM_IMPI,
SIM_IMPI_PUK,
- SIM_NS_SP, // Network subset service provider
+ /** Network subset service provider */
+ SIM_NS_SP,
SIM_NS_SP_PUK,
};
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 09305de..621825f 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -969,7 +969,10 @@
}
}
-TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) {
+/*
+ * Test IRadio.setRadioPower_1_5() for the response returned.
+ */
+TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancelled) {
// Set radio power to off.
serial = GetRandomSerialNumber();
radio_v1_5->setRadioPower_1_5(serial, false, false, false);
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index d1c17e6..ce7b1ab 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -114,9 +114,6 @@
Return<void> supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
int32_t remainingRetries);
- Return<void> supplySimDepersonalizationResponse(const RadioResponseInfo& info,
- ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries);
-
Return<void> getCurrentCallsResponse(
const RadioResponseInfo& info,
const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls);
@@ -579,6 +576,10 @@
Return<void> sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
const SendSmsResult& sms);
+
+ Return<void> supplySimDepersonalizationResponse(
+ const RadioResponseInfo& info,
+ ::android::hardware::radio::V1_5::PersoSubstate persoType, int32_t remainingRetries);
};
/* Callback class for radio indication */
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index a62d086..26401eb 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -62,13 +62,6 @@
return Void();
}
-Return<void> RadioResponse_v1_5::supplySimDepersonalizationResponse(
- const RadioResponseInfo& /*info*/,
- ::android::hardware::radio::V1_5::PersoSubstate /*persoType*/,
- int32_t /*remainingRetries*/) {
- return Void();
-}
-
Return<void> RadioResponse_v1_5::getCurrentCallsResponse(
const RadioResponseInfo& /*info*/,
const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) {
@@ -1011,3 +1004,10 @@
const SendSmsResult& /*sms*/) {
return Void();
}
+
+Return<void> RadioResponse_v1_5::supplySimDepersonalizationResponse(
+ const RadioResponseInfo& /*info*/,
+ ::android::hardware::radio::V1_5::PersoSubstate /*persoType*/,
+ int32_t /*remainingRetries*/) {
+ return Void();
+}
diff --git a/radio/config/1.3/types.hal b/radio/config/1.3/types.hal
index 7860006..aef0ff8 100644
--- a/radio/config/1.3/types.hal
+++ b/radio/config/1.3/types.hal
@@ -50,17 +50,17 @@
/** 3GPP capability. */
THREE_GPP_REG = 1 << 1,
/** CDMA 2000 with EHRPD capability. */
- CDMA2000_EHRPD_REG = 1 << 2,
- /** GSM capability. */
- GERAN_REG = 1 << 3,
+ CDMA2000_EHRPD = 1 << 2,
+ /** GSM/EDGE capability. */
+ GERAN = 1 << 3,
/** UMTS capability. */
- UTRAN_REG = 1 << 4,
+ UTRAN = 1 << 4,
/** LTE capability. */
- EUTRAN_REG = 1 << 5,
+ EUTRAN = 1 << 5,
/** 5G capability. */
- NGRAN_REG = 1 << 6,
- /** Dual Connectivity capability. */
- EN_DC_REG = 1 << 7,
+ NGRAN = 1 << 6,
+ /** 5G dual connectivity capability. */
+ EN_DC = 1 << 7,
/** VoLTE capability (IMS registered). */
PS_VOICE_REG = 1 << 8,
/** CS voice call capability. */
@@ -72,7 +72,7 @@
/** Network scanning capability. */
NETWORK_SCAN = 1 << 12,
/** CDMA capability for SIM associated with modem. */
- CSIM = 1 << 13,
+ CSIM_APP = 1 << 13,
};
struct ConcurrentModemFeatures {
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index 7c52661..ac6f17a 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -290,6 +290,8 @@
stream << " Wakelock ref count: " << mWakelockRefCount << std::endl;
stream << " # of events on pending write writes queue: " << mSizePendingWriteEventsQueue
<< std::endl;
+ stream << " Most events seen on pending write events queue: "
+ << mMostEventsObservedPendingWriteEventsQueue << std::endl;
if (!mPendingWriteEventsQueue.empty()) {
stream << " Size of events list on front of pending writes queue: "
<< mPendingWriteEventsQueue.front().first.size() << std::endl;
@@ -571,6 +573,8 @@
std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
mSizePendingWriteEventsQueue += numLeft;
+ mMostEventsObservedPendingWriteEventsQueue =
+ std::max(mMostEventsObservedPendingWriteEventsQueue, mSizePendingWriteEventsQueue);
mEventQueueWriteCV.notify_one();
}
}
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
index ce28e67..978f7cf 100644
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -200,6 +200,9 @@
*/
std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
+ //! The most events observed on the pending write events queue for debug purposes.
+ size_t mMostEventsObservedPendingWriteEventsQueue = 0;
+
//! The max number of events allowed in the pending write events queue
static constexpr size_t kMaxSizePendingWriteEventsQueue = 100000;
diff --git a/soundtrigger/2.3/types.hal b/soundtrigger/2.3/types.hal
index 730f969..10fc34e 100644
--- a/soundtrigger/2.3/types.hal
+++ b/soundtrigger/2.3/types.hal
@@ -66,7 +66,7 @@
* Bit field encoding of the AudioCapabilities
* supported by the firmware.
*/
- uint32_t audioCapabilities;
+ bitfield<AudioCapabilities> audioCapabilities;
};
/**
diff --git a/wifi/1.2/IWifiStaIface.hal b/wifi/1.2/IWifiStaIface.hal
index 3a7f777..d65b33b 100644
--- a/wifi/1.2/IWifiStaIface.hal
+++ b/wifi/1.2/IWifiStaIface.hal
@@ -23,7 +23,7 @@
/**
* Interface used to represent a single STA iface.
*
- * IWifiChip.createStaIface() may return a @1.2::IWifiStaIface when supported.
+ * IWifiChip.createStaIface() must return a @1.2::IWifiStaIface when supported.
*/
interface IWifiStaIface extends @1.0::IWifiStaIface {
/**
diff --git a/wifi/1.3/IWifiStaIface.hal b/wifi/1.3/IWifiStaIface.hal
index 81c0c38..3a75509 100644
--- a/wifi/1.3/IWifiStaIface.hal
+++ b/wifi/1.3/IWifiStaIface.hal
@@ -23,7 +23,7 @@
/**
* Interface used to represent a single STA iface.
*
- * IWifiChip.createStaIface() may return a @1.3::IWifiStaIface when supported.
+ * IWifiChip.createStaIface() must return a @1.3::IWifiStaIface when supported.
*/
interface IWifiStaIface extends @1.2::IWifiStaIface {
/**
diff --git a/wifi/1.4/default/hidl_struct_util.cpp b/wifi/1.4/default/hidl_struct_util.cpp
index 4996e35..fd1d5b1 100644
--- a/wifi/1.4/default/hidl_struct_util.cpp
+++ b/wifi/1.4/default/hidl_struct_util.cpp
@@ -2715,6 +2715,21 @@
}
return true;
}
+
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
+ IfaceType hidl_interface_type) {
+ switch (hidl_interface_type) {
+ case IfaceType::STA:
+ return legacy_hal::WIFI_INTERFACE_TYPE_STA;
+ case IfaceType::AP:
+ return legacy_hal::WIFI_INTERFACE_TYPE_AP;
+ case IfaceType::P2P:
+ return legacy_hal::WIFI_INTERFACE_TYPE_P2P;
+ case IfaceType::NAN:
+ return legacy_hal::WIFI_INTERFACE_TYPE_NAN;
+ }
+ CHECK(false);
+}
} // namespace hidl_struct_util
} // namespace implementation
} // namespace V1_4
diff --git a/wifi/1.4/default/hidl_struct_util.h b/wifi/1.4/default/hidl_struct_util.h
index d040c1f..929f877 100644
--- a/wifi/1.4/default/hidl_struct_util.h
+++ b/wifi/1.4/default/hidl_struct_util.h
@@ -65,6 +65,8 @@
bool convertLegacyWifiMacInfosToHidl(
const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+legacy_hal::wifi_interface_type convertHidlIfaceTypeToLegacy(
+ IfaceType hidl_interface_type);
// STA iface conversion methods.
bool convertLegacyFeaturesToHidlStaCapabilities(
diff --git a/wifi/1.4/default/wifi_chip.cpp b/wifi/1.4/default/wifi_chip.cpp
index 3498510..4c9fad1 100644
--- a/wifi/1.4/default/wifi_chip.cpp
+++ b/wifi/1.4/default/wifi_chip.cpp
@@ -797,6 +797,15 @@
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
std::string ifname = allocateApIfaceName();
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->createVirtualInterface(
+ ifname,
+ hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::AP));
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to add interface: " << ifname << " "
+ << legacyErrorToString(legacy_status);
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
sp<WifiApIface> iface = new WifiApIface(ifname, legacy_hal_, iface_util_);
ap_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -835,6 +844,12 @@
// nan/rtt objects over AP iface. But, there is no harm to do it
// here and not make that assumption all over the place.
invalidateAndRemoveDependencies(ifname);
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->deleteVirtualInterface(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+ << legacyErrorToString(legacy_status);
+ }
invalidateAndClear(ap_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::AP, ifname).isOk()) {
@@ -944,6 +959,15 @@
return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
}
std::string ifname = allocateStaIfaceName();
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->createVirtualInterface(
+ ifname,
+ hidl_struct_util::convertHidlIfaceTypeToLegacy(IfaceType::STA));
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to add interface: " << ifname << " "
+ << legacyErrorToString(legacy_status);
+ return {createWifiStatusFromLegacyError(legacy_status), {}};
+ }
sp<WifiStaIface> iface = new WifiStaIface(ifname, legacy_hal_, iface_util_);
sta_ifaces_.push_back(iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
@@ -979,6 +1003,12 @@
}
// Invalidate & remove any dependent objects first.
invalidateAndRemoveDependencies(ifname);
+ legacy_hal::wifi_error legacy_status =
+ legacy_hal_.lock()->deleteVirtualInterface(ifname);
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to remove interface: " << ifname << " "
+ << legacyErrorToString(legacy_status);
+ }
invalidateAndClear(sta_ifaces_, iface);
for (const auto& callback : event_cb_handler_.getCallbacks()) {
if (!callback->onIfaceRemoved(IfaceType::STA, ifname).isOk()) {
diff --git a/wifi/1.4/default/wifi_legacy_hal.cpp b/wifi/1.4/default/wifi_legacy_hal.cpp
index 3ca3226..a040c89 100644
--- a/wifi/1.4/default/wifi_legacy_hal.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <cutils/properties.h>
+#include <net/if.h>
#include "hidl_sync_util.h"
#include "wifi_legacy_hal.h"
@@ -1355,6 +1356,7 @@
LOG(ERROR) << "Failed to enumerate interface handles";
return status;
}
+ iface_name_to_handle_.clear();
for (int i = 0; i < num_iface_handles; ++i) {
std::array<char, IFNAMSIZ> iface_name_arr = {};
status = global_func_table_.wifi_get_iface_name(
@@ -1421,6 +1423,39 @@
return {status, std::move(cached_scan_results)};
}
+wifi_error WifiLegacyHal::createVirtualInterface(const std::string& ifname,
+ wifi_interface_type iftype) {
+ // Create the interface if it doesn't exist. If interface already exist,
+ // Vendor Hal should return WIFI_SUCCESS.
+ wifi_error status = global_func_table_.wifi_virtual_interface_create(
+ global_handle_, ifname.c_str(), iftype);
+ return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::deleteVirtualInterface(const std::string& ifname) {
+ // Delete the interface if it was created dynamically.
+ wifi_error status = global_func_table_.wifi_virtual_interface_delete(
+ global_handle_, ifname.c_str());
+ return handleVirtualInterfaceCreateOrDeleteStatus(ifname, status);
+}
+
+wifi_error WifiLegacyHal::handleVirtualInterfaceCreateOrDeleteStatus(
+ const std::string& ifname, wifi_error status) {
+ if (status == WIFI_SUCCESS) {
+ // refresh list of handlers now.
+ status = retrieveIfaceHandles();
+ } else if (status == WIFI_ERROR_NOT_SUPPORTED) {
+ // Vendor hal does not implement this API. Such vendor implementations
+ // are expected to create / delete interface by other means.
+
+ // check if interface exists.
+ if (if_nametoindex(ifname.c_str())) {
+ status = retrieveIfaceHandles();
+ }
+ }
+ return status;
+}
+
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
iface_name_to_handle_.clear();
diff --git a/wifi/1.4/default/wifi_legacy_hal.h b/wifi/1.4/default/wifi_legacy_hal.h
index a7b40a0..72cf197 100644
--- a/wifi/1.4/default/wifi_legacy_hal.h
+++ b/wifi/1.4/default/wifi_legacy_hal.h
@@ -369,6 +369,11 @@
wifi_error setCountryCode(const std::string& iface_name,
std::array<int8_t, 2> code);
+ // interface functions.
+ wifi_error createVirtualInterface(const std::string& ifname,
+ wifi_interface_type iftype);
+ wifi_error deleteVirtualInterface(const std::string& ifname);
+
private:
// Retrieve interface handles for all the available interfaces.
wifi_error retrieveIfaceHandles();
@@ -380,6 +385,9 @@
std::pair<wifi_error, std::vector<wifi_cached_scan_results>>
getGscanCachedResults(const std::string& iface_name);
void invalidate();
+ // Handles wifi (error) status of Virtual interface create/delete
+ wifi_error handleVirtualInterfaceCreateOrDeleteStatus(
+ const std::string& ifname, wifi_error status);
// Global function table of legacy HAL.
wifi_hal_fn global_func_table_;
diff --git a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
index bbe470e..6945b4c 100644
--- a/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.4/default/wifi_legacy_hal_stubs.cpp
@@ -139,6 +139,8 @@
populateStubFor(&hal_fn->wifi_set_radio_mode_change_handler);
populateStubFor(&hal_fn->wifi_set_latency_mode);
populateStubFor(&hal_fn->wifi_set_thermal_mitigation_mode);
+ populateStubFor(&hal_fn->wifi_virtual_interface_create);
+ populateStubFor(&hal_fn->wifi_virtual_interface_delete);
return true;
}
} // namespace legacy_hal
diff --git a/wifi/hostapd/1.2/types.hal b/wifi/hostapd/1.2/types.hal
index 54e6529..9c187fa 100644
--- a/wifi/hostapd/1.2/types.hal
+++ b/wifi/hostapd/1.2/types.hal
@@ -38,6 +38,9 @@
WLAN_REASON_DISASSOC_AP_BUSY = 5,
};
+/**
+ * Mac Address type. 6 octets representing physical address of a device.
+ */
typedef uint8_t[6] MacAddress;
/**
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
index 8116c3f..f38dda4 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_iface_hidl_test.cpp
@@ -111,9 +111,14 @@
// If DPP is not supported, we just pass the test.
sta_iface_->getKeyMgmtCapabilities(
[&](const SupplicantStatus& status, uint32_t keyMgmtMaskInternal) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ // Since getKeyMgmtCapabilities() is overridden by an
+ // upgraded API in newer HAL versions, allow for
+ // FAILURE_UNKNOWN and return DPP is not supported.
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
- keyMgmtMask = keyMgmtMaskInternal;
+ keyMgmtMask = keyMgmtMaskInternal;
+ }
});
if (!(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::DPP)) {
@@ -268,8 +273,12 @@
* GetKeyMgmtCapabilities
*/
TEST_P(SupplicantStaIfaceHidlTest, GetKeyMgmtCapabilities) {
- sta_iface_->getKeyMgmtCapabilities(
- [&](const SupplicantStatus& status, uint32_t keyMgmtMask) {
+ sta_iface_->getKeyMgmtCapabilities([&](const SupplicantStatus& status,
+ uint32_t keyMgmtMask) {
+ // Since this API is overridden by an upgraded API in newer HAL
+ // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+ // longer supported on newer HAL.
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
// Even though capabilities vary, these two are always set in HAL
@@ -277,7 +286,8 @@
EXPECT_TRUE(keyMgmtMask & ISupplicantStaNetwork::KeyMgmtMask::NONE);
EXPECT_TRUE(keyMgmtMask &
ISupplicantStaNetwork::KeyMgmtMask::IEEE8021X);
- });
+ }
+ });
}
/*
@@ -455,4 +465,4 @@
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
android::hardware::wifi::supplicant::V1_2::ISupplicant::
descriptor))),
- android::hardware::PrintInstanceTupleNameToString<>);
\ No newline at end of file
+ android::hardware::PrintInstanceTupleNameToString<>);
diff --git a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
index 4c3d808..54ceb20 100644
--- a/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.2/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -112,13 +112,23 @@
uint32_t keyMgmt = (uint32_t)ISupplicantStaNetwork::KeyMgmtMask::SAE;
sta_network_->setKeyMgmt_1_2(keyMgmt, [](const SupplicantStatus &status) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ // Since this API is overridden by an upgraded API in newer HAL
+ // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+ // longer supported on newer HALs.
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ }
});
sta_network_->getKeyMgmt_1_2(
[&keyMgmt](const SupplicantStatus &status, uint32_t keyMgmtOut) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
- EXPECT_EQ(keyMgmtOut, keyMgmt);
+ // Since this API is overridden by an upgraded API in newer HAL
+ // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+ // longer supported on newer HALs.
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(keyMgmtOut, keyMgmt);
+ }
});
}
@@ -131,14 +141,24 @@
sta_network_->setGroupCipher_1_2(
groupCipher, [](const SupplicantStatus &status) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ // Since this API is overridden by an upgraded API in newer HAL
+ // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+ // longer supported on newer HALs.
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ }
});
sta_network_->getGroupCipher_1_2(
[&groupCipher](const SupplicantStatus &status,
uint32_t groupCipherOut) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
- EXPECT_EQ(groupCipherOut, groupCipher);
+ // Since this API is overridden by an upgraded API in newer HAL
+ // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+ // longer supported on newer HALs.
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(groupCipherOut, groupCipher);
+ }
});
}
@@ -151,14 +171,24 @@
sta_network_->setPairwiseCipher_1_2(
pairwiseCipher, [](const SupplicantStatus &status) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ // Since this API is overridden by an upgraded API in newer HAL
+ // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+ // longer supported on newer HALs.
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ }
});
sta_network_->getPairwiseCipher_1_2(
[&pairwiseCipher](const SupplicantStatus &status,
uint32_t pairwiseCipherOut) {
- EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
- EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+ // Since this API is overridden by an upgraded API in newer HAL
+ // versions, allow FAILURE_UNKNOWN to indicate that the test is no
+ // longer supported on newer HALs.
+ if (status.code != SupplicantStatusCode::FAILURE_UNKNOWN) {
+ EXPECT_EQ(SupplicantStatusCode::SUCCESS, status.code);
+ EXPECT_EQ(pairwiseCipherOut, pairwiseCipher);
+ }
});
}
diff --git a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
index 13f3366..93eabd6 100644
--- a/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.3/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -17,7 +17,6 @@
#include <android-base/logging.h>
#include <VtsCoreUtil.h>
-#include <VtsHalHidlTargetTestBase.h>
#include <android/hardware/wifi/1.0/IWifi.h>
#include <android/hardware/wifi/1.1/IWifi.h>
#include <android/hardware/wifi/supplicant/1.3/ISupplicant.h>