Merge "Remove creation time checks."
diff --git a/current.txt b/current.txt
index a0864da..69f4164 100644
--- a/current.txt
+++ b/current.txt
@@ -604,10 +604,10 @@
619fc9839ec6e369cfa9b28e3e9412e6885720ff8f9b5750c1b6ffb905120391 android.hardware.wifi.supplicant@1.3::ISupplicantStaIfaceCallback
c9273429fcf98d797d3bb07fdba6f1be95bf960f9255cde169fd1ca4db85f856 android.hardware.wifi.supplicant@1.3::ISupplicantStaNetwork
9b0a3ab6f4f74b971ed094426d8a443e29b512ff03e1ab50c07156396cdb2483 android.hardware.wifi.supplicant@1.3::types
-0e3c23f1c815469fdcdc39bc33a486817771c7c6b6e5303f2f25569499fc6c69 android.hardware.radio@1.5::types
-52abfa4c94104189fa4b2bc3132fc7c9852b7428283463b020d1a3671a4f374c android.hardware.radio@1.5::IRadio
+b91398c7475d9f6decb760f6e4721bab8bd588b6d36115d3048ebbfdf70ccf7b android.hardware.radio@1.5::types
+5ae0401fdaad9b85de7bebc5bdd7388a4ea661c46f1e4929341981b0540c67de android.hardware.radio@1.5::IRadio
3afac66f21a33bc9c4b80481c7d5540038348651d9a7d8af64ea13610af138da android.hardware.radio@1.5::IRadioIndication
-957ffbaf195aa046431ebe05a5906d215e80650e8e4933b394d6454b217ef3a9 android.hardware.radio@1.5::IRadioResponse
+f4888f9676890b43a459c6380f335fea7a6ad32ed3bafafeb018a88d6c0be8a4 android.hardware.radio@1.5::IRadioResponse
55f0a15642869ec98a55ea0a5ac049d3e1a6245ff7750deb6bcb7182057eee83 android.hardware.radio.config@1.3::types
b27ab0cd40b0b078cdcd024bfe1061c4c4c065f3519eeb9347fa359a3268a5ae android.hardware.radio.config@1.3::IRadioConfig
742360c775313438b0f82256eac62fb5bbc76a6ae6f388573f3aa142fb2c1eea android.hardware.radio.config@1.3::IRadioConfigIndication
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index d2dfebf..194c438 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -420,27 +420,33 @@
EXPECT_EQ(ErrorCode::OK, error);
if (avb_verification_enabled()) {
- property_get("ro.boot.vbmeta.digest", property_value, "nogood");
- EXPECT_NE(strcmp(property_value, "nogood"), 0);
+ EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
string prop_string(property_value);
EXPECT_EQ(prop_string.size(), 64);
EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
- property_get("ro.boot.vbmeta.device_state", property_value, "nogood");
- EXPECT_NE(strcmp(property_value, "nogood"), 0);
+ EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
if (!strcmp(property_value, "unlocked")) {
EXPECT_FALSE(device_locked);
} else {
EXPECT_TRUE(device_locked);
}
+
+ // Check that the expected result from VBMeta matches the build type. Only a user build
+ // should have AVB reporting the device is locked.
+ EXPECT_NE(property_get("ro.build.type", property_value, ""), 0);
+ if (!strcmp(property_value, "user")) {
+ EXPECT_TRUE(device_locked);
+ } else {
+ EXPECT_FALSE(device_locked);
+ }
}
// Verified boot key should be all 0's if the boot state is not verified or self signed
std::string empty_boot_key(32, '\0');
std::string verified_boot_key_str((const char*)verified_boot_key.data(),
verified_boot_key.size());
- property_get("ro.boot.verifiedbootstate", property_value, "nogood");
- EXPECT_NE(property_value, "nogood");
+ EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
if (!strcmp(property_value, "green")) {
EXPECT_EQ(verified_boot_state, KM_VERIFIED_BOOT_VERIFIED);
EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
@@ -543,7 +549,7 @@
EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
<< "Key size " << key_size << "missing";
- EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 3U));
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
CheckedDeleteKey(&key_blob);
}
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
index a3a3d90..09be37a 100644
--- a/radio/1.5/IRadio.hal
+++ b/radio/1.5/IRadio.hal
@@ -18,8 +18,10 @@
import @1.2::DataRequestReason;
import @1.4::IRadio;
+import @1.4::DataProfileInfo;
import @1.5::AccessNetwork;
import @1.5::DataProfileInfo;
+import @1.5::LinkAddress;
import @1.5::NetworkScanRequest;
import @1.5::RadioAccessSpecifier;
import @1.5::SignalThresholdInfo;
@@ -149,11 +151,7 @@
* @param reason The request reason. Must be DataRequestReason.NORMAL or
* DataRequestReason.HANDOVER.
* @param addresses If the reason is DataRequestReason.HANDOVER, this indicates the list of link
- * addresses of the existing data connection. The format is IP address with optional "/"
- * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
- * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
- * the prefix length is absent, then the addresses are assumed to be point to point with
- * IPv4 with prefix length 32 or IPv6 with prefix length 128. This parameter must be ignored
+ * addresses of the existing data connection. This parameter must be ignored
* unless reason is DataRequestReason.HANDOVER.
* @param dnses If the reason is DataRequestReason.HANDOVER, this indicates the list of DNS
* addresses of the existing data connection. The format is defined in RFC-4291 section
@@ -167,7 +165,7 @@
*/
oneway setupDataCall_1_5(int32_t serial, AccessNetwork accessNetwork,
DataProfileInfo dataProfileInfo, bool roamingAllowed,
- DataRequestReason reason, vec<string> addresses, vec<string> dnses);
+ DataRequestReason reason, vec<LinkAddress> addresses, vec<string> dnses);
/**
* Set an apn to initial attach network
@@ -191,7 +189,34 @@
* Response callback is IRadioResponse.setDataProfileResponse_1_5()
*
* Note this API is the same as the 1.4 version except using the 1.5 DataProfileInfo
- * as the input param.
+ * and LinkAddress as the input param.
*/
oneway setDataProfile_1_5(int32_t serial, vec<DataProfileInfo> profiles);
+
+ /**
+ * Toggle radio on and off (for "airplane" mode)
+ * If the radio is turned off/on the radio modem subsystem
+ * is expected return to an initialized state. For instance,
+ * any voice and data calls must be terminated and all associated
+ * lists emptied.
+ *
+ * When setting radio power on to exit from airplane mode to place an emergency call on this
+ * logical modem, powerOn, forEmergencyCall and preferredForEmergencyCall must be true. In
+ * this case, this modem is optimized to scan only emergency call bands, until:
+ * 1) Emergency call is completed; or
+ * 2) Another setRadioPower_1_5 is issued with forEmergencyCall being false or
+ * preferredForEmergencyCall being false; or
+ * 3) Timeout after a long period of time.
+ *
+ * @param serial Serial number of request.
+ * @param powerOn To turn on radio -> on = true, to turn off radio -> on = false.
+ * @param forEmergencyCall To indication to radio if this request is due to emergency call.
+ * No effect if powerOn is false.
+ * @param preferredForEmergencyCall indicate whether the following emergency call will be sent
+ * on this modem or not. No effect if forEmergencyCall is false, or powerOn is false.
+ *
+ * Response callback is IRadioConfigResponse. setRadioPowerResponse_1_5.
+ */
+ oneway setRadioPower_1_5(int32_t serial, bool powerOn, bool forEmergencyCall,
+ bool preferredForEmergencyCall);
};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
index 11ec265..968948b 100644
--- a/radio/1.5/IRadioResponse.hal
+++ b/radio/1.5/IRadioResponse.hal
@@ -18,7 +18,7 @@
import @1.0::RadioResponseInfo;
import @1.4::IRadioResponse;
-import @1.4::SetupDataCallResult;
+import @1.5::SetupDataCallResult;
/**
* Interface declaring response functions to solicited radio requests.
@@ -135,4 +135,14 @@
* RadioError:SIM_ABSENT
*/
oneway setDataProfileResponse_1_5(RadioResponseInfo info);
+
+ /**
+ * @param info Response info struct containing response type, serial no. and error
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:INTERNAL_ERR
+ * RadioError:INVALID_ARGUMENTS
+ */
+ oneway setRadioPowerResponse_1_5(RadioResponseInfo info);
};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
index 5795f7b..3c6e67a 100644
--- a/radio/1.5/types.hal
+++ b/radio/1.5/types.hal
@@ -25,7 +25,10 @@
import @1.2::NetworkScanRequest;
import @1.4::AccessNetwork;
import @1.4::ApnTypes;
+import @1.4::DataCallFailCause;
+import @1.4::DataConnActiveStatus;
import @1.4::DataProfileInfo;
+import @1.4::PdpProtocolType;
/**
* Defining signal strength type.
@@ -54,9 +57,9 @@
RSRP = 3,
/**
* Reference Signal Received Quality
- * Range: -20 dB to -3 dB;
+ * Range: -34 dB to 3 dB;
* Used RAN: EUTRAN
- * Reference: 3GPP TS 36.133 9.1.7
+ * Reference: 3GPP TS 36.133 v12.6.0 section 9.1.7
*/
RSRQ = 4,
/**
@@ -289,3 +292,105 @@
/** Supported APN types bitmap. See ApnTypes for the value of each bit. */
bitfield<ApnTypes> supportedApnTypesBitmap;
};
+
+/**
+ * The properties of the link address. This enum reflects the definition in
+ * if_addr.h in Linux kernel.
+ */
+enum AddressProperty : int32_t {
+ NONE = 0,
+
+ /** Indicates this address is deprecated */
+ DEPRECATED = 0x20,
+};
+
+struct LinkAddress {
+ /**
+ * The format is IP address with optional "/"
+ * prefix length (The format is defined in RFC-4291 section 2.3). For example, "192.0.1.3",
+ * "192.0.1.11/16", or "2001:db8::1/64". Typically one IPv4 or one IPv6 or one of each. If
+ * the prefix length is absent, then the addresses are assumed to be point to point with
+ * IPv4 with prefix length 32 or IPv6 with prefix length 128.
+ */
+ string address;
+
+ /**
+ * The properties of the link address
+ */
+ bitfield<AddressProperty> properties;
+
+ /**
+ * The UTC time that this link address will be deprecated. 0 indicates this information is not
+ * available.
+ */
+ uint64_t deprecatedTime;
+
+ /**
+ * The UTC time that this link address will expire and no longer valid. 0 indicates this
+ * information is not available.
+ */
+ uint64_t expiredTime;
+};
+
+/**
+ * Overwritten from @1.4::SetupDataCallResult in order to update the addresses to 1.5
+ * version.
+ */
+struct SetupDataCallResult {
+ /** Data call fail cause. DataCallFailCause.NONE if no error. */
+ DataCallFailCause cause;
+
+ /**
+ * If status != DataCallFailCause.NONE, this field indicates the suggested retry back-off timer
+ * value RIL wants to override the one pre-configured in FW. The unit is milliseconds.
+ * The value < 0 means no value is suggested.
+ * The value 0 means retry must be done ASAP.
+ * The value of INT_MAX(0x7fffffff) means no retry.
+ */
+ int32_t suggestedRetryTime;
+
+ /** Context ID, uniquely identifies this call. */
+ int32_t cid;
+
+ /** Data connection active status. */
+ DataConnActiveStatus active;
+
+ /**
+ * PDP_type values. If cause is DataCallFailCause.ONLY_SINGLE_BEARER_ALLOWED, this is the type
+ * supported such as "IP" or "IPV6".
+ */
+ PdpProtocolType type;
+
+ /** The network interface name. */
+ string ifname;
+
+ /**
+ * List of link address.
+ */
+ vec<LinkAddress> addresses;
+
+ /**
+ * List of DNS server addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1". Empty if no dns
+ * server addresses returned.
+ */
+ vec<string> dnses;
+
+ /**
+ * List of default gateway addresses, e.g., "192.0.1.3" or "192.0.1.11 2001:db8::1".
+ * When empty, the addresses represent point to point connections.
+ */
+ vec<string> gateways;
+
+ /**
+ * List of P-CSCF(Proxy Call State Control Function) addresses via PCO(Protocol Configuration
+ * Option), e.g., "2001:db8::1 2001:db8::2 2001:db8::3". Empty if not IMS client.
+ */
+ vec<string> pcscf;
+
+ /**
+ * MTU received from network. Value <= 0 means network has either not sent a value or sent an
+ * invalid value.
+ */
+ int32_t mtu;
+};
+
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 1243bed..77d9a02 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -853,10 +853,11 @@
bool roamingAllowed = false;
+ std::vector<::android::hardware::radio::V1_5::LinkAddress> addresses = {};
+ std::vector<hidl_string> dnses = {};
+
::android::hardware::radio::V1_2::DataRequestReason reason =
::android::hardware::radio::V1_2::DataRequestReason::NORMAL;
- std::vector<hidl_string> addresses = {""};
- std::vector<hidl_string> dnses = {""};
Return<void> res = radio_v1_5->setupDataCall_1_5(serial, accessNetwork, dataProfileInfo,
roamingAllowed, reason, addresses, dnses);
@@ -958,3 +959,31 @@
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE}));
}
}
+
+TEST_F(RadioHidlTest_v1_5, setRadioPower_1_5_emergencyCall_cancalled) {
+ // Set radio power to off.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, false, false, false);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+ // Set radio power to on with forEmergencyCall being true. This should put modem to only scan
+ // emergency call bands.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, true, true, true);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+ // Set radio power to on with forEmergencyCall being false. This should put modem in regular
+ // operation modem.
+ serial = GetRandomSerialNumber();
+ radio_v1_5->setRadioPower_1_5(serial, true, false, false);
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+ EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+}
\ No newline at end of file
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 f7526d9..ba11257 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
@@ -544,11 +544,13 @@
Return<void> setupDataCallResponse_1_5(
const RadioResponseInfo& info,
- const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse);
+ const android::hardware::radio::V1_5::SetupDataCallResult& dcResponse);
Return<void> setInitialAttachApnResponse_1_5(const RadioResponseInfo& info);
Return<void> setDataProfileResponse_1_5(const RadioResponseInfo& info);
+
+ Return<void> setRadioPowerResponse_1_5(const RadioResponseInfo& info);
};
/* 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 5dee191..a0b3d5f 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -931,7 +931,7 @@
Return<void> RadioResponse_v1_5::setupDataCallResponse_1_5(
const RadioResponseInfo& info,
- const android::hardware::radio::V1_4::SetupDataCallResult& /* dcResponse */) {
+ const android::hardware::radio::V1_5::SetupDataCallResult& /* dcResponse */) {
rspInfo = info;
parent_v1_5.notify(info.serial);
return Void();
@@ -948,3 +948,9 @@
parent_v1_5.notify(info.serial);
return Void();
}
+
+Return<void> RadioResponse_v1_5::setRadioPowerResponse_1_5(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_v1_5.notify(info.serial);
+ return Void();
+}
\ No newline at end of file
diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal
index 3ed09f6..94e3c0c 100644
--- a/tv/tuner/1.0/IFilter.hal
+++ b/tv/tuner/1.0/IFilter.hal
@@ -104,11 +104,11 @@
*
* It is used by the client to ask the hardware resource id for the filter.
*
- * @param filterId the hardware resource Id for the filter.
* @return result Result status of the operation.
* SUCCESS if successful,
* INVALID_STATE if failed for wrong state.
* UNKNOWN_ERROR if failed for other reasons.
+ * @return filterId the hardware resource Id for the filter.
*/
getId() generates (Result result, uint32_t filterId);
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 71a26ab..43c4e3a 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -51,7 +51,8 @@
mFrontendSourceFile = mFrontend->getSourceFile();
mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
- return startBroadcastInputLoop();
+
+ return startFrontendInputLoop();
}
Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
@@ -136,14 +137,14 @@
return Void();
}
- sp<Dvr> dvr = new Dvr(type, bufferSize, cb, this);
+ mDvr = new Dvr(type, bufferSize, cb, this);
- if (!dvr->createDvrMQ()) {
- _hidl_cb(Result::UNKNOWN_ERROR, dvr);
+ if (!mDvr->createDvrMQ()) {
+ _hidl_cb(Result::UNKNOWN_ERROR, mDvr);
return Void();
}
- _hidl_cb(Result::SUCCESS, dvr);
+ _hidl_cb(Result::SUCCESS, mDvr);
return Void();
}
@@ -166,13 +167,14 @@
// resetFilterRecords(filterId);
mUsedFilterIds.erase(filterId);
+ mRecordFilterIds.erase(filterId);
mUnusedFilterIds.insert(filterId);
mFilters.erase(filterId);
return Result::SUCCESS;
}
-void Demux::startTsFilter(vector<uint8_t> data) {
+void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
set<uint32_t>::iterator it;
for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
@@ -185,7 +187,17 @@
}
}
-bool Demux::startFilterDispatcher() {
+void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
+ set<uint32_t>::iterator it;
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ if (DEBUG_FILTER) {
+ ALOGW("update record filter output");
+ }
+ mFilters[*it]->updateRecordOutput(data);
+ }
+}
+
+bool Demux::startBroadcastFilterDispatcher() {
set<uint32_t>::iterator it;
// Handle the output data per filter type
@@ -198,6 +210,18 @@
return true;
}
+bool Demux::startRecordFilterDispatcher() {
+ set<uint32_t>::iterator it;
+
+ for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
+ if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
Result Demux::startFilterHandler(uint32_t filterId) {
return mFilters[filterId]->startFilterHandler();
}
@@ -210,22 +234,22 @@
return mFilters[filterId]->getTpid();
}
-Result Demux::startBroadcastInputLoop() {
- pthread_create(&mBroadcastInputThread, NULL, __threadLoopBroadcast, this);
- pthread_setname_np(mBroadcastInputThread, "broadcast_input_thread");
+Result Demux::startFrontendInputLoop() {
+ pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
+ pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
return Result::SUCCESS;
}
-void* Demux::__threadLoopBroadcast(void* user) {
+void* Demux::__threadLoopFrontend(void* user) {
Demux* const self = static_cast<Demux*>(user);
- self->broadcastInputThreadLoop();
+ self->frontendInputThreadLoop();
return 0;
}
-void Demux::broadcastInputThreadLoop() {
- std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
- mBroadcastInputThreadRunning = true;
+void Demux::frontendInputThreadLoop() {
+ std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+ mFrontendInputThreadRunning = true;
mKeepFetchingDataFromFrontend = true;
// open the stream and get its length
@@ -234,20 +258,20 @@
int packetSize = 188;
int writePacketAmount = 6;
char* buffer = new char[packetSize];
- ALOGW("[Demux] broadcast input thread loop start %s", mFrontendSourceFile.c_str());
+ ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str());
if (!inputData.is_open()) {
- mBroadcastInputThreadRunning = false;
+ mFrontendInputThreadRunning = false;
ALOGW("[Demux] Error %s", strerror(errno));
}
- while (mBroadcastInputThreadRunning) {
+ while (mFrontendInputThreadRunning) {
// move the stream pointer for packet size * 6 every read until the end
while (mKeepFetchingDataFromFrontend) {
for (int i = 0; i < writePacketAmount; i++) {
inputData.read(buffer, packetSize);
if (!inputData) {
mKeepFetchingDataFromFrontend = false;
- mBroadcastInputThreadRunning = false;
+ mFrontendInputThreadRunning = false;
break;
}
// filter and dispatch filter output
@@ -256,23 +280,61 @@
for (int index = 0; index < byteBuffer.size(); index++) {
byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
}
- startTsFilter(byteBuffer);
+ if (mIsRecording) {
+ // Feed the data into the Dvr recording input
+ sendFrontendInputToRecord(byteBuffer);
+ } else {
+ // Feed the data into the broadcast demux filter
+ startBroadcastTsFilter(byteBuffer);
+ }
}
- startFilterDispatcher();
+ if (mIsRecording) {
+ // Dispatch the data into the broadcasting filters.
+ startRecordFilterDispatcher();
+ } else {
+ // Dispatch the data into the broadcasting filters.
+ startBroadcastFilterDispatcher();
+ }
usleep(100);
}
}
- ALOGW("[Demux] Broadcast Input thread end.");
+ ALOGW("[Demux] Frontend Input thread end.");
delete[] buffer;
inputData.close();
}
-void Demux::stopBroadcastInput() {
+void Demux::stopFrontendInput() {
ALOGD("[Demux] stop frontend on demux");
mKeepFetchingDataFromFrontend = false;
- mBroadcastInputThreadRunning = false;
- std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
+ mFrontendInputThreadRunning = false;
+ std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
+}
+
+void Demux::setIsRecording(bool isRecording) {
+ mIsRecording = isRecording;
+}
+
+bool Demux::attachRecordFilter(int filterId) {
+ if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+ return false;
+ }
+
+ mRecordFilterIds.insert(filterId);
+ mFilters[filterId]->attachFilterToRecord(mDvr);
+
+ return true;
+}
+
+bool Demux::detachRecordFilter(int filterId) {
+ if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+ return false;
+ }
+
+ mRecordFilterIds.erase(filterId);
+ mFilters[filterId]->detachFilterFromRecord();
+
+ return true;
}
} // namespace implementation
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 037429d..1405d0c 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -81,11 +81,14 @@
virtual Return<Result> disconnectCiCam() override;
// Functions interacts with Tuner Service
- void stopBroadcastInput();
+ void stopFrontendInput();
Result removeFilter(uint32_t filterId);
+ bool attachRecordFilter(int filterId);
+ bool detachRecordFilter(int filterId);
Result startFilterHandler(uint32_t filterId);
void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
uint16_t getFilterTpid(uint32_t filterId);
+ void setIsRecording(bool isRecording);
private:
// Tuner service
@@ -101,9 +104,9 @@
uint32_t filterId;
};
- Result startBroadcastInputLoop();
- static void* __threadLoopBroadcast(void* user);
- void broadcastInputThreadLoop();
+ Result startFrontendInputLoop();
+ static void* __threadLoopFrontend(void* user);
+ void frontendInputThreadLoop();
/**
* To create a FilterMQ with the the next available Filter ID.
@@ -117,9 +120,13 @@
/**
* A dispatcher to read and dispatch input data to all the started filters.
* Each filter handler handles the data filtering/output writing/filterEvent updating.
+ * Note that recording filters are not included.
*/
- bool startFilterDispatcher();
- void startTsFilter(vector<uint8_t> data);
+ bool startBroadcastFilterDispatcher();
+ void startBroadcastTsFilter(vector<uint8_t> data);
+
+ void sendFrontendInputToRecord(vector<uint8_t> data);
+ bool startRecordFilterDispatcher();
uint32_t mDemuxId;
uint32_t mCiCamId;
@@ -141,26 +148,40 @@
*/
set<uint32_t> mUnusedFilterIds;
/**
+ * Record all the attached record filter Ids.
+ * Any removed filter id should be removed from this set.
+ */
+ set<uint32_t> mRecordFilterIds;
+ /**
* A list of created FilterMQ ptrs.
* The array number is the filter ID.
*/
std::map<uint32_t, sp<Filter>> mFilters;
+ /**
+ * Local reference to the opened DVR object.
+ */
+ sp<Dvr> mDvr;
+
// Thread handlers
- pthread_t mBroadcastInputThread;
+ pthread_t mFrontendInputThread;
/**
* If a specific filter's writing loop is still running
*/
- bool mBroadcastInputThreadRunning;
+ bool mFrontendInputThreadRunning;
bool mKeepFetchingDataFromFrontend;
/**
+ * If the dvr recording is running.
+ */
+ bool mIsRecording = false;
+ /**
* Lock to protect writes to the FMQs
*/
std::mutex mWriteLock;
/**
* Lock to protect writes to the input status
*/
- std::mutex mBroadcastInputThreadLock;
+ std::mutex mFrontendInputThreadLock;
// temp handle single PES filter
// TODO handle mulptiple Pes filters
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index eb38f90..3088a9d 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -70,7 +70,14 @@
return status;
}
+ // check if the attached filter is a record filter
+
mFilters[filterId] = filter;
+ mIsRecordFilterAttached = true;
+ if (!mDemux->attachRecordFilter(filterId)) {
+ return Result::INVALID_ARGUMENT;
+ }
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
return Result::SUCCESS;
}
@@ -95,6 +102,15 @@
it = mFilters.find(filterId);
if (it != mFilters.end()) {
mFilters.erase(filterId);
+ if (!mDemux->detachRecordFilter(filterId)) {
+ return Result::INVALID_ARGUMENT;
+ }
+ }
+
+ // If all the filters are detached, record can't be started
+ if (mFilters.empty()) {
+ mIsRecordFilterAttached = false;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
}
return Result::SUCCESS;
@@ -115,8 +131,9 @@
pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
pthread_setname_np(mDvrThread, "playback_waiting_loop");
} else if (mType == DvrType::RECORD) {
- /*pthread_create(&mInputThread, NULL, __threadLoopInput, this);
- pthread_setname_np(mInputThread, "playback_waiting_loop");*/
+ mRecordStatus = RecordStatus::DATA_READY;
+ mIsRecordStarted = true;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
}
// TODO start another thread to send filter status callback to the framework
@@ -131,12 +148,17 @@
std::lock_guard<std::mutex> lock(mDvrThreadLock);
+ mIsRecordStarted = false;
+ mDemux->setIsRecording(mIsRecordStarted | mIsRecordFilterAttached);
+
return Result::SUCCESS;
}
Return<Result> Dvr::flush() {
ALOGV("%s", __FUNCTION__);
+ mRecordStatus = RecordStatus::DATA_READY;
+
return Result::SUCCESS;
}
@@ -272,6 +294,45 @@
return true;
}
+bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
+ std::lock_guard<std::mutex> lock(mWriteLock);
+ ALOGW("[Dvr] write record FMQ");
+ if (mDvrMQ->write(data.data(), data.size())) {
+ mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+ maySendRecordStatusCallback();
+ return true;
+ }
+
+ maySendRecordStatusCallback();
+ return false;
+}
+
+void Dvr::maySendRecordStatusCallback() {
+ std::lock_guard<std::mutex> lock(mRecordStatusLock);
+ int availableToRead = mDvrMQ->availableToRead();
+ int availableToWrite = mDvrMQ->availableToWrite();
+
+ RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
+ mDvrSettings.record().highThreshold,
+ mDvrSettings.record().lowThreshold);
+ if (mRecordStatus != newStatus) {
+ mCallback->onRecordStatus(newStatus);
+ mRecordStatus = newStatus;
+ }
+}
+
+RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold) {
+ if (availableToWrite == 0) {
+ return DemuxFilterStatus::OVERFLOW;
+ } else if (availableToRead > highThreshold) {
+ return DemuxFilterStatus::HIGH_WATER;
+ } else if (availableToRead < lowThreshold) {
+ return DemuxFilterStatus::LOW_WATER;
+ }
+ return mRecordStatus;
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
index fbb778c..f39d8db 100644
--- a/tv/tuner/1.0/default/Dvr.h
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -79,6 +79,8 @@
* Return false is any of the above processes fails.
*/
bool createDvrMQ();
+ void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer);
+ bool writeRecordFMQ(const std::vector<uint8_t>& data);
private:
// Demux service
@@ -95,6 +97,8 @@
void maySendRecordStatusCallback();
PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
uint32_t highThreshold, uint32_t lowThreshold);
+ RecordStatus checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+ uint32_t highThreshold, uint32_t lowThreshold);
/**
* A dispatcher to read and dispatch input data to all the started filters.
* Each filter handler handles the data filtering/output writing/filterEvent updating.
@@ -103,9 +107,9 @@
void startTpidFilter(vector<uint8_t> data);
bool startFilterDispatcher();
static void* __threadLoopPlayback(void* user);
- static void* __threadLoopBroadcast(void* user);
+ static void* __threadLoopRecord(void* user);
void playbackThreadLoop();
- void broadcastInputThreadLoop();
+ void recordThreadLoop();
unique_ptr<DvrMQ> mDvrMQ;
EventFlag* mDvrEventFlag;
@@ -121,6 +125,7 @@
// FMQ status local records
PlaybackStatus mPlaybackStatus;
+ RecordStatus mRecordStatus;
/**
* If a specific filter's writing loop is still running
*/
@@ -135,10 +140,16 @@
* Lock to protect writes to the input status
*/
std::mutex mPlaybackStatusLock;
+ std::mutex mRecordStatusLock;
std::mutex mBroadcastInputThreadLock;
std::mutex mDvrThreadLock;
const bool DEBUG_DVR = false;
+
+ // Booleans to check if recording is running.
+ // Recording is ready when both of the following are set to true.
+ bool mIsRecordStarted = false;
+ bool mIsRecordFilterAttached = false;
};
} // namespace implementation
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index befd1e6..b3160fc 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -265,10 +265,16 @@
void Filter::updateFilterOutput(vector<uint8_t> data) {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
- ALOGD("[Filter] handler output updated");
+ ALOGD("[Filter] filter output updated");
mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
}
+void Filter::updateRecordOutput(vector<uint8_t> data) {
+ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+ ALOGD("[Filter] record filter output updated");
+ mRecordFilterOutput.insert(mRecordFilterOutput.end(), data.begin(), data.end());
+}
+
Result Filter::startFilterHandler() {
std::lock_guard<std::mutex> lock(mFilterOutputLock);
switch (mType.mainType) {
@@ -292,12 +298,11 @@
case DemuxTsFilterType::PCR:
startPcrFilterHandler();
break;
- case DemuxTsFilterType::RECORD:
- startRecordFilterHandler();
- break;
case DemuxTsFilterType::TEMI:
startTemiFilterHandler();
break;
+ default:
+ break;
}
break;
case DemuxFilterMainType::MMTP:
@@ -342,12 +347,16 @@
if (mPesSizeLeft == 0) {
uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
mFilterOutput[i + 6];
- ALOGD("[Filter] prefix %d", prefix);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] prefix %d", prefix);
+ }
if (prefix == 0x000001) {
// TODO handle mulptiple Pes filters
mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
mPesSizeLeft += 6;
- ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+ }
} else {
continue;
}
@@ -360,7 +369,9 @@
mPesOutput.insert(mPesOutput.end(), first, last);
// size does not match then continue
mPesSizeLeft -= endPoint;
- ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+ }
if (mPesSizeLeft > 0) {
continue;
}
@@ -377,7 +388,9 @@
.streamId = mPesOutput[3],
.dataLength = static_cast<uint16_t>(mPesOutput.size()),
};
- ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+ }
int size = mFilterEvent.events.size();
mFilterEvent.events.resize(size + 1);
@@ -413,13 +426,23 @@
}
Result Filter::startRecordFilterHandler() {
- DemuxFilterTsRecordEvent tsRecordEvent;
+ /*DemuxFilterTsRecordEvent tsRecordEvent;
tsRecordEvent.pid.tPid(0);
tsRecordEvent.indexMask.tsIndexMask(0x01);
mFilterEvent.events.resize(1);
mFilterEvent.events[0].tsRecord(tsRecordEvent);
+*/
+ std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
+ if (mRecordFilterOutput.empty()) {
+ return Result::SUCCESS;
+ }
- mFilterOutput.clear();
+ if (mDvr == nullptr || !mDvr->writeRecordFMQ(mRecordFilterOutput)) {
+ ALOGD("[Filter] dvr fails to write into record FMQ.");
+ return Result::UNKNOWN_ERROR;
+ }
+
+ mRecordFilterOutput.clear();
return Result::SUCCESS;
}
@@ -462,6 +485,14 @@
return false;
}
+void Filter::attachFilterToRecord(const sp<Dvr> dvr) {
+ mDvr = dvr;
+}
+
+void Filter::detachFilterFromRecord() {
+ mDvr = nullptr;
+}
+
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index fbd965a..d397f73 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -22,6 +22,7 @@
#include <math.h>
#include <set>
#include "Demux.h"
+#include "Dvr.h"
#include "Frontend.h"
using namespace std;
@@ -44,6 +45,7 @@
using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
class Demux;
+class Dvr;
class Filter : public IFilter {
public:
@@ -80,11 +82,17 @@
bool createFilterMQ();
uint16_t getTpid();
void updateFilterOutput(vector<uint8_t> data);
+ void updateRecordOutput(vector<uint8_t> data);
Result startFilterHandler();
+ Result startRecordFilterHandler();
+ void attachFilterToRecord(const sp<Dvr> dvr);
+ void detachFilterFromRecord();
private:
// Tuner service
sp<Demux> mDemux;
+ // Dvr reference once the filter is attached to any
+ sp<Dvr> mDvr = nullptr;
/**
* Filter callbacks used on filter events or FMQ status
*/
@@ -99,6 +107,7 @@
sp<IFilter> mDataSource;
bool mIsDataSourceDemux = true;
vector<uint8_t> mFilterOutput;
+ vector<uint8_t> mRecordFilterOutput;
unique_ptr<FilterMQ> mFilterMQ;
EventFlag* mFilterEventFlag;
DemuxFilterEvent mFilterEvent;
@@ -120,6 +129,8 @@
*/
const uint16_t SECTION_WRITE_COUNT = 10;
+ bool DEBUG_FILTER = false;
+
/**
* Filter handlers to handle the data filtering.
* They are also responsible to write the filtered output into the filter FMQ
@@ -129,7 +140,6 @@
Result startPesFilterHandler();
Result startTsFilterHandler();
Result startMediaFilterHandler();
- Result startRecordFilterHandler();
Result startPcrFilterHandler();
Result startTemiFilterHandler();
Result startFilterLoop();
@@ -165,6 +175,7 @@
std::mutex mFilterStatusLock;
std::mutex mFilterThreadLock;
std::mutex mFilterOutputLock;
+ std::mutex mRecordFilterOutputLock;
// temp handle single PES filter
// TODO handle mulptiple Pes filters
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index f86b28d..c143d61 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -148,7 +148,7 @@
uint32_t demuxId;
if (it != mFrontendToDemux.end()) {
demuxId = it->second;
- mDemuxes[demuxId]->stopBroadcastInput();
+ mDemuxes[demuxId]->stopFrontendInput();
}
}
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index ef33952..944da5a 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -2230,8 +2230,6 @@
DemuxFilterSectionSettings section;
- DemuxFilterPesDataSettings pesData;
-
/**
* true if the data from IP subtype go to next filter directly
*/
@@ -2248,7 +2246,7 @@
/**
* true if the filtered data is commpressed ip packet
*/
- bool bIsCompressedIpPacket;
+ bool isCompressedIpPacket;
safe_union FilterSettings {
/**
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index da3e300..7977f25 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -65,6 +65,7 @@
using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
@@ -95,6 +96,7 @@
using android::hardware::tv::tuner::V1_0::ITuner;
using android::hardware::tv::tuner::V1_0::PlaybackSettings;
using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordSettings;
using android::hardware::tv::tuner::V1_0::RecordStatus;
using android::hardware::tv::tuner::V1_0::Result;
@@ -379,7 +381,20 @@
class DvrCallback : public IDvrCallback {
public:
- virtual Return<void> onRecordStatus(RecordStatus /*status*/) override { return Void(); }
+ virtual Return<void> onRecordStatus(DemuxFilterStatus status) override {
+ ALOGW("[vts] record status %hhu", status);
+ switch (status) {
+ case DemuxFilterStatus::DATA_READY:
+ break;
+ case DemuxFilterStatus::LOW_WATER:
+ break;
+ case DemuxFilterStatus::HIGH_WATER:
+ case DemuxFilterStatus::OVERFLOW:
+ ALOGW("[vts] record overflow. Flushing");
+ break;
+ }
+ return Void();
+ }
virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
// android::Mutex::Autolock autoLock(mMsgLock);
@@ -401,10 +416,17 @@
void testFilterDataOutput();
void stopPlaybackThread();
+ void testRecordOutput();
+ void stopRecordThread();
void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
+ void startRecordOutputThread(RecordSettings recordSetting, MQDesc& recordMQDescriptor);
static void* __threadLoopPlayback(void* threadArgs);
+ static void* __threadLoopRecord(void* threadArgs);
void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
+ void recordThreadLoop(RecordSettings* recordSetting, bool* keepWritingPlaybackFMQ);
+
+ bool readRecordFMQ();
private:
struct PlaybackThreadArgs {
@@ -412,22 +434,31 @@
PlaybackConf* playbackConf;
bool* keepWritingPlaybackFMQ;
};
+ struct RecordThreadArgs {
+ DvrCallback* user;
+ RecordSettings* recordSetting;
+ bool* keepReadingRecordFMQ;
+ };
uint16_t mDataLength = 0;
std::vector<uint8_t> mDataOutputBuffer;
std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
std::unique_ptr<FilterMQ> mPlaybackMQ;
+ std::unique_ptr<FilterMQ> mRecordMQ;
std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
- EventFlag* mPlaybackMQEventFlag;
android::Mutex mMsgLock;
android::Mutex mPlaybackThreadLock;
+ android::Mutex mRecordThreadLock;
android::Condition mMsgCondition;
bool mKeepWritingPlaybackFMQ = true;
+ bool mKeepReadingRecordFMQ = true;
bool mPlaybackThreadRunning;
+ bool mRecordThreadRunning;
pthread_t mPlaybackThread;
+ pthread_t mRecordThread;
int mPidFilterOutputCount = 0;
};
@@ -516,6 +547,92 @@
inputData.close();
}
+void DvrCallback::testRecordOutput() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (mDataOutputBuffer.empty()) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
+ return;
+ }
+ }
+ stopRecordThread();
+ ALOGW("[vts] record pass and stop");
+}
+
+void DvrCallback::startRecordOutputThread(RecordSettings recordSetting,
+ MQDesc& recordMQDescriptor) {
+ mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
+ EXPECT_TRUE(mRecordMQ);
+ struct RecordThreadArgs* threadArgs =
+ (struct RecordThreadArgs*)malloc(sizeof(struct RecordThreadArgs));
+ threadArgs->user = this;
+ threadArgs->recordSetting = &recordSetting;
+ threadArgs->keepReadingRecordFMQ = &mKeepReadingRecordFMQ;
+
+ pthread_create(&mRecordThread, NULL, __threadLoopRecord, (void*)threadArgs);
+ pthread_setname_np(mRecordThread, "test_record_input_loop");
+}
+
+void* DvrCallback::__threadLoopRecord(void* threadArgs) {
+ DvrCallback* const self =
+ static_cast<DvrCallback*>(((struct RecordThreadArgs*)threadArgs)->user);
+ self->recordThreadLoop(((struct RecordThreadArgs*)threadArgs)->recordSetting,
+ ((struct RecordThreadArgs*)threadArgs)->keepReadingRecordFMQ);
+ return 0;
+}
+
+void DvrCallback::recordThreadLoop(RecordSettings* /*recordSetting*/, bool* keepReadingRecordFMQ) {
+ ALOGD("[vts] DvrCallback record threadLoop start.");
+ android::Mutex::Autolock autoLock(mRecordThreadLock);
+ mRecordThreadRunning = true;
+
+ // Create the EventFlag that is used to signal the HAL impl that data have been
+ // read from the Record FMQ
+ EventFlag* recordMQEventFlag;
+ EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
+ android::OK);
+
+ while (mRecordThreadRunning) {
+ while (*keepReadingRecordFMQ) {
+ uint32_t efState = 0;
+ android::status_t status = recordMQEventFlag->wait(
+ static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+ true /* retry on spurious wake */);
+ if (status != android::OK) {
+ ALOGD("[vts] wait for data ready on the record FMQ");
+ continue;
+ }
+ // Our current implementation filter the data and write it into the filter FMQ
+ // immediately after the DATA_READY from the VTS/framework
+ if (!readRecordFMQ()) {
+ ALOGD("[vts] record data failed to be filtered. Ending thread");
+ mRecordThreadRunning = false;
+ break;
+ }
+ }
+ }
+
+ mRecordThreadRunning = false;
+ ALOGD("[vts] record thread ended.");
+}
+
+bool DvrCallback::readRecordFMQ() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ bool result = false;
+ mDataOutputBuffer.clear();
+ mDataOutputBuffer.resize(mRecordMQ->availableToRead());
+ result = mRecordMQ->read(mDataOutputBuffer.data(), mRecordMQ->availableToRead());
+ EXPECT_TRUE(result) << "can't read from Record MQ";
+ mMsgCondition.signal();
+ return result;
+}
+
+void DvrCallback::stopRecordThread() {
+ mKeepReadingRecordFMQ = false;
+ mRecordThreadRunning = false;
+ android::Mutex::Autolock autoLock(mRecordThreadLock);
+}
+
// Test environment for Tuner HIDL HAL.
class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
public:
@@ -555,6 +672,7 @@
sp<DvrCallback> mDvrCallback;
MQDesc mFilterMQDescriptor;
MQDesc mPlaybackMQDescriptor;
+ MQDesc mRecordMQDescriptor;
vector<uint32_t> mUsedFilterIds;
uint32_t mDemuxId;
@@ -572,6 +690,8 @@
FrontendSettings settings);
::testing::AssertionResult getPlaybackMQDescriptor();
::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting);
+ ::testing::AssertionResult getRecordMQDescriptor();
+ ::testing::AssertionResult addRecordToDemux(RecordSettings setting);
::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
::testing::AssertionResult getFilterMQDescriptor();
::testing::AssertionResult closeDemux();
@@ -581,6 +701,9 @@
::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
PlaybackConf playbackConf,
vector<string> goldenOutputFiles);
+ ::testing::AssertionResult recordDataFlowTest(vector<FilterConf> filterConf,
+ RecordSettings recordSetting,
+ vector<string> goldenOutputFiles);
::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
vector<string> goldenOutputFiles);
};
@@ -766,6 +889,49 @@
return ::testing::AssertionResult(status == Result::SUCCESS);
}
+::testing::AssertionResult TunerHidlTest::addRecordToDemux(RecordSettings setting) {
+ Result status;
+
+ if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+
+ // Create dvr callback
+ mDvrCallback = new DvrCallback();
+
+ // Add playback input to the local demux
+ mDemux->openDvr(DvrType::RECORD, FMQ_SIZE_1M, mDvrCallback,
+ [&](Result result, const sp<IDvr>& dvr) {
+ mDvr = dvr;
+ status = result;
+ });
+
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ DvrSettings dvrSetting;
+ dvrSetting.record(setting);
+ status = mDvr->configure(dvrSetting);
+
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::getRecordMQDescriptor() {
+ Result status;
+
+ if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
+ return ::testing::AssertionFailure();
+ }
+
+ mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+ mRecordMQDescriptor = dvrMQDesc;
+ status = result;
+ });
+
+ return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type,
DemuxFilterSettings setting) {
Result status;
@@ -997,6 +1163,82 @@
return closeDemux();
}
+::testing::AssertionResult TunerHidlTest::recordDataFlowTest(vector<FilterConf> filterConf,
+ RecordSettings recordSetting,
+ vector<string> /*goldenOutputFiles*/) {
+ Result status;
+ hidl_vec<FrontendId> feIds;
+
+ mService->getFrontendIds([&](Result result, const hidl_vec<FrontendId>& frontendIds) {
+ status = result;
+ feIds = frontendIds;
+ });
+
+ if (feIds.size() == 0) {
+ ALOGW("[ WARN ] Frontend isn't available");
+ return ::testing::AssertionFailure();
+ }
+
+ FrontendDvbtSettings dvbt{
+ .frequency = 1000,
+ };
+ FrontendSettings settings;
+ settings.dvbt(dvbt);
+
+ int filterIdsSize;
+ // Filter Configuration Module
+ for (int i = 0; i < filterConf.size(); i++) {
+ if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
+ ::testing::AssertionFailure() ||
+ // TODO use a map to save the FMQs/EvenFlags and pass to callback
+ getFilterMQDescriptor() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+ filterIdsSize = mUsedFilterIds.size();
+ mUsedFilterIds.resize(filterIdsSize + 1);
+ mUsedFilterIds[filterIdsSize] = mFilterId;
+ mFilters[mFilterId] = mFilter;
+ }
+
+ // Record Config Module
+ if (addRecordToDemux(recordSetting) == ::testing::AssertionFailure() ||
+ getRecordMQDescriptor() == ::testing::AssertionFailure()) {
+ return ::testing::AssertionFailure();
+ }
+ for (int i = 0; i <= filterIdsSize; i++) {
+ if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ }
+
+ mDvrCallback->startRecordOutputThread(recordSetting, mRecordMQDescriptor);
+ status = mDvr->start();
+ if (status != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+
+ if (createDemuxWithFrontend(feIds[0], settings) != ::testing::AssertionSuccess()) {
+ return ::testing::AssertionFailure();
+ }
+
+ // Data Verify Module
+ mDvrCallback->testRecordOutput();
+
+ // Clean Up Module
+ for (int i = 0; i <= filterIdsSize; i++) {
+ if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ }
+ if (mFrontend->stopTune() != Result::SUCCESS) {
+ return ::testing::AssertionFailure();
+ }
+ mUsedFilterIds.clear();
+ mFilterCallbacks.clear();
+ mFilters.clear();
+ return closeDemux();
+}
+
/*
* API STATUS TESTS
*/
@@ -1203,6 +1445,44 @@
ASSERT_TRUE(broadcastDataFlowTest(filterConf, goldenOutputFiles));
}
+TEST_F(TunerHidlTest, RecordDataFlowWithTsRecordFilterTest) {
+ description("Feed ts data from frontend to recording and test with ts record filter");
+
+ // todo modulize the filter conf parser
+ vector<FilterConf> filterConf;
+ filterConf.resize(1);
+
+ DemuxFilterSettings filterSetting;
+ DemuxTsFilterSettings tsFilterSetting{
+ .tpid = 119,
+ };
+ DemuxFilterRecordSettings recordFilterSetting;
+ tsFilterSetting.filterSettings.record(recordFilterSetting);
+ filterSetting.ts(tsFilterSetting);
+
+ DemuxFilterType type{
+ .mainType = DemuxFilterMainType::TS,
+ };
+ type.subType.tsFilterType(DemuxTsFilterType::RECORD);
+ FilterConf recordFilterConf{
+ .type = type,
+ .setting = filterSetting,
+ };
+ filterConf[0] = recordFilterConf;
+
+ RecordSettings recordSetting{
+ .statusMask = 0xf,
+ .lowThreshold = 0x1000,
+ .highThreshold = 0x07fff,
+ .dataFormat = DataFormat::TS,
+ .packetSize = 188,
+ };
+
+ vector<string> goldenOutputFiles;
+
+ ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles));
+}
+
} // namespace
int main(int argc, char** argv) {
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index f47b10d..0e2b3e1 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -34,18 +34,10 @@
using android::hardware::vibrator::EffectStrength;
using android::hardware::vibrator::IVibrator;
-// TODO(b/143992652): autogenerate
-const std::vector<Effect> kEffects = {
- Effect::CLICK, Effect::DOUBLE_CLICK, Effect::TICK, Effect::THUD,
- Effect::POP, Effect::HEAVY_CLICK, Effect::RINGTONE_1, Effect::RINGTONE_2,
- Effect::RINGTONE_3, Effect::RINGTONE_4, Effect::RINGTONE_5, Effect::RINGTONE_6,
- Effect::RINGTONE_7, Effect::RINGTONE_8, Effect::RINGTONE_9, Effect::RINGTONE_10,
- Effect::RINGTONE_11, Effect::RINGTONE_12, Effect::RINGTONE_13, Effect::RINGTONE_14,
- Effect::RINGTONE_15, Effect::TEXTURE_TICK};
-
-// TODO(b/143992652): autogenerate
-const std::vector<EffectStrength> kEffectStrengths = {EffectStrength::LIGHT, EffectStrength::MEDIUM,
- EffectStrength::STRONG};
+const std::vector<Effect> kEffects{android::enum_range<Effect>().begin(),
+ android::enum_range<Effect>().end()};
+const std::vector<EffectStrength> kEffectStrengths{android::enum_range<EffectStrength>().begin(),
+ android::enum_range<EffectStrength>().end()};
const std::vector<Effect> kInvalidEffects = {
static_cast<Effect>(static_cast<int32_t>(kEffects.front()) - 1),
diff --git a/wifi/supplicant/1.0/vts/functional/Android.bp b/wifi/supplicant/1.0/vts/functional/Android.bp
index 15525bb..332ee4a 100644
--- a/wifi/supplicant/1.0/vts/functional/Android.bp
+++ b/wifi/supplicant/1.0/vts/functional/Android.bp
@@ -19,7 +19,7 @@
defaults: ["VtsHalTargetTestDefaults"],
srcs: ["supplicant_hidl_test_utils.cpp"],
export_include_dirs: [
- "."
+ ".",
],
static_libs: [
"VtsHalWifiV1_0TargetTestUtil",
@@ -51,14 +51,17 @@
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
cc_test {
name: "VtsHalWifiSupplicantP2pV1_0TargetTest",
defaults: ["VtsHalTargetTestDefaults"],
srcs: [
- "VtsHalWifiSupplicantV1_0TargetTest.cpp",
+ "VtsHalWifiSupplicantP2pV1_0TargetTest.cpp",
"supplicant_p2p_iface_hidl_test.cpp",
],
static_libs: [
@@ -71,5 +74,8 @@
"libwifi-system",
"libwifi-system-iface",
],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: [
+ "general-tests",
+ "vts-core",
+ ],
}
diff --git a/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
new file mode 100644
index 0000000..a132707
--- /dev/null
+++ b/wifi/supplicant/1.0/vts/functional/VtsHalWifiSupplicantP2pV1_0TargetTest.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <VtsCoreUtil.h>
+#include "supplicant_hidl_test_utils.h"
+
+// TODO(b/143892896): Remove this line after wifi_hidl_test_utils.cpp is
+// updated.
+WifiSupplicantHidlEnvironment* gEnv = nullptr;
+
+int main(int argc, char** argv) {
+ if (!::testing::deviceSupportsFeature("android.hardware.wifi.direct"))
+ return 0;
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}