Check for app manifest opt-out from playback capture

Query the package manager to check if the app has not opt-out of its
playback being captured.

Test: adb shell audiorecorder   --target /data/file1.raw &
      adb shell am start -a android.intent.action.VIEW -d file:///system/media/audio/ringtones/Lollipop.ogg -t audio/ogg
      adb dumpsys media.audio_policy # check playback is not recorded
      # change media player manifest to allowPlaybackCapture=true
      adb dumpsys media.audio_policy # check playback is recorded
      kill %1
      adb pull /data/file1.raw && sox -r 48000 -e signed -b 16 -c 2 file1.raw file.wav&& audacity file.wav
      # check silence then sound

Bug: 111453086
Change-Id: Id6fb7d0e10c02b0473bcbc0786e8360536996f48
Signed-off-by: Kevin Rocard <krocard@google.com>
gugelfrei
Kevin Rocard 5 years ago
parent be20185b2f
commit 8be94978a3

@ -16,6 +16,7 @@ LOCAL_SHARED_LIBRARIES := \
libhwbinder \
libmedia \
libmedialogservice \
libmediautils \
libnbaio \
libnblog \
libsoundtriggerservice \

@ -22,6 +22,9 @@
#include <binder/PermissionCache.h>
#include "mediautils/ServiceUtilities.h"
#include <iterator>
#include <algorithm>
/* When performing permission checks we do not use permission cache for
* runtime permissions (protection level dangerous) as they may change at
* runtime. All other permissions (protection level normal and dangerous)
@ -220,4 +223,85 @@ status_t checkIMemory(const sp<IMemory>& iMemory)
return NO_ERROR;
}
sp<content::pm::IPackageManagerNative> MediaPackageManager::retreivePackageManager() {
const sp<IServiceManager> sm = defaultServiceManager();
if (sm == nullptr) {
ALOGW("%s: failed to retrieve defaultServiceManager", __func__);
return nullptr;
}
sp<IBinder> packageManager = sm->checkService(String16(nativePackageManagerName));
if (packageManager == nullptr) {
ALOGW("%s: failed to retrieve native package manager", __func__);
return nullptr;
}
return interface_cast<content::pm::IPackageManagerNative>(packageManager);
}
std::optional<bool> MediaPackageManager::doIsAllowed(uid_t uid) {
if (mPackageManager == nullptr) {
/** Can not fetch package manager at construction it may not yet be registered. */
mPackageManager = retreivePackageManager();
if (mPackageManager == nullptr) {
ALOGW("%s: Playback capture is denied as package manager is not reachable", __func__);
return std::nullopt;
}
}
std::vector<std::string> packageNames;
auto status = mPackageManager->getNamesForUids({(int32_t)uid}, &packageNames);
if (!status.isOk()) {
ALOGW("%s: Playback capture is denied for uid %u as the package names could not be "
"retrieved from the package manager: %s", __func__, uid, status.toString8().c_str());
return std::nullopt;
}
if (packageNames.empty()) {
ALOGW("%s: Playback capture for uid %u is denied as no package name could be retrieved "
"from the package manager: %s", __func__, uid, status.toString8().c_str());
return std::nullopt;
}
std::vector<bool> isAllowed;
status = mPackageManager->isAudioPlaybackCaptureAllowed(packageNames, &isAllowed);
if (!status.isOk()) {
ALOGW("%s: Playback capture is denied for uid %u as the manifest property could not be "
"retrieved from the package manager: %s", __func__, uid, status.toString8().c_str());
return std::nullopt;
}
if (packageNames.size() != isAllowed.size()) {
ALOGW("%s: Playback capture is denied for uid %u as the package manager returned incoherent"
" response size: %zu != %zu", __func__, uid, packageNames.size(), isAllowed.size());
return std::nullopt;
}
// Zip together packageNames and isAllowed for debug logs
Packages& packages = mDebugLog[uid];
packages.resize(packageNames.size()); // Reuse all objects
std::transform(begin(packageNames), end(packageNames), begin(isAllowed),
begin(packages), [] (auto& name, bool isAllowed) -> Package {
return {std::move(name), isAllowed};
});
// Only allow playback record if all packages in this UID allow it
bool playbackCaptureAllowed = std::all_of(begin(isAllowed), end(isAllowed),
[](bool b) { return b; });
return playbackCaptureAllowed;
}
void MediaPackageManager::dump(int fd, int spaces) const {
dprintf(fd, "%*sAllow playback capture log:\n", spaces, "");
if (mPackageManager == nullptr) {
dprintf(fd, "%*sNo package manager\n", spaces + 2, "");
}
dprintf(fd, "%*sPackage manager errors: %u\n", spaces + 2, "", mPackageManagerErrors);
for (const auto& uidCache : mDebugLog) {
for (const auto& package : std::get<Packages>(uidCache)) {
dprintf(fd, "%*s- uid=%5u, allowPlaybackCapture=%s, packageName=%s\n", spaces + 2, "",
std::get<const uid_t>(uidCache),
package.playbackCaptureAllowed ? "true " : "false",
package.name.c_str());
}
}
}
} // namespace android

@ -14,13 +14,22 @@
* limitations under the License.
*/
#ifndef ANDROID_MEDIAUTILS_SERVICEUTILITIES_H
#define ANDROID_MEDIAUTILS_SERVICEUTILITIES_H
#include <unistd.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <binder/IMemory.h>
#include <binder/PermissionController.h>
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
#include <map>
#include <optional>
#include <string>
#include <vector>
namespace android {
// Audio permission utilities
@ -72,4 +81,31 @@ bool modifyDefaultAudioEffectsAllowed();
bool dumpAllowed();
bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
status_t checkIMemory(const sp<IMemory>& iMemory);
class MediaPackageManager {
public:
/** Query the PackageManager to check if all apps of an UID allow playback capture. */
bool allowPlaybackCapture(uid_t uid) {
auto result = doIsAllowed(uid);
if (!result) {
mPackageManagerErrors++;
}
return result.value_or(false);
}
void dump(int fd, int spaces = 0) const;
private:
static constexpr const char* nativePackageManagerName = "package_native";
std::optional<bool> doIsAllowed(uid_t uid);
sp<content::pm::IPackageManagerNative> retreivePackageManager();
sp<content::pm::IPackageManagerNative> mPackageManager; // To check apps manifest
uint_t mPackageManagerErrors = 0;
struct Package {
std::string name;
bool playbackCaptureAllowed = false;
};
using Packages = std::vector<Package>;
std::map<uid_t, Packages> mDebugLog;
};
}
#endif // ANDROID_MEDIAUTILS_SERVICEUTILITIES_H

@ -90,7 +90,7 @@ LOCAL_STATIC_LIBRARIES := \
LOCAL_SHARED_LIBRARIES += libmedia_helper
LOCAL_SHARED_LIBRARIES += libmediametrics
LOCAL_SHARED_LIBRARIES += libhidlbase libxml2
LOCAL_SHARED_LIBRARIES += libbinder libhidlbase libxml2
ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF

@ -20,7 +20,6 @@
#include "AudioPolicyService.h"
#include "TypeConverter.h"
#include <media/MediaAnalyticsItem.h>
#include <mediautils/ServiceUtilities.h>
#include <media/AudioPolicy.h>
#include <utils/Log.h>
@ -167,7 +166,7 @@ audio_io_handle_t AudioPolicyService::getOutput(audio_stream_type_t stream)
return mAudioPolicyManager->getOutput(stream);
}
status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *originalAttr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
@ -191,9 +190,13 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
"%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
uid = callingUid;
}
audio_attributes_t attr = *originalAttr;
if (!mPackageManager.allowPlaybackCapture(uid)) {
attr.flags |= AUDIO_FLAG_NO_CAPTURE;
}
audio_output_flags_t originalFlags = flags;
AutoCallerClear acc;
status_t result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid,
status_t result = mAudioPolicyManager->getOutputForAttr(&attr, output, session, stream, uid,
config,
&flags, selectedDeviceId, portId,
secondaryOutputs);
@ -209,14 +212,14 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
*selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
*portId = AUDIO_PORT_HANDLE_NONE;
secondaryOutputs->clear();
result = mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, config,
result = mAudioPolicyManager->getOutputForAttr(&attr, output, session, stream, uid, config,
&flags, selectedDeviceId, portId,
secondaryOutputs);
}
if (result == NO_ERROR) {
sp <AudioPlaybackClient> client =
new AudioPlaybackClient(*attr, *output, uid, pid, session, *selectedDeviceId, *stream);
new AudioPlaybackClient(attr, *output, uid, pid, session, *selectedDeviceId, *stream);
mAudioPlaybackClients.add(*portId, client);
}
return result;

@ -551,6 +551,8 @@ status_t AudioPolicyService::dump(int fd, const Vector<String16>& args __unused)
mAudioPolicyManager->dump(fd);
}
mPackageManager.dump(fd);
if (locked) mLock.unlock();
}
return NO_ERROR;

@ -31,6 +31,7 @@
#include <media/ToneGenerator.h>
#include <media/AudioEffect.h>
#include <media/AudioPolicy.h>
#include <mediautils/ServiceUtilities.h>
#include "AudioPolicyEffects.h"
#include "managerdefault/AudioPolicyManager.h"
#include <android/hardware/BnSensorPrivacyListener.h>
@ -784,6 +785,8 @@ private:
DefaultKeyedVector< audio_port_handle_t, sp<AudioRecordClient> > mAudioRecordClients;
DefaultKeyedVector< audio_port_handle_t, sp<AudioPlaybackClient> > mAudioPlaybackClients;
MediaPackageManager mPackageManager; // To check allowPlaybackCapture
};
} // namespace android

Loading…
Cancel
Save