Merge "wifi: Add access network type support"
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
index 85d1f57..9cbf343 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -20,7 +20,7 @@
interface IFingerprint {
android.hardware.biometrics.fingerprint.SensorProps[] getSensorProps();
android.hardware.biometrics.fingerprint.ISession createSession(in int sensorId, in int userId, in android.hardware.biometrics.fingerprint.ISessionCallback cb);
- void setResetLockoutCallback(in android.hardware.biometrics.fingerprint.IResetLockoutCallback cb);
+ void setLockoutCallback(in android.hardware.biometrics.fingerprint.ILockoutCallback cb);
void generateChallenge(in int sensorId, in int userId, in int timeoutSec, in android.hardware.biometrics.fingerprint.IGenerateChallengeCallback cb);
- void revokeChallenge(in int sensorId, in int userId, in android.hardware.biometrics.fingerprint.IRevokeChallengeCallback cb);
+ void revokeChallenge(in int sensorId, in int userId, in long challenge, in android.hardware.biometrics.fingerprint.IRevokeChallengeCallback cb);
}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
index eaf27d2..063be60 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
@@ -18,5 +18,5 @@
package android.hardware.biometrics.fingerprint;
@VintfStability
interface IGenerateChallengeCallback {
- oneway void onChallengeGenerated(in int sensorId, in int userId, in long keystoreOperationId, in long challenge);
+ oneway void onChallengeGenerated(in int sensorId, in int userId, in long challenge);
}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl
similarity index 82%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
copy to biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl
index ac0decd..88aabbf 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
+++ b/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl
@@ -17,6 +17,8 @@
package android.hardware.biometrics.fingerprint;
@VintfStability
-interface IResetLockoutCallback {
- oneway void onLockoutReset(in int sensorId, in int userId, in long durationMilli);
+interface ILockoutCallback {
+ oneway void onLockoutTimed(in int sensorId, in int userId, in long durationMillis);
+ oneway void onLockoutPermanent(in int sensorId, in int userId);
+ oneway void onLockoutCleared(in int sensorId, in int userId);
}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
index 4709778..57319b2 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -17,7 +17,7 @@
package android.hardware.biometrics.fingerprint;
import android.hardware.biometrics.fingerprint.IGenerateChallengeCallback;
-import android.hardware.biometrics.fingerprint.IResetLockoutCallback;
+import android.hardware.biometrics.fingerprint.ILockoutCallback;
import android.hardware.biometrics.fingerprint.IRevokeChallengeCallback;
import android.hardware.biometrics.fingerprint.ISession;
import android.hardware.biometrics.fingerprint.ISessionCallback;
@@ -25,13 +25,144 @@
@VintfStability
interface IFingerprint {
+ /**
+ * getSensorProps:
+ *
+ * @return A list of properties for all sensors that an instance of the
+ * HAL supports.
+ */
SensorProps[] getSensorProps();
+ /**
+ * createSession:
+ *
+ * Creates a session which can then be used by the framework to perform
+ * operations such as enroll, authenticate, etc for the given sensorId
+ * and userId.
+ *
+ * A physical sensor identified by sensorId typically supports only a
+ * single in-flight session at a time. As such, if a session is currently
+ * in a state other than SessionState::IDLING, the HAL MUST finish or
+ * cancel the current operation and return to SessionState::IDLING before
+ * the new session is created. For example:
+ * 1) If a session for sensorId=0, userId=0
+ * is currently in a cancellable state (see ICancellationSignal) such
+ * as SessionState::AUTHENTICATING and the framework requests a new
+ * session for sensorId=0, userId=10, the HAL must end the current
+ * session with Error::CANCELED, invoke
+ * ISessionCallback#onStateChanged with SessionState::IDLING, and
+ * then return a new session for sensorId=0, userId=10.
+ * 2) If a session for sensorId=0, userId=0 is currently in a
+ * non-cancellable state such as SessionState::REMOVING_ENROLLMENTS,
+ * and the framework requests a new session for sensorId=0, userId=10,
+ * the HAL must finish the current operation before invoking
+ * ISessionCallback#onStateChanged with SessionState::IDLING, and
+ * return a new session for sensorId=0, userId=10.
+ *
+ * Implementations must store user-specific state or metadata in
+ * /data/vendor_de/<user>/fpdata as specified by the SeLinux policy. This
+ * directory is created/removed by vold (see vold_prepare_subdirs.cpp).
+ * Implementations may store additional user-specific data, such as
+ * embeddings or templates in StrongBox.
+ *
+ * @param sensorId The sensor with which this session is being created.
+ * @param userId The userId with which this session is being created.
+ * @param cb Used to notify the framework.
+ * @return A new session
+ */
ISession createSession(in int sensorId, in int userId, in ISessionCallback cb);
- void setResetLockoutCallback(in IResetLockoutCallback cb);
+ /**
+ * setLockoutCallback:
+ *
+ * Sets a callback to notify the framework lockout changes. Note
+ * that lockout is user AND sensor specific. In other words, there is a
+ * separate lockout state for each (user, sensor) pair. For example, the
+ * following is a valid state on a multi-sensor device:
+ * ------------------------------------------------------------------
+ * | SensorId | UserId | FailedAttempts | LockedOut | LockedUntil |
+ * |----------|--------|----------------|-----------|---------------|
+ * | 0 | 0 | 1 | false | x |
+ * | 1 | 0 | 5 | true | <future_time> |
+ * | 0 | 10 | 0 | false | x |
+ * | 1 | 10 | 0 | false | x |
+ * ------------------------------------------------------------------
+ *
+ * Lockout may be cleared in the following ways:
+ * 1) ISession#resetLockout
+ * 2) After a period of time, according to a rate-limiter.
+ *
+ * In addition, lockout states MUST persist after device reboots, HAL
+ * crashes, etc.
+ *
+ * See the Android CDD section 7.3.10 for the full set of lockout and
+ * rate-limiting requirements.
+ *
+ * @param cb Used to notify the framework of lockout changes.
+ */
+ void setLockoutCallback(in ILockoutCallback cb);
+ /**
+ * generateChallenge:
+ *
+ * Begins a secure transaction request. Note that the challenge by itself
+ * is not useful. It only becomes useful when wrapped in a verifiable
+ * message such as a HardwareAuthToken.
+ *
+ * Canonical example:
+ * 1) User requests an operation, such as fingerprint enrollment.
+ * 2) Fingerprint enrollment cannot happen until the user confirms
+ * their lockscreen credential (PIN/Pattern/Password).
+ * 3) However, the biometric subsystem does not want just "any"
+ * proof of credential confirmation. It needs proof that the
+ * user explicitly authenticated credential in order to allow
+ * addition of biometric enrollments.
+ * To secure this path, the following path is taken:
+ * 1) Upon user requesting fingerprint enroll, the framework requests
+ * IFingerprint#generateChallenge
+ * 2) Framework sends the challenge to the credential subsystem, and upon
+ * credential confirmation, a HAT is created, containing the challenge
+ * in the "challenge" field.
+ * 3) Framework sends the HAT to the HAL, e.g. ISession#enroll.
+ * 4) Implementation verifies the authenticity and integrity of the HAT.
+ * 5) Implementation now has confidence that the user entered their
+ * credential to allow biometric enrollment.
+ *
+ * Note that the interface allows multiple in-flight challenges. For
+ * example, invoking generateChallenge(0, 0, timeoutSec, cb) twice
+ * does not invalidate the first challenge. The challenge is invalidated
+ * only when:
+ * 1) The provided timeout expires, or
+ * 2) IFingerprint#revokeChallenge is invoked
+ *
+ * For example, the following is a possible table of valid challenges:
+ * ----------------------------------------------
+ * | SensorId | UserId | ValidUntil | Challenge |
+ * |----------|--------|------------|-----------|
+ * | 0 | 0 | <Time1> | <Random1> |
+ * | 0 | 0 | <Time2> | <Random2> |
+ * | 1 | 0 | <Time3> | <Random3> |
+ * | 0 | 10 | <Time4> | <Random4> |
+ * ----------------------------------------------
+ *
+ * @param sensorId Sensor to associate the challenge with
+ * @param userId User to associate the challenge with
+ * @param timeoutSec Duration for which the challenge is valid for
+ * @param cb Callback to notify the framework
+ */
void generateChallenge(in int sensorId, in int userId, in int timeoutSec, in IGenerateChallengeCallback cb);
- void revokeChallenge(in int sensorId, in int userId, in IRevokeChallengeCallback cb);
+ /**
+ * revokeChallenge:
+ *
+ * Revokes a challenge that was previously generated. Note that if an
+ * invalid combination of parameters is requested, the implementation
+ * must still notify the framework using the provided callback.
+ *
+ * @param sensorId Sensor that the revocation should apply to.
+ * @param userId User that the revocation should apply to.
+ * @param challenge Challenge that should be revoked.
+ * @param cb Used to notify the framework.
+ */
+ void revokeChallenge(in int sensorId, in int userId, in long challenge, in IRevokeChallengeCallback cb);
}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
index 93a2d7b..a51b188 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IGenerateChallengeCallback.aidl
@@ -18,6 +18,9 @@
@VintfStability
oneway interface IGenerateChallengeCallback {
- void onChallengeGenerated(in int sensorId, in int userId, in long keystoreOperationId, in long challenge);
+ /**
+ * Notifies the framework when a challenge is successfully generated.
+ */
+ void onChallengeGenerated(in int sensorId, in int userId, in long challenge);
}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl
new file mode 100644
index 0000000..4b31a38
--- /dev/null
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ILockoutCallback.aidl
@@ -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.
+ */
+
+package android.hardware.biometrics.fingerprint;
+
+@VintfStability
+oneway interface ILockoutCallback {
+ /**
+ * Notifies the framework that the user has just entered the Error::LOCKOUT state. This must be
+ * sent in the following scenarios:
+ * 1) The user just attempted authentication and was rejected, resulting in a timed lockout.
+ * 2) The framework just created a session for a sensorId/userId pair that has not been
+ * created since the HAL started (e.g. there is no active or idle session for this
+ * sensorId/userId pair.
+ *
+ * @param sensorId Sensor for which the user is locked out.
+ * @param userId User for which the sensor is locked out.
+ * @param durationMillis Remaining duration of the lockout.
+ */
+ void onLockoutTimed(in int sensorId, in int userId, in long durationMillis);
+
+ /**
+ * Notifies the framework that the user has just entered the Error::LOCKOUT_PERMANENT state.
+ * This must be sent in the following scenarios:
+ * 1) The user just attempted authentication and was rejected, resulting in a permanent lockout.
+ * 2) The framework just created a session for a sensorId/userId pair that has not been
+ * created since the HAL started (e.g. there is no active or idle session for this
+ * sensorId/userId pair.
+ *
+ * @param sensorId Sensor for which the user is locked out.
+ * @param userId User for which the sensor is locked out.
+ */
+ void onLockoutPermanent(in int sensorId, in int userId);
+
+ /**
+ * Notifies the framework that lockout has been cleared for this sensorId/userId pair. This
+ * can happen in the following scenarios:
+ * 1) A timed lockout has ended (e.g. original durationMillis specified in #onLockoutTimed
+ * has expired.
+ * 2) See ISession#resetLockout.
+ *
+ * @param sensorId Sensor for which the user's lockout is cleared.
+ * @param userId User for the sensor's lockout is cleared.
+ */
+ void onLockoutCleared(in int sensorId, in int userId);
+}
+
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl
index cca3453..eadba52 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IRevokeChallengeCallback.aidl
@@ -18,6 +18,9 @@
@VintfStability
oneway interface IRevokeChallengeCallback {
+ /**
+ * Notifies the framework when a challenge has been revoked.
+ */
void onChallengeRevoked(in int sensorId, in int userId, in long challenge);
}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
index dd340e8..e2d23a6 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -82,12 +82,14 @@
* The following only applies to sensors that are configured as
* SensorStrength::STRONG.
*
- * When invoked by the framework, the HAL implementation must perform the
+ * When invoked by the framework, the implementation must perform the
* following sequence of events:
* 1) Verify the authenticity and integrity of the provided HAT
- * 2) Update the authenticatorId with a new entropy-encoded random number
- * 3) Persist the new authenticatorId to non-ephemeral storage
- * 4) Notify the framework that the above is completed, via
+ * 2) Verify that the timestamp provided within the HAT is relatively
+ * recent (e.g. on the order of minutes, not hours).
+ * 3) Update the authenticatorId with a new entropy-encoded random number
+ * 4) Persist the new authenticatorId to non-ephemeral storage
+ * 5) Notify the framework that the above is completed, via
* ISessionCallback#onAuthenticatorInvalidated
*
* A practical use case of invalidation would be when the user adds a new
@@ -105,6 +107,26 @@
*/
void invalidateAuthenticatorId(in int cookie, in HardwareAuthToken hat);
+ /**
+ * resetLockout:
+ *
+ * Requests the implementation to clear the lockout counter. Upon receiving
+ * this request, the implementation must perform the following:
+ * 1) Verify the authenticity and integrity of the provided HAT
+ * 2) Verify that the timestamp provided within the HAT is relatively
+ * recent (e.g. on the order of minutes, not hours).
+ *
+ * Upon successful verification, the HAL must notify the framework via
+ * ILockoutCallback#onLockoutChanged(sensorId, userId, 0).
+ *
+ * If verification was uncessful, the HAL must notify the framework via
+ * ILockoutCallback#onLockoutChanged(sensorId, userId, remaining_time).
+ *
+ * @param cookie An identifier used to track subsystem operations related
+ * to this call path. The framework will guarantee that it is
+ * unique per ISession.
+ * @param hat HardwareAuthToken See above documentation.
+ */
void resetLockout(in int cookie, in HardwareAuthToken hat);
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.cpp b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
index a1d9d0a..b3bd4e7 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.cpp
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.cpp
@@ -61,8 +61,8 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Fingerprint::setResetLockoutCallback(
- const std::shared_ptr<IResetLockoutCallback>& /*cb*/) {
+ndk::ScopedAStatus Fingerprint::setLockoutCallback(
+ const std::shared_ptr<ILockoutCallback>& /*cb*/) {
return ndk::ScopedAStatus::ok();
}
@@ -73,7 +73,7 @@
}
ndk::ScopedAStatus Fingerprint::revokeChallenge(
- int32_t /*sensorId*/, int32_t /*userId*/,
+ int32_t /*sensorId*/, int32_t /*userId*/, int64_t /*challenge*/,
const std::shared_ptr<IRevokeChallengeCallback>& /*cb*/) {
return ndk::ScopedAStatus::ok();
}
diff --git a/biometrics/fingerprint/aidl/default/Fingerprint.h b/biometrics/fingerprint/aidl/default/Fingerprint.h
index b5b09c0..463d07d 100644
--- a/biometrics/fingerprint/aidl/default/Fingerprint.h
+++ b/biometrics/fingerprint/aidl/default/Fingerprint.h
@@ -28,15 +28,15 @@
const std::shared_ptr<ISessionCallback>& cb,
std::shared_ptr<ISession>* _aidl_return) override;
- ndk::ScopedAStatus setResetLockoutCallback(
- const std::shared_ptr<IResetLockoutCallback>& cb) override;
+ ndk::ScopedAStatus setLockoutCallback(
+ const std::shared_ptr<ILockoutCallback>& cb) override;
ndk::ScopedAStatus generateChallenge(
int32_t sensorId, int32_t userId, int32_t timeoutSec,
const std::shared_ptr<IGenerateChallengeCallback>& cb) override;
ndk::ScopedAStatus revokeChallenge(
- int32_t sensorId, int32_t userId,
+ int32_t sensorId, int32_t userId, int64_t challenge,
const std::shared_ptr<IRevokeChallengeCallback>& cb) override;
};
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/SynchronizedReadWrite.aidl
similarity index 85%
copy from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
copy to common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/SynchronizedReadWrite.aidl
index ac0decd..aec3d6d 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/SynchronizedReadWrite.aidl
@@ -15,8 +15,8 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.biometrics.fingerprint;
+package android.hardware.common;
@VintfStability
-interface IResetLockoutCallback {
- oneway void onLockoutReset(in int sensorId, in int userId, in long durationMilli);
+enum SynchronizedReadWrite {
+ EMPTY = 0,
}
diff --git a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
similarity index 85%
rename from biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
rename to common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
index ac0decd..e390d20 100644
--- a/biometrics/fingerprint/aidl/aidl_api/android.hardware.biometrics.fingerprint/current/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/UnsynchronizedWrite.aidl
@@ -15,8 +15,8 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.biometrics.fingerprint;
+package android.hardware.common;
@VintfStability
-interface IResetLockoutCallback {
- oneway void onLockoutReset(in int sensorId, in int userId, in long durationMilli);
+enum UnsynchronizedWrite {
+ EMPTY = 0,
}
diff --git a/common/aidl/android/hardware/common/MQDescriptor.aidl b/common/aidl/android/hardware/common/MQDescriptor.aidl
index 8997688..7e89b15 100644
--- a/common/aidl/android/hardware/common/MQDescriptor.aidl
+++ b/common/aidl/android/hardware/common/MQDescriptor.aidl
@@ -22,9 +22,12 @@
* For use with libfmq. This is created from an instance of AidlMessageQueue,
* and is used to pass information required to create another instance of that
* queue for fast communication.
+ * T - is used to specify the type of the payload
+ * Flavor - is used to specify the type of the queue using
+ * android.hardware.common.SynchronizedReadWrite or UnsynchronizedWrite
*/
@VintfStability
-parcelable MQDescriptor {
+parcelable MQDescriptor<T, Flavor> {
/*
* Describes each of the grantors for the message queue. They are used to
* get the readptr, writeptr, dataptr, and the optional EventFlag word
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
similarity index 62%
rename from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
rename to common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
index d97a701..ef93bf2 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
+++ b/common/aidl/android/hardware/common/SynchronizedReadWrite.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package android.hardware.biometrics.fingerprint;
+package android.hardware.common;
+/*
+ * For use with android.hardware.common.MQDescriptor to specify which type of
+ * queue to use. SynchronizedReadWrite is single reader, single writer, with no
+ * overflow. All messages written need to be read.
+ */
@VintfStability
-oneway interface IResetLockoutCallback {
- void onLockoutReset(in int sensorId, in int userId, in long durationMilli);
+enum SynchronizedReadWrite {
+ EMPTY,
}
-
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl b/common/aidl/android/hardware/common/UnsynchronizedWrite.aidl
similarity index 61%
copy from biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
copy to common/aidl/android/hardware/common/UnsynchronizedWrite.aidl
index d97a701..aa27c8d 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IResetLockoutCallback.aidl
+++ b/common/aidl/android/hardware/common/UnsynchronizedWrite.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,10 +14,14 @@
* limitations under the License.
*/
-package android.hardware.biometrics.fingerprint;
+package android.hardware.common;
+/*
+ * For use with android.hardware.common.MQDescriptor to specify which type of
+ * queue to use. UnsynchronizedWrite is single writer, multiple reader, with
+ * overflow. If messages are not read fast enough, they can be overwritten.
+ */
@VintfStability
-oneway interface IResetLockoutCallback {
- void onLockoutReset(in int sensorId, in int userId, in long durationMilli);
+enum UnsynchronizedWrite {
+ EMPTY,
}
-
diff --git a/tests/msgq/1.0/ITestMsgQ.hal b/tests/msgq/1.0/ITestMsgQ.hal
index 112270a..bd10237 100644
--- a/tests/msgq/1.0/ITestMsgQ.hal
+++ b/tests/msgq/1.0/ITestMsgQ.hal
@@ -31,7 +31,7 @@
*
* @return ret True if the setup is successful.
*/
- configureFmqSyncReadWrite(fmq_sync<uint16_t> mqDesc) generates(bool ret);
+ configureFmqSyncReadWrite(fmq_sync<int32_t> mqDesc) generates(bool ret);
/**
* This method requests the service to return an MQDescriptor to
@@ -46,7 +46,7 @@
* @return mqDesc This structure describes the unsynchronized FMQ that was
* set up by the service. Client can use it to set up the FMQ at its end.
*/
- getFmqUnsyncWrite(bool configureFmq) generates(bool ret, fmq_unsync<uint16_t> mqDesc);
+ getFmqUnsyncWrite(bool configureFmq) generates(bool ret, fmq_unsync<int32_t> mqDesc);
/**
* This method request the service to write into the synchronized read/write
diff --git a/tests/msgq/1.0/default/TestMsgQ.cpp b/tests/msgq/1.0/default/TestMsgQ.cpp
index ba665c9..4473737 100644
--- a/tests/msgq/1.0/default/TestMsgQ.cpp
+++ b/tests/msgq/1.0/default/TestMsgQ.cpp
@@ -25,7 +25,7 @@
// Methods from ::android::hardware::tests::msgq::V1_0::ITestMsgQ follow.
Return<bool> TestMsgQ::configureFmqSyncReadWrite(
- const android::hardware::MQDescriptorSync<uint16_t>& mqDesc) {
+ const android::hardware::MQDescriptorSync<int32_t>& mqDesc) {
mFmqSynchronized.reset(new (std::nothrow) MessageQueueSync(mqDesc));
if ((mFmqSynchronized == nullptr) || (mFmqSynchronized->isValid() == false)) {
return false;
@@ -56,7 +56,7 @@
}
Return<bool> TestMsgQ::requestWriteFmqSync(int32_t count) {
- std::vector<uint16_t> data(count);
+ std::vector<int32_t> data(count);
for (int i = 0; i < count; i++) {
data[i] = i;
}
@@ -65,14 +65,14 @@
}
Return<bool> TestMsgQ::requestReadFmqSync(int32_t count) {
- std::vector<uint16_t> data(count);
+ std::vector<int32_t> data(count);
bool result = mFmqSynchronized->read(&data[0], count)
&& verifyData(&data[0], count);
return result;
}
Return<bool> TestMsgQ::requestWriteFmqUnsync(int32_t count) {
- std::vector<uint16_t> data(count);
+ std::vector<int32_t> data(count);
for (int i = 0; i < count; i++) {
data[i] = i;
}
@@ -81,14 +81,14 @@
}
Return<bool> TestMsgQ::requestReadFmqUnsync(int32_t count) {
- std::vector<uint16_t> data(count);
+ std::vector<int32_t> data(count);
bool result =
mFmqUnsynchronized->read(&data[0], count) && verifyData(&data[0], count);
return result;
}
Return<void> TestMsgQ::requestBlockingRead(int32_t count) {
- std::vector<uint16_t> data(count);
+ std::vector<int32_t> data(count);
bool result = mFmqSynchronized->readBlocking(
&data[0],
count,
@@ -103,7 +103,7 @@
}
Return<void> TestMsgQ::requestBlockingReadDefaultEventFlagBits(int32_t count) {
- std::vector<uint16_t> data(count);
+ std::vector<int32_t> data(count);
bool result = mFmqSynchronized->readBlocking(
&data[0],
count);
@@ -116,7 +116,7 @@
}
Return<void> TestMsgQ::requestBlockingReadRepeat(int32_t count, int32_t numIter) {
- std::vector<uint16_t> data(count);
+ std::vector<int32_t> data(count);
for (int i = 0; i < numIter; i++) {
bool result = mFmqSynchronized->readBlocking(
&data[0],
diff --git a/tests/msgq/1.0/default/TestMsgQ.h b/tests/msgq/1.0/default/TestMsgQ.h
index f9fcddd..8a204b7 100644
--- a/tests/msgq/1.0/default/TestMsgQ.h
+++ b/tests/msgq/1.0/default/TestMsgQ.h
@@ -49,13 +49,13 @@
using android::hardware::MessageQueue;
struct TestMsgQ : public ITestMsgQ {
- typedef MessageQueue<uint16_t, kSynchronizedReadWrite> MessageQueueSync;
- typedef MessageQueue<uint16_t, kUnsynchronizedWrite> MessageQueueUnsync;
+ typedef MessageQueue<int32_t, kSynchronizedReadWrite> MessageQueueSync;
+ typedef MessageQueue<int32_t, kUnsynchronizedWrite> MessageQueueUnsync;
TestMsgQ() : mFmqSynchronized(nullptr), mFmqUnsynchronized(nullptr) {}
// Methods from ::android::hardware::tests::msgq::V1_0::ITestMsgQ follow.
- Return<bool> configureFmqSyncReadWrite(const MQDescriptorSync<uint16_t>& mqDesc) override;
+ Return<bool> configureFmqSyncReadWrite(const MQDescriptorSync<int32_t>& mqDesc) override;
Return<void> getFmqUnsyncWrite(bool configureFmq, getFmqUnsyncWrite_cb _hidl_cb) override;
Return<bool> requestWriteFmqSync(int32_t count) override;
Return<bool> requestReadFmqSync(int32_t count) override;
@@ -73,7 +73,7 @@
/*
* Utility function to verify data read from the fast message queue.
*/
- bool verifyData(uint16_t* data, int count) {
+ bool verifyData(int32_t* data, int count) {
for (int i = 0; i < count; i++) {
if (data[i] != i) return false;
}
diff --git a/tv/tuner/1.1/IFilter.hal b/tv/tuner/1.1/IFilter.hal
index b362e32..2ba9bb7 100644
--- a/tv/tuner/1.1/IFilter.hal
+++ b/tv/tuner/1.1/IFilter.hal
@@ -51,4 +51,23 @@
* UNKNOWN_ERROR if failed for other reasons.
*/
configureIpCid(uint32_t ipCid) generates (Result result);
+
+ /**
+ * Get the shared AV memory handle. Use IFilter.releaseAvHandle to release the handle.
+ *
+ * When media filters are opened, call this API to initialize the share memory handle if it's
+ * needed.
+ *
+ * If DemuxFilterMediaEvent.avMemory contains file descriptor, share memory should be ignored.
+ *
+ * @return avMemory A handle associated to the shared memory for audio or video.
+ * avMemory.data[0] is normally an fd for ION memory. When the avMemory->numFd is 0, the
+ * share memory is not initialized and does not contain valid fd.
+ * avMemory.data[avMemory.numFds] is an index used as a parameter of
+ * C2DataIdInfo to build C2 buffer in Codec. No C2 buffer would be created if the index
+ * does not exist.
+ * @return avMemSize the size of the shared av memory. It should be ignored when the share
+ * memory is not initialized.
+ */
+ getAvSharedHandle() generates (Result result, handle avMemory, uint64_t avMemSize);
};
diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp
index 3db8b9e..c69beca 100644
--- a/tv/tuner/1.1/default/Filter.cpp
+++ b/tv/tuner/1.1/default/Filter.cpp
@@ -163,8 +163,17 @@
return Result::SUCCESS;
}
-Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t avDataId) {
+Return<Result> Filter::releaseAvHandle(const hidl_handle& avMemory, uint64_t avDataId) {
ALOGV("%s", __FUNCTION__);
+
+ if ((avMemory.getNativeHandle()->numFds > 0) &&
+ (mSharedAvMemHandle.getNativeHandle()->numFds > 0) &&
+ (sameFile(avMemory.getNativeHandle()->data[0],
+ mSharedAvMemHandle.getNativeHandle()->data[0]))) {
+ freeSharedAvHandle();
+ return Result::SUCCESS;
+ }
+
if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) {
return Result::INVALID_ARGUMENT;
}
@@ -190,6 +199,35 @@
return Result::SUCCESS;
}
+Return<void> Filter::getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) {
+ ALOGV("%s", __FUNCTION__);
+
+ if (!mIsMediaFilter) {
+ _hidl_cb(Result::INVALID_STATE, NULL, BUFFER_SIZE_16M);
+ return Void();
+ }
+
+ if (mSharedAvMemHandle.getNativeHandle() != nullptr) {
+ _hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M);
+ return Void();
+ }
+
+ int av_fd = createAvIonFd(BUFFER_SIZE_16M);
+ if (av_fd == -1) {
+ _hidl_cb(Result::UNKNOWN_ERROR, NULL, 0);
+ }
+
+ native_handle_t* nativeHandle = createNativeHandle(av_fd);
+ if (nativeHandle == NULL) {
+ _hidl_cb(Result::UNKNOWN_ERROR, NULL, 0);
+ }
+ mSharedAvMemHandle.setTo(nativeHandle, /*shouldOwn=*/true);
+ ::close(av_fd);
+
+ _hidl_cb(Result::SUCCESS, mSharedAvMemHandle, BUFFER_SIZE_16M);
+ return Void();
+}
+
bool Filter::createFilterMQ() {
ALOGV("%s", __FUNCTION__);
@@ -313,10 +351,19 @@
}
for (int i = 0; i < mFilterEvent.events.size(); i++) {
::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]);
- native_handle_close(mFilterEvent.events[i].media().avMemory.getNativeHandle());
+ native_handle_delete(const_cast<native_handle_t*>(
+ mFilterEvent.events[i].media().avMemory.getNativeHandle()));
}
}
+void Filter::freeSharedAvHandle() {
+ if (!mIsMediaFilter) {
+ return;
+ }
+ ::close(mSharedAvMemHandle.getNativeHandle()->data[0]);
+ native_handle_delete(const_cast<native_handle_t*>(mSharedAvMemHandle.getNativeHandle()));
+}
+
void Filter::maySendFilterStatusCallback() {
if (!mIsUsingFMQ) {
return;
@@ -509,8 +556,8 @@
return Result::SUCCESS;
}
+ Result result;
if (mPts) {
- Result result;
result = createMediaFilterEventWithIon(mFilterOutput);
if (result == Result::SUCCESS) {
mFilterOutput.clear();
@@ -551,7 +598,10 @@
continue;
}
- createMediaFilterEventWithIon(mPesOutput);
+ result = createMediaFilterEventWithIon(mPesOutput);
+ if (result != Result::SUCCESS) {
+ return result;
+ }
}
mFilterOutput.clear();
@@ -560,51 +610,14 @@
}
Result Filter::createMediaFilterEventWithIon(vector<uint8_t> output) {
- int av_fd = createAvIonFd(output.size());
- if (av_fd == -1) {
- return Result::UNKNOWN_ERROR;
+ if (mUsingSharedAvMem) {
+ if (mSharedAvMemHandle.getNativeHandle() == nullptr) {
+ return Result::UNKNOWN_ERROR;
+ }
+ return createShareMemMediaEvents(output);
}
- // copy the filtered data to the buffer
- uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
- if (avBuffer == NULL) {
- return Result::UNKNOWN_ERROR;
- }
- memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));
- native_handle_t* nativeHandle = createNativeHandle(av_fd);
- if (nativeHandle == NULL) {
- return Result::UNKNOWN_ERROR;
- }
- hidl_handle handle;
- handle.setTo(nativeHandle, /*shouldOwn=*/true);
-
- // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
- uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
- mDataId2Avfd[dataId] = dup(av_fd);
-
- // Create mediaEvent and send callback
- DemuxFilterMediaEvent mediaEvent;
- mediaEvent = {
- .avMemory = std::move(handle),
- .dataLength = static_cast<uint32_t>(output.size()),
- .avDataId = dataId,
- };
- if (mPts) {
- mediaEvent.pts = mPts;
- mPts = 0;
- }
- int size = mFilterEvent.events.size();
- mFilterEvent.events.resize(size + 1);
- mFilterEvent.events[size].media(mediaEvent);
-
- // Clear and log
- output.clear();
- mAvBufferCopyCount = 0;
- ::close(av_fd);
- if (DEBUG_FILTER) {
- ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
- }
- return Result::SUCCESS;
+ return createIndependentMediaEvents(output);
}
Result Filter::startRecordFilterHandler() {
@@ -713,15 +726,119 @@
}
native_handle_t* Filter::createNativeHandle(int fd) {
- // Create a native handle to pass the av fd via the callback event.
- native_handle_t* nativeHandle = native_handle_create(/*numFd*/ 1, 0);
+ native_handle_t* nativeHandle;
+ if (fd < 0) {
+ nativeHandle = native_handle_create(/*numFd*/ 0, 0);
+ } else {
+ // Create a native handle to pass the av fd via the callback event.
+ nativeHandle = native_handle_create(/*numFd*/ 1, 0);
+ }
if (nativeHandle == NULL) {
ALOGE("[Filter] Failed to create native_handle %d", errno);
return NULL;
}
- nativeHandle->data[0] = dup(fd);
+ if (nativeHandle->numFds > 0) {
+ nativeHandle->data[0] = dup(fd);
+ }
return nativeHandle;
}
+
+Result Filter::createIndependentMediaEvents(vector<uint8_t> output) {
+ int av_fd = createAvIonFd(output.size());
+ if (av_fd == -1) {
+ return Result::UNKNOWN_ERROR;
+ }
+ // copy the filtered data to the buffer
+ uint8_t* avBuffer = getIonBuffer(av_fd, output.size());
+ if (avBuffer == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ memcpy(avBuffer, output.data(), output.size() * sizeof(uint8_t));
+
+ native_handle_t* nativeHandle = createNativeHandle(av_fd);
+ if (nativeHandle == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ hidl_handle handle;
+ handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+ // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
+ uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
+ mDataId2Avfd[dataId] = dup(av_fd);
+
+ // Create mediaEvent and send callback
+ DemuxFilterMediaEvent mediaEvent;
+ mediaEvent = {
+ .avMemory = std::move(handle),
+ .dataLength = static_cast<uint32_t>(output.size()),
+ .avDataId = dataId,
+ };
+ if (mPts) {
+ mediaEvent.pts = mPts;
+ mPts = 0;
+ }
+ int size = mFilterEvent.events.size();
+ mFilterEvent.events.resize(size + 1);
+ mFilterEvent.events[size].media(mediaEvent);
+
+ // Clear and log
+ output.clear();
+ mAvBufferCopyCount = 0;
+ ::close(av_fd);
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] av data length %d", mediaEvent.dataLength);
+ }
+ return Result::SUCCESS;
+}
+
+Result Filter::createShareMemMediaEvents(vector<uint8_t> output) {
+ // copy the filtered data to the shared buffer
+ uint8_t* sharedAvBuffer = getIonBuffer(mSharedAvMemHandle.getNativeHandle()->data[0],
+ output.size() + mSharedAvMemOffset);
+ if (sharedAvBuffer == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ memcpy(sharedAvBuffer + mSharedAvMemOffset, output.data(), output.size() * sizeof(uint8_t));
+
+ // Create a memory handle with numFds == 0
+ native_handle_t* nativeHandle = createNativeHandle(-1);
+ if (nativeHandle == NULL) {
+ return Result::UNKNOWN_ERROR;
+ }
+ hidl_handle handle;
+ handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+ // Create mediaEvent and send callback
+ DemuxFilterMediaEvent mediaEvent;
+ mediaEvent = {
+ .offset = static_cast<uint32_t>(mSharedAvMemOffset),
+ .dataLength = static_cast<uint32_t>(output.size()),
+ .avMemory = handle,
+ };
+ mSharedAvMemOffset += output.size();
+ if (mPts) {
+ mediaEvent.pts = mPts;
+ mPts = 0;
+ }
+ int size = mFilterEvent.events.size();
+ mFilterEvent.events.resize(size + 1);
+ mFilterEvent.events[size].media(mediaEvent);
+
+ // Clear and log
+ output.clear();
+ if (DEBUG_FILTER) {
+ ALOGD("[Filter] shared av data length %d", mediaEvent.dataLength);
+ }
+ return Result::SUCCESS;
+}
+
+bool Filter::sameFile(int fd1, int fd2) {
+ struct stat stat1, stat2;
+ if (fstat(fd1, &stat1) < 0 || fstat(fd2, &stat2) < 0) {
+ return false;
+ }
+ return (stat1.st_dev == stat2.st_dev) && (stat1.st_ino == stat2.st_ino);
+}
} // namespace implementation
} // namespace V1_0
} // namespace tuner
diff --git a/tv/tuner/1.1/default/Filter.h b/tv/tuner/1.1/default/Filter.h
index 23bc25c..f677666 100644
--- a/tv/tuner/1.1/default/Filter.h
+++ b/tv/tuner/1.1/default/Filter.h
@@ -23,6 +23,7 @@
#include <inttypes.h>
#include <ion/ion.h>
#include <math.h>
+#include <sys/stat.h>
#include <set>
#include "Demux.h"
#include "Dvr.h"
@@ -43,6 +44,7 @@
using ::android::hardware::MQDescriptorSync;
using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+const uint32_t BUFFER_SIZE_16M = 0x1000000;
class Demux;
class Dvr;
@@ -78,6 +80,8 @@
virtual Return<Result> configureIpCid(uint32_t ipCid) override;
+ virtual Return<void> getAvSharedHandle(getAvSharedHandle_cb _hidl_cb) override;
+
/**
* To create a FilterMQ and its Event Flag.
*
@@ -93,6 +97,7 @@
void attachFilterToRecord(const sp<Dvr> dvr);
void detachFilterFromRecord();
void freeAvHandle();
+ void freeSharedAvHandle();
bool isMediaFilter() { return mIsMediaFilter; };
bool isPcrFilter() { return mIsPcrFilter; };
bool isRecordFilter() { return mIsRecordFilter; };
@@ -185,6 +190,9 @@
uint8_t* getIonBuffer(int fd, int size);
native_handle_t* createNativeHandle(int fd);
Result createMediaFilterEventWithIon(vector<uint8_t> output);
+ Result createIndependentMediaEvents(vector<uint8_t> output);
+ Result createShareMemMediaEvents(vector<uint8_t> output);
+ bool sameFile(int fd1, int fd2);
/**
* Lock to protect writes to the FMQs
@@ -212,6 +220,11 @@
std::map<uint64_t, int> mDataId2Avfd;
uint64_t mLastUsedDataId = 1;
int mAvBufferCopyCount = 0;
+
+ // Shared A/V memory handle
+ hidl_handle mSharedAvMemHandle;
+ bool mUsingSharedAvMem = true;
+ uint32_t mSharedAvMemOffset = 0;
};
} // namespace implementation
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp
index 7e5b549..5a8985d 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.cpp
+++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp
@@ -16,22 +16,70 @@
#include "FilterTests.h"
-bool FilterCallback::readFilterEventData() {
- bool result = false;
- ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
+void FilterCallback::testFilterDataOutput() {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ while (mPidFilterOutputCount < 1) {
+ if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+ EXPECT_TRUE(false) << "filter output matching pid does not output within timeout";
+ return;
+ }
+ }
+ mPidFilterOutputCount = 0;
+ ALOGW("[vts] pass and stop");
+}
+
+void FilterCallback::readFilterEventData() {
+ ALOGW("[vts] reading filter event");
// todo separate filter handlers
+ for (int i = 0; i < mFilterEvent.events.size(); i++) {
+ auto event = mFilterEvent.events[i];
+ switch (event.getDiscriminator()) {
+ case DemuxFilterEvent::Event::hidl_discriminator::media:
+ ALOGD("[vts] Media filter event, avMemHandle numFds=%d.",
+ event.media().avMemory.getNativeHandle()->numFds);
+ dumpAvData(event.media());
+ break;
+ default:
+ break;
+ }
+ }
for (int i = 0; i < mFilterEventExt.events.size(); i++) {
auto eventExt = mFilterEventExt.events[i];
switch (eventExt.getDiscriminator()) {
case DemuxFilterEventExt::Event::hidl_discriminator::tsRecord:
- ALOGW("[vts] Extended TS record filter event, pts=%" PRIu64 ".",
+ ALOGD("[vts] Extended TS record filter event, pts=%" PRIu64 ".",
eventExt.tsRecord().pts);
break;
default:
break;
}
}
- return result;
+}
+
+bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
+ uint32_t length = event.dataLength;
+ uint32_t offset = event.offset;
+ // read data from buffer pointed by a handle
+ hidl_handle handle = event.avMemory;
+ if (handle.getNativeHandle()->numFds == 0) {
+ if (mAvSharedHandle == NULL) {
+ return false;
+ }
+ handle = mAvSharedHandle;
+ }
+
+ int av_fd = handle.getNativeHandle()->data[0];
+ uint8_t* buffer =
+ static_cast<uint8_t*>(mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0));
+ if (buffer == MAP_FAILED) {
+ ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
+ return false;
+ }
+ uint8_t output[length + 1];
+ memcpy(output, buffer + offset, length);
+ // print buffer and check with golden output.
+ ::close(av_fd);
+ return true;
}
AssertionResult FilterTests::openFilterInDemux(DemuxFilterType type, uint32_t bufferSize) {
@@ -81,6 +129,33 @@
return AssertionResult(status == Result::SUCCESS);
}
+AssertionResult FilterTests::getSharedAvMemoryHandle(uint64_t filterId) {
+ EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
+ Result status = Result::UNKNOWN_ERROR;
+ sp<android::hardware::tv::tuner::V1_1::IFilter> filter_v1_1 =
+ android::hardware::tv::tuner::V1_1::IFilter::castFrom(mFilters[filterId]);
+ if (filter_v1_1 != NULL) {
+ filter_v1_1->getAvSharedHandle([&](Result r, hidl_handle avMemory, uint64_t avMemSize) {
+ status = r;
+ if (status == Result::SUCCESS) {
+ mFilterCallbacks[mFilterId]->setSharedHandle(avMemory);
+ mFilterCallbacks[mFilterId]->setMemSize(avMemSize);
+ mAvSharedHandle = avMemory;
+ }
+ });
+ }
+ return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::releaseShareAvHandle(uint64_t filterId) {
+ Result status;
+ EXPECT_TRUE(mFilters[filterId]) << "Open media filter first.";
+ EXPECT_TRUE(mAvSharedHandle) << "No shared av handle to release.";
+ status = mFilters[filterId]->releaseAvHandle(mAvSharedHandle, 0 /*dataId*/);
+
+ return AssertionResult(status == Result::SUCCESS);
+}
+
AssertionResult FilterTests::configFilter(DemuxFilterSettings setting, uint64_t filterId) {
Result status;
EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h
index a47f631..bc6db86 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.h
+++ b/tv/tuner/1.1/vts/functional/FilterTests.h
@@ -46,6 +46,7 @@
using android::hardware::Void;
using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
using android::hardware::tv::tuner::V1_0::DemuxFilterType;
@@ -93,7 +94,14 @@
}
virtual Return<void> onFilterEvent(
- const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& /*filterEvent*/) override {
+ const android::hardware::tv::tuner::V1_0::DemuxFilterEvent& filterEvent) override {
+ android::Mutex::Autolock autoLock(mMsgLock);
+ // Temprarily we treat the first coming back filter data on the matching pid a success
+ // once all of the MQ are cleared, means we got all the expected output
+ mFilterEvent = filterEvent;
+ readFilterEventData();
+ mPidFilterOutputCount++;
+ mMsgCondition.signal();
return Void();
}
@@ -104,8 +112,13 @@
void setFilterId(uint32_t filterId) { mFilterId = filterId; }
void setFilterInterface(sp<IFilter> filter) { mFilter = filter; }
void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
+ void setSharedHandle(hidl_handle sharedHandle) { mAvSharedHandle = sharedHandle; }
+ void setMemSize(uint64_t size) { mAvSharedMemSize = size; }
- bool readFilterEventData();
+ void testFilterDataOutput();
+
+ void readFilterEventData();
+ bool dumpAvData(DemuxFilterMediaEvent event);
private:
uint32_t mFilterId;
@@ -114,6 +127,9 @@
DemuxFilterEvent mFilterEvent;
DemuxFilterEventExt mFilterEventExt;
+ hidl_handle mAvSharedHandle = NULL;
+ uint64_t mAvSharedMemSize = -1;
+
android::Mutex mMsgLock;
android::Mutex mFilterOutputLock;
android::Condition mMsgCondition;
@@ -127,10 +143,12 @@
void setDemux(sp<IDemux> demux) { mDemux = demux; }
sp<IFilter> getFilterById(uint64_t filterId) { return mFilters[filterId]; }
- std::map<uint64_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
+ map<uint64_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize);
AssertionResult getNewlyOpenedFilterId_64bit(uint64_t& filterId);
+ AssertionResult getSharedAvMemoryHandle(uint64_t filterId);
+ AssertionResult releaseShareAvHandle(uint64_t filterId);
AssertionResult configFilter(DemuxFilterSettings setting, uint64_t filterId);
AssertionResult configIpFilterCid(uint32_t ipCid, uint64_t filterId);
AssertionResult getFilterMQDescriptor(uint64_t filterId);
@@ -193,12 +211,14 @@
sp<ITuner> mService;
sp<IFilter> mFilter;
sp<IDemux> mDemux;
- std::map<uint64_t, sp<IFilter>> mFilters;
- std::map<uint64_t, sp<FilterCallback>> mFilterCallbacks;
+ map<uint64_t, sp<IFilter>> mFilters;
+ map<uint64_t, sp<FilterCallback>> mFilterCallbacks;
sp<FilterCallback> mFilterCallback;
MQDesc mFilterMQDescriptor;
vector<uint64_t> mUsedFilterIds;
+ hidl_handle mAvSharedHandle = NULL;
+
uint64_t mFilterId = -1;
};
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
index e06de53..f87fa3c 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -18,6 +18,10 @@
namespace {
+AssertionResult TunerBroadcastHidlTest::filterDataOutputTest() {
+ return filterDataOutputTestBase(mFilterTests);
+}
+
void TunerFilterHidlTest::configSingleFilterInDemuxTest(FilterConfig filterConf,
FrontendConfig frontendConf) {
uint32_t feId;
@@ -46,6 +50,38 @@
ASSERT_TRUE(mFrontendTests.closeFrontend());
}
+void TunerBroadcastHidlTest::mediaFilterUsingSharedMemoryTest(FilterConfig filterConf,
+ FrontendConfig frontendConf) {
+ uint32_t feId;
+ uint32_t demuxId;
+ sp<IDemux> demux;
+ uint64_t filterId;
+
+ mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+ ASSERT_TRUE(feId != INVALID_ID);
+ ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+ ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+ ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+ ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+ mFrontendTests.setDemux(demux);
+ mFilterTests.setDemux(demux);
+ ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+ ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
+ ASSERT_TRUE(mFilterTests.getSharedAvMemoryHandle(filterId));
+ ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+ ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+ ASSERT_TRUE(mFilterTests.startFilter(filterId));
+ // tune test
+ ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+ ASSERT_TRUE(filterDataOutputTest());
+ ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+ ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+ ASSERT_TRUE(mFilterTests.releaseShareAvHandle(filterId));
+ ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+ ASSERT_TRUE(mDemuxTests.closeDemux());
+ ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
void TunerRecordHidlTest::recordSingleFilterTest(FilterConfig filterConf,
FrontendConfig frontendConf, DvrConfig dvrConf) {
uint32_t feId;
@@ -116,6 +152,16 @@
mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND);
}
+TEST_P(TunerBroadcastHidlTest, MediaFilterWithSharedMemoryHandle) {
+ description("Test the Media Filter with shared memory handle");
+ mediaFilterUsingSharedMemoryTest(filterArray[TS_VIDEO0], frontendArray[DVBT]);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, TunerBroadcastHidlTest,
+ testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
+ android::hardware::PrintInstanceNameToString);
+
INSTANTIATE_TEST_SUITE_P(
PerInstance, TunerFrontendHidlTest,
testing::ValuesIn(android::hardware::getAllHalInstanceNames(ITuner::descriptor)),
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
index 47004f6..f77a740 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
@@ -26,6 +26,20 @@
initDvrConfig();
}
+static AssertionResult success() {
+ return ::testing::AssertionSuccess();
+}
+
+AssertionResult filterDataOutputTestBase(FilterTests tests) {
+ // Data Verify Module
+ std::map<uint64_t, sp<FilterCallback>>::iterator it;
+ std::map<uint64_t, sp<FilterCallback>> filterCallbacks = tests.getFilterCallbacks();
+ for (it = filterCallbacks.begin(); it != filterCallbacks.end(); it++) {
+ it->second->testFilterDataOutput();
+ }
+ return success();
+}
+
class TunerFilterHidlTest : public testing::TestWithParam<std::string> {
public:
virtual void SetUp() override {
@@ -103,4 +117,34 @@
};
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerFrontendHidlTest);
+
+class TunerBroadcastHidlTest : public testing::TestWithParam<std::string> {
+ public:
+ virtual void SetUp() override {
+ mService = ITuner::getService(GetParam());
+ ASSERT_NE(mService, nullptr);
+ initConfiguration();
+
+ mFrontendTests.setService(mService);
+ mDemuxTests.setService(mService);
+ mFilterTests.setService(mService);
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ sp<ITuner> mService;
+ FrontendTests mFrontendTests;
+ DemuxTests mDemuxTests;
+ FilterTests mFilterTests;
+
+ AssertionResult filterDataOutputTest();
+
+ void mediaFilterUsingSharedMemoryTest(FilterConfig filterConf, FrontendConfig frontendConf);
+};
+
+// TODO remove from the allow list once the cf tv target is enabled for testing
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(TunerBroadcastHidlTest);
} // namespace
\ No newline at end of file