Merge "stagefright: reuse buffers instead of cloning"
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 63076e9..f7eb397 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -180,7 +180,7 @@
                                     audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
-                                    int uid = -1,
+                                    uid_t uid = AUDIO_UID_INVALID,
                                     pid_t pid = -1,
                                     const audio_attributes_t* pAttributes = NULL);
 
@@ -218,7 +218,7 @@
                             audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
-                            int uid = -1,
+                            uid_t uid = AUDIO_UID_INVALID,
                             pid_t pid = -1,
                             const audio_attributes_t* pAttributes = NULL);
 
@@ -642,7 +642,7 @@
 
     sp<DeathNotifier>       mDeathNotifier;
     uint32_t                mSequence;              // incremented for each new IAudioRecord attempt
-    int                     mClientUid;
+    uid_t                   mClientUid;
     pid_t                   mClientPid;
     audio_attributes_t      mAttributes;
 
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 399154c..7c5686a 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -233,7 +233,7 @@
                                     audio_session_t sessionId  = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    int uid = -1,
+                                    uid_t uid = AUDIO_UID_INVALID,
                                     pid_t pid = -1,
                                     const audio_attributes_t* pAttributes = NULL,
                                     bool doNotReconnect = false,
@@ -263,7 +263,7 @@
                                     audio_session_t sessionId   = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    int uid = -1,
+                                    uid_t uid = AUDIO_UID_INVALID,
                                     pid_t pid = -1,
                                     const audio_attributes_t* pAttributes = NULL,
                                     bool doNotReconnect = false,
@@ -309,7 +309,7 @@
                             audio_session_t sessionId  = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             const audio_offload_info_t *offloadInfo = NULL,
-                            int uid = -1,
+                            uid_t uid = AUDIO_UID_INVALID,
                             pid_t pid = -1,
                             const audio_attributes_t* pAttributes = NULL,
                             bool doNotReconnect = false,
@@ -1130,7 +1130,7 @@
 
     sp<DeathNotifier>       mDeathNotifier;
     uint32_t                mSequence;              // incremented for each new IAudioTrack attempt
-    int                     mClientUid;
+    uid_t                   mClientUid;
     pid_t                   mClientPid;
 
     sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index ff5903d..7476519 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -85,7 +85,7 @@
         audio_session_t sessionId,
         transfer_type transferType,
         audio_input_flags_t flags,
-        int uid,
+        uid_t uid,
         pid_t pid,
         const audio_attributes_t* pAttributes)
     : mActive(false),
@@ -143,7 +143,7 @@
         audio_session_t sessionId,
         transfer_type transferType,
         audio_input_flags_t flags,
-        int uid,
+        uid_t uid,
         pid_t pid,
         const audio_attributes_t* pAttributes)
 {
@@ -236,7 +236,7 @@
 
     int callingpid = IPCThreadState::self()->getCallingPid();
     int mypid = getpid();
-    if (uid == -1 || (callingpid != mypid)) {
+    if (uid == AUDIO_UID_INVALID || (callingpid != mypid)) {
         mClientUid = IPCThreadState::self()->getCallingUid();
     } else {
         mClientUid = uid;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 6a1e31e..3c7e8b7 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -204,7 +204,7 @@
         audio_session_t sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid,
+        uid_t uid,
         pid_t pid,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
@@ -235,7 +235,7 @@
         audio_session_t sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid,
+        uid_t uid,
         pid_t pid,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
@@ -296,7 +296,7 @@
         audio_session_t sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid,
+        uid_t uid,
         pid_t pid,
         const audio_attributes_t* pAttributes,
         bool doNotReconnect,
@@ -490,7 +490,7 @@
     }
     int callingpid = IPCThreadState::self()->getCallingPid();
     int mypid = getpid();
-    if (uid == -1 || (callingpid != mypid)) {
+    if (uid == AUDIO_UID_INVALID || (callingpid != mypid)) {
         mClientUid = IPCThreadState::self()->getCallingUid();
     } else {
         mClientUid = uid;
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 4c71907..1d9801f 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -59,6 +59,8 @@
 
 #define DISCARD_MEASUREMENTS_TIME_MS 2000 // discard measurements older than this number of ms
 
+#define MAX_LATENCY_MS 3000 // 3 seconds of latency for audio pipeline
+
 // maximum number of buffers for which we keep track of the measurements
 #define MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS 25 // note: buffer index is stored in uint8_t
 
@@ -519,18 +521,29 @@
             break;
         }
         switch (*(uint32_t *)p->data) {
-        case VISUALIZER_PARAM_CAPTURE_SIZE:
-            pContext->mCaptureSize = *((uint32_t *)p->data + 1);
-            ALOGV("set mCaptureSize = %" PRIu32, pContext->mCaptureSize);
-            break;
+        case VISUALIZER_PARAM_CAPTURE_SIZE: {
+            const uint32_t captureSize = *((uint32_t *)p->data + 1);
+            if (captureSize > VISUALIZER_CAPTURE_SIZE_MAX) {
+                android_errorWriteLog(0x534e4554, "31781965");
+                *(int32_t *)pReplyData = -EINVAL;
+                ALOGW("set mCaptureSize = %u > %u", captureSize, VISUALIZER_CAPTURE_SIZE_MAX);
+            } else {
+                pContext->mCaptureSize = captureSize;
+                ALOGV("set mCaptureSize = %u", captureSize);
+            }
+            } break;
         case VISUALIZER_PARAM_SCALING_MODE:
             pContext->mScalingMode = *((uint32_t *)p->data + 1);
             ALOGV("set mScalingMode = %" PRIu32, pContext->mScalingMode);
             break;
-        case VISUALIZER_PARAM_LATENCY:
-            pContext->mLatency = *((uint32_t *)p->data + 1);
-            ALOGV("set mLatency = %" PRIu32, pContext->mLatency);
-            break;
+        case VISUALIZER_PARAM_LATENCY: {
+            uint32_t latency = *((uint32_t *)p->data + 1);
+            if (latency > MAX_LATENCY_MS) {
+                latency = MAX_LATENCY_MS; // clamp latency b/31781965
+            }
+            pContext->mLatency = latency;
+            ALOGV("set mLatency = %u", latency);
+            } break;
         case VISUALIZER_PARAM_MEASUREMENT_MODE:
             pContext->mMeasurementMode = *((uint32_t *)p->data + 1);
             ALOGV("set mMeasurementMode = %" PRIu32, pContext->mMeasurementMode);
@@ -569,10 +582,18 @@
                 if (latencyMs < 0) {
                     latencyMs = 0;
                 }
-                const uint32_t deltaSmpl =
-                    pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
-                int32_t capturePoint = pContext->mCaptureIdx - captureSize - deltaSmpl;
+                uint32_t deltaSmpl = captureSize
+                        + pContext->mConfig.inputCfg.samplingRate * latencyMs / 1000;
 
+                // large sample rate, latency, or capture size, could cause overflow.
+                // do not offset more than the size of buffer.
+                if (deltaSmpl > CAPTURE_BUF_SIZE) {
+                    android_errorWriteLog(0x534e4554, "31781965");
+                    deltaSmpl = CAPTURE_BUF_SIZE;
+                }
+
+                int32_t capturePoint = pContext->mCaptureIdx - deltaSmpl;
+                // a negative capturePoint means we wrap the buffer.
                 if (capturePoint < 0) {
                     uint32_t size = -capturePoint;
                     if (size > captureSize) {
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index baf7f31..3a04651 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -365,6 +365,8 @@
 
     if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
         mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_MONO;
+        mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
+        ALOGV("Overriding auxiliary effect input as MONO and output as STEREO");
     } else {
         mConfig.inputCfg.channels = channelMask;
         // TODO: Update this logic when multichannel effects are implemented.
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index cfa3e1a..0bcb9a0 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -32,7 +32,7 @@
                                 void *buffer,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_session_t sessionId,
-                                int uid,
+                                uid_t uid,
                                 audio_output_flags_t flags,
                                 track_type type);
     virtual             ~Track();
@@ -188,7 +188,7 @@
                                 audio_format_t format,
                                 audio_channel_mask_t channelMask,
                                 size_t frameCount,
-                                int uid);
+                                uid_t uid);
     virtual             ~OutputTrack();
 
     virtual status_t    start(AudioSystem::sync_event_t event =
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 123e033..883ff6b 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -30,7 +30,7 @@
                                 size_t frameCount,
                                 void *buffer,
                                 audio_session_t sessionId,
-                                int uid,
+                                uid_t uid,
                                 audio_input_flags_t flags,
                                 track_type type);
     virtual             ~RecordTrack();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 8818d8b..1d7b946 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -508,7 +508,8 @@
         mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
         // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this)),
-        mSystemReady(systemReady)
+        mSystemReady(systemReady),
+        mNotifiedBatteryStart(false)
 {
     memset(&mPatch, 0, sizeof(struct audio_patch));
 }
@@ -849,10 +850,10 @@
     }
 }
 
-void AudioFlinger::ThreadBase::acquireWakeLock()
+void AudioFlinger::ThreadBase::acquireWakeLock(int uid)
 {
     Mutex::Autolock _l(mLock);
-    acquireWakeLock_l();
+    acquireWakeLock_l(uid);
 }
 
 String16 AudioFlinger::ThreadBase::getWakeLockTag()
@@ -874,23 +875,37 @@
     }
 }
 
-void AudioFlinger::ThreadBase::acquireWakeLock_l()
+void AudioFlinger::ThreadBase::acquireWakeLock_l(int uid)
 {
     getPowerManager_l();
     if (mPowerManager != 0) {
         sp<IBinder> binder = new BBinder();
-        // Uses AID_AUDIOSERVER for wakelock.  updateWakeLockUids_l() updates with client uids.
-        status_t status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
+        status_t status;
+        if (uid >= 0) {
+            status = mPowerManager->acquireWakeLockWithUid(POWERMANAGER_PARTIAL_WAKE_LOCK,
+                    binder,
+                    getWakeLockTag(),
+                    String16("audioserver"),
+                    uid,
+                    true /* FIXME force oneway contrary to .aidl */);
+        } else {
+            status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
                     binder,
                     getWakeLockTag(),
                     String16("audioserver"),
                     true /* FIXME force oneway contrary to .aidl */);
+        }
         if (status == NO_ERROR) {
             mWakeLockToken = binder;
         }
         ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status);
     }
 
+    if (!mNotifiedBatteryStart) {
+        // TODO: call this function for each track when it becomes active.
+        BatteryNotifier::getInstance().noteStartAudio(AID_AUDIOSERVER);
+        mNotifiedBatteryStart = true;
+    }
     gBoottime.acquire(mWakeLockToken);
     mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME] =
             gBoottime.getBoottimeOffset();
@@ -913,6 +928,12 @@
         }
         mWakeLockToken.clear();
     }
+
+    if (mNotifiedBatteryStart) {
+        // TODO: call this function for each track when it becomes inactive.
+        BatteryNotifier::getInstance().noteStopAudio(AID_AUDIOSERVER);
+        mNotifiedBatteryStart = false;
+    }
 }
 
 void AudioFlinger::ThreadBase::getPowerManager_l() {
@@ -931,15 +952,6 @@
 
 void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uids) {
     getPowerManager_l();
-
-#if !LOG_NDEBUG
-    std::stringstream s;
-    for (int uid : uids) {
-        s << uid << " ";
-    }
-    ALOGD("updateWakeLockUids_l %s uids:%s", mThreadName, s.str().c_str());
-#endif
-
     if (mWakeLockToken == NULL) { // token may be NULL if AudioFlinger::systemReady() not called.
         if (mSystemReady) {
             ALOGE("no wake lock to update, but system ready!");
@@ -949,10 +961,10 @@
         return;
     }
     if (mPowerManager != 0) {
-        sp<IBinder> binder = new BBinder();
-        status_t status;
-        status = mPowerManager->updateWakeLockUids(mWakeLockToken, uids.size(), uids.array(),
-                    true /* FIXME force oneway contrary to .aidl */);
+        std::vector<int> uidsAsInt(uids.begin(), uids.end()); // powermanager expects uids as ints
+        status_t status = mPowerManager->updateWakeLockUids(
+                mWakeLockToken, uidsAsInt.size(), uidsAsInt.data(),
+                true /* FIXME force oneway contrary to .aidl */);
         ALOGV("updateWakeLockUids_l() %s status %d", mThreadName, status);
     }
 }
@@ -1501,41 +1513,6 @@
     mPendingConfigEvents.clear();
 }
 
-template <typename T>
-ssize_t AudioFlinger::ThreadBase::ActiveTracks<T>::add(const sp<T> &track) {
-    ssize_t index = mActiveTracks.indexOf(track);
-    if (index >= 0) {
-        ALOGW("ActiveTracks<T>::add track %p already there", track.get());
-        return index;
-    }
-    mActiveTracksGeneration++;
-    mLatestActiveTrack = track;
-    BatteryNotifier::getInstance().noteStartAudio(track->uid());
-    return mActiveTracks.add(track);
-}
-
-template <typename T>
-ssize_t AudioFlinger::ThreadBase::ActiveTracks<T>::remove(const sp<T> &track) {
-    ssize_t index = mActiveTracks.remove(track);
-    if (index < 0) {
-        ALOGW("ActiveTracks<T>::remove nonexistent track %p", track.get());
-        return index;
-    }
-    mActiveTracksGeneration++;
-    BatteryNotifier::getInstance().noteStopAudio(track->uid());
-    // mLatestActiveTrack is not cleared even if is the same as track.
-    return index;
-}
-
-template <typename T>
-void AudioFlinger::ThreadBase::ActiveTracks<T>::clear() {
-    for (const sp<T> &track : mActiveTracks) {
-        BatteryNotifier::getInstance().noteStopAudio(track->uid());
-    }
-    mLastActiveTracksGeneration = mActiveTracksGeneration;
-    mActiveTracks.clear();
-    mLatestActiveTrack.clear();
-}
 
 // ----------------------------------------------------------------------------
 //      Playback
@@ -1562,6 +1539,7 @@
         mSuspended(0), mBytesWritten(0),
         mFramesWritten(0),
         mSuspendedFrames(0),
+        mActiveTracksGeneration(0),
         // mStreamTypes[] initialized in constructor body
         mOutput(output),
         mLastWriteTime(-1), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
@@ -1680,8 +1658,8 @@
         result.append(buffer);
         Track::appendDumpHeader(result);
         for (size_t i = 0; i < numactive; ++i) {
-            sp<Track> track = mActiveTracks[i];
-            if (mTracks.indexOf(track) < 0) {
+            sp<Track> track = mActiveTracks[i].promote();
+            if (track != 0 && mTracks.indexOf(track) < 0) {
                 track->dump(buffer, SIZE, true);
                 result.append(buffer);
             }
@@ -1753,7 +1731,7 @@
         audio_session_t sessionId,
         audio_output_flags_t *flags,
         pid_t tid,
-        int uid,
+        uid_t uid,
         status_t *status)
 {
     size_t frameCount = *pFrameCount;
@@ -2084,6 +2062,9 @@
         track->mResetDone = false;
         track->mPresentationCompleteFrames = 0;
         mActiveTracks.add(track);
+        mWakeLockUids.add(track->uid());
+        mActiveTracksGeneration++;
+        mLatestActiveTrack = track;
         sp<EffectChain> chain = getEffectChain_l(track->sessionId());
         if (chain != 0) {
             ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(),
@@ -2718,7 +2699,11 @@
         }
 
         // indicate all active tracks in the chain
-        for (const sp<Track> &track : mActiveTracks) {
+        for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
+            sp<Track> track = mActiveTracks[i].promote();
+            if (track == 0) {
+                continue;
+            }
             if (session == track->sessionId()) {
                 ALOGV("addEffectChain_l() activating track %p on session %d", track.get(), session);
                 chain->incActiveTrackCnt();
@@ -2765,7 +2750,11 @@
         if (chain == mEffectChains[i]) {
             mEffectChains.removeAt(i);
             // detach all active tracks from the chain
-            for (const sp<Track> &track : mActiveTracks) {
+            for (size_t i = 0 ; i < mActiveTracks.size() ; ++i) {
+                sp<Track> track = mActiveTracks[i].promote();
+                if (track == 0) {
+                    continue;
+                }
                 if (session == track->sessionId()) {
                     ALOGV("removeEffectChain_l(): stopping track on chain %p for session Id: %d",
                             chain.get(), session);
@@ -2842,6 +2831,8 @@
     // FIXME could this be made local to while loop?
     writeFrames = 0;
 
+    int lastGeneration = 0;
+
     cacheParameters_l();
     mSleepTimeUs = mIdleSleepTimeUs;
 
@@ -2939,9 +2930,10 @@
                     mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] = mLastWriteTime == -1
                             ? systemTime() : mLastWriteTime;
                 }
-
-                for (const sp<Track> &t : mActiveTracks) {
-                    if (!t->isFastTrack()) {
+                const size_t size = mActiveTracks.size();
+                for (size_t i = 0; i < size; ++i) {
+                    sp<Track> t = mActiveTracks[i].promote();
+                    if (t != 0 && !t->isFastTrack()) {
                         t->updateTrackFrameInfo(
                                 t->mAudioTrackServerProxy->framesReleased(),
                                 mFramesWritten,
@@ -2962,6 +2954,8 @@
                 if (!keepWakeLock()) {
                     releaseWakeLock_l();
                     released = true;
+                    mWakeLockUids.clear();
+                    mActiveTracksGeneration++;
                 }
                 ALOGV("wait async completion");
                 mWaitWorkCV.wait(mLock);
@@ -2995,6 +2989,8 @@
                     }
 
                     releaseWakeLock_l();
+                    mWakeLockUids.clear();
+                    mActiveTracksGeneration++;
                     // wait until we have something to do...
                     ALOGV("%s going to sleep", myName.string());
                     mWaitWorkCV.wait(mLock);
@@ -3019,7 +3015,12 @@
             // mMixerStatusIgnoringFastTracks is also updated internally
             mMixerStatus = prepareTracks_l(&tracksToRemove);
 
-            mActiveTracks.updateWakeLockUids(this);
+            // compare with previously applied list
+            if (lastGeneration != mActiveTracksGeneration) {
+                // update wakelock
+                updateWakeLockUids_l(mWakeLockUids);
+                lastGeneration = mActiveTracksGeneration;
+            }
 
             // prevent any changes in effect chain list and in each effect chain
             // during mixing and effect process as the audio buffers could be deleted
@@ -3237,6 +3238,8 @@
     }
 
     releaseWakeLock();
+    mWakeLockUids.clear();
+    mActiveTracksGeneration++;
 
     ALOGV("Thread %p type %d exiting", this, mType);
     return false;
@@ -3250,6 +3253,8 @@
         for (size_t i=0 ; i<count ; i++) {
             const sp<Track>& track = tracksToRemove.itemAt(i);
             mActiveTracks.remove(track);
+            mWakeLockUids.remove(track->uid());
+            mActiveTracksGeneration++;
             ALOGV("removeTracks_l removing track on session %d", track->sessionId());
             sp<EffectChain> chain = getEffectChain_l(track->sessionId());
             if (chain != 0) {
@@ -3868,7 +3873,10 @@
     mEffectBufferValid = false; // mEffectBuffer has no valid data until tracks found.
 
     for (size_t i=0 ; i<count ; i++) {
-        const sp<Track> t = mActiveTracks[i];
+        const sp<Track> t = mActiveTracks[i].promote();
+        if (t == 0) {
+            continue;
+        }
 
         // this const just means the local variable doesn't change
         Track* const track = t.get();
@@ -4364,7 +4372,11 @@
         size_t i = __builtin_ctz(resetMask);
         ALOG_ASSERT(i < count);
         resetMask &= ~(1 << i);
-        sp<Track> track = mActiveTracks[i];
+        sp<Track> t = mActiveTracks[i].promote();
+        if (t == 0) {
+            continue;
+        }
+        Track* track = t.get();
         ALOG_ASSERT(track->isFastTrack() && track->isStopped());
         track->reset();
     }
@@ -4416,7 +4428,7 @@
 {
     uint32_t trackCount = 0;
     for (size_t i = 0; i < mTracks.size() ; i++) {
-        if (mTracks[i]->uid() == (int)uid) {
+        if (mTracks[i]->uid() == uid) {
             trackCount++;
         }
     }
@@ -4625,7 +4637,7 @@
 {
 }
 
-void AudioFlinger::DirectOutputThread::processVolume_l(sp<Track> track, bool lastTrack)
+void AudioFlinger::DirectOutputThread::processVolume_l(Track *track, bool lastTrack)
 {
     float left, right;
 
@@ -4674,7 +4686,7 @@
 void AudioFlinger::DirectOutputThread::onAddNewTrack_l()
 {
     sp<Track> previousTrack = mPreviousTrack.promote();
-    sp<Track> latestTrack = mActiveTracks.getLatest();
+    sp<Track> latestTrack = mLatestActiveTrack.promote();
 
     if (previousTrack != 0 && latestTrack != 0) {
         if (mType == DIRECT) {
@@ -4700,13 +4712,20 @@
     bool doHwResume = false;
 
     // find out which tracks need to be processed
-    for (const sp<Track> &track : mActiveTracks) {
-        if (track->isInvalid()) {
-            ALOGW("An invalidated track shouldn't be in active list");
-            tracksToRemove->add(track);
+    for (size_t i = 0; i < count; i++) {
+        sp<Track> t = mActiveTracks[i].promote();
+        // The track died recently
+        if (t == 0) {
             continue;
         }
 
+        if (t->isInvalid()) {
+            ALOGW("An invalidated track shouldn't be in active list");
+            tracksToRemove->add(t);
+            continue;
+        }
+
+        Track* const track = t.get();
 #ifdef VERY_VERY_VERBOSE_LOGGING
         audio_track_cblk_t* cblk = track->cblk();
 #endif
@@ -4714,7 +4733,8 @@
         // In theory an older track could underrun and restart after the new one starts
         // but as we only care about the transition phase between two tracks on a
         // direct output, it is not a problem to ignore the underrun case.
-        bool last = mActiveTracks.getLatest() == track;
+        sp<Track> l = mLatestActiveTrack.promote();
+        bool last = l.get() == track;
 
         if (track->isPausing()) {
             track->setPaused();
@@ -4786,7 +4806,7 @@
 
                 // reset retry count
                 track->mRetryCount = kMaxTrackRetriesDirect;
-                mActiveTrack = track; // save track as mActiveTracks may change without lock.
+                mActiveTrack = t;
                 mixerStatus = MIXER_TRACKS_READY;
                 if (mHwPaused) {
                     doHwResume = true;
@@ -5247,7 +5267,13 @@
     ALOGV("OffloadThread::prepareTracks_l active tracks %zu", count);
 
     // find out which tracks need to be processed
-    for (const sp<Track> &track : mActiveTracks) {
+    for (size_t i = 0; i < count; i++) {
+        sp<Track> t = mActiveTracks[i].promote();
+        // The track died recently
+        if (t == 0) {
+            continue;
+        }
+        Track* const track = t.get();
 #ifdef VERY_VERY_VERBOSE_LOGGING
         audio_track_cblk_t* cblk = track->cblk();
 #endif
@@ -5255,7 +5281,8 @@
         // In theory an older track could underrun and restart after the new one starts
         // but as we only care about the transition phase between two tracks on a
         // direct output, it is not a problem to ignore the underrun case.
-        bool last = mActiveTracks.getLatest() == track;
+        sp<Track> l = mLatestActiveTrack.promote();
+        bool last = l.get() == track;
 
         if (track->isInvalid()) {
             ALOGW("An invalidated track shouldn't be in active list");
@@ -5361,7 +5388,7 @@
                 } else {
                     track->mRetryCount = kMaxTrackRetriesOffload;
                 }
-                mActiveTrack = track; // save track as mActiveTracks may change without lock.
+                mActiveTrack = t;
                 mixerStatus = MIXER_TRACKS_READY;
             }
         } else {
@@ -5713,7 +5740,7 @@
 #endif
                                          ) :
     ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD, systemReady),
-    mInput(input), mRsmpInBuffer(NULL),
+    mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL),
     // mRsmpInFrames, mRsmpInFramesP2, and mRsmpInFramesOA are set by readInputParameters_l()
     mRsmpInRear(0)
 #ifdef TEE_SINK
@@ -5871,9 +5898,25 @@
 
 reacquire_wakelock:
     sp<RecordTrack> activeTrack;
+    int activeTracksGen;
     {
         Mutex::Autolock _l(mLock);
-        acquireWakeLock_l();
+        size_t size = mActiveTracks.size();
+        activeTracksGen = mActiveTracksGen;
+        if (size > 0) {
+            // FIXME an arbitrary choice
+            activeTrack = mActiveTracks[0];
+            acquireWakeLock_l(activeTrack->uid());
+            if (size > 1) {
+                SortedVector<int> tmp;
+                for (size_t i = 0; i < size; i++) {
+                    tmp.add(mActiveTracks[i]->uid());
+                }
+                updateWakeLockUids_l(tmp);
+            }
+        } else {
+            acquireWakeLock_l(-1);
+        }
     }
 
     // used to request a deferred sleep, to be executed later while mutex is unlocked
@@ -5925,6 +5968,15 @@
                 goto reacquire_wakelock;
             }
 
+            if (mActiveTracksGen != activeTracksGen) {
+                activeTracksGen = mActiveTracksGen;
+                SortedVector<int> tmp;
+                for (size_t i = 0; i < size; i++) {
+                    tmp.add(mActiveTracks[i]->uid());
+                }
+                updateWakeLockUids_l(tmp);
+            }
+
             bool doBroadcast = false;
             bool allStopped = true;
             for (size_t i = 0; i < size; ) {
@@ -5937,6 +5989,7 @@
                     }
                     removeTrack_l(activeTrack);
                     mActiveTracks.remove(activeTrack);
+                    mActiveTracksGen++;
                     size--;
                     continue;
                 }
@@ -5946,6 +5999,7 @@
 
                 case TrackBase::PAUSING:
                     mActiveTracks.remove(activeTrack);
+                    mActiveTracksGen++;
                     doBroadcast = true;
                     size--;
                     continue;
@@ -5985,8 +6039,6 @@
                 }
             }
 
-            mActiveTracks.updateWakeLockUids(this);
-
             if (allStopped) {
                 standbyIfNotAlreadyInStandby();
             }
@@ -6285,6 +6337,7 @@
             track->invalidate();
         }
         mActiveTracks.clear();
+        mActiveTracksGen++;
         mStartStopCond.broadcast();
     }
 
@@ -6351,7 +6404,7 @@
         size_t *pFrameCount,
         audio_session_t sessionId,
         size_t *notificationFrames,
-        int uid,
+        uid_t uid,
         audio_input_flags_t *flags,
         pid_t tid,
         status_t *status)
@@ -6538,6 +6591,7 @@
         //      or using a separate command thread
         recordTrack->mState = TrackBase::STARTING_1;
         mActiveTracks.add(recordTrack);
+        mActiveTracksGen++;
         status_t status = NO_ERROR;
         if (recordTrack->isExternalTrack()) {
             mLock.unlock();
@@ -6546,6 +6600,7 @@
             // FIXME should verify that recordTrack is still in mActiveTracks
             if (status != NO_ERROR) {
                 mActiveTracks.remove(recordTrack);
+                mActiveTracksGen++;
                 recordTrack->clearSyncStartEvent();
                 ALOGV("RecordThread::start error %d", status);
                 return status;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 862dc51..5235cde 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -400,8 +400,8 @@
                     effect_uuid_t mType;    // effect type UUID
                 };
 
-                void        acquireWakeLock();
-                virtual void acquireWakeLock_l();
+                void        acquireWakeLock(int uid = -1);
+                virtual void acquireWakeLock_l(int uid = -1);
                 void        releaseWakeLock();
                 void        releaseWakeLock_l();
                 void        updateWakeLockUids_l(const SortedVector<int> &uids);
@@ -478,88 +478,8 @@
                 static const size_t     kLogSize = 4 * 1024;
                 sp<NBLog::Writer>       mNBLogWriter;
                 bool                    mSystemReady;
+                bool                    mNotifiedBatteryStart;
                 ExtendedTimestamp       mTimestamp;
-
-                // ActiveTracks is a sorted vector of track type T representing the
-                // active tracks of threadLoop() to be considered by the locked prepare portion.
-                // ActiveTracks should be accessed with the ThreadBase lock held.
-                //
-                // During processing and I/O, the threadLoop does not hold the lock;
-                // hence it does not directly use ActiveTracks.  Care should be taken
-                // to hold local strong references or defer removal of tracks
-                // if the threadLoop may still be accessing those tracks due to mix, etc.
-                //
-                // This class updates power information appropriately.
-                //
-
-                template <typename T>
-                class ActiveTracks {
-                public:
-                    ActiveTracks()
-                        : mActiveTracksGeneration(0)
-                        , mLastActiveTracksGeneration(0)
-                    { }
-
-                    ~ActiveTracks() {
-                        clear();
-                    }
-                    // returns the last track added (even though it may have been
-                    // subsequently removed from ActiveTracks).
-                    //
-                    // Used for DirectOutputThread to ensure a flush is called when transitioning
-                    // to a new track (even though it may be on the same session).
-                    // Used for OffloadThread to ensure that volume and mixer state is
-                    // taken from the latest track added.
-                    //
-                    // The latest track is saved with a weak pointer to prevent keeping an
-                    // otherwise useless track alive. Thus the function will return nullptr
-                    // if the latest track has subsequently been removed and destroyed.
-                    sp<T> getLatest() {
-                        return mLatestActiveTrack.promote();
-                    }
-
-                    // Updates ActiveTracks client uids to the thread wakelock.
-                    void updateWakeLockUids(sp<ThreadBase> thread, bool force = false) {
-                        if (mActiveTracksGeneration != mLastActiveTracksGeneration || force) {
-                            thread->updateWakeLockUids_l(getWakeLockUids());
-                            mLastActiveTracksGeneration = mActiveTracksGeneration;
-                        }
-                    }
-
-                    // SortedVector methods
-                    ssize_t         add(const sp<T> &track);
-                    ssize_t         remove(const sp<T> &track);
-                    size_t          size() const {
-                        return mActiveTracks.size();
-                    }
-                    ssize_t         indexOf(const sp<T>& item) {
-                        return mActiveTracks.indexOf(item);
-                    }
-                    sp<T>           operator[](size_t index) const {
-                        return mActiveTracks[index];
-                    }
-                    typename SortedVector<sp<T>>::iterator begin() {
-                        return mActiveTracks.begin();
-                    }
-                    typename SortedVector<sp<T>>::iterator end() {
-                        return mActiveTracks.end();
-                    }
-                    void            clear();
-
-                private:
-                    SortedVector<int> getWakeLockUids() {
-                        SortedVector<int> wakeLockUids;
-                        for (const sp<T> &track : mActiveTracks) {
-                            wakeLockUids.add(track->uid());
-                        }
-                        return wakeLockUids; // moved by underlying SharedBuffer
-                    }
-
-                    SortedVector<sp<T>> mActiveTracks;
-                    int                 mActiveTracksGeneration;
-                    int                 mLastActiveTracksGeneration;
-                    wp<T>               mLatestActiveTrack; // latest track added to ActiveTracks
-                };
 };
 
 // --- PlaybackThread ---
@@ -638,10 +558,6 @@
     virtual     void        preExit();
 
     virtual     bool        keepWakeLock() const { return true; }
-    virtual     void        acquireWakeLock_l() {
-                                ThreadBase::acquireWakeLock_l();
-                                mActiveTracks.updateWakeLockUids(this, true /* force */);
-                            }
 
 public:
 
@@ -671,7 +587,7 @@
                                 audio_session_t sessionId,
                                 audio_output_flags_t *flags,
                                 pid_t tid,
-                                int uid,
+                                uid_t uid,
                                 status_t *status /*non-NULL*/);
 
                 AudioStreamOut* getOutput() const;
@@ -814,7 +730,10 @@
     bool                            mMasterMute;
                 void        setMasterMute_l(bool muted) { mMasterMute = muted; }
 protected:
-    ActiveTracks<Track>     mActiveTracks;
+    SortedVector< wp<Track> >       mActiveTracks;  // FIXME check if this could be sp<>
+    SortedVector<int>               mWakeLockUids;
+    int                             mActiveTracksGeneration;
+    wp<Track>                       mLatestActiveTrack; // latest track added to mActiveTracks
 
     // Allocate a track name for a given channel mask.
     //   Returns name >= 0 if successful, -1 on failure.
@@ -980,8 +899,8 @@
     virtual     uint32_t    suspendSleepTimeUs() const;
     virtual     void        cacheParameters_l();
 
-    virtual void acquireWakeLock_l() {
-        PlaybackThread::acquireWakeLock_l();
+    virtual void acquireWakeLock_l(int uid = -1) {
+        PlaybackThread::acquireWakeLock_l(uid);
         if (hasFastMixer()) {
             mFastMixer->setBoottimeOffset(
                     mTimestamp.mTimebaseOffset[ExtendedTimestamp::TIMEBASE_BOOTTIME]);
@@ -1077,7 +996,7 @@
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
                         audio_io_handle_t id, uint32_t device, ThreadBase::type_t type,
                         bool systemReady);
-    void processVolume_l(sp<Track> track, bool lastTrack);
+    void processVolume_l(Track *track, bool lastTrack);
 
     // prepareTracks_l() tells threadLoop_mix() the name of the single active track
     sp<Track>               mActiveTrack;
@@ -1366,7 +1285,7 @@
                     size_t *pFrameCount,
                     audio_session_t sessionId,
                     size_t *notificationFrames,
-                    int uid,
+                    uid_t uid,
                     audio_input_flags_t *flags,
                     pid_t tid,
                     status_t *status /*non-NULL*/);
@@ -1420,11 +1339,6 @@
     virtual status_t    checkEffectCompatibility_l(const effect_descriptor_t *desc,
                                                    audio_session_t sessionId);
 
-    virtual void        acquireWakeLock_l() {
-                            ThreadBase::acquireWakeLock_l();
-                            mActiveTracks.updateWakeLockUids(this, true /* force */);
-                        }
-
 private:
             // Enter standby if not already in standby, and set mStandby flag
             void    standbyIfNotAlreadyInStandby();
@@ -1436,8 +1350,9 @@
             SortedVector < sp<RecordTrack> >    mTracks;
             // mActiveTracks has dual roles:  it indicates the current active track(s), and
             // is used together with mStartStopCond to indicate start()/stop() progress
-            ActiveTracks<RecordTrack>           mActiveTracks;
-
+            SortedVector< sp<RecordTrack> >     mActiveTracks;
+            // generation counter for mActiveTracks
+            int                                 mActiveTracksGen;
             Condition                           mStartStopCond;
 
             // resampler converts input at HAL Hz to output at AudioRecord client Hz
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 7c48375..4fcb596 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -62,7 +62,7 @@
                                 size_t frameCount,
                                 void *buffer,
                                 audio_session_t sessionId,
-                                int uid,
+                                uid_t uid,
                                 bool isOut,
                                 alloc_type alloc = ALLOC_CBLK,
                                 track_type type = TYPE_DEFAULT);
@@ -75,7 +75,7 @@
             sp<IMemory> getCblk() const { return mCblkMemory; }
             audio_track_cblk_t* cblk() const { return mCblk; }
             audio_session_t sessionId() const { return mSessionId; }
-            int         uid() const { return mUid; }
+            uid_t       uid() const { return mUid; }
     virtual status_t    setSyncEvent(const sp<SyncEvent>& event);
 
             sp<IMemory> getBuffers() const { return mBufferMemory; }
@@ -153,7 +153,7 @@
                                     // openRecord(), and then adjusted as needed
 
     const audio_session_t mSessionId;
-    int                 mUid;
+    uid_t               mUid;
     Vector < sp<SyncEvent> >mSyncEvents;
     const bool          mIsOut;
     sp<ServerProxy>     mServerProxy;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index e1fe7e2..8f134c1 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -72,7 +72,7 @@
             size_t frameCount,
             void *buffer,
             audio_session_t sessionId,
-            int clientUid,
+            uid_t clientUid,
             bool isOut,
             alloc_type alloc,
             track_type type)
@@ -99,10 +99,10 @@
         mThreadIoHandle(thread->id())
 {
     const uid_t callingUid = IPCThreadState::self()->getCallingUid();
-    if (!isTrustedCallingUid(callingUid) || clientUid == -1) {
-        ALOGW_IF(clientUid != -1 && clientUid != (int)callingUid,
+    if (!isTrustedCallingUid(callingUid) || clientUid == AUDIO_UID_INVALID) {
+        ALOGW_IF(clientUid != AUDIO_UID_INVALID && clientUid != callingUid,
                 "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
-        clientUid = (int)callingUid;
+        clientUid = callingUid;
     }
     // clientUid contains the uid of the app that is responsible for this track, so we can blame
     // battery usage on it.
@@ -341,7 +341,7 @@
             void *buffer,
             const sp<IMemory>& sharedBuffer,
             audio_session_t sessionId,
-            int uid,
+            uid_t uid,
             audio_output_flags_t flags,
             track_type type)
     :   TrackBase(thread, client, sampleRate, format, channelMask, frameCount,
@@ -1138,7 +1138,7 @@
             audio_format_t format,
             audio_channel_mask_t channelMask,
             size_t frameCount,
-            int uid)
+            uid_t uid)
     :   Track(playbackThread, NULL, AUDIO_STREAM_PATCH,
               sampleRate, format, channelMask, frameCount,
               NULL, 0, AUDIO_SESSION_NONE, uid, AUDIO_OUTPUT_FLAG_NONE,
@@ -1474,7 +1474,7 @@
             size_t frameCount,
             void *buffer,
             audio_session_t sessionId,
-            int uid,
+            uid_t uid,
             audio_input_flags_t flags,
             track_type type)
     :   TrackBase(thread, client, sampleRate, format,