Loading media/audioaidlconversion/AidlConversionCppNdk.cpp +32 −4 Original line number Diff line number Diff line Loading @@ -1055,6 +1055,14 @@ AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& de return OK; } namespace { // Use '01' for LSB bits 0 and 1 as Bluetooth MAC addresses are never multicast // and universaly administered constexpr std::array<uint8_t, 4> BTANON_PREFIX {0xFD, 0xFF, 0xFF, 0xFF}; // Keep sync with ServiceUtilities.cpp mustAnonymizeBluetoothAddress constexpr const char * BTANON_PREFIX_STR = "XX:XX:XX:XX:"; } ::android::status_t aidl2legacy_AudioDevice_audio_device( const AudioDevice& aidl, audio_devices_t* legacyType, std::string* legacyAddress) { Loading @@ -1069,8 +1077,16 @@ AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& de case Tag::mac: { const std::vector<uint8_t>& mac = aidl.address.get<AudioDeviceAddress::mac>(); if (mac.size() != 6) return BAD_VALUE; snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", if (std::equal(BTANON_PREFIX.begin(), BTANON_PREFIX.end(), mac.begin())) { // special case for anonymized mac address: // change anonymized bytes back from FD:FF:FF:FF: to XX:XX:XX:XX: snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%s%02X:%02X", BTANON_PREFIX_STR, mac[4], mac[5]); } else { snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } } break; case Tag::ipv4: { const std::vector<uint8_t>& ipv4 = aidl.address.get<AudioDeviceAddress::ipv4>(); Loading Loading @@ -1132,8 +1148,20 @@ legacy2aidl_audio_device_AudioDevice( switch (suggestDeviceAddressTag(aidl.type)) { case Tag::mac: { std::vector<uint8_t> mac(6); int status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", int status; // special case for anonymized mac address: // change anonymized bytes so that they can be scanned as HEX bytes if (legacyAddress.starts_with(BTANON_PREFIX_STR)) { std::copy(BTANON_PREFIX.begin(), BTANON_PREFIX.end(), mac.begin()); LOG_ALWAYS_FATAL_IF(legacyAddress.length() <= strlen(BTANON_PREFIX_STR)); status = sscanf(legacyAddress.c_str() + strlen(BTANON_PREFIX_STR), "%hhX:%hhX", &mac[4], &mac[5]); status += 4; } else { status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); } if (status != mac.size()) { ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str()); return unexpected(BAD_VALUE); Loading media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -483,8 +483,27 @@ INSTANTIATE_TEST_SUITE_P( AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>( std::vector<int32_t>{1, 2})))); TEST(AnonymizedBluetoothAddressRoundTripTest, Legacy2Aidl2Legacy) { const std::vector<uint8_t> sAnonymizedAidlAddress {0xFD, 0xFF, 0xFF, 0xFF, 0xAB, 0xCD}; const std::string sAnonymizedLegacyAddress = std::string("XX:XX:XX:XX:AB:CD"); auto device = legacy2aidl_audio_device_AudioDevice(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, sAnonymizedLegacyAddress); ASSERT_TRUE(device.ok()); ASSERT_EQ(AudioDeviceAddress::Tag::mac, device.value().address.getTag()); ASSERT_EQ(sAnonymizedAidlAddress, device.value().address.get<AudioDeviceAddress::mac>()); audio_devices_t legacyType; std::string legacyAddress; status_t status = aidl2legacy_AudioDevice_audio_device(device.value(), &legacyType, &legacyAddress); ASSERT_EQ(OK, status); EXPECT_EQ(legacyType, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP); EXPECT_EQ(sAnonymizedLegacyAddress, legacyAddress); } class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam<AudioFormatDescription> { }; TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) { const auto initial = GetParam(); auto conv = aidl2legacy_AudioFormatDescription_audio_format_t(initial); Loading media/libmediametrics/MediaMetricsItem.cpp +8 −8 Original line number Diff line number Diff line Loading @@ -334,22 +334,22 @@ bool BaseItem::isEnabled() { // This is checked only once in the lifetime of the process. const uid_t uid = getuid(); switch (uid) { case AID_RADIO: // telephony subsystem, RIL const uid_t appid = multiuser_get_app_id(uid); if (appid == AID_RADIO) { // telephony subsystem, RIL return false; default: } if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { // Some isolated processes can access the audio system; see // AudioSystem::setAudioFlingerBinder (currently only the HotwordDetectionService). Instead // of also allowing access to the MediaMetrics service, it's simpler to just disable it for // now. // TODO(b/190151205): Either allow the HotwordDetectionService to access MediaMetrics or // make this disabling specific to that process. uid_t appid = multiuser_get_app_id(uid); if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { return false; } break; } int enabled = property_get_int32(Item::EnabledProperty, -1); if (enabled == -1) { Loading media/utils/ServiceUtilities.cpp +104 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define LOG_TAG "ServiceUtilities" #include <audio_utils/clock.h> #include <android-base/properties.h> #include <binder/AppOpsManager.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> Loading @@ -28,9 +29,11 @@ #include <media/AidlConversionUtil.h> #include <android/content/AttributionSourceState.h> #include <iterator> #include <algorithm> #include <iterator> #include <mutex> #include <pwd.h> #include <thread> /* When performing permission checks we do not use permission cache for * runtime permissions (protection level dangerous) as they may change at Loading Loading @@ -396,6 +399,106 @@ status_t checkIMemory(const sp<IMemory>& iMemory) return NO_ERROR; } // TODO(b/285588444), clean this up on main, but soak it for backporting purposes for now namespace { class BluetoothPermissionCache { static constexpr auto SYSPROP_NAME = "cache_key.system_server.package_info"; const String16 BLUETOOTH_PERM {"android.permission.BLUETOOTH_CONNECT"}; mutable std::mutex mLock; // Cached property conditionally defined, since only avail on bionic. On host, don't inval cache #if defined(__BIONIC__) // Unlocked, but only accessed from mListenerThread base::CachedProperty mCachedProperty; #endif // This thread is designed to never join/terminate, so no signal is fine const std::thread mListenerThread; GUARDED_BY(mLock) std::string mPropValue; GUARDED_BY(mLock) std::unordered_map<uid_t, bool> mCache; PermissionController mPc{}; public: BluetoothPermissionCache() #if defined(__BIONIC__) : mCachedProperty{SYSPROP_NAME}, mListenerThread([this]() mutable { while (true) { std::string newVal = mCachedProperty.WaitForChange() ?: ""; std::lock_guard l{mLock}; if (newVal != mPropValue) { ALOGV("Bluetooth permission update"); mPropValue = newVal; mCache.clear(); } } }) #endif {} bool checkPermission(uid_t uid, pid_t pid) { std::lock_guard l{mLock}; auto it = mCache.find(uid); if (it == mCache.end()) { it = mCache.insert({uid, mPc.checkPermission(BLUETOOTH_PERM, uid, pid)}).first; } return it->second; } }; // Don't call this from locks, since it potentially calls up to system server! // Check for non-app UIDs above this method! bool checkBluetoothPermission(const AttributionSourceState& attr) { [[clang::no_destroy]] static BluetoothPermissionCache impl{}; return impl.checkPermission(attr.uid, attr.pid); } } // anonymous /** * Determines if the MAC address in Bluetooth device descriptors returned by APIs of * a native audio service (audio flinger, audio policy) must be anonymized. * MAC addresses returned to system server or apps with BLUETOOTH_CONNECT permission * are not anonymized. * * @param attributionSource The attribution source of the calling app. * @param caller string identifying the caller for logging. * @return true if the MAC addresses must be anonymized, false otherwise. */ bool mustAnonymizeBluetoothAddress( const AttributionSourceState& attributionSource, const String16&) { uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)); bool res; switch(multiuser_get_app_id(uid)) { case AID_ROOT: case AID_SYSTEM: case AID_RADIO: case AID_BLUETOOTH: case AID_MEDIA: case AID_AUDIOSERVER: // Don't anonymize for privileged clients res = false; break; default: res = !checkBluetoothPermission(attributionSource); break; } ALOGV("%s uid: %d, result: %d", __func__, uid, res); return res; } /** * Modifies the passed MAC address string in place for consumption by unprivileged clients. * the string is assumed to have a valid MAC address format. * the anonymization must be kept in sync with toAnonymizedAddress() in BluetoothUtils.java * * @param address input/output the char string contining the MAC address to anonymize. */ void anonymizeBluetoothAddress(char *address) { if (address == nullptr || strlen(address) != strlen("AA:BB:CC:DD:EE:FF")) { return; } memcpy(address, "XX:XX:XX:XX", strlen("XX:XX:XX:XX")); } sp<content::pm::IPackageManagerNative> MediaPackageManager::retrievePackageManager() { const sp<IServiceManager> sm = defaultServiceManager(); if (sm == nullptr) { Loading media/utils/include/mediautils/ServiceUtilities.h +4 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,10 @@ bool modifyPhoneStateAllowed(const AttributionSourceState& attributionSource); bool bypassInterruptionPolicyAllowed(const AttributionSourceState& attributionSource); bool callAudioInterceptionAllowed(const AttributionSourceState& attributionSource); void purgePermissionCache(); bool mustAnonymizeBluetoothAddress( const AttributionSourceState& attributionSource, const String16& caller); void anonymizeBluetoothAddress(char *address); int32_t getOpForSource(audio_source_t source); AttributionSourceState getCallingAttributionSource(); Loading Loading
media/audioaidlconversion/AidlConversionCppNdk.cpp +32 −4 Original line number Diff line number Diff line Loading @@ -1055,6 +1055,14 @@ AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& de return OK; } namespace { // Use '01' for LSB bits 0 and 1 as Bluetooth MAC addresses are never multicast // and universaly administered constexpr std::array<uint8_t, 4> BTANON_PREFIX {0xFD, 0xFF, 0xFF, 0xFF}; // Keep sync with ServiceUtilities.cpp mustAnonymizeBluetoothAddress constexpr const char * BTANON_PREFIX_STR = "XX:XX:XX:XX:"; } ::android::status_t aidl2legacy_AudioDevice_audio_device( const AudioDevice& aidl, audio_devices_t* legacyType, std::string* legacyAddress) { Loading @@ -1069,8 +1077,16 @@ AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& de case Tag::mac: { const std::vector<uint8_t>& mac = aidl.address.get<AudioDeviceAddress::mac>(); if (mac.size() != 6) return BAD_VALUE; snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", if (std::equal(BTANON_PREFIX.begin(), BTANON_PREFIX.end(), mac.begin())) { // special case for anonymized mac address: // change anonymized bytes back from FD:FF:FF:FF: to XX:XX:XX:XX: snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%s%02X:%02X", BTANON_PREFIX_STR, mac[4], mac[5]); } else { snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } } break; case Tag::ipv4: { const std::vector<uint8_t>& ipv4 = aidl.address.get<AudioDeviceAddress::ipv4>(); Loading Loading @@ -1132,8 +1148,20 @@ legacy2aidl_audio_device_AudioDevice( switch (suggestDeviceAddressTag(aidl.type)) { case Tag::mac: { std::vector<uint8_t> mac(6); int status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", int status; // special case for anonymized mac address: // change anonymized bytes so that they can be scanned as HEX bytes if (legacyAddress.starts_with(BTANON_PREFIX_STR)) { std::copy(BTANON_PREFIX.begin(), BTANON_PREFIX.end(), mac.begin()); LOG_ALWAYS_FATAL_IF(legacyAddress.length() <= strlen(BTANON_PREFIX_STR)); status = sscanf(legacyAddress.c_str() + strlen(BTANON_PREFIX_STR), "%hhX:%hhX", &mac[4], &mac[5]); status += 4; } else { status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); } if (status != mac.size()) { ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str()); return unexpected(BAD_VALUE); Loading
media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -483,8 +483,27 @@ INSTANTIATE_TEST_SUITE_P( AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>( std::vector<int32_t>{1, 2})))); TEST(AnonymizedBluetoothAddressRoundTripTest, Legacy2Aidl2Legacy) { const std::vector<uint8_t> sAnonymizedAidlAddress {0xFD, 0xFF, 0xFF, 0xFF, 0xAB, 0xCD}; const std::string sAnonymizedLegacyAddress = std::string("XX:XX:XX:XX:AB:CD"); auto device = legacy2aidl_audio_device_AudioDevice(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, sAnonymizedLegacyAddress); ASSERT_TRUE(device.ok()); ASSERT_EQ(AudioDeviceAddress::Tag::mac, device.value().address.getTag()); ASSERT_EQ(sAnonymizedAidlAddress, device.value().address.get<AudioDeviceAddress::mac>()); audio_devices_t legacyType; std::string legacyAddress; status_t status = aidl2legacy_AudioDevice_audio_device(device.value(), &legacyType, &legacyAddress); ASSERT_EQ(OK, status); EXPECT_EQ(legacyType, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP); EXPECT_EQ(sAnonymizedLegacyAddress, legacyAddress); } class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam<AudioFormatDescription> { }; TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) { const auto initial = GetParam(); auto conv = aidl2legacy_AudioFormatDescription_audio_format_t(initial); Loading
media/libmediametrics/MediaMetricsItem.cpp +8 −8 Original line number Diff line number Diff line Loading @@ -334,22 +334,22 @@ bool BaseItem::isEnabled() { // This is checked only once in the lifetime of the process. const uid_t uid = getuid(); switch (uid) { case AID_RADIO: // telephony subsystem, RIL const uid_t appid = multiuser_get_app_id(uid); if (appid == AID_RADIO) { // telephony subsystem, RIL return false; default: } if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { // Some isolated processes can access the audio system; see // AudioSystem::setAudioFlingerBinder (currently only the HotwordDetectionService). Instead // of also allowing access to the MediaMetrics service, it's simpler to just disable it for // now. // TODO(b/190151205): Either allow the HotwordDetectionService to access MediaMetrics or // make this disabling specific to that process. uid_t appid = multiuser_get_app_id(uid); if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { return false; } break; } int enabled = property_get_int32(Item::EnabledProperty, -1); if (enabled == -1) { Loading
media/utils/ServiceUtilities.cpp +104 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #define LOG_TAG "ServiceUtilities" #include <audio_utils/clock.h> #include <android-base/properties.h> #include <binder/AppOpsManager.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> Loading @@ -28,9 +29,11 @@ #include <media/AidlConversionUtil.h> #include <android/content/AttributionSourceState.h> #include <iterator> #include <algorithm> #include <iterator> #include <mutex> #include <pwd.h> #include <thread> /* When performing permission checks we do not use permission cache for * runtime permissions (protection level dangerous) as they may change at Loading Loading @@ -396,6 +399,106 @@ status_t checkIMemory(const sp<IMemory>& iMemory) return NO_ERROR; } // TODO(b/285588444), clean this up on main, but soak it for backporting purposes for now namespace { class BluetoothPermissionCache { static constexpr auto SYSPROP_NAME = "cache_key.system_server.package_info"; const String16 BLUETOOTH_PERM {"android.permission.BLUETOOTH_CONNECT"}; mutable std::mutex mLock; // Cached property conditionally defined, since only avail on bionic. On host, don't inval cache #if defined(__BIONIC__) // Unlocked, but only accessed from mListenerThread base::CachedProperty mCachedProperty; #endif // This thread is designed to never join/terminate, so no signal is fine const std::thread mListenerThread; GUARDED_BY(mLock) std::string mPropValue; GUARDED_BY(mLock) std::unordered_map<uid_t, bool> mCache; PermissionController mPc{}; public: BluetoothPermissionCache() #if defined(__BIONIC__) : mCachedProperty{SYSPROP_NAME}, mListenerThread([this]() mutable { while (true) { std::string newVal = mCachedProperty.WaitForChange() ?: ""; std::lock_guard l{mLock}; if (newVal != mPropValue) { ALOGV("Bluetooth permission update"); mPropValue = newVal; mCache.clear(); } } }) #endif {} bool checkPermission(uid_t uid, pid_t pid) { std::lock_guard l{mLock}; auto it = mCache.find(uid); if (it == mCache.end()) { it = mCache.insert({uid, mPc.checkPermission(BLUETOOTH_PERM, uid, pid)}).first; } return it->second; } }; // Don't call this from locks, since it potentially calls up to system server! // Check for non-app UIDs above this method! bool checkBluetoothPermission(const AttributionSourceState& attr) { [[clang::no_destroy]] static BluetoothPermissionCache impl{}; return impl.checkPermission(attr.uid, attr.pid); } } // anonymous /** * Determines if the MAC address in Bluetooth device descriptors returned by APIs of * a native audio service (audio flinger, audio policy) must be anonymized. * MAC addresses returned to system server or apps with BLUETOOTH_CONNECT permission * are not anonymized. * * @param attributionSource The attribution source of the calling app. * @param caller string identifying the caller for logging. * @return true if the MAC addresses must be anonymized, false otherwise. */ bool mustAnonymizeBluetoothAddress( const AttributionSourceState& attributionSource, const String16&) { uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid)); bool res; switch(multiuser_get_app_id(uid)) { case AID_ROOT: case AID_SYSTEM: case AID_RADIO: case AID_BLUETOOTH: case AID_MEDIA: case AID_AUDIOSERVER: // Don't anonymize for privileged clients res = false; break; default: res = !checkBluetoothPermission(attributionSource); break; } ALOGV("%s uid: %d, result: %d", __func__, uid, res); return res; } /** * Modifies the passed MAC address string in place for consumption by unprivileged clients. * the string is assumed to have a valid MAC address format. * the anonymization must be kept in sync with toAnonymizedAddress() in BluetoothUtils.java * * @param address input/output the char string contining the MAC address to anonymize. */ void anonymizeBluetoothAddress(char *address) { if (address == nullptr || strlen(address) != strlen("AA:BB:CC:DD:EE:FF")) { return; } memcpy(address, "XX:XX:XX:XX", strlen("XX:XX:XX:XX")); } sp<content::pm::IPackageManagerNative> MediaPackageManager::retrievePackageManager() { const sp<IServiceManager> sm = defaultServiceManager(); if (sm == nullptr) { Loading
media/utils/include/mediautils/ServiceUtilities.h +4 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,10 @@ bool modifyPhoneStateAllowed(const AttributionSourceState& attributionSource); bool bypassInterruptionPolicyAllowed(const AttributionSourceState& attributionSource); bool callAudioInterceptionAllowed(const AttributionSourceState& attributionSource); void purgePermissionCache(); bool mustAnonymizeBluetoothAddress( const AttributionSourceState& attributionSource, const String16& caller); void anonymizeBluetoothAddress(char *address); int32_t getOpForSource(audio_source_t source); AttributionSourceState getCallingAttributionSource(); Loading