summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.cpp6
-rw-r--r--services/audioflinger/AudioFlinger.h2
-rw-r--r--services/audioflinger/PlaybackTracks.h5
-rw-r--r--services/audioflinger/ServiceUtilities.cpp84
-rw-r--r--services/audioflinger/ServiceUtilities.h3
-rw-r--r--services/audioflinger/Tracks.cpp47
-rw-r--r--services/audiopolicy/AudioPolicyInterface.h4
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp6
-rw-r--r--services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp4
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.cpp167
-rw-r--r--services/audiopolicy/managerdefault/AudioPolicyManager.h47
-rw-r--r--services/audiopolicy/service/AudioPolicyEffects.cpp6
-rw-r--r--services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp27
-rw-r--r--services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp2
-rw-r--r--services/audiopolicy/service/AudioPolicyService.cpp2
-rw-r--r--services/audiopolicy/service/AudioPolicyService.h2
-rw-r--r--services/camera/libcameraservice/CameraService.cpp16
-rw-r--r--services/camera/libcameraservice/CameraService.h9
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.cpp117
-rw-r--r--services/camera/libcameraservice/api1/client2/Parameters.h13
20 files changed, 346 insertions, 223 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 3e4b1fc..bd6889d 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1421,6 +1421,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
+ const String16& opPackageName,
size_t *frameCount,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
@@ -1440,7 +1441,7 @@ sp<IAudioRecord> AudioFlinger::openRecord(
buffers.clear();
// check calling permissions
- if (!recordingAllowed()) {
+ if (!recordingAllowed(opPackageName)) {
ALOGE("openRecord() permission denied: recording not allowed");
lStatus = PERMISSION_DENIED;
goto Exit;
@@ -2456,6 +2457,7 @@ sp<IEffect> AudioFlinger::createEffect(
int32_t priority,
audio_io_handle_t io,
int sessionId,
+ const String16& opPackageName,
status_t *status,
int *id,
int *enabled)
@@ -2552,7 +2554,7 @@ sp<IEffect> AudioFlinger::createEffect(
// check recording permission for visualizer
if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
- !recordingAllowed()) {
+ !recordingAllowed(opPackageName)) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8e06138..8085ec2 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -120,6 +120,7 @@ public:
uint32_t sampleRate,
audio_format_t format,
audio_channel_mask_t channelMask,
+ const String16& opPackageName,
size_t *pFrameCount,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
@@ -216,6 +217,7 @@ public:
int32_t priority,
audio_io_handle_t io,
int sessionId,
+ const String16& opPackageName,
status_t *status /*non-NULL*/,
int *id,
int *enabled);
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index c51021b..7bc6f0c 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -156,11 +156,6 @@ private:
bool mResumeToStopping; // track was paused in stopping state.
bool mFlushHwPending; // track requests for thread flush
- // for last call to getTimestamp
- bool mPreviousTimestampValid;
- // This is either the first timestamp or one that has passed
- // the check to prevent retrograde motion.
- AudioTimestamp mPreviousTimestamp;
}; // end of Track
class TimedTrack : public Track {
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 8246fef..0a718fb 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -14,38 +14,97 @@
* limitations under the License.
*/
+#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PermissionCache.h>
#include "ServiceUtilities.h"
+/* 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)
+ * can be cached as they never change. Of course all permission checked
+ * here are platform defined.
+ */
+
namespace android {
// Not valid until initialized by AudioFlinger constructor. It would have to be
// re-initialized if the process containing AudioFlinger service forks (which it doesn't).
pid_t getpid_cached;
-bool recordingAllowed() {
+bool recordingAllowed(const String16& opPackageName) {
+ // Note: We are getting the UID from the calling IPC thread state because all
+ // clients that perform recording create AudioRecord in their own processes
+ // and the system does not create AudioRecord objects on behalf of apps. This
+ // differs from playback where in some situations the system recreates AudioTrack
+ // instances associated with a client's MediaPlayer on behalf of this client.
+ // In the latter case we have to store the client UID and pass in along for
+ // security checks.
+
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
static const String16 sRecordAudio("android.permission.RECORD_AUDIO");
- // don't use PermissionCache; this is not a system permission
- bool ok = checkCallingPermission(sRecordAudio);
- if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO");
- return ok;
+
+ // IMPORTANT: Don't use PermissionCache - a runtime permission and may change.
+ const bool ok = checkCallingPermission(sRecordAudio);
+ if (!ok) {
+ ALOGE("Request requires android.permission.RECORD_AUDIO");
+ return false;
+ }
+
+ const uid_t uid = IPCThreadState::self()->getCallingUid();
+ String16 checkedOpPackageName = opPackageName;
+
+ // In some cases the calling code has no access to the package it runs under.
+ // For example, code using the wilhelm framework's OpenSL-ES APIs. In this
+ // case we will get the packages for the calling UID and pick the first one
+ // for attributing the app op. This will work correctly for runtime permissions
+ // as for legacy apps we will toggle the app op for all packages in the UID.
+ // The caveat is that the operation may be attributed to the wrong package and
+ // stats based on app ops may be slightly off.
+ if (checkedOpPackageName.size() <= 0) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("permission"));
+ if (binder == 0) {
+ ALOGE("Cannot get permission service");
+ return false;
+ }
+
+ sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
+ Vector<String16> packages;
+
+ permCtrl->getPackagesForUid(uid, packages);
+
+ if (packages.isEmpty()) {
+ ALOGE("No packages for calling UID");
+ return false;
+ }
+ checkedOpPackageName = packages[0];
+ }
+
+ AppOpsManager appOps;
+ if (appOps.noteOp(AppOpsManager::OP_RECORD_AUDIO, uid, opPackageName)
+ != AppOpsManager::MODE_ALLOWED) {
+ ALOGE("Request denied by app op OP_RECORD_AUDIO");
+ return false;
+ }
+
+ return true;
}
bool captureAudioOutputAllowed() {
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
static const String16 sCaptureAudioOutput("android.permission.CAPTURE_AUDIO_OUTPUT");
- // don't use PermissionCache; this is not a system permission
- bool ok = checkCallingPermission(sCaptureAudioOutput);
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sCaptureAudioOutput);
if (!ok) ALOGE("Request requires android.permission.CAPTURE_AUDIO_OUTPUT");
return ok;
}
bool captureHotwordAllowed() {
static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD");
- bool ok = checkCallingPermission(sCaptureHotwordAllowed);
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sCaptureHotwordAllowed);
if (!ok) ALOGE("android.permission.CAPTURE_AUDIO_HOTWORD");
return ok;
}
@@ -53,15 +112,16 @@ bool captureHotwordAllowed() {
bool settingsAllowed() {
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
- // don't use PermissionCache; this is not a system permission
- bool ok = checkCallingPermission(sAudioSettings);
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sAudioSettings);
if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
return ok;
}
bool modifyAudioRoutingAllowed() {
static const String16 sModifyAudioRoutingAllowed("android.permission.MODIFY_AUDIO_ROUTING");
- bool ok = checkCallingPermission(sModifyAudioRoutingAllowed);
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sModifyAudioRoutingAllowed);
if (!ok) ALOGE("android.permission.MODIFY_AUDIO_ROUTING");
return ok;
}
@@ -69,7 +129,7 @@ bool modifyAudioRoutingAllowed() {
bool dumpAllowed() {
// don't optimize for same pid, since mediaserver never dumps itself
static const String16 sDump("android.permission.DUMP");
- // OK to use PermissionCache; this is a system permission
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
bool ok = PermissionCache::checkCallingPermission(sDump);
// convention is for caller to dump an error message to fd instead of logging here
//if (!ok) ALOGE("Request requires android.permission.DUMP");
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index df6f6f4..fba6dce 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -20,11 +20,10 @@ namespace android {
extern pid_t getpid_cached;
-bool recordingAllowed();
+bool recordingAllowed(const String16& opPackageName);
bool captureAudioOutputAllowed();
bool captureHotwordAllowed();
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
bool dumpAllowed();
-
}
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index c6e9745..1b03060 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -404,8 +404,7 @@ AudioFlinger::PlaybackThread::Track::Track(
mIsInvalid(false),
mAudioTrackServerProxy(NULL),
mResumeToStopping(false),
- mFlushHwPending(false),
- mPreviousTimestampValid(false)
+ mFlushHwPending(false)
{
// client == 0 implies sharedBuffer == 0
ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
@@ -863,7 +862,6 @@ void AudioFlinger::PlaybackThread::Track::reset()
if (mState == FLUSHED) {
mState = IDLE;
}
- mPreviousTimestampValid = false;
}
}
@@ -885,12 +883,10 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times
{
// Client should implement this using SSQ; the unpresented frame count in latch is irrelevant
if (isFastTrack()) {
- // FIXME no lock held to set mPreviousTimestampValid = false
return INVALID_OPERATION;
}
sp<ThreadBase> thread = mThread.promote();
if (thread == 0) {
- // FIXME no lock held to set mPreviousTimestampValid = false
return INVALID_OPERATION;
}
@@ -900,7 +896,6 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times
status_t result = INVALID_OPERATION;
if (!isOffloaded() && !isDirect()) {
if (!playbackThread->mLatchQValid) {
- mPreviousTimestampValid = false;
return INVALID_OPERATION;
}
// FIXME Not accurate under dynamic changes of sample rate and speed.
@@ -919,10 +914,7 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times
uint32_t framesWritten = i >= 0 ?
playbackThread->mLatchQ.mFramesReleased[i] :
mAudioTrackServerProxy->framesReleased();
- if (framesWritten < unpresentedFrames) {
- mPreviousTimestampValid = false;
- // return invalid result
- } else {
+ if (framesWritten >= unpresentedFrames) {
timestamp.mPosition = framesWritten - unpresentedFrames;
timestamp.mTime = playbackThread->mLatchQ.mTimestamp.mTime;
result = NO_ERROR;
@@ -931,41 +923,6 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times
result = playbackThread->getTimestamp_l(timestamp);
}
- // Prevent retrograde motion in timestamp.
- if (result == NO_ERROR) {
- if (mPreviousTimestampValid) {
- if (timestamp.mTime.tv_sec < mPreviousTimestamp.mTime.tv_sec ||
- (timestamp.mTime.tv_sec == mPreviousTimestamp.mTime.tv_sec &&
- timestamp.mTime.tv_nsec < mPreviousTimestamp.mTime.tv_nsec)) {
- ALOGW("WARNING - retrograde timestamp time");
- // FIXME Consider blocking this from propagating upwards.
- }
-
- // Looking at signed delta will work even when the timestamps
- // are wrapping around.
- int32_t deltaPosition = static_cast<int32_t>(timestamp.mPosition
- - mPreviousTimestamp.mPosition);
- // position can bobble slightly as an artifact; this hides the bobble
- static const int32_t MINIMUM_POSITION_DELTA = 8;
- if (deltaPosition < 0) {
-#define TIME_TO_NANOS(time) ((uint64_t)time.tv_sec * 1000000000 + time.tv_nsec)
- ALOGW("WARNING - retrograde timestamp position corrected,"
- " %d = %u - %u, (at %llu, %llu nanos)",
- deltaPosition,
- timestamp.mPosition,
- mPreviousTimestamp.mPosition,
- TIME_TO_NANOS(timestamp.mTime),
- TIME_TO_NANOS(mPreviousTimestamp.mTime));
-#undef TIME_TO_NANOS
- }
- if (deltaPosition < MINIMUM_POSITION_DELTA) {
- // Current timestamp is bad. Use last valid timestamp.
- timestamp = mPreviousTimestamp;
- }
- }
- mPreviousTimestamp = timestamp;
- mPreviousTimestampValid = true;
- }
return result;
}
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 9230750..8523fc5 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -106,6 +106,7 @@ public:
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -129,6 +130,7 @@ public:
virtual status_t getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -209,7 +211,7 @@ public:
struct audio_patch *patches,
unsigned int *generation) = 0;
virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
- virtual void clearAudioPatches(uid_t uid) = 0;
+ virtual void releaseResourcesForUid(uid_t uid) = 0;
virtual status_t acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 144d8ad..a278375 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -315,13 +315,15 @@ void SwAudioOutputDescriptor::changeRefCount(audio_stream_type_t stream,
mGlobalRefCount += delta;
}
if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) {
- if ((mPolicyMix != NULL) && ((mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) {
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
MIX_STATE_MIXING);
}
} else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) {
- if ((mPolicyMix != NULL) && ((mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) {
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
MIX_STATE_IDLE);
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 77fc0b9..6f1998c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -176,14 +176,14 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A
ssize_t index = indexOfKey(address);
if (index < 0) {
- ALOGW("getInputForAttr() no policy for address %s", address.string());
+ ALOGW("getInputMixForAttr() no policy for address %s", address.string());
return BAD_VALUE;
}
sp<AudioPolicyMix> audioPolicyMix = valueAt(index);
AudioMix *mix = audioPolicyMix->getMix();
if (mix->mMixType != MIX_TYPE_PLAYERS) {
- ALOGW("getInputForAttr() bad policy mix type for address %s", address.string());
+ ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string());
return BAD_VALUE;
}
*policyMix = mix;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 7de72de..b7eed62 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -620,6 +620,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -659,8 +660,22 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
return BAD_VALUE;
}
- ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x",
- attributes.usage, attributes.content_type, attributes.tags, attributes.flags);
+ ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x"
+ " session %d selectedDeviceId %d",
+ attributes.usage, attributes.content_type, attributes.tags, attributes.flags,
+ session, selectedDeviceId);
+
+ *stream = streamTypefromAttributesInt(&attributes);
+
+ // Explicit routing?
+ sp<DeviceDescriptor> deviceDesc;
+ for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
+ if (mAvailableOutputDevices[i]->getId() == selectedDeviceId) {
+ deviceDesc = mAvailableOutputDevices[i];
+ break;
+ }
+ }
+ mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
@@ -672,24 +687,14 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
ALOGV("getOutputForAttr() device 0x%x, samplingRate %d, format %x, channelMask %x, flags %x",
device, samplingRate, format, channelMask, flags);
- *stream = streamTypefromAttributesInt(&attributes);
*output = getOutputForDevice(device, session, *stream,
samplingRate, format, channelMask,
flags, offloadInfo);
if (*output == AUDIO_IO_HANDLE_NONE) {
+ mOutputRoutes.removeRoute(session);
return INVALID_OPERATION;
}
- // Explicit routing?
- sp<DeviceDescriptor> deviceDesc;
-
- for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) {
- if (mAvailableOutputDevices[i]->getId() == selectedDeviceId) {
- deviceDesc = mAvailableOutputDevices[i];
- break;
- }
- }
- mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc);
return NO_ERROR;
}
@@ -966,24 +971,26 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ // Routing?
+ mOutputRoutes.incRouteActivity(session);
+
audio_devices_t newDevice;
if (outputDesc->mPolicyMix != NULL) {
newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
} else if (mOutputRoutes.hasRouteChanged(session)) {
newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
+ checkStrategyRoute(getStrategy(stream), output);
} else {
newDevice = AUDIO_DEVICE_NONE;
}
uint32_t delayMs = 0;
- // Routing?
- mOutputRoutes.incRouteActivity(session);
-
status_t status = startSource(outputDesc, stream, newDevice, &delayMs);
if (status != NO_ERROR) {
mOutputRoutes.decRouteActivity(session);
+ return status;
}
// Automatically enable the remote submix input when output is started on a re routing mix
// of type MIX_TYPE_RECORDERS
@@ -1112,15 +1119,22 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
}
// Routing?
+ bool forceDeviceUpdate = false;
if (outputDesc->mRefCount[stream] > 0) {
- mOutputRoutes.decRouteActivity(session);
+ int activityCount = mOutputRoutes.decRouteActivity(session);
+ forceDeviceUpdate = (mOutputRoutes.hasRoute(session) && (activityCount == 0));
+
+ if (forceDeviceUpdate) {
+ checkStrategyRoute(getStrategy(stream), AUDIO_IO_HANDLE_NONE);
+ }
}
- return stopSource(outputDesc, stream);
+ return stopSource(outputDesc, stream, forceDeviceUpdate);
}
status_t AudioPolicyManager::stopSource(sp<AudioOutputDescriptor> outputDesc,
- audio_stream_type_t stream)
+ audio_stream_type_t stream,
+ bool forceDeviceUpdate)
{
// always handle stream stop, check which stream type is stopping
handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT);
@@ -1135,7 +1149,7 @@ status_t AudioPolicyManager::stopSource(sp<AudioOutputDescriptor> outputDesc,
outputDesc->changeRefCount(stream, -1);
// store time at which the stream was stopped - see isStreamActive()
- if (outputDesc->mRefCount[stream] == 0) {
+ if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) {
outputDesc->mStopTime[stream] = systemTime();
audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
// delay the device switch by twice the latency because stopOutput() is executed when
@@ -1222,6 +1236,7 @@ void AudioPolicyManager::releaseOutput(audio_io_handle_t output,
status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -1256,7 +1271,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
break;
}
}
- mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc);
+ mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
@@ -1431,17 +1446,17 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input,
}
}
+ // Routing?
+ mInputRoutes.incRouteActivity(session);
+
if (inputDesc->mRefCount == 0 || mInputRoutes.hasRouteChanged(session)) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
- && ((inputDesc->mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) {
+ && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
MIX_STATE_MIXING);
}
- // Routing?
- mInputRoutes.incRouteActivity(session);
-
if (mInputs.activeInputsCount() == 0) {
SoundTrigger::setCaptureState(true);
}
@@ -1501,7 +1516,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
if (inputDesc->mRefCount == 0) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
- && ((inputDesc->mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) {
+ && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId,
MIX_STATE_IDLE);
}
@@ -2479,6 +2494,12 @@ status_t AudioPolicyManager::setAudioPortConfig(const struct audio_port_config *
return status;
}
+void AudioPolicyManager::releaseResourcesForUid(uid_t uid)
+{
+ clearAudioPatches(uid);
+ clearSessionRoutes(uid);
+}
+
void AudioPolicyManager::clearAudioPatches(uid_t uid)
{
for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) {
@@ -2489,6 +2510,82 @@ void AudioPolicyManager::clearAudioPatches(uid_t uid)
}
}
+
+void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy,
+ audio_io_handle_t ouptutToSkip)
+{
+ audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+ SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs);
+ for (size_t j = 0; j < mOutputs.size(); j++) {
+ if (mOutputs.keyAt(j) == ouptutToSkip) {
+ continue;
+ }
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(j);
+ if (!isStrategyActive(outputDesc, (routing_strategy)strategy)) {
+ continue;
+ }
+ // If the default device for this strategy is on another output mix,
+ // invalidate all tracks in this strategy to force re connection.
+ // Otherwise select new device on the output mix.
+ if (outputs.indexOf(mOutputs.keyAt(j)) < 0) {
+ for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) {
+ if (stream == AUDIO_STREAM_PATCH) {
+ continue;
+ }
+ if (getStrategy((audio_stream_type_t)stream) == strategy) {
+ mpClientInterface->invalidateStream((audio_stream_type_t)stream);
+ }
+ }
+ } else {
+ audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
+ setOutputDevice(outputDesc, newDevice, false);
+ }
+ }
+}
+
+void AudioPolicyManager::clearSessionRoutes(uid_t uid)
+{
+ // remove output routes associated with this uid
+ SortedVector<routing_strategy> affectedStrategies;
+ for (ssize_t i = (ssize_t)mOutputRoutes.size() - 1; i >= 0; i--) {
+ sp<SessionRoute> route = mOutputRoutes.valueAt(i);
+ if (route->mUid == uid) {
+ mOutputRoutes.removeItemsAt(i);
+ if (route->mDeviceDescriptor != 0) {
+ affectedStrategies.add(getStrategy(route->mStreamType));
+ }
+ }
+ }
+ // reroute outputs if necessary
+ for (size_t i = 0; i < affectedStrategies.size(); i++) {
+ checkStrategyRoute(affectedStrategies[i], AUDIO_IO_HANDLE_NONE);
+ }
+
+ // remove input routes associated with this uid
+ SortedVector<audio_source_t> affectedSources;
+ for (ssize_t i = (ssize_t)mInputRoutes.size() - 1; i >= 0; i--) {
+ sp<SessionRoute> route = mInputRoutes.valueAt(i);
+ if (route->mUid == uid) {
+ mInputRoutes.removeItemsAt(i);
+ if (route->mDeviceDescriptor != 0) {
+ affectedSources.add(route->mSource);
+ }
+ }
+ }
+ // reroute inputs if necessary
+ SortedVector<audio_io_handle_t> inputsToClose;
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
+ if (affectedSources.indexOf(inputDesc->mInputSource) >= 0) {
+ inputsToClose.add(inputDesc->mIoHandle);
+ }
+ }
+ for (size_t i = 0; i < inputsToClose.size(); i++) {
+ closeInput(inputsToClose[i]);
+ }
+}
+
+
status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
audio_devices_t *device)
@@ -3563,7 +3660,8 @@ SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(
ALOGVV("getOutputsForDevice() device %04x", device);
for (size_t i = 0; i < openOutputs.size(); i++) {
ALOGVV("output %d isDuplicated=%d device=%04x",
- i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices());
+ i, openOutputs.valueAt(i)->isDuplicated(),
+ openOutputs.valueAt(i)->supportedDevices());
if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) {
ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i));
outputs.add(openOutputs.keyAt(i));
@@ -3925,7 +4023,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate
for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
routing_strategy strat = getStrategy(route->mStreamType);
- if (strat == strategy && route->mDeviceDescriptor != 0 /*&& route->mActivityCount != 0*/) {
+ if (strat == strategy && route->isActive()) {
return route->mDeviceDescriptor->type();
}
}
@@ -4315,8 +4413,7 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input
{
for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {
sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);
- if (inputSource == route->mSource && route->mDeviceDescriptor != 0
- /*&& route->mActivityCount != 0*/) {
+ if (inputSource == route->mSource && route->isActive()) {
return route->mDeviceDescriptor->type();
}
}
@@ -4605,7 +4702,8 @@ void AudioPolicyManager::SessionRouteMap::log(const char* caption) {
void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session,
audio_stream_type_t streamType,
audio_source_t source,
- sp<DeviceDescriptor> descriptor)
+ sp<DeviceDescriptor> descriptor,
+ uid_t uid)
{
if (mMapType == MAPTYPE_INPUT && streamType != SessionRoute::STREAM_TYPE_NA) {
ALOGE("Adding Output Route to InputRouteMap");
@@ -4618,14 +4716,15 @@ void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session,
sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0;
if (route != 0) {
- if ((route->mDeviceDescriptor == 0 && descriptor != 0) ||
- (!route->mDeviceDescriptor->equals(descriptor))) {
+ if (((route->mDeviceDescriptor == 0) && (descriptor != 0)) ||
+ ((route->mDeviceDescriptor != 0) &&
+ ((descriptor == 0) || (!route->mDeviceDescriptor->equals(descriptor))))) {
route->mChanged = true;
}
route->mRefCount++;
route->mDeviceDescriptor = descriptor;
} else {
- route = new AudioPolicyManager::SessionRoute(session, streamType, source, descriptor);
+ route = new AudioPolicyManager::SessionRoute(session, streamType, source, descriptor, uid);
route->mRefCount++;
add(session, route);
if (descriptor != 0) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index b965411..ea16864 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -109,6 +109,7 @@ public:
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -127,6 +128,7 @@ public:
virtual status_t getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -207,7 +209,6 @@ public:
struct audio_patch *patches,
unsigned int *generation);
virtual status_t setAudioPortConfig(const struct audio_port_config *config);
- virtual void clearAudioPatches(uid_t uid);
virtual status_t acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
@@ -226,6 +227,8 @@ public:
audio_io_handle_t *handle);
virtual status_t stopAudioSource(audio_io_handle_t handle);
+ virtual void releaseResourcesForUid(uid_t uid);
+
// Audio policy configuration file parsing (audio_policy.conf)
// TODO candidates to be moved to ConfigParsingUtils
void defaultAudioPolicyConfig(void);
@@ -248,31 +251,36 @@ protected:
SessionRoute(audio_session_t session,
audio_stream_type_t streamType,
audio_source_t source,
- sp<DeviceDescriptor> deviceDescriptor)
- : mSession(session),
+ sp<DeviceDescriptor> deviceDescriptor,
+ uid_t uid)
+ : mUid(uid),
+ mSession(session),
mDeviceDescriptor(deviceDescriptor),
mRefCount(0),
mActivityCount(0),
mChanged(false),
mStreamType(streamType),
- mSource(source) {}
+ mSource(source)
+ {}
- audio_session_t mSession;
+ void log(const char* prefix);
- sp<DeviceDescriptor> mDeviceDescriptor;
+ bool isActive() {
+ return (mDeviceDescriptor != 0) && (mChanged || (mActivityCount > 0));
+ }
- void log(const char* prefix);
+ uid_t mUid;
+ audio_session_t mSession;
+ sp<DeviceDescriptor> mDeviceDescriptor;
// "reference" counting
- int mRefCount; // +/- on references
- int mActivityCount; // +/- on start/stop
- bool mChanged;
-
+ int mRefCount; // +/- on references
+ int mActivityCount; // +/- on start/stop
+ bool mChanged;
// for outputs
- const audio_stream_type_t mStreamType;
-
+ const audio_stream_type_t mStreamType;
// for inputs
- const audio_source_t mSource;
+ const audio_source_t mSource;
};
class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute>> {
@@ -292,6 +300,7 @@ protected:
}
bool hasRoute(audio_session_t session);
+
void removeRoute(audio_session_t session);
int incRouteActivity(audio_session_t session);
@@ -306,7 +315,8 @@ protected:
void addRoute(audio_session_t session,
audio_stream_type_t streamType,
audio_source_t source,
- sp<DeviceDescriptor> deviceDescriptor);
+ sp<DeviceDescriptor> deviceDescriptor,
+ uid_t uid);
private:
// Used to mark a SessionRoute as for either inputs (mMapType == kSessionRouteMap_Input)
@@ -559,7 +569,12 @@ protected:
audio_devices_t device,
uint32_t *delayMs);
status_t stopSource(sp<AudioOutputDescriptor> outputDesc,
- audio_stream_type_t stream);
+ audio_stream_type_t stream,
+ bool forceDeviceUpdate);
+
+ void clearAudioPatches(uid_t uid);
+ void clearSessionRoutes(uid_t uid);
+ void checkStrategyRoute(routing_strategy strategy, audio_io_handle_t ouptutToSkip);
uid_t mUidCached;
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index e6ace20..282ddeb 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -109,8 +109,8 @@ status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
for (size_t i = 0; i < effects.size(); i++) {
EffectDesc *effect = effects[i];
- sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0,
- audioSession, input);
+ sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, -1, 0,
+ 0, audioSession, input);
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
ALOGW("addInputEffects(): failed to create Fx %s on source %d",
@@ -254,7 +254,7 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output,
Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
for (size_t i = 0; i < effects.size(); i++) {
EffectDesc *effect = effects[i];
- sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0,
+ sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, 0, 0, 0,
audioSession, output);
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 5ceb1cf..65639c3 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -146,6 +146,7 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -158,7 +159,16 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
}
ALOGV("getOutput()");
Mutex::Autolock _l(mLock);
- return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, samplingRate,
+
+ // if the caller is us, trust the specified uid
+ if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
+ uid_t newclientUid = IPCThreadState::self()->getCallingUid();
+ if (uid != (uid_t)-1 && uid != newclientUid) {
+ ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
+ }
+ uid = newclientUid;
+ }
+ return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate,
format, channelMask, flags, selectedDeviceId, offloadInfo);
}
@@ -248,6 +258,7 @@ void AudioPolicyService::doReleaseOutput(audio_io_handle_t output,
status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -269,12 +280,22 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
sp<AudioPolicyEffects>audioPolicyEffects;
status_t status;
AudioPolicyInterface::input_type_t inputType;
+ // if the caller is us, trust the specified uid
+ if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
+ uid_t newclientUid = IPCThreadState::self()->getCallingUid();
+ if (uid != (uid_t)-1 && uid != newclientUid) {
+ ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
+ }
+ uid = newclientUid;
+ }
+
{
Mutex::Autolock _l(mLock);
// the audio_in_acoustics_t parameter is ignored by get_input()
- status = mAudioPolicyManager->getInputForAttr(attr, input, session,
+ status = mAudioPolicyManager->getInputForAttr(attr, input, session, uid,
samplingRate, format, channelMask,
- flags, selectedDeviceId, &inputType);
+ flags, selectedDeviceId,
+ &inputType);
audioPolicyEffects = mAudioPolicyEffects;
if (status == NO_ERROR) {
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 433e712..13af3ef 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -234,6 +234,7 @@ void AudioPolicyService::doReleaseOutput(audio_io_handle_t output,
status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
+ uid_t uid __unused,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
@@ -565,6 +566,7 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *output,
audio_session_t session __unused,
audio_stream_type_t *stream,
+ uid_t uid __unused,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index ccf9f9b..c5f4fb7 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -177,7 +177,7 @@ void AudioPolicyService::removeNotificationClient(uid_t uid)
{
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager) {
- mAudioPolicyManager->clearAudioPatches(uid);
+ mAudioPolicyManager->releaseResourcesForUid(uid);
}
}
#endif
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 07ea96b..eb50cdd 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -80,6 +80,7 @@ public:
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
+ uid_t uid,
uint32_t samplingRate = 0,
audio_format_t format = AUDIO_FORMAT_DEFAULT,
audio_channel_mask_t channelMask = 0,
@@ -98,6 +99,7 @@ public:
virtual status_t getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
+ uid_t uid,
uint32_t samplingRate,
audio_format_t format,
audio_channel_mask_t channelMask,
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 8c5c43a..e28464d 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -890,9 +890,12 @@ status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clien
if (current != nullptr) {
auto clientSp = current->getValue();
if (clientSp.get() != nullptr) { // should never be needed
- if (clientSp->getRemote() == remoteCallback) {
+ if (!clientSp->canCastToApiClient(effectiveApiLevel)) {
+ ALOGW("CameraService connect called from same client, but with a different"
+ " API level, evicting prior client...");
+ } else if (clientSp->getRemote() == remoteCallback) {
ALOGI("CameraService::connect X (PID %d) (second call from same"
- "app binder, returning the same client)", clientPid);
+ " app binder, returning the same client)", clientPid);
*client = clientSp;
return NO_ERROR;
}
@@ -1754,6 +1757,11 @@ int CameraService::BasicClient::getClientPid() const {
return mClientPid;
}
+bool CameraService::BasicClient::canCastToApiClient(apiLevel level) const {
+ // Defaults to API2.
+ return level == API_2;
+}
+
status_t CameraService::BasicClient::startCameraOps() {
int32_t res;
// Notify app ops that the camera is not available
@@ -1866,6 +1874,10 @@ void CameraService::Client::disconnect() {
BasicClient::disconnect();
}
+bool CameraService::Client::canCastToApiClient(apiLevel level) const {
+ return level == API_1;
+}
+
CameraService::Client::OpsCallback::OpsCallback(wp<BasicClient> client):
mClient(client) {
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 84e61c5..a8b4c4a 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -65,6 +65,7 @@ public:
class Client;
class BasicClient;
+ // The effective API level. The Camera2 API running in LEGACY mode counts as API_1.
enum apiLevel {
API_1 = 1,
API_2 = 2
@@ -215,6 +216,10 @@ public:
// Get the PID of the application client using this
virtual int getClientPid() const;
+
+ // Check what API level is used for this client. This is used to determine which
+ // superclass this can be cast to.
+ virtual bool canCastToApiClient(apiLevel level) const;
protected:
BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
@@ -323,6 +328,10 @@ public:
virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras);
+
+ // Check what API level is used for this client. This is used to determine which
+ // superclass this can be cast to.
+ virtual bool canCastToApiClient(apiLevel level) const;
protected:
// Convert client from cookie.
static sp<CameraService::Client> getClientFromCookie(void* user);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 6b0f8b5..c3a6842 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -2100,12 +2100,7 @@ status_t Parameters::updateRequest(CameraMetadata *request) const {
delete[] reqMeteringAreas;
- /* don't include jpeg thumbnail size - it's valid for
- it to be set to (0,0), meaning 'no thumbnail' */
- CropRegion crop = calculateCropRegion( (CropRegion::Outputs)(
- CropRegion::OUTPUT_PREVIEW |
- CropRegion::OUTPUT_VIDEO |
- CropRegion::OUTPUT_PICTURE ));
+ CropRegion crop = calculateCropRegion(/*previewOnly*/ false);
int32_t reqCropRegion[4] = {
static_cast<int32_t>(crop.left),
static_cast<int32_t>(crop.top),
@@ -2603,7 +2598,7 @@ int Parameters::cropXToArray(int x) const {
ALOG_ASSERT(x >= 0, "Crop-relative X coordinate = '%d' is out of bounds"
"(lower = 0)", x);
- CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ CropRegion previewCrop = calculateCropRegion(/*previewOnly*/ true);
ALOG_ASSERT(x < previewCrop.width, "Crop-relative X coordinate = '%d' "
"is out of bounds (upper = %f)", x, previewCrop.width);
@@ -2619,7 +2614,7 @@ int Parameters::cropYToArray(int y) const {
ALOG_ASSERT(y >= 0, "Crop-relative Y coordinate = '%d' is out of bounds "
"(lower = 0)", y);
- CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ CropRegion previewCrop = calculateCropRegion(/*previewOnly*/ true);
ALOG_ASSERT(y < previewCrop.height, "Crop-relative Y coordinate = '%d' is "
"out of bounds (upper = %f)", y, previewCrop.height);
@@ -2634,12 +2629,12 @@ int Parameters::cropYToArray(int y) const {
}
int Parameters::normalizedXToCrop(int x) const {
- CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ CropRegion previewCrop = calculateCropRegion(/*previewOnly*/ true);
return (x + 1000) * (previewCrop.width - 1) / 2000;
}
int Parameters::normalizedYToCrop(int y) const {
- CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
+ CropRegion previewCrop = calculateCropRegion(/*previewOnly*/ true);
return (y + 1000) * (previewCrop.height - 1) / 2000;
}
@@ -2855,8 +2850,7 @@ Vector<Parameters::Size> Parameters::getAvailableJpegSizes() {
return jpegSizes;
}
-Parameters::CropRegion Parameters::calculateCropRegion(
- Parameters::CropRegion::Outputs outputs) const {
+Parameters::CropRegion Parameters::calculateCropRegion(bool previewOnly) const {
float zoomLeft, zoomTop, zoomWidth, zoomHeight;
@@ -2880,90 +2874,45 @@ Parameters::CropRegion Parameters::calculateCropRegion(
maxDigitalZoom.data.f[0], zoomIncrement, zoomRatio, previewWidth,
previewHeight, fastInfo.arrayWidth, fastInfo.arrayHeight);
- /*
- * Assumption: On the HAL side each stream buffer calculates its crop
- * rectangle as follows:
- * cropRect = (zoomLeft, zoomRight,
- * zoomWidth, zoomHeight * zoomWidth / outputWidth);
- *
- * Note that if zoomWidth > bufferWidth, the new cropHeight > zoomHeight
- * (we can then get into trouble if the cropHeight > arrayHeight).
- * By selecting the zoomRatio based on the smallest outputRatio, we
- * guarantee this will never happen.
- */
+ if (previewOnly) {
+ // Calculate a tight crop region for the preview stream only
+ float previewRatio = static_cast<float>(previewWidth) / previewHeight;
- // Enumerate all possible output sizes, select the one with the smallest
- // aspect ratio
- float minOutputWidth, minOutputHeight, minOutputRatio;
- {
- float outputSizes[][2] = {
- { static_cast<float>(previewWidth),
- static_cast<float>(previewHeight) },
- { static_cast<float>(videoWidth),
- static_cast<float>(videoHeight) },
- { static_cast<float>(jpegThumbSize[0]),
- static_cast<float>(jpegThumbSize[1]) },
- { static_cast<float>(pictureWidth),
- static_cast<float>(pictureHeight) },
- };
-
- minOutputWidth = outputSizes[0][0];
- minOutputHeight = outputSizes[0][1];
- minOutputRatio = minOutputWidth / minOutputHeight;
- for (unsigned int i = 0;
- i < sizeof(outputSizes) / sizeof(outputSizes[0]);
- ++i) {
-
- // skip over outputs we don't want to consider for the crop region
- if ( !((1 << i) & outputs) ) {
- continue;
- }
-
- float outputWidth = outputSizes[i][0];
- float outputHeight = outputSizes[i][1];
- float outputRatio = outputWidth / outputHeight;
-
- if (minOutputRatio > outputRatio) {
- minOutputRatio = outputRatio;
- minOutputWidth = outputWidth;
- minOutputHeight = outputHeight;
- }
+ /* Ensure that the width/height never go out of bounds
+ * by scaling across a diffent dimension if an out-of-bounds
+ * possibility exists.
+ *
+ * e.g. if the previewratio < arrayratio and e.g. zoomratio = 1.0, then by
+ * calculating the zoomWidth from zoomHeight we'll actually get a
+ * zoomheight > arrayheight
+ */
+ float arrayRatio = 1.f * fastInfo.arrayWidth / fastInfo.arrayHeight;
+ if (previewRatio >= arrayRatio) {
+ // Adjust the height based on the width
+ zoomWidth = fastInfo.arrayWidth / zoomRatio;
+ zoomHeight = zoomWidth *
+ previewHeight / previewWidth;
- // and then use this output ratio instead of preview output ratio
- ALOGV("Enumerating output ratio %f = %f / %f, min is %f",
- outputRatio, outputWidth, outputHeight, minOutputRatio);
+ } else {
+ // Adjust the width based on the height
+ zoomHeight = fastInfo.arrayHeight / zoomRatio;
+ zoomWidth = zoomHeight *
+ previewWidth / previewHeight;
}
- }
-
- /* Ensure that the width/height never go out of bounds
- * by scaling across a diffent dimension if an out-of-bounds
- * possibility exists.
- *
- * e.g. if the previewratio < arrayratio and e.g. zoomratio = 1.0, then by
- * calculating the zoomWidth from zoomHeight we'll actually get a
- * zoomheight > arrayheight
- */
- float arrayRatio = 1.f * fastInfo.arrayWidth / fastInfo.arrayHeight;
- if (minOutputRatio >= arrayRatio) {
- // Adjust the height based on the width
- zoomWidth = fastInfo.arrayWidth / zoomRatio;
- zoomHeight = zoomWidth *
- minOutputHeight / minOutputWidth;
-
} else {
- // Adjust the width based on the height
+ // Calculate the global crop region with a shape matching the active
+ // array.
+ zoomWidth = fastInfo.arrayWidth / zoomRatio;
zoomHeight = fastInfo.arrayHeight / zoomRatio;
- zoomWidth = zoomHeight *
- minOutputWidth / minOutputHeight;
}
- // centering the zoom area within the active area
+
+ // center the zoom area within the active area
zoomLeft = (fastInfo.arrayWidth - zoomWidth) / 2;
zoomTop = (fastInfo.arrayHeight - zoomHeight) / 2;
ALOGV("Crop region calculated (x=%d,y=%d,w=%f,h=%f) for zoom=%d",
(int32_t)zoomLeft, (int32_t)zoomTop, zoomWidth, zoomHeight, this->zoom);
-
CropRegion crop = { zoomLeft, zoomTop, zoomWidth, zoomHeight };
return crop;
}
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index e628a7e..46d48bc 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -271,21 +271,16 @@ struct Parameters {
// if video snapshot size is currently overridden
bool isJpegSizeOverridden();
- // Calculate the crop region rectangle based on current stream sizes
+ // Calculate the crop region rectangle, either tightly about the preview
+ // resolution, or a region just based on the active array; both take
+ // into account the current zoom level.
struct CropRegion {
float left;
float top;
float width;
float height;
-
- enum Outputs {
- OUTPUT_PREVIEW = 0x01,
- OUTPUT_VIDEO = 0x02,
- OUTPUT_JPEG_THUMBNAIL = 0x04,
- OUTPUT_PICTURE = 0x08,
- };
};
- CropRegion calculateCropRegion(CropRegion::Outputs outputs) const;
+ CropRegion calculateCropRegion(bool previewOnly) const;
// Calculate the field of view of the high-resolution JPEG capture
status_t calculatePictureFovs(float *horizFov, float *vertFov) const;