diff options
Diffstat (limited to 'services')
27 files changed, 1985 insertions, 780 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 86d4cc3..0323fe0 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -81,6 +81,8 @@ static const int kDumpLockSleep = 20000; static const nsecs_t kWarningThrottle = seconds(5); +// RecordThread loop sleep time upon application overrun or audio HAL read error +static const int kRecordThreadSleepUs = 5000; // ---------------------------------------------------------------------------- @@ -417,7 +419,7 @@ sp<IAudioTrack> AudioFlinger::createTrack( lSessionId = *sessionId; } else { // if no audio session id is provided, create one here - lSessionId = nextUniqueId_l(); + lSessionId = nextUniqueId(); if (sessionId != NULL) { *sessionId = lSessionId; } @@ -725,6 +727,15 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs) thread = checkPlaybackThread_l(ioHandle); if (thread == NULL) { thread = checkRecordThread_l(ioHandle); + } else if (thread.get() == primaryPlaybackThread_l()) { + // indicate output device change to all input threads for pre processing + AudioParameter param = AudioParameter(keyValuePairs); + int value; + if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { + for (size_t i = 0; i < mRecordThreads.size(); i++) { + mRecordThreads.valueAt(i)->setParameters(keyValuePairs); + } + } } } if (thread != NULL) { @@ -873,10 +884,10 @@ void AudioFlinger::removeClient_l(pid_t pid) // ---------------------------------------------------------------------------- -AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id) +AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device) : Thread(false), mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0), - mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false) + mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false), mDevice(device) { } @@ -1032,14 +1043,15 @@ status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args return NO_ERROR; } - // ---------------------------------------------------------------------------- -AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) - : ThreadBase(audioFlinger, id), +AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, + AudioStreamOut* output, + int id, + uint32_t device) + : ThreadBase(audioFlinger, id, device), mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output), - mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false), - mDevice(device) + mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false) { readOutputParameters(); @@ -1199,9 +1211,9 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra } } - if (mOutput == 0) { + lStatus = initCheck(); + if (lStatus != NO_ERROR) { LOGE("Audio driver not initialized."); - lStatus = NO_INIT; goto Exit; } @@ -1423,7 +1435,7 @@ status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, ui if (halFrames == 0 || dspFrames == 0) { return BAD_VALUE; } - if (mOutput == 0) { + if (initCheck() != NO_ERROR) { return INVALID_OPERATION; } *halFrames = mBytesWritten / audio_stream_frame_size(&mOutput->stream->common); @@ -1468,34 +1480,6 @@ uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId) return AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC); } -sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId) -{ - Mutex::Autolock _l(mLock); - return getEffectChain_l(sessionId); -} - -sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId) -{ - sp<EffectChain> chain; - - size_t size = mEffectChains.size(); - for (size_t i = 0; i < size; i++) { - if (mEffectChains[i]->sessionId() == sessionId) { - chain = mEffectChains[i]; - break; - } - } - return chain; -} - -void AudioFlinger::PlaybackThread::setMode(uint32_t mode) -{ - Mutex::Autolock _l(mLock); - size_t size = mEffectChains.size(); - for (size_t i = 0; i < size; i++) { - mEffectChains[i]->setMode_l(mode); - } -} // ---------------------------------------------------------------------------- @@ -1503,7 +1487,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud : PlaybackThread(audioFlinger, output, id, device), mAudioMixer(0) { - mType = PlaybackThread::MIXER; + mType = ThreadBase::MIXER; mAudioMixer = new AudioMixer(mFrameCount, mSampleRate); // FIXME - Current mixer implementation only supports stereo output @@ -2072,7 +2056,7 @@ uint32_t AudioFlinger::MixerThread::suspendSleepTimeUs() AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device) : PlaybackThread(audioFlinger, output, id, device) { - mType = PlaybackThread::DIRECT; + mType = ThreadBase::DIRECT; } AudioFlinger::DirectOutputThread::~DirectOutputThread() @@ -2551,7 +2535,7 @@ uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs() AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id) : MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX) { - mType = PlaybackThread::DUPLICATING; + mType = ThreadBase::DUPLICATING; addOutputTrack(mainThread); } @@ -2970,7 +2954,7 @@ AudioFlinger::PlaybackThread::Track::Track( mStreamType = streamType; // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack - mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * audio_bytes_per_sample(format) : sizeof(uint8_t); + mCblk->frameSize = audio_is_linear_pcm(format) ? mChannelCount * sizeof(int16_t) : sizeof(uint8_t); } } @@ -3751,21 +3735,26 @@ sp<IAudioRecord> AudioFlinger::openRecord( if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) { lSessionId = *sessionId; } else { - lSessionId = nextUniqueId_l(); + lSessionId = nextUniqueId(); if (sessionId != NULL) { *sessionId = lSessionId; } } // create new record track. The record track uses one track in mHardwareMixerThread by convention. - recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate, - format, channelMask, frameCount, flags, lSessionId); - } - if (recordTrack->getCblk() == NULL) { + recordTrack = thread->createRecordTrack_l(client, + sampleRate, + format, + channelMask, + frameCount, + flags, + lSessionId, + &lStatus); + } + if (lStatus != NO_ERROR) { // remove local strong reference to Client before deleting the RecordTrack so that the Client // destructor is called by the TrackBase destructor with mLock held client.clear(); recordTrack.clear(); - lStatus = NO_MEMORY; goto Exit; } @@ -3814,10 +3803,16 @@ status_t AudioFlinger::RecordHandle::onTransact( // ---------------------------------------------------------------------------- -AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, int id) : - ThreadBase(audioFlinger, id), - mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0) +AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, + AudioStreamIn *input, + uint32_t sampleRate, + uint32_t channels, + int id, + uint32_t device) : + ThreadBase(audioFlinger, id, device), + mInput(input), mTrack(NULL), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0) { + mType = ThreadBase::RECORD; mReqChannelCount = popcount(channels); mReqSampleRate = sampleRate; readInputParameters(); @@ -3847,6 +3842,7 @@ bool AudioFlinger::RecordThread::threadLoop() { AudioBufferProvider::Buffer buffer; sp<RecordTrack> activeTrack; + Vector< sp<EffectChain> > effectChains; nsecs_t lastWarning = 0; @@ -3897,14 +3893,22 @@ bool AudioFlinger::RecordThread::threadLoop() mStandby = false; } } + lockEffectChains_l(effectChains); } if (mActiveTrack != 0) { if (mActiveTrack->mState != TrackBase::ACTIVE && mActiveTrack->mState != TrackBase::RESUMING) { - usleep(5000); + unlockEffectChains(effectChains); + usleep(kRecordThreadSleepUs); continue; } + for (size_t i = 0; i < effectChains.size(); i ++) { + effectChains[i]->process_l(); + } + // enable changes in effect chain + unlockEffectChains(effectChains); + buffer.frameCount = mFrameCount; if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) { size_t framesOut = buffer.frameCount; @@ -3953,7 +3957,7 @@ bool AudioFlinger::RecordThread::threadLoop() // Force input into standby so that it tries to // recover at next read attempt mInput->stream->common.standby(&mInput->stream->common); - usleep(5000); + usleep(kRecordThreadSleepUs); } mRsmpInIndex = mFrameCount; framesOut = 0; @@ -4001,9 +4005,12 @@ bool AudioFlinger::RecordThread::threadLoop() // Release the processor for a while before asking for a new buffer. // This will give the application more chance to read from the buffer and // clear the overflow. - usleep(5000); + usleep(kRecordThreadSleepUs); } + } else { + unlockEffectChains(effectChains); } + effectChains.clear(); } if (!mStandby) { @@ -4017,6 +4024,49 @@ bool AudioFlinger::RecordThread::threadLoop() return false; } + +sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l( + const sp<AudioFlinger::Client>& client, + uint32_t sampleRate, + int format, + int channelMask, + int frameCount, + uint32_t flags, + int sessionId, + status_t *status) +{ + sp<RecordTrack> track; + status_t lStatus; + + lStatus = initCheck(); + if (lStatus != NO_ERROR) { + LOGE("Audio driver not initialized."); + goto Exit; + } + + { // scope for mLock + Mutex::Autolock _l(mLock); + + track = new RecordTrack(this, client, sampleRate, + format, channelMask, frameCount, flags, sessionId); + + if (track->getCblk() == NULL) { + lStatus = NO_MEMORY; + goto Exit; + } + + mTrack = track.get(); + + } + lStatus = NO_ERROR; + +Exit: + if (status) { + *status = lStatus; + } + return track; +} + status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack) { LOGV("RecordThread::start"); @@ -4146,7 +4196,7 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* // Force input into standby so that it tries to // recover at next read attempt mInput->stream->common.standby(&mInput->stream->common); - usleep(5000); + usleep(kRecordThreadSleepUs); } buffer->raw = 0; buffer->frameCount = 0; @@ -4211,6 +4261,23 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l() reconfig = true; } } + if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) { + // forward device change to effects that have requested to be + // aware of attached audio device. + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->setDevice_l(value); + } + // store input device and output device but do not forward output device to audio HAL. + // Note that status is ignored by the caller for output device + // (see AudioFlinger::setParameters() + if (value & AUDIO_DEVICE_OUT_ALL) { + mDevice &= (uint32_t)~(value & AUDIO_DEVICE_OUT_ALL); + status = BAD_VALUE; + } else { + mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL); + } + mDevice |= (uint32_t)value; + } if (status == NO_ERROR) { status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string()); if (status == INVALID_OPERATION) { @@ -4320,6 +4387,21 @@ unsigned int AudioFlinger::RecordThread::getInputFramesLost() return mInput->stream->get_input_frames_lost(mInput->stream); } +uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId) +{ + Mutex::Autolock _l(mLock); + uint32_t result = 0; + if (getEffectChain_l(sessionId) != 0) { + result = EFFECT_SESSION; + } + + if (mTrack != NULL && sessionId == mTrack->sessionId()) { + result |= TRACK_SESSION; + } + + return result; +} + // ---------------------------------------------------------------------------- int AudioFlinger::openOutput(uint32_t *pDevices, @@ -4368,7 +4450,7 @@ int AudioFlinger::openOutput(uint32_t *pDevices, mHardwareStatus = AUDIO_HW_IDLE; if (outStream != NULL) { AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream); - int id = nextUniqueId_l(); + int id = nextUniqueId(); if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) || (format != AUDIO_FORMAT_PCM_16_BIT) || @@ -4405,7 +4487,7 @@ int AudioFlinger::openDuplicateOutput(int output1, int output2) return 0; } - int id = nextUniqueId_l(); + int id = nextUniqueId(); DuplicatingThread *thread = new DuplicatingThread(this, thread1, id); thread->addOutputTrack(thread2); mPlaybackThreads.add(id, thread); @@ -4428,9 +4510,9 @@ status_t AudioFlinger::closeOutput(int output) LOGV("closeOutput() %d", output); - if (thread->type() == PlaybackThread::MIXER) { + if (thread->type() == ThreadBase::MIXER) { for (size_t i = 0; i < mPlaybackThreads.size(); i++) { - if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) { + if (mPlaybackThreads.valueAt(i)->type() == ThreadBase::DUPLICATING) { DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get(); dupThread->removeOutputTrack((MixerThread *)thread.get()); } @@ -4442,7 +4524,7 @@ status_t AudioFlinger::closeOutput(int output) } thread->exit(); - if (thread->type() != PlaybackThread::DUPLICATING) { + if (thread->type() != ThreadBase::DUPLICATING) { AudioStreamOut *out = thread->getOutput(); out->hwDev->close_output_stream(out->hwDev, out->stream); delete out; @@ -4537,9 +4619,17 @@ int AudioFlinger::openInput(uint32_t *pDevices, if (inStream != NULL) { AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream); - int id = nextUniqueId_l(); - // Start record thread - thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id); + int id = nextUniqueId(); + // Start record thread + // RecorThread require both input and output device indication to forward to audio + // pre processing modules + uint32_t device = (*pDevices) | primaryOutputDevice_l(); + thread = new RecordThread(this, + input, + reqSamplingRate, + reqChannels, + id, + device); mRecordThreads.add(id, thread); LOGV("openInput() created record thread: ID %d thread %p", id, thread); if (pSamplingRate) *pSamplingRate = reqSamplingRate; @@ -4597,7 +4687,7 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) for (size_t i = 0; i < mPlaybackThreads.size(); i++) { PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); if (thread != dstThread && - thread->type() != PlaybackThread::DIRECT) { + thread->type() != ThreadBase::DIRECT) { MixerThread *srcThread = (MixerThread *)thread; srcThread->invalidateTracks(stream); } @@ -4609,8 +4699,7 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) int AudioFlinger::newAudioSessionId() { - AutoMutex _l(mLock); - return nextUniqueId_l(); + return nextUniqueId(); } // checkPlaybackThread_l() must be called with AudioFlinger::mLock held @@ -4628,7 +4717,7 @@ AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const { PlaybackThread *thread = checkPlaybackThread_l(output); if (thread != NULL) { - if (thread->type() == PlaybackThread::DIRECT) { + if (thread->type() == ThreadBase::DIRECT) { thread = NULL; } } @@ -4645,12 +4734,34 @@ AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const return thread; } -// nextUniqueId_l() must be called with AudioFlinger::mLock held -int AudioFlinger::nextUniqueId_l() +uint32_t AudioFlinger::nextUniqueId() +{ + return android_atomic_inc(&mNextUniqueId); +} + +AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l() { - return mNextUniqueId++; + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + PlaybackThread *thread = mPlaybackThreads.valueAt(i).get(); + if (thread->getOutput()->hwDev == mPrimaryHardwareDev) { + return thread; + } + } + return NULL; +} + +uint32_t AudioFlinger::primaryOutputDevice_l() +{ + PlaybackThread *thread = primaryPlaybackThread_l(); + + if (thread == NULL) { + return 0; + } + + return thread->device(); } + // ---------------------------------------------------------------------------- // Effect management // ---------------------------------------------------------------------------- @@ -4683,7 +4794,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, effect_descriptor_t *pDesc, const sp<IEffectClient>& effectClient, int32_t priority, - int output, + int io, int sessionId, status_t *status, int *id, @@ -4695,8 +4806,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, sp<Client> client; wp<Client> wclient; - LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d", - pid, effectClient.get(), priority, sessionId, output); + LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, io %d", + pid, effectClient.get(), priority, sessionId, io); if (pDesc == NULL) { lStatus = BAD_VALUE; @@ -4724,7 +4835,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, goto Exit; } - if (output == 0) { + if (io == 0) { if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) { // output must be specified by AudioPolicyManager when using session // AUDIO_SESSION_OUTPUT_STAGE @@ -4732,9 +4843,9 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, goto Exit; } else if (sessionId == AUDIO_SESSION_OUTPUT_MIX) { // if the output returned by getOutputForEffect() is removed before we lock the - // mutex below, the call to checkPlaybackThread_l(output) below will detect it + // mutex below, the call to checkPlaybackThread_l(io) below will detect it // and we will exit safely - output = AudioSystem::getOutputForEffect(&desc); + io = AudioSystem::getOutputForEffect(&desc); } } @@ -4811,31 +4922,41 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, // output threads. // If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX // because of code checking output when entering the function. - if (output == 0) { + // Note: io is never 0 when creating an effect on an input + if (io == 0) { // look for the thread where the specified audio session is present for (size_t i = 0; i < mPlaybackThreads.size(); i++) { if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) { - output = mPlaybackThreads.keyAt(i); + io = mPlaybackThreads.keyAt(i); break; } } + if (io == 0) { + for (size_t i = 0; i < mRecordThreads.size(); i++) { + if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) { + io = mRecordThreads.keyAt(i); + break; + } + } + } // If no output thread contains the requested session ID, default to // first output. The effect chain will be moved to the correct output // thread when a track with the same session ID is created - if (output == 0 && mPlaybackThreads.size()) { - output = mPlaybackThreads.keyAt(0); + if (io == 0 && mPlaybackThreads.size()) { + io = mPlaybackThreads.keyAt(0); } + LOGV("createEffect() got io %d for effect %s", io, desc.name); } - LOGV("createEffect() got output %d for effect %s", output, desc.name); - PlaybackThread *thread = checkPlaybackThread_l(output); + ThreadBase *thread = checkRecordThread_l(io); if (thread == NULL) { - LOGE("createEffect() unknown output thread"); - lStatus = BAD_VALUE; - goto Exit; + thread = checkPlaybackThread_l(io); + if (thread == NULL) { + LOGE("createEffect() unknown output thread"); + lStatus = BAD_VALUE; + goto Exit; + } } - // TODO: allow attachment of effect to inputs - wclient = mClients.valueFor(pid); if (wclient != NULL) { @@ -4943,8 +5064,9 @@ status_t AudioFlinger::moveEffectChain_l(int session, return NO_ERROR; } + // PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held -sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( +sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l( const sp<AudioFlinger::Client>& client, const sp<IEffectClient>& effectClient, int32_t priority, @@ -4957,24 +5079,14 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( sp<EffectModule> effect; sp<EffectHandle> handle; status_t lStatus; - sp<Track> track; sp<EffectChain> chain; bool chainCreated = false; bool effectCreated = false; bool effectRegistered = false; - if (mOutput == 0) { + lStatus = initCheck(); + if (lStatus != NO_ERROR) { LOGW("createEffect_l() Audio driver not initialized."); - lStatus = NO_INIT; - goto Exit; - } - - // Do not allow auxiliary effect on session other than 0 - if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY && - sessionId != AUDIO_SESSION_OUTPUT_MIX) { - LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", - desc->name, sessionId); - lStatus = BAD_VALUE; goto Exit; } @@ -4986,6 +5098,16 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( lStatus = BAD_VALUE; goto Exit; } + // Only Pre processor effects are allowed on input threads and only on input threads + if ((mType == RECORD && + (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) || + (mType != RECORD && + (desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) { + LOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d", + desc->name, desc->flags, mType); + lStatus = BAD_VALUE; + goto Exit; + } LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId); @@ -5008,7 +5130,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get()); if (effect == 0) { - int id = mAudioFlinger->nextUniqueId_l(); + int id = mAudioFlinger->nextUniqueId(); // Check CPU and memory usage lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id); if (lStatus != NO_ERROR) { @@ -5059,9 +5181,20 @@ Exit: return handle; } +sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect_l(int sessionId, int effectId) +{ + sp<EffectModule> effect; + + sp<EffectChain> chain = getEffectChain_l(sessionId); + if (chain != 0) { + effect = chain->getEffectFromId_l(effectId); + } + return effect; +} + // PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and // PlaybackThread::mLock held -status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effect) +status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect) { // check for existing effect chain with the requested audio session int sessionId = effect->sessionId(); @@ -5097,7 +5230,7 @@ status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effec return NO_ERROR; } -void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect) { +void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect) { LOGV("removeEffect_l() %p effect %p", this, effect.get()); effect_descriptor_t desc = effect->desc(); @@ -5116,7 +5249,53 @@ void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect } } -void AudioFlinger::PlaybackThread::disconnectEffect(const sp<EffectModule>& effect, +void AudioFlinger::ThreadBase::lockEffectChains_l( + Vector<sp <AudioFlinger::EffectChain> >& effectChains) +{ + effectChains = mEffectChains; + for (size_t i = 0; i < mEffectChains.size(); i++) { + mEffectChains[i]->lock(); + } +} + +void AudioFlinger::ThreadBase::unlockEffectChains( + Vector<sp <AudioFlinger::EffectChain> >& effectChains) +{ + for (size_t i = 0; i < effectChains.size(); i++) { + effectChains[i]->unlock(); + } +} + +sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain(int sessionId) +{ + Mutex::Autolock _l(mLock); + return getEffectChain_l(sessionId); +} + +sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId) +{ + sp<EffectChain> chain; + + size_t size = mEffectChains.size(); + for (size_t i = 0; i < size; i++) { + if (mEffectChains[i]->sessionId() == sessionId) { + chain = mEffectChains[i]; + break; + } + } + return chain; +} + +void AudioFlinger::ThreadBase::setMode(uint32_t mode) +{ + Mutex::Autolock _l(mLock); + size_t size = mEffectChains.size(); + for (size_t i = 0; i < size; i++) { + mEffectChains[i]->setMode_l(mode); + } +} + +void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect, const wp<EffectHandle>& handle) { Mutex::Autolock _l(mLock); LOGV("disconnectEffect() %p effect %p", this, effect.get()); @@ -5222,35 +5401,6 @@ size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>& return mEffectChains.size(); } -void AudioFlinger::PlaybackThread::lockEffectChains_l( - Vector<sp <AudioFlinger::EffectChain> >& effectChains) -{ - effectChains = mEffectChains; - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->lock(); - } -} - -void AudioFlinger::PlaybackThread::unlockEffectChains( - Vector<sp <AudioFlinger::EffectChain> >& effectChains) -{ - for (size_t i = 0; i < effectChains.size(); i++) { - effectChains[i]->unlock(); - } -} - - -sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId) -{ - sp<EffectModule> effect; - - sp<EffectChain> chain = getEffectChain_l(sessionId); - if (chain != 0) { - effect = chain->getEffectFromId_l(effectId); - } - return effect; -} - status_t AudioFlinger::PlaybackThread::attachAuxEffect( const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) { @@ -5291,6 +5441,34 @@ void AudioFlinger::PlaybackThread::detachAuxEffect_l(int effectId) } } +status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain) +{ + // only one chain per input thread + if (mEffectChains.size() != 0) { + return INVALID_OPERATION; + } + LOGV("addEffectChain_l() %p on thread %p", chain.get(), this); + + chain->setInBuffer(NULL); + chain->setOutBuffer(NULL); + + mEffectChains.add(chain); + + return NO_ERROR; +} + +size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& chain) +{ + LOGV("removeEffectChain_l() %p from thread %p", chain.get(), this); + LOGW_IF(mEffectChains.size() != 1, + "removeEffectChain_l() %p invalid chain size %d on thread %p", + chain.get(), mEffectChains.size(), this); + if (mEffectChains.size() == 1) { + mEffectChains.removeAt(0); + } + return 0; +} + // ---------------------------------------------------------------------------- // EffectModule implementation // ---------------------------------------------------------------------------- @@ -5312,12 +5490,11 @@ AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread, if (thread == 0) { return; } - PlaybackThread *p = (PlaybackThread *)thread.get(); memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t)); // create effect engine from effect factory - mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface); + mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface); if (mStatus != NO_ERROR) { return; @@ -5340,6 +5517,13 @@ AudioFlinger::EffectModule::~EffectModule() { LOGV("Destructor %p", this); if (mEffectInterface != NULL) { + if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC || + (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) { + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface); + } + } // release effect engine EffectRelease(mEffectInterface); } @@ -5415,8 +5599,7 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle) { sp<ThreadBase> thread = mThread.promote(); if (thread != 0) { - PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); - playbackThread->disconnectEffect(keep, handle); + thread->disconnectEffect(keep, handle); } } } @@ -5626,6 +5809,14 @@ status_t AudioFlinger::EffectModule::start_l() if (status == 0) { status = cmdStatus; } + if (status == 0 && + ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC || + (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) { + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + thread->stream()->add_audio_effect(thread->stream(), mEffectInterface); + } + } return status; } @@ -5645,6 +5836,14 @@ status_t AudioFlinger::EffectModule::stop_l() if (status == 0) { status = cmdStatus; } + if (status == 0 && + ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC || + (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) { + sp<ThreadBase> thread = mThread.promote(); + if (thread != 0) { + thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface); + } + } return status; } @@ -5784,17 +5983,41 @@ status_t AudioFlinger::EffectModule::setDevice(uint32_t device) { Mutex::Autolock _l(mLock); status_t status = NO_ERROR; - if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { - status_t cmdStatus; - uint32_t size = sizeof(status_t); - status = (*mEffectInterface)->command(mEffectInterface, - EFFECT_CMD_SET_DEVICE, - sizeof(uint32_t), - &device, - &size, - &cmdStatus); - if (status == NO_ERROR) { - status = cmdStatus; + if (device && (mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) { + // audio pre processing modules on RecordThread can receive both output and + // input device indication in the same call + uint32_t dev = device & AUDIO_DEVICE_OUT_ALL; + if (dev) { + status_t cmdStatus; + uint32_t size = sizeof(status_t); + + status = (*mEffectInterface)->command(mEffectInterface, + EFFECT_CMD_SET_DEVICE, + sizeof(uint32_t), + &dev, + &size, + &cmdStatus); + if (status == NO_ERROR) { + status = cmdStatus; + } + } + dev = device & AUDIO_DEVICE_IN_ALL; + if (dev) { + status_t cmdStatus; + uint32_t size = sizeof(status_t); + + status_t status2 = (*mEffectInterface)->command(mEffectInterface, + EFFECT_CMD_SET_INPUT_DEVICE, + sizeof(uint32_t), + &dev, + &size, + &cmdStatus); + if (status2 == NO_ERROR) { + status2 = cmdStatus; + } + if (status == NO_ERROR) { + status = status2; + } } } return status; @@ -6168,7 +6391,6 @@ void AudioFlinger::EffectChain::process_l() LOGW("process_l(): cannot promote mixer thread"); return; } - PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) || (mSessionId == AUDIO_SESSION_OUTPUT_STAGE); bool tracksOnSession = false; @@ -6180,7 +6402,7 @@ void AudioFlinger::EffectChain::process_l() // will not do it if (tracksOnSession && activeTrackCnt() == 0) { - size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount(); + size_t numSamples = thread->frameCount() * thread->channelCount(); memset(mInBuffer, 0, numSamples * sizeof(int16_t)); } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 1fad987..fff4f06 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -157,7 +157,7 @@ public: effect_descriptor_t *pDesc, const sp<IEffectClient>& effectClient, int32_t priority, - int output, + int io, int sessionId, status_t *status, int *id, @@ -273,9 +273,17 @@ private: class ThreadBase : public Thread { public: - ThreadBase (const sp<AudioFlinger>& audioFlinger, int id); + ThreadBase (const sp<AudioFlinger>& audioFlinger, int id, uint32_t device); virtual ~ThreadBase(); + + enum type { + MIXER, // Thread class is MixerThread + DIRECT, // Thread class is DirectOutputThread + DUPLICATING, // Thread class is DuplicatingThread + RECORD // Thread class is RecordThread + }; + status_t dumpBase(int fd, const Vector<String16>& args); // base for record and playback @@ -377,6 +385,8 @@ private: int mParam; }; + virtual status_t initCheck() const = 0; + int type() const { return mType; } uint32_t sampleRate() const; int channelCount() const; uint32_t format() const; @@ -392,6 +402,60 @@ private: void processConfigEvents(); int id() const { return mId;} bool standby() { return mStandby; } + uint32_t device() { return mDevice; } + virtual audio_stream_t* stream() = 0; + + sp<EffectHandle> createEffect_l( + const sp<AudioFlinger::Client>& client, + const sp<IEffectClient>& effectClient, + int32_t priority, + int sessionId, + effect_descriptor_t *desc, + int *enabled, + status_t *status); + void disconnectEffect(const sp< EffectModule>& effect, + const wp<EffectHandle>& handle); + + // return values for hasAudioSession (bit field) + enum effect_state { + EFFECT_SESSION = 0x1, // the audio session corresponds to at least one + // effect + TRACK_SESSION = 0x2 // the audio session corresponds to at least one + // track + }; + + // get effect chain corresponding to session Id. + sp<EffectChain> getEffectChain(int sessionId); + // same as getEffectChain() but must be called with ThreadBase mutex locked + sp<EffectChain> getEffectChain_l(int sessionId); + // add an effect chain to the chain list (mEffectChains) + virtual status_t addEffectChain_l(const sp<EffectChain>& chain) = 0; + // remove an effect chain from the chain list (mEffectChains) + virtual size_t removeEffectChain_l(const sp<EffectChain>& chain) = 0; + // lock mall effect chains Mutexes. Must be called before releasing the + // ThreadBase mutex before processing the mixer and effects. This guarantees the + // integrity of the chains during the process. + void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains); + // unlock effect chains after process + void unlockEffectChains(Vector<sp <EffectChain> >& effectChains); + // set audio mode to all effect chains + void setMode(uint32_t mode); + // get effect module with corresponding ID on specified audio session + sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId); + // add and effect module. Also creates the effect chain is none exists for + // the effects audio session + status_t addEffect_l(const sp< EffectModule>& effect); + // remove and effect module. Also removes the effect chain is this was the last + // effect + void removeEffect_l(const sp< EffectModule>& effect); + // detach all tracks connected to an auxiliary effect + virtual void detachAuxEffect_l(int effectId) {} + // returns either EFFECT_SESSION if effects on this audio session exist in one + // chain, or TRACK_SESSION if tracks on this audio session exist, or both + virtual uint32_t hasAudioSession(int sessionId) = 0; + // the value returned by default implementation is not important as the + // strategy is only meaningful for PlaybackThread which implements this method + virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; } mutable Mutex mLock; @@ -406,6 +470,7 @@ private: friend class RecordThread; friend class RecordTrack; + int mType; Condition mWaitWorkCV; sp<AudioFlinger> mAudioFlinger; uint32_t mSampleRate; @@ -421,18 +486,15 @@ private: bool mStandby; int mId; bool mExiting; + Vector< sp<EffectChain> > mEffectChains; + uint32_t mDevice; // output device for PlaybackThread + // input + output devices for RecordThread }; // --- PlaybackThread --- class PlaybackThread : public ThreadBase { public: - enum type { - MIXER, - DIRECT, - DUPLICATING - }; - enum mixer_state { MIXER_IDLE, MIXER_TRACKS_ENABLED, @@ -569,6 +631,8 @@ private: virtual status_t readyToRun(); virtual void onFirstRef(); + virtual status_t initCheck() const { return (mOutput == 0) ? NO_INIT : NO_ERROR; } + virtual uint32_t latency() const; virtual status_t setMasterVolume(float value); @@ -595,8 +659,8 @@ private: status_t *status); AudioStreamOut* getOutput() { return mOutput; } + virtual audio_stream_t* stream() { return &mOutput->stream->common; } - virtual int type() const { return mType; } void suspend() { mSuspended++; } void restore() { if (mSuspended) mSuspended--; } bool isSuspended() { return (mSuspended != 0); } @@ -605,45 +669,16 @@ private: virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); int16_t *mixBuffer() { return mMixBuffer; }; - sp<EffectHandle> createEffect_l( - const sp<AudioFlinger::Client>& client, - const sp<IEffectClient>& effectClient, - int32_t priority, - int sessionId, - effect_descriptor_t *desc, - int *enabled, - status_t *status); - void disconnectEffect(const sp< EffectModule>& effect, - const wp<EffectHandle>& handle); - - // return values for hasAudioSession (bit field) - enum effect_state { - EFFECT_SESSION = 0x1, // the audio session corresponds to at least one - // effect - TRACK_SESSION = 0x2 // the audio session corresponds to at least one - // track - }; - - uint32_t hasAudioSession(int sessionId); - sp<EffectChain> getEffectChain(int sessionId); - sp<EffectChain> getEffectChain_l(int sessionId); - status_t addEffectChain_l(const sp<EffectChain>& chain); - size_t removeEffectChain_l(const sp<EffectChain>& chain); - void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains); - void unlockEffectChains(Vector<sp <EffectChain> >& effectChains); - - sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId); - void detachAuxEffect_l(int effectId); + virtual void detachAuxEffect_l(int effectId); status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId); status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId); - void setMode(uint32_t mode); - status_t addEffect_l(const sp< EffectModule>& effect); - void removeEffect_l(const sp< EffectModule>& effect); - - uint32_t getStrategyForSession_l(int sessionId); + virtual status_t addEffectChain_l(const sp<EffectChain>& chain); + virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); + virtual uint32_t hasAudioSession(int sessionId); + virtual uint32_t getStrategyForSession_l(int sessionId); struct stream_type_t { stream_type_t() @@ -656,7 +691,6 @@ private: }; protected: - int mType; int16_t* mMixBuffer; int mSuspended; int mBytesWritten; @@ -688,8 +722,6 @@ private: void readOutputParameters(); - uint32_t device() { return mDevice; } - virtual status_t dumpInternals(int fd, const Vector<String16>& args); status_t dumpTracks(int fd, const Vector<String16>& args); status_t dumpEffectChains(int fd, const Vector<String16>& args); @@ -703,8 +735,6 @@ private: int mNumWrites; int mNumDelayedWrites; bool mInWrite; - Vector< sp<EffectChain> > mEffectChains; - uint32_t mDevice; }; class MixerThread : public PlaybackThread { @@ -788,11 +818,13 @@ private: float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; } void audioConfigChanged_l(int event, int ioHandle, void *param2); - int nextUniqueId_l(); + uint32_t nextUniqueId(); status_t moveEffectChain_l(int session, AudioFlinger::PlaybackThread *srcThread, AudioFlinger::PlaybackThread *dstThread, bool reRegister); + PlaybackThread *primaryPlaybackThread_l(); + uint32_t primaryOutputDevice_l(); friend class AudioBuffer; @@ -864,18 +896,33 @@ private: AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, - int id); + int id, + uint32_t device); ~RecordThread(); virtual bool threadLoop(); virtual status_t readyToRun() { return NO_ERROR; } virtual void onFirstRef(); + virtual status_t initCheck() const { return (mInput == 0) ? NO_INIT : NO_ERROR; } + sp<AudioFlinger::RecordThread::RecordTrack> createRecordTrack_l( + const sp<AudioFlinger::Client>& client, + uint32_t sampleRate, + int format, + int channelMask, + int frameCount, + uint32_t flags, + int sessionId, + status_t *status); + status_t start(RecordTrack* recordTrack); void stop(RecordTrack* recordTrack); status_t dump(int fd, const Vector<String16>& args); AudioStreamIn* getInput() { return mInput; } + virtual audio_stream_t* stream() { return &mInput->stream->common; } + + void setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; } virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer); virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer); virtual bool checkForNewParameters_l(); @@ -884,9 +931,14 @@ private: void readInputParameters(); virtual unsigned int getInputFramesLost(); + virtual status_t addEffectChain_l(const sp<EffectChain>& chain); + virtual size_t removeEffectChain_l(const sp<EffectChain>& chain); + virtual uint32_t hasAudioSession(int sessionId); + private: RecordThread(); AudioStreamIn *mInput; + RecordTrack* mTrack; sp<RecordTrack> mActiveTrack; Condition mStartStopCond; AudioResampler *mResampler; @@ -1103,9 +1155,8 @@ private: status_t addEffect_l(const sp<EffectModule>& handle); size_t removeEffect_l(const sp<EffectModule>& handle); - int sessionId() { - return mSessionId; - } + int sessionId() { return mSessionId; } + void setSessionId(int sessionId) { mSessionId = sessionId; } sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor); sp<EffectModule> getEffectFromId_l(int id); diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index 8e16d94..dd1e153 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -33,11 +33,14 @@ #include <cutils/properties.h> #include <dlfcn.h> #include <hardware_legacy/power.h> +#include <media/AudioEffect.h> +#include <media/EffectsFactoryApi.h> #include <hardware/hardware.h> #include <system/audio.h> #include <system/audio_policy.h> #include <hardware/audio_policy.h> +#include <audio_effects/audio_effects_conf.h> namespace android { @@ -101,6 +104,13 @@ AudioPolicyService::AudioPolicyService() mpAudioPolicy->set_can_mute_enforced_audible(mpAudioPolicy, !forced_val); LOGI("Loaded audio policy from %s (%s)", module->name, module->id); + + // load audio pre processing modules + if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) { + loadPreProcessorConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE); + } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) { + loadPreProcessorConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE); + } } AudioPolicyService::~AudioPolicyService() @@ -110,6 +120,31 @@ AudioPolicyService::~AudioPolicyService() mAudioCommandThread->exit(); mAudioCommandThread.clear(); + + // release audio pre processing resources + for (size_t i = 0; i < mInputSources.size(); i++) { + InputSourceDesc *source = mInputSources.valueAt(i); + Vector <EffectDesc *> effects = source->mEffects; + for (size_t j = 0; j < effects.size(); j++) { + delete effects[j]->mName; + Vector <effect_param_t *> params = effects[j]->mParams; + for (size_t k = 0; k < params.size(); k++) { + delete params[k]; + } + params.clear(); + delete effects[j]; + } + effects.clear(); + delete source; + } + mInputSources.clear(); + + for (size_t i = 0; i < mInputs.size(); i++) { + mInputs.valueAt(i)->mEffects.clear(); + delete mInputs.valueAt(i); + } + mInputs.clear(); + if (mpAudioPolicy && mpAudioPolicyDev) mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy); if (mpAudioPolicyDev) @@ -276,13 +311,51 @@ audio_io_handle_t AudioPolicyService::getInput(int inputSource, uint32_t samplingRate, uint32_t format, uint32_t channels, - audio_in_acoustics_t acoustics) + audio_in_acoustics_t acoustics, + int audioSession) { if (mpAudioPolicy == NULL) { return 0; } Mutex::Autolock _l(mLock); - return mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, format, channels, acoustics); + audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, + format, channels, acoustics); + + if (input == 0) { + return input; + } + // create audio pre processors according to input source + ssize_t index = mInputSources.indexOfKey((audio_source_t)inputSource); + if (index < 0) { + return input; + } + ssize_t idx = mInputs.indexOfKey(input); + InputDesc *inputDesc; + if (idx < 0) { + inputDesc = new InputDesc(); + inputDesc->mSessionId = audioSession; + mInputs.add(input, inputDesc); + } else { + inputDesc = mInputs.valueAt(idx); + } + + 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); + status_t status = fx->initCheck(); + if (status != NO_ERROR && status != ALREADY_EXISTS) { + LOGW("Failed to create Fx %s on input %d", effect->mName, input); + // fx goes out of scope and strong ref on AudioEffect is released + continue; + } + for (size_t j = 0; j < effect->mParams.size(); j++) { + fx->setParameter(effect->mParams[j]); + } + inputDesc->mEffects.add(fx); + } + setPreProcessorEnabled(inputDesc, true); + return input; } status_t AudioPolicyService::startInput(audio_io_handle_t input) @@ -291,6 +364,7 @@ status_t AudioPolicyService::startInput(audio_io_handle_t input) return NO_INIT; } Mutex::Autolock _l(mLock); + return mpAudioPolicy->start_input(mpAudioPolicy, input); } @@ -300,6 +374,7 @@ status_t AudioPolicyService::stopInput(audio_io_handle_t input) return NO_INIT; } Mutex::Autolock _l(mLock); + return mpAudioPolicy->stop_input(mpAudioPolicy, input); } @@ -310,6 +385,16 @@ void AudioPolicyService::releaseInput(audio_io_handle_t input) } Mutex::Autolock _l(mLock); mpAudioPolicy->release_input(mpAudioPolicy, input); + + ssize_t index = mInputs.indexOfKey(input); + if (index < 0) { + return; + } + InputDesc *inputDesc = mInputs.valueAt(index); + setPreProcessorEnabled(inputDesc, false); + inputDesc->mEffects.clear(); + delete inputDesc; + mInputs.removeItemsAt(index); } status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream, @@ -384,7 +469,7 @@ audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *de } status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc, - audio_io_handle_t output, + audio_io_handle_t io, uint32_t strategy, int session, int id) @@ -392,7 +477,7 @@ status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc, if (mpAudioPolicy == NULL) { return NO_INIT; } - return mpAudioPolicy->register_effect(mpAudioPolicy, desc, output, strategy, session, id); + return mpAudioPolicy->register_effect(mpAudioPolicy, desc, io, strategy, session, id); } status_t AudioPolicyService::unregisterEffect(int id) @@ -489,6 +574,15 @@ status_t AudioPolicyService::dumpPermissionDenial(int fd) return NO_ERROR; } +void AudioPolicyService::setPreProcessorEnabled(InputDesc *inputDesc, bool enabled) +{ + Vector<sp<AudioEffect> > fxVector = inputDesc->mEffects; + for (size_t i = 0; i < fxVector.size(); i++) { + sp<AudioEffect> fx = fxVector.itemAt(i); + fx->setEnabled(enabled); + } +} + status_t AudioPolicyService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { @@ -918,6 +1012,300 @@ int AudioPolicyService::setVoiceVolume(float volume, int delayMs) return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs); } +// ---------------------------------------------------------------------------- +// Audio pre-processing configuration +// ---------------------------------------------------------------------------- + +const char *AudioPolicyService::kInputSourceNames[AUDIO_SOURCE_CNT -1] = { + MIC_SRC_TAG, + VOICE_UL_SRC_TAG, + VOICE_DL_SRC_TAG, + VOICE_CALL_SRC_TAG, + CAMCORDER_SRC_TAG, + VOICE_REC_SRC_TAG, + VOICE_COMM_SRC_TAG +}; + +// returns the audio_source_t enum corresponding to the input source name or +// AUDIO_SOURCE_CNT is no match found +audio_source_t AudioPolicyService::inputSourceNameToEnum(const char *name) +{ + int i; + for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) { + if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) { + LOGV("inputSourceNameToEnum found source %s %d", name, i); + break; + } + } + return (audio_source_t)i; +} + +size_t AudioPolicyService::growParamSize(char *param, + size_t size, + size_t *curSize, + size_t *totSize) +{ + // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int) + size_t pos = ((*curSize - 1 ) / size + 1) * size; + + if (pos + size > *totSize) { + while (pos + size > *totSize) { + *totSize += ((*totSize + 7) / 8) * 4; + } + param = (char *)realloc(param, *totSize); + } + *curSize = pos + size; + return pos; +} + +size_t AudioPolicyService::readParamValue(cnode *node, + char *param, + size_t *curSize, + size_t *totSize) +{ + if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) { + size_t pos = growParamSize(param, sizeof(short), curSize, totSize); + *(short *)((char *)param + pos) = (short)atoi(node->value); + LOGV("readParamValue() reading short %d", *(short *)((char *)param + pos)); + return sizeof(short); + } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) { + size_t pos = growParamSize(param, sizeof(int), curSize, totSize); + *(int *)((char *)param + pos) = atoi(node->value); + LOGV("readParamValue() reading int %d", *(int *)((char *)param + pos)); + return sizeof(int); + } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) { + size_t pos = growParamSize(param, sizeof(float), curSize, totSize); + *(float *)((char *)param + pos) = (float)atof(node->value); + LOGV("readParamValue() reading float %f",*(float *)((char *)param + pos)); + return sizeof(float); + } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) { + size_t pos = growParamSize(param, sizeof(bool), curSize, totSize); + if (strncmp(node->value, "false", strlen("false") + 1) == 0) { + *(bool *)((char *)param + pos) = false; + } else { + *(bool *)((char *)param + pos) = true; + } + LOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false"); + return sizeof(bool); + } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) { + size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX); + if (*curSize + len + 1 > *totSize) { + *totSize = *curSize + len + 1; + param = (char *)realloc(param, *totSize); + } + strncpy(param + *curSize, node->value, len); + *curSize += len; + param[*curSize] = '\0'; + LOGV("readParamValue() reading string %s", param + *curSize - len); + return len; + } + LOGW("readParamValue() unknown param type %s", node->name); + return 0; +} + +effect_param_t *AudioPolicyService::loadEffectParameter(cnode *root) +{ + cnode *param; + cnode *value; + size_t curSize = sizeof(effect_param_t); + size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int); + effect_param_t *fx_param = (effect_param_t *)malloc(totSize); + + param = config_find(root, PARAM_TAG); + value = config_find(root, VALUE_TAG); + if (param == NULL && value == NULL) { + // try to parse simple parameter form {int int} + param = root->first_child; + if (param) { + // Note: that a pair of random strings is read as 0 0 + int *ptr = (int *)fx_param->data; + int *ptr2 = (int *)((char *)param + sizeof(effect_param_t)); + LOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2); + *ptr++ = atoi(param->name); + *ptr = atoi(param->value); + fx_param->psize = sizeof(int); + fx_param->vsize = sizeof(int); + return fx_param; + } + } + if (param == NULL || value == NULL) { + LOGW("loadEffectParameter() invalid parameter description %s", root->name); + goto error; + } + + fx_param->psize = 0; + param = param->first_child; + while (param) { + LOGV("loadEffectParameter() reading param of type %s", param->name); + size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize); + if (size == 0) { + goto error; + } + fx_param->psize += size; + param = param->next; + } + + // align start of value field on 32 bit boundary + curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int); + + fx_param->vsize = 0; + value = value->first_child; + while (value) { + LOGV("loadEffectParameter() reading value of type %s", value->name); + size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize); + if (size == 0) { + goto error; + } + fx_param->vsize += size; + value = value->next; + } + + return fx_param; + +error: + delete fx_param; + return NULL; +} + +void AudioPolicyService::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params) +{ + cnode *node = root->first_child; + while (node) { + LOGV("loadEffectParameters() loading param %s", node->name); + effect_param_t *param = loadEffectParameter(node); + if (param == NULL) { + node = node->next; + continue; + } + params.add(param); + node = node->next; + } +} + +AudioPolicyService::InputSourceDesc *AudioPolicyService::loadInputSource( + cnode *root, + const Vector <EffectDesc *>& effects) +{ + cnode *node = root->first_child; + if (node == NULL) { + LOGW("loadInputSource() empty element %s", root->name); + return NULL; + } + InputSourceDesc *source = new InputSourceDesc(); + while (node) { + size_t i; + for (i = 0; i < effects.size(); i++) { + if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) { + LOGV("loadInputSource() found effect %s in list", node->name); + break; + } + } + if (i == effects.size()) { + LOGV("loadInputSource() effect %s not in list", node->name); + node = node->next; + continue; + } + EffectDesc *effect = new EffectDesc(*effects[i]); + loadEffectParameters(node, effect->mParams); + LOGV("loadInputSource() adding effect %s uuid %08x", effect->mName, effect->mUuid.timeLow); + source->mEffects.add(effect); + node = node->next; + } + if (source->mEffects.size() == 0) { + LOGW("loadInputSource() no valid effects found in source %s", root->name); + delete source; + return NULL; + } + return source; +} + +status_t AudioPolicyService::loadInputSources(cnode *root, const Vector <EffectDesc *>& effects) +{ + cnode *node = config_find(root, PREPROCESSING_TAG); + if (node == NULL) { + return -ENOENT; + } + node = node->first_child; + while (node) { + audio_source_t source = inputSourceNameToEnum(node->name); + if (source == AUDIO_SOURCE_CNT) { + LOGW("loadInputSources() invalid input source %s", node->name); + node = node->next; + continue; + } + LOGV("loadInputSources() loading input source %s", node->name); + InputSourceDesc *desc = loadInputSource(node, effects); + if (desc == NULL) { + node = node->next; + continue; + } + mInputSources.add(source, desc); + node = node->next; + } + return NO_ERROR; +} + +AudioPolicyService::EffectDesc *AudioPolicyService::loadEffect(cnode *root) +{ + cnode *node = config_find(root, UUID_TAG); + if (node == NULL) { + return NULL; + } + effect_uuid_t uuid; + if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) { + LOGW("loadEffect() invalid uuid %s", node->value); + return NULL; + } + EffectDesc *effect = new EffectDesc(); + effect->mName = strdup(root->name); + memcpy(&effect->mUuid, &uuid, sizeof(effect_uuid_t)); + + return effect; +} + +status_t AudioPolicyService::loadEffects(cnode *root, Vector <EffectDesc *>& effects) +{ + cnode *node = config_find(root, EFFECTS_TAG); + if (node == NULL) { + return -ENOENT; + } + node = node->first_child; + while (node) { + LOGV("loadEffects() loading effect %s", node->name); + EffectDesc *effect = loadEffect(node); + if (effect == NULL) { + node = node->next; + continue; + } + effects.add(effect); + node = node->next; + } + return NO_ERROR; +} + +status_t AudioPolicyService::loadPreProcessorConfig(const char *path) +{ + cnode *root; + char *data; + + data = (char *)load_file(path, NULL); + if (data == NULL) { + return -ENODEV; + } + root = config_node("", ""); + config_load(root, data); + + Vector <EffectDesc *> effects; + loadEffects(root, effects); + loadInputSources(root, effects); + + config_free(root); + free(root); + free(data); + + return NO_ERROR; +} + /* implementation of the interface to the policy manager */ extern "C" { diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index b830120..62ad29e 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -17,14 +17,17 @@ #ifndef ANDROID_AUDIOPOLICYSERVICE_H #define ANDROID_AUDIOPOLICYSERVICE_H -#include <media/IAudioPolicyService.h> -#include <media/ToneGenerator.h> +#include <cutils/misc.h> +#include <cutils/config_utils.h> #include <utils/Vector.h> +#include <utils/SortedVector.h> #include <binder/BinderService.h> - #include <system/audio.h> #include <system/audio_policy.h> #include <hardware/audio_policy.h> +#include <media/IAudioPolicyService.h> +#include <media/ToneGenerator.h> +#include <media/AudioEffect.h> namespace android { @@ -78,7 +81,8 @@ public: uint32_t format = AUDIO_FORMAT_DEFAULT, uint32_t channels = 0, audio_in_acoustics_t acoustics = - (audio_in_acoustics_t)0); + (audio_in_acoustics_t)0, + int audioSession = 0); virtual status_t startInput(audio_io_handle_t input); virtual status_t stopInput(audio_io_handle_t input); virtual void releaseInput(audio_io_handle_t input); @@ -93,7 +97,7 @@ public: virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); virtual status_t registerEffect(effect_descriptor_t *desc, - audio_io_handle_t output, + audio_io_handle_t io, uint32_t strategy, int session, int id); @@ -218,6 +222,51 @@ private: String8 mName; // string used by wake lock fo delayed commands }; + class EffectDesc { + public: + EffectDesc() {} + virtual ~EffectDesc() {} + char *mName; + effect_uuid_t mUuid; + Vector <effect_param_t *> mParams; + }; + + class InputSourceDesc { + public: + InputSourceDesc() {} + virtual ~InputSourceDesc() {} + Vector <EffectDesc *> mEffects; + }; + + + class InputDesc { + public: + InputDesc() {} + virtual ~InputDesc() {} + int mSessionId; + Vector< sp<AudioEffect> >mEffects; + }; + + static const char *kInputSourceNames[AUDIO_SOURCE_CNT -1]; + + void setPreProcessorEnabled(InputDesc *inputDesc, bool enabled); + status_t loadPreProcessorConfig(const char *path); + status_t loadEffects(cnode *root, Vector <EffectDesc *>& effects); + EffectDesc *loadEffect(cnode *root); + status_t loadInputSources(cnode *root, const Vector <EffectDesc *>& effects); + audio_source_t inputSourceNameToEnum(const char *name); + InputSourceDesc *loadInputSource(cnode *root, const Vector <EffectDesc *>& effects); + void loadEffectParameters(cnode *root, Vector <effect_param_t *>& params); + effect_param_t *loadEffectParameter(cnode *root); + size_t readParamValue(cnode *node, + char *param, + size_t *curSize, + size_t *totSize); + size_t growParamSize(char *param, + size_t size, + size_t *curSize, + size_t *totSize); + // Internal dump utilities. status_t dumpPermissionDenial(int fd); @@ -226,9 +275,10 @@ private: // device connection state or routing sp <AudioCommandThread> mAudioCommandThread; // audio commands thread sp <AudioCommandThread> mTonePlaybackThread; // tone playback thread - struct audio_policy_device *mpAudioPolicyDev; struct audio_policy *mpAudioPolicy; + KeyedVector< audio_source_t, InputSourceDesc* > mInputSources; + KeyedVector< audio_io_handle_t, InputDesc* > mInputs; }; }; // namespace android diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 1cac502..039b003 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -215,14 +215,6 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); - mInboundQueue.headSentinel.refCount = -1; - mInboundQueue.headSentinel.type = EventEntry::TYPE_SENTINEL; - mInboundQueue.headSentinel.eventTime = LONG_LONG_MIN; - - mInboundQueue.tailSentinel.refCount = -1; - mInboundQueue.tailSentinel.type = EventEntry::TYPE_SENTINEL; - mInboundQueue.tailSentinel.eventTime = LONG_LONG_MAX; - mKeyRepeatState.lastKeyEntry = NULL; policy->getDispatcherConfiguration(&mConfig); @@ -319,7 +311,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { } } else { // Inbound queue has at least one entry. - EventEntry* entry = mInboundQueue.headSentinel.next; + EventEntry* entry = mInboundQueue.head; // Throttle the entry if it is a move event and there are no // other events behind it in the queue. Due to movement batching, additional @@ -335,7 +327,7 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { int32_t deviceId = motionEntry->deviceId; uint32_t source = motionEntry->source; if (! isAppSwitchDue - && motionEntry->next == & mInboundQueue.tailSentinel // exactly one event + && !motionEntry->next // exactly one event, no successors && (motionEntry->action == AMOTION_EVENT_ACTION_MOVE || motionEntry->action == AMOTION_EVENT_ACTION_HOVER_MOVE) && deviceId == mThrottleState.lastDeviceId @@ -641,13 +633,13 @@ bool InputDispatcher::runCommandsLockedInterruptible() { (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' commandEntry->connection.clear(); - mAllocator.releaseCommandEntry(commandEntry); + delete commandEntry; } while (! mCommandQueue.isEmpty()); return true; } InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { - CommandEntry* commandEntry = mAllocator.obtainCommandEntry(command); + CommandEntry* commandEntry = new CommandEntry(command); mCommandQueue.enqueueAtTail(commandEntry); return commandEntry; } @@ -674,12 +666,12 @@ void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { #endif setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); } - mAllocator.releaseEventEntry(entry); + entry->release(); } void InputDispatcher::resetKeyRepeatLocked() { if (mKeyRepeatState.lastKeyEntry) { - mAllocator.releaseKeyEntry(mKeyRepeatState.lastKeyEntry); + mKeyRepeatState.lastKeyEntry->release(); mKeyRepeatState.lastKeyEntry = NULL; } } @@ -691,18 +683,18 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t cu uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK) | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED; if (entry->refCount == 1) { - mAllocator.recycleKeyEntry(entry); + entry->recycle(); entry->eventTime = currentTime; entry->policyFlags = policyFlags; entry->repeatCount += 1; } else { - KeyEntry* newEntry = mAllocator.obtainKeyEntry(currentTime, + KeyEntry* newEntry = new KeyEntry(currentTime, entry->deviceId, entry->source, policyFlags, entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount + 1, entry->downTime); mKeyRepeatState.lastKeyEntry = newEntry; - mAllocator.releaseKeyEntry(entry); + entry->release(); entry = newEntry; } @@ -887,7 +879,7 @@ bool InputDispatcher::dispatchMotionLocked( uint32_t originalSampleCount = entry->countSamples(); #endif MotionSample* nextSample = splitBatchAfterSample->next; - MotionEntry* nextEntry = mAllocator.obtainMotionEntry(nextSample->eventTime, + MotionEntry* nextEntry = new MotionEntry(nextSample->eventTime, entry->deviceId, entry->source, entry->policyFlags, entry->action, entry->flags, entry->metaState, entry->buttonState, entry->edgeFlags, @@ -897,7 +889,7 @@ bool InputDispatcher::dispatchMotionLocked( nextEntry->firstSample.next = nextSample->next; nextEntry->lastSample = entry->lastSample; } - mAllocator.freeMotionSample(nextSample); + delete nextSample; entry->lastSample = const_cast<MotionSample*>(splitBatchAfterSample); entry->lastSample->next = NULL; @@ -1992,7 +1984,7 @@ void InputDispatcher::enqueueDispatchEntryLocked( // This is a new event. // Enqueue a new dispatch entry onto the outbound queue for this connection. - DispatchEntry* dispatchEntry = mAllocator.obtainDispatchEntry(eventEntry, // increments ref + DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor); if (dispatchEntry->hasForegroundTarget()) { @@ -2087,7 +2079,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, LOG_ASSERT(connection->status == Connection::STATUS_NORMAL); LOG_ASSERT(! connection->outboundQueue.isEmpty()); - DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; + DispatchEntry* dispatchEntry = connection->outboundQueue.head; LOG_ASSERT(! dispatchEntry->inProgress); // Mark the dispatch entry as in progress. @@ -2276,7 +2268,7 @@ void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) { // Start the next dispatch cycle for this connection. while (! connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; + DispatchEntry* dispatchEntry = connection->outboundQueue.head; if (dispatchEntry->inProgress) { // Finish or resume current event in progress. if (dispatchEntry->tailMotionSample) { @@ -2293,7 +2285,7 @@ void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime, if (dispatchEntry->hasForegroundTarget()) { decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); } - mAllocator.releaseDispatchEntry(dispatchEntry); + delete dispatchEntry; } else { // If the head is not in progress, then we must have already dequeued the in // progress event, which means we actually aborted it. @@ -2333,7 +2325,7 @@ void InputDispatcher::drainOutboundQueueLocked(Connection* connection) { if (dispatchEntry->hasForegroundTarget()) { decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); } - mAllocator.releaseDispatchEntry(dispatchEntry); + delete dispatchEntry; } deactivateConnectionLocked(connection); @@ -2407,7 +2399,7 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( nsecs_t currentTime = now(); mTempCancelationEvents.clear(); - connection->inputState.synthesizeCancelationEvents(currentTime, & mAllocator, + connection->inputState.synthesizeCancelationEvents(currentTime, mTempCancelationEvents, options); if (! mTempCancelationEvents.isEmpty() @@ -2448,10 +2440,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref &target, false, InputTarget::FLAG_DISPATCH_AS_IS); - mAllocator.releaseEventEntry(cancelationEventEntry); + cancelationEventEntry->release(); } - if (!connection->outboundQueue.headSentinel.next->inProgress) { + if (!connection->outboundQueue.head->inProgress) { startDispatchCycleLocked(currentTime, connection); } } @@ -2523,7 +2515,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet } } - MotionEntry* splitMotionEntry = mAllocator.obtainMotionEntry( + MotionEntry* splitMotionEntry = new MotionEntry( originalMotionEntry->eventTime, originalMotionEntry->deviceId, originalMotionEntry->source, @@ -2547,8 +2539,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet originalMotionSample->pointerCoords[originalPointerIndex]); } - mAllocator.appendMotionSample(splitMotionEntry, originalMotionSample->eventTime, - splitPointerCoords); + splitMotionEntry->appendSample(originalMotionSample->eventTime, splitPointerCoords); } if (originalMotionEntry->injectionState) { @@ -2568,7 +2559,7 @@ void InputDispatcher::notifyConfigurationChanged(nsecs_t eventTime) { { // acquire lock AutoMutex _l(mLock); - ConfigurationChangedEntry* newEntry = mAllocator.obtainConfigurationChangedEntry(eventTime); + ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(eventTime); needWake = enqueueInboundEventLocked(newEntry); } // release lock @@ -2638,7 +2629,7 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, uint32_t so } int32_t repeatCount = 0; - KeyEntry* newEntry = mAllocator.obtainKeyEntry(eventTime, + KeyEntry* newEntry = new KeyEntry(eventTime, deviceId, source, policyFlags, action, flags, keyCode, scanCode, metaState, repeatCount, downTime); @@ -2718,8 +2709,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t // Try to append a move sample to the tail of the inbound queue for this device. // Give up if we encounter a non-move motion event for this device since that // means we cannot append any new samples until a new motion event has started. - for (EventEntry* entry = mInboundQueue.tailSentinel.prev; - entry != & mInboundQueue.headSentinel; entry = entry->prev) { + for (EventEntry* entry = mInboundQueue.tail; entry; entry = entry->prev) { if (entry->type != EventEntry::TYPE_MOTION) { // Keep looking for motion events. continue; @@ -2798,7 +2788,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t continue; } - DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; + DispatchEntry* dispatchEntry = connection->outboundQueue.head; if (! dispatchEntry->inProgress || dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION || dispatchEntry->isSplit()) { @@ -2844,7 +2834,7 @@ void InputDispatcher::notifyMotion(nsecs_t eventTime, int32_t deviceId, uint32_t // Hurray! This foreground target is currently dispatching a move event // that we can stream onto. Append the motion sample and resume dispatch. - mAllocator.appendMotionSample(motionEntry, eventTime, pointerCoords); + motionEntry->appendSample(eventTime, pointerCoords); #if DEBUG_BATCHING LOGD("Appended motion sample onto batch for most recently dispatched " "motion event for this device and source in the outbound queues. " @@ -2864,7 +2854,7 @@ NoBatchingOrStreaming:; } // Just enqueue a new motion event. - MotionEntry* newEntry = mAllocator.obtainMotionEntry(eventTime, + MotionEntry* newEntry = new MotionEntry(eventTime, deviceId, source, policyFlags, action, flags, metaState, buttonState, edgeFlags, xPrecision, yPrecision, downTime, pointerCount, pointerProperties, pointerCoords); @@ -2901,7 +2891,7 @@ void InputDispatcher::batchMotionLocked(MotionEntry* entry, nsecs_t eventTime, } // Append the sample. - mAllocator.appendMotionSample(entry, eventTime, pointerCoords); + entry->appendSample(eventTime, pointerCoords); #if DEBUG_BATCHING LOGD("Appended motion sample onto batch for %s, events were %0.3f ms apart", eventDescription, interval * 0.000001f); @@ -2958,7 +2948,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, } mLock.lock(); - injectedEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(), + injectedEntry = new KeyEntry(keyEvent->getEventTime(), keyEvent->getDeviceId(), keyEvent->getSource(), policyFlags, action, flags, keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), @@ -2983,7 +2973,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, mLock.lock(); const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - MotionEntry* motionEntry = mAllocator.obtainMotionEntry(*sampleEventTimes, + MotionEntry* motionEntry = new MotionEntry(*sampleEventTimes, motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, action, motionEvent->getFlags(), motionEvent->getMetaState(), motionEvent->getButtonState(), @@ -2994,7 +2984,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { sampleEventTimes += 1; samplePointerCoords += pointerCount; - mAllocator.appendMotionSample(motionEntry, *sampleEventTimes, samplePointerCoords); + motionEntry->appendSample(*sampleEventTimes, samplePointerCoords); } injectedEntry = motionEntry; break; @@ -3005,7 +2995,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, return INPUT_EVENT_INJECTION_FAILED; } - InjectionState* injectionState = mAllocator.obtainInjectionState(injectorPid, injectorUid); + InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { injectionState->injectionIsAsync = true; } @@ -3068,7 +3058,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event, } } - mAllocator.releaseInjectionState(injectionState); + injectionState->release(); } // release lock #if DEBUG_INJECTION @@ -3704,7 +3694,7 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( entry->interceptKeyResult = consumed ? KeyEntry::INTERCEPT_KEY_RESULT_SKIP : KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - mAllocator.releaseKeyEntry(entry); + entry->release(); } void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( @@ -3714,7 +3704,7 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( bool skipNext = false; if (!connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.headSentinel.next; + DispatchEntry* dispatchEntry = connection->outboundQueue.head; if (dispatchEntry->inProgress) { if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); @@ -3796,7 +3786,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con return true; // skip next cycle } - LOG_ASSERT(connection->outboundQueue.headSentinel.next == dispatchEntry); + LOG_ASSERT(connection->outboundQueue.head == dispatchEntry); // Latch the fallback keycode for this key on an initial down. // The fallback keycode cannot change at any other point in the lifecycle. @@ -3929,230 +3919,137 @@ void InputDispatcher::dump(String8& dump) { template <typename T> uint32_t InputDispatcher::Queue<T>::count() const { uint32_t result = 0; - for (const T* entry = headSentinel.next; entry != & tailSentinel; entry = entry->next) { + for (const T* entry = head; entry; entry = entry->next) { result += 1; } return result; } -// --- InputDispatcher::Allocator --- +// --- InputDispatcher::InjectionState --- -InputDispatcher::Allocator::Allocator() { +InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : + refCount(1), + injectorPid(injectorPid), injectorUid(injectorUid), + injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false), + pendingForegroundDispatches(0) { } -InputDispatcher::InjectionState* -InputDispatcher::Allocator::obtainInjectionState(int32_t injectorPid, int32_t injectorUid) { - InjectionState* injectionState = mInjectionStatePool.alloc(); - injectionState->refCount = 1; - injectionState->injectorPid = injectorPid; - injectionState->injectorUid = injectorUid; - injectionState->injectionIsAsync = false; - injectionState->injectionResult = INPUT_EVENT_INJECTION_PENDING; - injectionState->pendingForegroundDispatches = 0; - return injectionState; +InputDispatcher::InjectionState::~InjectionState() { } -void InputDispatcher::Allocator::initializeEventEntry(EventEntry* entry, int32_t type, - nsecs_t eventTime, uint32_t policyFlags) { - entry->type = type; - entry->refCount = 1; - entry->dispatchInProgress = false; - entry->eventTime = eventTime; - entry->policyFlags = policyFlags; - entry->injectionState = NULL; -} - -void InputDispatcher::Allocator::releaseEventEntryInjectionState(EventEntry* entry) { - if (entry->injectionState) { - releaseInjectionState(entry->injectionState); - entry->injectionState = NULL; +void InputDispatcher::InjectionState::release() { + refCount -= 1; + if (refCount == 0) { + delete this; + } else { + LOG_ASSERT(refCount > 0); } } -InputDispatcher::ConfigurationChangedEntry* -InputDispatcher::Allocator::obtainConfigurationChangedEntry(nsecs_t eventTime) { - ConfigurationChangedEntry* entry = mConfigurationChangeEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_CONFIGURATION_CHANGED, eventTime, 0); - return entry; -} -InputDispatcher::KeyEntry* InputDispatcher::Allocator::obtainKeyEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime) { - KeyEntry* entry = mKeyEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_KEY, eventTime, policyFlags); - - entry->deviceId = deviceId; - entry->source = source; - entry->action = action; - entry->flags = flags; - entry->keyCode = keyCode; - entry->scanCode = scanCode; - entry->metaState = metaState; - entry->repeatCount = repeatCount; - entry->downTime = downTime; - entry->syntheticRepeat = false; - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - return entry; -} +// --- InputDispatcher::EventEntry --- -InputDispatcher::MotionEntry* InputDispatcher::Allocator::obtainMotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, - int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) { - MotionEntry* entry = mMotionEntryPool.alloc(); - initializeEventEntry(entry, EventEntry::TYPE_MOTION, eventTime, policyFlags); - - entry->eventTime = eventTime; - entry->deviceId = deviceId; - entry->source = source; - entry->action = action; - entry->flags = flags; - entry->metaState = metaState; - entry->buttonState = buttonState; - entry->edgeFlags = edgeFlags; - entry->xPrecision = xPrecision; - entry->yPrecision = yPrecision; - entry->downTime = downTime; - entry->pointerCount = pointerCount; - entry->firstSample.eventTime = eventTime; - entry->firstSample.eventTimeBeforeCoalescing = eventTime; - entry->firstSample.next = NULL; - entry->lastSample = & entry->firstSample; - for (uint32_t i = 0; i < pointerCount; i++) { - entry->pointerProperties[i].copyFrom(pointerProperties[i]); - entry->firstSample.pointerCoords[i].copyFrom(pointerCoords[i]); - } - return entry; +InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) : + refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags), + injectionState(NULL), dispatchInProgress(false) { } -InputDispatcher::DispatchEntry* InputDispatcher::Allocator::obtainDispatchEntry( - EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) { - DispatchEntry* entry = mDispatchEntryPool.alloc(); - entry->eventEntry = eventEntry; - eventEntry->refCount += 1; - entry->targetFlags = targetFlags; - entry->xOffset = xOffset; - entry->yOffset = yOffset; - entry->scaleFactor = scaleFactor; - entry->inProgress = false; - entry->headMotionSample = NULL; - entry->tailMotionSample = NULL; - return entry; +InputDispatcher::EventEntry::~EventEntry() { + releaseInjectionState(); } -InputDispatcher::CommandEntry* InputDispatcher::Allocator::obtainCommandEntry(Command command) { - CommandEntry* entry = mCommandEntryPool.alloc(); - entry->command = command; - return entry; -} - -void InputDispatcher::Allocator::releaseInjectionState(InjectionState* injectionState) { - injectionState->refCount -= 1; - if (injectionState->refCount == 0) { - mInjectionStatePool.free(injectionState); +void InputDispatcher::EventEntry::release() { + refCount -= 1; + if (refCount == 0) { + delete this; } else { - LOG_ASSERT(injectionState->refCount > 0); + LOG_ASSERT(refCount > 0); } } -void InputDispatcher::Allocator::releaseEventEntry(EventEntry* entry) { - switch (entry->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: - releaseConfigurationChangedEntry(static_cast<ConfigurationChangedEntry*>(entry)); - break; - case EventEntry::TYPE_KEY: - releaseKeyEntry(static_cast<KeyEntry*>(entry)); - break; - case EventEntry::TYPE_MOTION: - releaseMotionEntry(static_cast<MotionEntry*>(entry)); - break; - default: - LOG_ASSERT(false); - break; +void InputDispatcher::EventEntry::releaseInjectionState() { + if (injectionState) { + injectionState->release(); + injectionState = NULL; } } -void InputDispatcher::Allocator::releaseConfigurationChangedEntry( - ConfigurationChangedEntry* entry) { - entry->refCount -= 1; - if (entry->refCount == 0) { - releaseEventEntryInjectionState(entry); - mConfigurationChangeEntryPool.free(entry); - } else { - LOG_ASSERT(entry->refCount > 0); - } -} -void InputDispatcher::Allocator::releaseKeyEntry(KeyEntry* entry) { - entry->refCount -= 1; - if (entry->refCount == 0) { - releaseEventEntryInjectionState(entry); - mKeyEntryPool.free(entry); - } else { - LOG_ASSERT(entry->refCount > 0); - } -} +// --- InputDispatcher::ConfigurationChangedEntry --- -void InputDispatcher::Allocator::releaseMotionEntry(MotionEntry* entry) { - entry->refCount -= 1; - if (entry->refCount == 0) { - releaseEventEntryInjectionState(entry); - for (MotionSample* sample = entry->firstSample.next; sample != NULL; ) { - MotionSample* next = sample->next; - mMotionSamplePool.free(sample); - sample = next; - } - mMotionEntryPool.free(entry); - } else { - LOG_ASSERT(entry->refCount > 0); - } +InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(nsecs_t eventTime) : + EventEntry(TYPE_CONFIGURATION_CHANGED, eventTime, 0) { } -void InputDispatcher::Allocator::freeMotionSample(MotionSample* sample) { - mMotionSamplePool.free(sample); +InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { } -void InputDispatcher::Allocator::releaseDispatchEntry(DispatchEntry* entry) { - releaseEventEntry(entry->eventEntry); - mDispatchEntryPool.free(entry); + +// --- InputDispatcher::KeyEntry --- + +InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, + int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, + int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, + int32_t repeatCount, nsecs_t downTime) : + EventEntry(TYPE_KEY, eventTime, policyFlags), + deviceId(deviceId), source(source), action(action), flags(flags), + keyCode(keyCode), scanCode(scanCode), metaState(metaState), + repeatCount(repeatCount), downTime(downTime), + syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { } -void InputDispatcher::Allocator::releaseCommandEntry(CommandEntry* entry) { - mCommandEntryPool.free(entry); +InputDispatcher::KeyEntry::~KeyEntry() { } -void InputDispatcher::Allocator::appendMotionSample(MotionEntry* motionEntry, - nsecs_t eventTime, const PointerCoords* pointerCoords) { - MotionSample* sample = mMotionSamplePool.alloc(); - sample->eventTime = eventTime; - sample->eventTimeBeforeCoalescing = eventTime; - uint32_t pointerCount = motionEntry->pointerCount; - for (uint32_t i = 0; i < pointerCount; i++) { - sample->pointerCoords[i].copyFrom(pointerCoords[i]); - } +void InputDispatcher::KeyEntry::recycle() { + releaseInjectionState(); - sample->next = NULL; - motionEntry->lastSample->next = sample; - motionEntry->lastSample = sample; + dispatchInProgress = false; + syntheticRepeat = false; + interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; } -void InputDispatcher::Allocator::recycleKeyEntry(KeyEntry* keyEntry) { - releaseEventEntryInjectionState(keyEntry); - keyEntry->dispatchInProgress = false; - keyEntry->syntheticRepeat = false; - keyEntry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; +// --- InputDispatcher::MotionSample --- + +InputDispatcher::MotionSample::MotionSample(nsecs_t eventTime, + const PointerCoords* pointerCoords, uint32_t pointerCount) : + next(NULL), eventTime(eventTime), eventTimeBeforeCoalescing(eventTime) { + for (uint32_t i = 0; i < pointerCount; i++) { + this->pointerCoords[i].copyFrom(pointerCoords[i]); + } } // --- InputDispatcher::MotionEntry --- +InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, + int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, + int32_t metaState, int32_t buttonState, + int32_t edgeFlags, float xPrecision, float yPrecision, + nsecs_t downTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) : + EventEntry(TYPE_MOTION, eventTime, policyFlags), + deviceId(deviceId), source(source), action(action), flags(flags), + metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), + xPrecision(xPrecision), yPrecision(yPrecision), + downTime(downTime), pointerCount(pointerCount), + firstSample(eventTime, pointerCoords, pointerCount), + lastSample(&firstSample) { + for (uint32_t i = 0; i < pointerCount; i++) { + this->pointerProperties[i].copyFrom(pointerProperties[i]); + } +} + +InputDispatcher::MotionEntry::~MotionEntry() { + for (MotionSample* sample = firstSample.next; sample != NULL; ) { + MotionSample* next = sample->next; + delete sample; + sample = next; + } +} + uint32_t InputDispatcher::MotionEntry::countSamples() const { uint32_t count = 1; for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) { @@ -4176,6 +4073,31 @@ bool InputDispatcher::MotionEntry::canAppendSamples(int32_t action, uint32_t poi return true; } +void InputDispatcher::MotionEntry::appendSample( + nsecs_t eventTime, const PointerCoords* pointerCoords) { + MotionSample* sample = new MotionSample(eventTime, pointerCoords, pointerCount); + + lastSample->next = sample; + lastSample = sample; +} + + +// --- InputDispatcher::DispatchEntry --- + +InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, + int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) : + eventEntry(eventEntry), targetFlags(targetFlags), + xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor), + inProgress(false), + resolvedAction(0), resolvedFlags(0), + headMotionSample(NULL), tailMotionSample(NULL) { + eventEntry->refCount += 1; +} + +InputDispatcher::DispatchEntry::~DispatchEntry() { + eventEntry->release(); +} + // --- InputDispatcher::InputState --- @@ -4380,12 +4302,11 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* } void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, - Allocator* allocator, Vector<EventEntry*>& outEvents, - const CancelationOptions& options) { + Vector<EventEntry*>& outEvents, const CancelationOptions& options) { for (size_t i = 0; i < mKeyMementos.size(); i++) { const KeyMemento& memento = mKeyMementos.itemAt(i); if (shouldCancelKey(memento, options)) { - outEvents.push(allocator->obtainKeyEntry(currentTime, + outEvents.push(new KeyEntry(currentTime, memento.deviceId, memento.source, 0, AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode, memento.scanCode, 0, 0, memento.downTime)); @@ -4395,7 +4316,7 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim for (size_t i = 0; i < mMotionMementos.size(); i++) { const MotionMemento& memento = mMotionMementos.itemAt(i); if (shouldCancelMotion(memento, options)) { - outEvents.push(allocator->obtainMotionEntry(currentTime, + outEvents.push(new MotionEntry(currentTime, memento.deviceId, memento.source, 0, memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT @@ -4516,8 +4437,8 @@ const char* InputDispatcher::Connection::getStatusLabel() const { InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent( const EventEntry* eventEntry) const { - for (DispatchEntry* dispatchEntry = outboundQueue.tailSentinel.prev; - dispatchEntry != & outboundQueue.headSentinel; dispatchEntry = dispatchEntry->prev) { + for (DispatchEntry* dispatchEntry = outboundQueue.tail; dispatchEntry; + dispatchEntry = dispatchEntry->prev) { if (dispatchEntry->eventEntry == eventEntry) { return dispatchEntry; } @@ -4528,8 +4449,8 @@ InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchE // --- InputDispatcher::CommandEntry --- -InputDispatcher::CommandEntry::CommandEntry() : - keyEntry(NULL) { +InputDispatcher::CommandEntry::CommandEntry(Command command) : + command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), handled(false) { } InputDispatcher::CommandEntry::~CommandEntry() { diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index 15fd274..1d39b2e 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -26,7 +26,6 @@ #include <utils/RefBase.h> #include <utils/String8.h> #include <utils/Looper.h> -#include <utils/Pool.h> #include <utils/BitSet.h> #include <stddef.h> @@ -434,11 +433,16 @@ private: int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING bool injectionIsAsync; // set to true if injection is not waiting for the result int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress + + InjectionState(int32_t injectorPid, int32_t injectorUid); + void release(); + + private: + ~InjectionState(); }; struct EventEntry : Link<EventEntry> { enum { - TYPE_SENTINEL, TYPE_CONFIGURATION_CHANGED, TYPE_KEY, TYPE_MOTION @@ -453,9 +457,20 @@ private: bool dispatchInProgress; // initially false, set to true while dispatching inline bool isInjected() const { return injectionState != NULL; } + + void release(); + + protected: + EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags); + virtual ~EventEntry(); + void releaseInjectionState(); }; struct ConfigurationChangedEntry : EventEntry { + ConfigurationChangedEntry(nsecs_t eventTime); + + protected: + virtual ~ConfigurationChangedEntry(); }; struct KeyEntry : EventEntry { @@ -477,6 +492,15 @@ private: INTERCEPT_KEY_RESULT_CONTINUE, }; InterceptKeyResult interceptKeyResult; // set based on the interception result + + KeyEntry(nsecs_t eventTime, + int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, + int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, + int32_t repeatCount, nsecs_t downTime); + void recycle(); + + protected: + virtual ~KeyEntry(); }; struct MotionSample { @@ -485,6 +509,9 @@ private: nsecs_t eventTime; // may be updated during coalescing nsecs_t eventTimeBeforeCoalescing; // not updated during coalescing PointerCoords pointerCoords[MAX_POINTERS]; + + MotionSample(nsecs_t eventTime, const PointerCoords* pointerCoords, + uint32_t pointerCount); }; struct MotionEntry : EventEntry { @@ -505,11 +532,23 @@ private: MotionSample firstSample; MotionSample* lastSample; + MotionEntry(nsecs_t eventTime, + int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, + int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, + float xPrecision, float yPrecision, + nsecs_t downTime, uint32_t pointerCount, + const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); + uint32_t countSamples() const; // Checks whether we can append samples, assuming the device id and source are the same. bool canAppendSamples(int32_t action, uint32_t pointerCount, const PointerProperties* pointerProperties) const; + + void appendSample(nsecs_t eventTime, const PointerCoords* pointerCoords); + + protected: + virtual ~MotionEntry(); }; // Tracks the progress of dispatching a particular event to a particular connection. @@ -540,6 +579,10 @@ private: // will be set to NULL. MotionSample* tailMotionSample; + DispatchEntry(EventEntry* eventEntry, + int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); + ~DispatchEntry(); + inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; } @@ -570,7 +613,7 @@ private: class Connection; struct CommandEntry : Link<CommandEntry> { - CommandEntry(); + CommandEntry(Command command); ~CommandEntry(); Command command; @@ -588,99 +631,65 @@ private: // Generic queue implementation. template <typename T> struct Queue { - T headSentinel; - T tailSentinel; - - inline Queue() { - headSentinel.prev = NULL; - headSentinel.next = & tailSentinel; - tailSentinel.prev = & headSentinel; - tailSentinel.next = NULL; + T* head; + T* tail; + + inline Queue() : head(NULL), tail(NULL) { } inline bool isEmpty() const { - return headSentinel.next == & tailSentinel; + return !head; } inline void enqueueAtTail(T* entry) { - T* last = tailSentinel.prev; - last->next = entry; - entry->prev = last; - entry->next = & tailSentinel; - tailSentinel.prev = entry; + entry->prev = tail; + if (tail) { + tail->next = entry; + } else { + head = entry; + } + entry->next = NULL; + tail = entry; } inline void enqueueAtHead(T* entry) { - T* first = headSentinel.next; - headSentinel.next = entry; - entry->prev = & headSentinel; - entry->next = first; - first->prev = entry; + entry->next = head; + if (head) { + head->prev = entry; + } else { + tail = entry; + } + entry->prev = NULL; + head = entry; } inline void dequeue(T* entry) { - entry->prev->next = entry->next; - entry->next->prev = entry->prev; + if (entry->prev) { + entry->prev->next = entry->next; + } else { + head = entry->next; + } + if (entry->next) { + entry->next->prev = entry->prev; + } else { + tail = entry->prev; + } } inline T* dequeueAtHead() { - T* first = headSentinel.next; - dequeue(first); - return first; + T* entry = head; + head = entry->next; + if (head) { + head->prev = NULL; + } else { + tail = NULL; + } + return entry; } uint32_t count() const; }; - /* Allocates queue entries and performs reference counting as needed. */ - class Allocator { - public: - Allocator(); - - InjectionState* obtainInjectionState(int32_t injectorPid, int32_t injectorUid); - ConfigurationChangedEntry* obtainConfigurationChangedEntry(nsecs_t eventTime); - KeyEntry* obtainKeyEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime); - MotionEntry* obtainMotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, - float xPrecision, float yPrecision, - nsecs_t downTime, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); - DispatchEntry* obtainDispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); - CommandEntry* obtainCommandEntry(Command command); - - void releaseInjectionState(InjectionState* injectionState); - void releaseEventEntry(EventEntry* entry); - void releaseConfigurationChangedEntry(ConfigurationChangedEntry* entry); - void releaseKeyEntry(KeyEntry* entry); - void releaseMotionEntry(MotionEntry* entry); - void freeMotionSample(MotionSample* sample); - void releaseDispatchEntry(DispatchEntry* entry); - void releaseCommandEntry(CommandEntry* entry); - - void recycleKeyEntry(KeyEntry* entry); - - void appendMotionSample(MotionEntry* motionEntry, - nsecs_t eventTime, const PointerCoords* pointerCoords); - - private: - Pool<InjectionState> mInjectionStatePool; - Pool<ConfigurationChangedEntry> mConfigurationChangeEntryPool; - Pool<KeyEntry> mKeyEntryPool; - Pool<MotionEntry> mMotionEntryPool; - Pool<MotionSample> mMotionSamplePool; - Pool<DispatchEntry> mDispatchEntryPool; - Pool<CommandEntry> mCommandEntryPool; - - void initializeEventEntry(EventEntry* entry, int32_t type, nsecs_t eventTime, - uint32_t policyFlags); - void releaseEventEntryInjectionState(EventEntry* entry); - }; - /* Specifies which events are to be canceled and why. */ struct CancelationOptions { enum Mode { @@ -728,7 +737,7 @@ private: bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags); // Synthesizes cancelation events for the current state and resets the tracked state. - void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator, + void synthesizeCancelationEvents(nsecs_t currentTime, Vector<EventEntry*>& outEvents, const CancelationOptions& options); // Clears the current state. @@ -856,7 +865,6 @@ private: Mutex mLock; - Allocator mAllocator; sp<Looper> mLooper; EventEntry* mPendingEvent; diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 438883e..a679ca7 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -230,8 +230,14 @@ class AppWidgetService extends IAppWidgetService.Stub pw.println(':'); pw.print(" min=("); pw.print(info.minWidth); pw.print("x"); pw.print(info.minHeight); + pw.print(") minResize=("); pw.print(info.minResizeWidth); + pw.print("x"); pw.print(info.minResizeHeight); pw.print(") updatePeriodMillis="); pw.print(info.updatePeriodMillis); + pw.print(" resizeMode="); + pw.print(info.resizeMode); + pw.print(" autoAdvanceViewId="); + pw.print(info.autoAdvanceViewId); pw.print(" initialLayout=#"); pw.print(Integer.toHexString(info.initialLayout)); pw.print(" zombie="); pw.println(p.zombie); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b78424b..79c0675 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -155,7 +155,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean mInetConditionChangeInFlight = false; private int mDefaultConnectionSequence = 0; + private Object mDnsLock = new Object(); private int mNumDnsEntries; + private boolean mDnsOverridden = false; private boolean mTestMode; private static ConnectivityService sServiceInstance; @@ -244,6 +246,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int EVENT_SET_DEPENDENCY_MET = MAX_NETWORK_STATE_TRACKER_EVENT + 10; + /** + * used internally to restore DNS properties back to the + * default network + */ + private static final int EVENT_RESTORE_DNS = + MAX_NETWORK_STATE_TRACKER_EVENT + 11; + private Handler mHandler; // list of DeathRecipients used to make sure features are turned off when @@ -1081,7 +1090,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { InetAddress addr = InetAddress.getByAddress(hostAddress); LinkProperties lp = tracker.getLinkProperties(); - return addRoute(lp, RouteInfo.makeHostRoute(addr)); + return addRouteToAddress(lp, addr); } catch (UnknownHostException e) {} return false; } @@ -1094,6 +1103,31 @@ public class ConnectivityService extends IConnectivityManager.Stub { return modifyRoute(p.getInterfaceName(), p, r, 0, false); } + private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) { + return modifyRouteToAddress(lp, addr, true); + } + + private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) { + return modifyRouteToAddress(lp, addr, false); + } + + private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd) { + RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr); + if (bestRoute == null) { + bestRoute = RouteInfo.makeHostRoute(addr); + } else { + if (bestRoute.getGateway().equals(addr)) { + // if there is no better route, add the implied hostroute for our gateway + bestRoute = RouteInfo.makeHostRoute(addr); + } else { + // if we will connect to this through another route, add a direct route + // to it's gateway + bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway()); + } + } + return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd); + } + private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd) { if ((ifaceName == null) || (lp == null) || (r == null)) return false; @@ -1704,49 +1738,50 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private void updateRoutes(LinkProperties newLp, LinkProperties curLp, boolean isLinkDefault) { Collection<RouteInfo> routesToAdd = null; - CompareResult<InetAddress> dnsDiff = null; - + CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>(); + CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>(); if (curLp != null) { // check for the delta between the current set and the new - CompareResult<RouteInfo> routeDiff = curLp.compareRoutes(newLp); + routeDiff = curLp.compareRoutes(newLp); dnsDiff = curLp.compareDnses(newLp); - - for (RouteInfo r : routeDiff.removed) { - if (isLinkDefault || ! r.isDefaultRoute()) { - removeRoute(curLp, r); - } - } - routesToAdd = routeDiff.added; + } else if (newLp != null) { + routeDiff.added = newLp.getRoutes(); + dnsDiff.added = newLp.getDnses(); } - if (newLp != null) { - // if we didn't get a diff from cur -> new, then just use the new - if (routesToAdd == null) { - routesToAdd = newLp.getRoutes(); + for (RouteInfo r : routeDiff.removed) { + if (isLinkDefault || ! r.isDefaultRoute()) { + removeRoute(curLp, r); } + } - for (RouteInfo r : routesToAdd) { - if (isLinkDefault || ! r.isDefaultRoute()) { - addRoute(newLp, r); - } + for (RouteInfo r : routeDiff.added) { + if (isLinkDefault || ! r.isDefaultRoute()) { + addRoute(newLp, r); } } if (!isLinkDefault) { // handle DNS routes - Collection<InetAddress> dnsToAdd = null; - if (dnsDiff != null) { - dnsToAdd = dnsDiff.added; - for (InetAddress dnsAddress : dnsDiff.removed) { - removeRoute(curLp, RouteInfo.makeHostRoute(dnsAddress)); + if (routeDiff.removed.size() == 0 && routeDiff.added.size() == 0) { + // no change in routes, check for change in dns themselves + for (InetAddress oldDns : dnsDiff.removed) { + removeRouteToAddress(curLp, oldDns); } - } - if (newLp != null) { - if (dnsToAdd == null) { - dnsToAdd = newLp.getDnses(); + for (InetAddress newDns : dnsDiff.added) { + addRouteToAddress(newLp, newDns); } - for(InetAddress dnsAddress : dnsToAdd) { - addRoute(newLp, RouteInfo.makeHostRoute(dnsAddress)); + } else { + // routes changed - remove all old dns entries and add new + if (curLp != null) { + for (InetAddress oldDns : curLp.getDnses()) { + removeRouteToAddress(curLp, oldDns); + } + } + if (newLp != null) { + for (InetAddress newDns : newLp.getDnses()) { + addRouteToAddress(newLp, newDns); + } } } } @@ -1890,6 +1925,50 @@ public class ConnectivityService extends IConnectivityManager.Stub { mContext.sendBroadcast(intent); } + // Caller must grab mDnsLock. + private boolean updateDns(String network, Collection<InetAddress> dnses, String domains) { + boolean changed = false; + int last = 0; + if (dnses.size() == 0 && mDefaultDns != null) { + ++last; + String value = mDefaultDns.getHostAddress(); + if (!value.equals(SystemProperties.get("net.dns1"))) { + if (DBG) { + log("no dns provided for " + network + " - using " + value); + } + changed = true; + SystemProperties.set("net.dns1", value); + } + } else { + for (InetAddress dns : dnses) { + ++last; + String key = "net.dns" + last; + String value = dns.getHostAddress(); + if (!changed && value.equals(SystemProperties.get(key))) { + continue; + } + if (DBG) { + log("adding dns " + value + " for " + network); + } + changed = true; + SystemProperties.set(key, value); + } + } + for (int i = last + 1; i <= mNumDnsEntries; ++i) { + String key = "net.dns" + i; + if (DBG) log("erasing " + key); + changed = true; + SystemProperties.set(key, ""); + } + mNumDnsEntries = last; + + if (!domains.equals(SystemProperties.get("net.dns.search"))) { + SystemProperties.set("net.dns.search", domains); + changed = true; + } + return changed; + } + private void handleDnsConfigurationChange(int netType) { // add default net's dns entries NetworkStateTracker nt = mNetTrackers[netType]; @@ -1899,40 +1978,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { Collection<InetAddress> dnses = p.getDnses(); boolean changed = false; if (mNetConfigs[netType].isDefault()) { - int j = 1; - if (dnses.size() == 0 && mDefaultDns != null) { - String dnsString = mDefaultDns.getHostAddress(); - if (!dnsString.equals(SystemProperties.get("net.dns1"))) { - if (DBG) { - log("no dns provided - using " + dnsString); - } - changed = true; - SystemProperties.set("net.dns1", dnsString); - } - j++; - } else { - for (InetAddress dns : dnses) { - String dnsString = dns.getHostAddress(); - if (!changed && dnsString.equals(SystemProperties.get("net.dns" + j))) { - j++; - continue; - } - if (DBG) { - log("adding dns " + dns + " for " + - nt.getNetworkInfo().getTypeName()); - } - changed = true; - SystemProperties.set("net.dns" + j++, dnsString); - } - } - for (int k=j ; k<mNumDnsEntries; k++) { - if (changed || !TextUtils.isEmpty(SystemProperties.get("net.dns" + k))) { - if (DBG) log("erasing net.dns" + k); - changed = true; - SystemProperties.set("net.dns" + k, ""); + String network = nt.getNetworkInfo().getTypeName(); + synchronized (mDnsLock) { + if (!mDnsOverridden) { + changed = updateDns(network, dnses, ""); } } - mNumDnsEntries = j; } else { // set per-pid dns for attached secondary nets List pids = mNetRequestersPids[netType]; @@ -2139,6 +2190,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleSetDependencyMet(msg.arg2, met); break; } + case EVENT_RESTORE_DNS: + { + if (mActiveDefaultNetwork != -1) { + handleDnsConfigurationChange(mActiveDefaultNetwork); + } + break; + } } } } @@ -2204,6 +2262,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + public int setUsbTethering(boolean enable) { + enforceTetherAccessPermission(); + if (isTetheringSupported()) { + return mTethering.setUsbTethering(enable); + } else { + return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; + } + } + // TODO - move iface listing, queries, etc to new module // javadoc from interface public String[] getTetherableIfaces() { @@ -2586,12 +2653,57 @@ public class ConnectivityService extends IConnectivityManager.Stub { private VpnCallback() { } - public synchronized void override(List<String> dnsServers, List<String> searchDomains) { - // TODO: override DNS servers and http proxy. + public void override(List<String> dnsServers, List<String> searchDomains) { + if (dnsServers == null) { + restore(); + return; + } + + // Convert DNS servers into addresses. + List<InetAddress> addresses = new ArrayList<InetAddress>(); + for (String address : dnsServers) { + // Double check the addresses and remove invalid ones. + try { + addresses.add(InetAddress.parseNumericAddress(address)); + } catch (Exception e) { + // ignore + } + } + if (addresses.isEmpty()) { + restore(); + return; + } + + // Concatenate search domains into a string. + StringBuilder buffer = new StringBuilder(); + if (searchDomains != null) { + for (String domain : searchDomains) { + buffer.append(domain).append(' '); + } + } + String domains = buffer.toString().trim(); + + // Apply DNS changes. + boolean changed = false; + synchronized (mDnsLock) { + changed = updateDns("VPN", addresses, domains); + mDnsOverridden = true; + } + if (changed) { + bumpDns(); + } + + // TODO: temporarily remove http proxy? } - public synchronized void restore() { - // TODO: restore VPN changes. + public void restore() { + synchronized (mDnsLock) { + if (!mDnsOverridden) { + return; + } + mDnsOverridden = false; + } + mHandler.sendEmptyMessage(EVENT_RESTORE_DNS); } } } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 2597978..73d790a 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -50,6 +50,7 @@ import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.res.Configuration; @@ -165,7 +166,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final KeyguardManager mKeyguardManager; private final Notification mImeSwitcherNotification; private final PendingIntent mImeSwitchPendingIntent; - private final boolean mShowOngoingImeSwitcherForPhones; + private boolean mShowOngoingImeSwitcherForPhones; private boolean mNotificationShown; class SessionState { @@ -537,8 +538,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mImeSwitcherNotification.vibrate = null; Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER); mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); - mShowOngoingImeSwitcherForPhones = mRes.getBoolean( - com.android.internal.R.bool.show_ongoing_ime_switcher); + + mShowOngoingImeSwitcherForPhones = false; synchronized (mMethodMap) { mFileManager = new InputMethodFileManager(mMethodMap); @@ -611,6 +612,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub synchronized (mMethodMap) { if (!mSystemReady) { mSystemReady = true; + mShowOngoingImeSwitcherForPhones = mRes.getBoolean( + com.android.internal.R.bool.show_ongoing_ime_switcher); try { startInputInnerLocked(); } catch (RuntimeException e) { @@ -1046,7 +1049,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mStatusBar.setIconVisibility("ime", false); } else if (packageName != null) { if (DEBUG) Slog.d(TAG, "show a small icon for the input method"); - mStatusBar.setIcon("ime", packageName, iconId, 0); + CharSequence contentDescription = null; + try { + PackageManager packageManager = mContext.getPackageManager(); + contentDescription = packageManager.getApplicationLabel( + packageManager.getApplicationInfo(packageName, 0)); + } catch (NameNotFoundException nnfe) { + /* ignore */ + } + mStatusBar.setIcon("ime", packageName, iconId, 0, + contentDescription != null ? contentDescription.toString() : null); mStatusBar.setIconVisibility("ime", true); } } @@ -1115,13 +1127,21 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mBackDisposition = backDisposition; mStatusBar.setImeWindowStatus(token, vis, backDisposition); final boolean iconVisibility = (vis & InputMethodService.IME_ACTIVE) != 0; - if (iconVisibility && needsToShowImeSwitchOngoingNotification()) { + final InputMethodInfo imi = mMethodMap.get(mCurMethodId); + if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) { final PackageManager pm = mContext.getPackageManager(); - final CharSequence label = mMethodMap.get(mCurMethodId).loadLabel(pm); final CharSequence title = mRes.getText( com.android.internal.R.string.select_input_method); + final CharSequence imiLabel = imi.loadLabel(pm); + final CharSequence summary = mCurrentSubtype != null + ? TextUtils.concat(mCurrentSubtype.getDisplayName(mContext, + imi.getPackageName(), imi.getServiceInfo().applicationInfo), + (TextUtils.isEmpty(imiLabel) ? + "" : " (" + imiLabel + ")")) + : imiLabel; + mImeSwitcherNotification.setLatestEventInfo( - mContext, title, label, mImeSwitchPendingIntent); + mContext, title, summary, mImeSwitchPendingIntent); mNotificationManager.notify( com.android.internal.R.string.select_input_method, mImeSwitcherNotification); diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java index 41e8a31..17ad268 100644 --- a/services/java/com/android/server/NetworkManagementService.java +++ b/services/java/com/android/server/NetworkManagementService.java @@ -93,6 +93,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { private static final String KEY_TX = "tx_bytes"; class NetdResponseCode { + /* Keep in sync with system/netd/ResponseCode.h */ public static final int InterfaceListResult = 110; public static final int TetherInterfaceListResult = 111; public static final int TetherDnsFwdTgtListResult = 112; @@ -108,6 +109,7 @@ class NetworkManagementService extends INetworkManagementService.Stub { public static final int InterfaceTxThrottleResult = 219; public static final int InterfaceChange = 600; + public static final int BandwidthControl = 601; } /** @@ -265,6 +267,20 @@ class NetworkManagementService extends INetworkManagementService.Stub { } /** + * Notify our observers of a limit reached. + */ + private void notifyLimitReached(String limitName, String iface) { + for (INetworkManagementEventObserver obs : mObservers) { + try { + obs.limitReached(limitName, iface); + Slog.d(TAG, "Observer notified limit reached for " + limitName + " " + iface); + } catch (Exception ex) { + Slog.w(TAG, "Observer notifier failed", ex); + } + } + } + + /** * Let us know the daemon is connected */ protected void onConnected() { @@ -286,33 +302,52 @@ class NetworkManagementService extends INetworkManagementService.Stub { }.start(); } public boolean onEvent(int code, String raw, String[] cooked) { - if (code == NetdResponseCode.InterfaceChange) { - /* - * a network interface change occured - * Format: "NNN Iface added <name>" - * "NNN Iface removed <name>" - * "NNN Iface changed <name> <up/down>" - * "NNN Iface linkstatus <name> <up/down>" - */ - if (cooked.length < 4 || !cooked[1].equals("Iface")) { + switch (code) { + case NetdResponseCode.InterfaceChange: + /* + * a network interface change occured + * Format: "NNN Iface added <name>" + * "NNN Iface removed <name>" + * "NNN Iface changed <name> <up/down>" + * "NNN Iface linkstatus <name> <up/down>" + */ + if (cooked.length < 4 || !cooked[1].equals("Iface")) { + throw new IllegalStateException( + String.format("Invalid event from daemon (%s)", raw)); + } + if (cooked[2].equals("added")) { + notifyInterfaceAdded(cooked[3]); + return true; + } else if (cooked[2].equals("removed")) { + notifyInterfaceRemoved(cooked[3]); + return true; + } else if (cooked[2].equals("changed") && cooked.length == 5) { + notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up")); + return true; + } else if (cooked[2].equals("linkstate") && cooked.length == 5) { + notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up")); + return true; + } throw new IllegalStateException( String.format("Invalid event from daemon (%s)", raw)); - } - if (cooked[2].equals("added")) { - notifyInterfaceAdded(cooked[3]); - return true; - } else if (cooked[2].equals("removed")) { - notifyInterfaceRemoved(cooked[3]); - return true; - } else if (cooked[2].equals("changed") && cooked.length == 5) { - notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up")); - return true; - } else if (cooked[2].equals("linkstate") && cooked.length == 5) { - notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up")); - return true; - } - throw new IllegalStateException( - String.format("Invalid event from daemon (%s)", raw)); + // break; + case NetdResponseCode.BandwidthControl: + /* + * Bandwidth control needs some attention + * Format: "NNN limit alert <alertName> <ifaceName>" + */ + if (cooked.length < 5 || !cooked[1].equals("limit")) { + throw new IllegalStateException( + String.format("Invalid event from daemon (%s)", raw)); + } + if (cooked[2].equals("alert")) { + notifyLimitReached(cooked[3], cooked[4]); + return true; + } + throw new IllegalStateException( + String.format("Invalid event from daemon (%s)", raw)); + // break; + default: break; } return false; } @@ -814,7 +849,6 @@ class NetworkManagementService extends INetworkManagementService.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); try { - mConnector.doCommand(String.format("softap stop " + wlanIface)); mConnector.doCommand(String.format("softap fwreload " + wlanIface + " AP")); mConnector.doCommand(String.format("softap start " + wlanIface)); if (wifiConfig == null) { @@ -862,13 +896,15 @@ class NetworkManagementService extends INetworkManagementService.Stub { } } - public void stopAccessPoint() throws IllegalStateException { + public void stopAccessPoint(String wlanIface) throws IllegalStateException { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService"); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CHANGE_WIFI_STATE, "NetworkManagementService"); try { mConnector.doCommand("softap stopap"); + mConnector.doCommand("softap stop " + wlanIface); + mConnector.doCommand(String.format("softap fwreload " + wlanIface + " STA")); } catch (NativeDaemonConnectorException e) { throw new IllegalStateException("Error communicating to native daemon to stop soft AP", e); diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 4ecdfed..5d7a48f 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -262,7 +262,7 @@ public class NotificationManagerService extends INotificationManager.Stub public void onNotificationClick(String pkg, String tag, int id) { cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL, - Notification.FLAG_FOREGROUND_SERVICE, true); + Notification.FLAG_FOREGROUND_SERVICE, false); } public void onNotificationClear(String pkg, String tag, int id) { diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java index 286a937..4ced83c 100644 --- a/services/java/com/android/server/StatusBarManagerService.java +++ b/services/java/com/android/server/StatusBarManagerService.java @@ -22,10 +22,10 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.os.IBinder; -import android.os.RemoteException; import android.os.Binder; import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; import android.util.Slog; import android.view.View; @@ -175,7 +175,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } - public void setIcon(String slot, String iconPackage, int iconId, int iconLevel) { + public void setIcon(String slot, String iconPackage, int iconId, int iconLevel, + String contentDescription) { enforceStatusBar(); synchronized (mIcons) { @@ -184,7 +185,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub throw new SecurityException("invalid status bar icon slot: " + slot); } - StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel); + StatusBarIcon icon = new StatusBarIcon(iconPackage, iconId, iconLevel, 0, + contentDescription); //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); mIcons.setIcon(index, icon); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 8c7e279..f15eca6 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -37,6 +37,7 @@ import android.provider.Settings; import android.server.BluetoothA2dpService; import android.server.BluetoothService; import android.server.search.SearchManagerService; +import android.server.WifiP2pService; import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Slog; @@ -108,6 +109,7 @@ class ServerThread extends Thread { NetworkStatsService networkStats = null; NetworkPolicyManagerService networkPolicy = null; ConnectivityService connectivity = null; + WifiP2pService wifiP2p = null; IPackageManager pm = null; Context context = null; WindowManagerService wm = null; @@ -230,6 +232,7 @@ class ServerThread extends Thread { WallpaperManagerService wallpaper = null; LocationManagerService location = null; CountryDetectorService countryDetector = null; + TextServicesManagerService tsms = null; if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { try { @@ -273,6 +276,14 @@ class ServerThread extends Thread { } try { + Slog.i(TAG, "Text Service Manager Service"); + tsms = new TextServicesManagerService(context); + ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting Text Service Manager Service", e); + } + + try { Slog.i(TAG, "NetworkStats Service"); networkStats = new NetworkStatsService(context, networkManagement, alarm); ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats); @@ -290,6 +301,14 @@ class ServerThread extends Thread { Slog.e(TAG, "Failure starting NetworkPolicy Service", e); } + try { + Slog.i(TAG, "Wi-Fi P2pService"); + wifiP2p = new WifiP2pService(context); + ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting Wi-Fi P2pService", e); + } + try { Slog.i(TAG, "Connectivity Service"); connectivity = new ConnectivityService(context, networkManagement, networkPolicy); @@ -538,6 +557,7 @@ class ServerThread extends Thread { final LocationManagerService locationF = location; final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; + final TextServicesManagerService textServiceManagerServiceF = tsms; // We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state @@ -571,6 +591,7 @@ class ServerThread extends Thread { if (countryDetectorF != null) countryDetectorF.systemReady(); if (throttleF != null) throttleF.systemReady(); if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady(); + if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady(); } }); diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java new file mode 100644 index 0000000..4a0c837 --- /dev/null +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import com.android.internal.content.PackageMonitor; +import com.android.internal.textservice.ISpellCheckerService; +import com.android.internal.textservice.ISpellCheckerSession; +import com.android.internal.textservice.ISpellCheckerSessionListener; +import com.android.internal.textservice.ITextServicesManager; +import com.android.internal.textservice.ITextServicesSessionListener; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.SystemClock; +import android.provider.Settings; +import android.text.TextUtils; +import android.service.textservice.SpellCheckerService; +import android.util.Log; +import android.util.Slog; +import android.view.textservice.SpellCheckerInfo; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; + +public class TextServicesManagerService extends ITextServicesManager.Stub { + private static final String TAG = TextServicesManagerService.class.getSimpleName(); + private static final boolean DBG = false; + + private final Context mContext; + private boolean mSystemReady; + private final TextServicesMonitor mMonitor; + private final HashMap<String, SpellCheckerInfo> mSpellCheckerMap = + new HashMap<String, SpellCheckerInfo>(); + private final ArrayList<SpellCheckerInfo> mSpellCheckerList = new ArrayList<SpellCheckerInfo>(); + private final HashMap<String, SpellCheckerBindGroup> mSpellCheckerBindGroups = + new HashMap<String, SpellCheckerBindGroup>(); + + public void systemReady() { + if (!mSystemReady) { + mSystemReady = true; + } + } + + public TextServicesManagerService(Context context) { + mSystemReady = false; + mContext = context; + mMonitor = new TextServicesMonitor(); + mMonitor.register(context, true); + synchronized (mSpellCheckerMap) { + buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap); + } + } + + private class TextServicesMonitor extends PackageMonitor { + @Override + public void onSomePackagesChanged() { + synchronized (mSpellCheckerMap) { + buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap); + // TODO: Update for each locale + SpellCheckerInfo sci = getCurrentSpellChecker(null); + if (sci == null) { + sci = findAvailSpellCheckerLocked(null, null); + if (sci == null) return; + // Set the current spell checker if there is one or more spell checkers + // available. In this case, "sci" is the first one in the available spell + // checkers. + setCurrentSpellChecker(sci); + } + final String packageName = sci.getPackageName(); + final int change = isPackageDisappearing(packageName); + if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) { + // Package disappearing + setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName)); + } else if (isPackageModified(packageName)) { + // Package modified + setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName)); + } + } + } + } + + private static void buildSpellCheckerMapLocked(Context context, + ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map) { + list.clear(); + map.clear(); + final PackageManager pm = context.getPackageManager(); + List<ResolveInfo> services = pm.queryIntentServices( + new Intent(SpellCheckerService.SERVICE_INTERFACE), PackageManager.GET_META_DATA); + final int N = services.size(); + for (int i = 0; i < N; ++i) { + final ResolveInfo ri = services.get(i); + final ServiceInfo si = ri.serviceInfo; + final ComponentName compName = new ComponentName(si.packageName, si.name); + if (!android.Manifest.permission.BIND_TEXT_SERVICE.equals(si.permission)) { + Slog.w(TAG, "Skipping text service " + compName + + ": it does not require the permission " + + android.Manifest.permission.BIND_TEXT_SERVICE); + continue; + } + if (DBG) Slog.d(TAG, "Add: " + compName); + final SpellCheckerInfo sci = new SpellCheckerInfo(context, ri); + list.add(sci); + map.put(sci.getId(), sci); + } + } + + // TODO: find an appropriate spell checker for specified locale + private SpellCheckerInfo findAvailSpellCheckerLocked(String locale, String prefPackage) { + final int spellCheckersCount = mSpellCheckerList.size(); + if (spellCheckersCount == 0) { + Slog.w(TAG, "no available spell checker services found"); + return null; + } + if (prefPackage != null) { + for (int i = 0; i < spellCheckersCount; ++i) { + final SpellCheckerInfo sci = mSpellCheckerList.get(i); + if (prefPackage.equals(sci.getPackageName())) { + return sci; + } + } + } + if (spellCheckersCount > 1) { + Slog.w(TAG, "more than one spell checker service found, picking first"); + } + return mSpellCheckerList.get(0); + } + + // TODO: Save SpellCheckerService by supported languages. Currently only one spell + // checker is saved. + @Override + public SpellCheckerInfo getCurrentSpellChecker(String locale) { + synchronized (mSpellCheckerMap) { + final String curSpellCheckerId = + Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.SPELL_CHECKER_SERVICE); + if (TextUtils.isEmpty(curSpellCheckerId)) { + return null; + } + return mSpellCheckerMap.get(curSpellCheckerId); + } + } + + @Override + public void getSpellCheckerService(SpellCheckerInfo info, String locale, + ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener) { + if (!mSystemReady) { + return; + } + if (info == null || tsListener == null) { + Slog.e(TAG, "getSpellCheckerService: Invalid input."); + return; + } + final String sciId = info.getId(); + synchronized(mSpellCheckerMap) { + if (!mSpellCheckerMap.containsKey(sciId)) { + return; + } + if (mSpellCheckerBindGroups.containsKey(sciId)) { + mSpellCheckerBindGroups.get(sciId).addListener(tsListener, locale, scListener); + return; + } + final InternalServiceConnection connection = new InternalServiceConnection( + sciId, locale, scListener); + final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE); + serviceIntent.setComponent(info.getComponent()); + if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) { + Slog.e(TAG, "Failed to get a spell checker service."); + return; + } + final SpellCheckerBindGroup group = new SpellCheckerBindGroup( + connection, tsListener, locale, scListener); + mSpellCheckerBindGroups.put(sciId, group); + } + return; + } + + @Override + public void finishSpellCheckerService(ISpellCheckerSessionListener listener) { + synchronized(mSpellCheckerMap) { + for (SpellCheckerBindGroup group : mSpellCheckerBindGroups.values()) { + if (group == null) continue; + group.removeListener(listener); + } + } + } + + private void setCurrentSpellChecker(SpellCheckerInfo sci) { + if (sci == null || mSpellCheckerMap.containsKey(sci.getId())) return; + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId()); + } + + // SpellCheckerBindGroup contains active text service session listeners. + // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from + // mSpellCheckerBindGroups + private class SpellCheckerBindGroup { + final InternalServiceConnection mInternalConnection; + final ArrayList<InternalDeathRecipient> mListeners = + new ArrayList<InternalDeathRecipient>(); + + public SpellCheckerBindGroup(InternalServiceConnection connection, + ITextServicesSessionListener listener, String locale, + ISpellCheckerSessionListener scListener) { + mInternalConnection = connection; + addListener(listener, locale, scListener); + } + + public void onServiceConnected(ISpellCheckerService spellChecker) { + synchronized(mSpellCheckerMap) { + for (InternalDeathRecipient listener : mListeners) { + try { + final ISpellCheckerSession session = spellChecker.getISpellCheckerSession( + listener.mScLocale, listener.mScListener); + listener.mTsListener.onServiceConnected(session); + } catch (RemoteException e) { + } + } + } + } + + public void addListener(ITextServicesSessionListener tsListener, String locale, + ISpellCheckerSessionListener scListener) { + synchronized(mSpellCheckerMap) { + try { + final int size = mListeners.size(); + for (int i = 0; i < size; ++i) { + if (mListeners.get(i).hasSpellCheckerListener(scListener)) { + // do not add the lister if the group already contains this. + return; + } + } + final InternalDeathRecipient recipient = new InternalDeathRecipient( + this, tsListener, locale, scListener); + scListener.asBinder().linkToDeath(recipient, 0); + mListeners.add(new InternalDeathRecipient( + this, tsListener, locale, scListener)); + } catch(RemoteException e) { + // do nothing + } + cleanLocked(); + } + } + + public void removeListener(ISpellCheckerSessionListener listener) { + synchronized(mSpellCheckerMap) { + final int size = mListeners.size(); + final ArrayList<InternalDeathRecipient> removeList = + new ArrayList<InternalDeathRecipient>(); + for (int i = 0; i < size; ++i) { + final InternalDeathRecipient tempRecipient = mListeners.get(i); + if(tempRecipient.hasSpellCheckerListener(listener)) { + removeList.add(tempRecipient); + } + } + final int removeSize = removeList.size(); + for (int i = 0; i < removeSize; ++i) { + mListeners.remove(removeList.get(i)); + } + cleanLocked(); + } + } + + private void cleanLocked() { + if (mListeners.isEmpty()) { + mSpellCheckerBindGroups.remove(this); + // Unbind service when there is no active clients. + mContext.unbindService(mInternalConnection); + } + } + } + + private class InternalServiceConnection implements ServiceConnection { + private final ISpellCheckerSessionListener mListener; + private final String mSciId; + private final String mLocale; + public InternalServiceConnection( + String id, String locale, ISpellCheckerSessionListener listener) { + mSciId = id; + mLocale = locale; + mListener = listener; + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized(mSpellCheckerMap) { + ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service); + final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId); + if (group != null) { + group.onServiceConnected(spellChecker); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mSpellCheckerBindGroups.remove(mSciId); + } + } + + private class InternalDeathRecipient implements IBinder.DeathRecipient { + public final ITextServicesSessionListener mTsListener; + public final ISpellCheckerSessionListener mScListener; + public final String mScLocale; + private final SpellCheckerBindGroup mGroup; + public InternalDeathRecipient(SpellCheckerBindGroup group, + ITextServicesSessionListener tsListener, String scLocale, + ISpellCheckerSessionListener scListener) { + mTsListener = tsListener; + mScListener = scListener; + mScLocale = scLocale; + mGroup = group; + } + + public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) { + return mScListener.equals(listener); + } + + @Override + public void binderDied() { + mGroup.removeListener(mScListener); + } + } +} diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java index b8890aa..cd649ce 100644 --- a/services/java/com/android/server/ThrottleService.java +++ b/services/java/com/android/server/ThrottleService.java @@ -194,6 +194,7 @@ public class ThrottleService extends IThrottleManager.Stub { } public void interfaceRemoved(String iface) {} + public void limitReached(String limitName, String iface) {} } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 7112553..f9f63b1 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -1461,7 +1461,7 @@ public class WifiService extends IWifiManager.Stub { if (mMulticasters.size() != 0) { return; } else { - mWifiStateMachine.startPacketFiltering(); + mWifiStateMachine.startFilteringMulticastV4Packets(); } } } @@ -1472,11 +1472,11 @@ public class WifiService extends IWifiManager.Stub { synchronized (mMulticasters) { mMulticastEnabled++; mMulticasters.add(new Multicaster(tag, binder)); - // Note that we could call stopPacketFiltering only when + // Note that we could call stopFilteringMulticastV4Packets only when // our new size == 1 (first call), but this function won't // be called often and by making the stopPacket call each // time we're less fragile and self-healing. - mWifiStateMachine.stopPacketFiltering(); + mWifiStateMachine.stopFilteringMulticastV4Packets(); } int uid = Binder.getCallingUid(); @@ -1513,7 +1513,7 @@ public class WifiService extends IWifiManager.Stub { removed.unlinkDeathRecipient(); } if (mMulticasters.size() == 0) { - mWifiStateMachine.startPacketFiltering(); + mWifiStateMachine.startFilteringMulticastV4Packets(); } Long ident = Binder.clearCallingIdentity(); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 0924b86..3389f33 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -3628,6 +3628,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE; app.forcingToForeground = null; app.foregroundServices = false; + app.hasShownUi = false; app.debugging = false; mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app); @@ -9218,6 +9219,7 @@ public final class ActivityManagerService extends ActivityManagerNative app.forcingToForeground = null; app.foregroundServices = false; app.foregroundActivities = false; + app.hasShownUi = false; killServicesLocked(app, true); @@ -9331,8 +9333,6 @@ public final class ActivityManagerService extends ActivityManagerNative // This app is persistent, so we need to keep its record around. // If it is not already on the pending app list, add it there // and start a new process for it. - app.forcingToForeground = null; - app.foregroundServices = false; if (mPersistentStartingProcesses.indexOf(app) < 0) { mPersistentStartingProcesses.add(app); restart = true; @@ -12728,21 +12728,31 @@ public final class ActivityManagerService extends ActivityManagerNative while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) { ServiceRecord s = jt.next(); if (s.startRequested) { - if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) { - // This service has seen some activity within - // recent memory, so we will keep its process ahead - // of the background processes. + if (app.hasShownUi) { + // If this process has shown some UI, let it immediately + // go to the LRU list because it may be pretty heavy with + // UI stuff. We'll tag it with a label just to help + // debug and understand what is going on. if (adj > SECONDARY_SERVER_ADJ) { - adj = SECONDARY_SERVER_ADJ; - app.adjType = "started-services"; - app.hidden = false; + app.adjType = "started-bg-ui-services"; + } + } else { + if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) { + // This service has seen some activity within + // recent memory, so we will keep its process ahead + // of the background processes. + if (adj > SECONDARY_SERVER_ADJ) { + adj = SECONDARY_SERVER_ADJ; + app.adjType = "started-services"; + app.hidden = false; + } + } + // If we have let the service slide into the background + // state, still have some text describing what it is doing + // even though the service no longer has an impact. + if (adj > SECONDARY_SERVER_ADJ) { + app.adjType = "started-bg-services"; } - } - // If we have let the service slide into the background - // state, still have some text describing what it is doing - // even though the service no longer has an impact. - if (adj > SECONDARY_SERVER_ADJ) { - app.adjType = "started-bg-services"; } // Don't kill this process because it is doing work; it // has said it is doing work. @@ -13351,15 +13361,15 @@ public final class ActivityManagerService extends ActivityManagerNative break; } } - } else if (app.curAdj >= PERCEPTIBLE_APP_ADJ) { - if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_INVISIBLE + } else if (app.curAdj == HEAVY_WEIGHT_APP_ADJ) { + if (app.trimMemoryLevel < ComponentCallbacks.TRIM_MEMORY_BACKGROUND && app.thread != null) { try { - app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_INVISIBLE); + app.thread.scheduleTrimMemory(ComponentCallbacks.TRIM_MEMORY_BACKGROUND); } catch (RemoteException e) { } } - app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_INVISIBLE; + app.trimMemoryLevel = ComponentCallbacks.TRIM_MEMORY_BACKGROUND; } else { app.trimMemoryLevel = 0; } @@ -13442,7 +13452,7 @@ public final class ActivityManagerService extends ActivityManagerNative } public boolean profileControl(String process, boolean start, - String path, ParcelFileDescriptor fd) throws RemoteException { + String path, ParcelFileDescriptor fd, int profileType) throws RemoteException { try { synchronized (this) { @@ -13487,7 +13497,7 @@ public final class ActivityManagerService extends ActivityManagerNative } } - proc.thread.profilerControl(start, path, fd); + proc.thread.profilerControl(start, path, fd, profileType); fd = null; return true; } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 0d89081..cc58eaf 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -559,6 +559,7 @@ final class ActivityStack { r.forceNewConfig = false; showAskCompatModeDialogLocked(r); r.compat = mService.compatibilityInfoForPackageLocked(r.info.applicationInfo); + app.hasShownUi = true; app.thread.scheduleLaunchActivity(new Intent(r.intent), r, System.identityHashCode(r), r.info, r.compat, r.icicle, results, newIntents, !andResume, diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 9e597aa..5b59363 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -66,6 +66,7 @@ class ProcessRecord { boolean setIsForeground; // Running foreground UI when last set? boolean foregroundServices; // Running any services that are foreground? boolean foregroundActivities; // Running any activities that are foreground? + boolean hasShownUi; // Has UI been shown in this process since it was started? boolean bad; // True if disabled in the bad process list boolean killedBackground; // True when proc has been killed due to too many bg String waitingToKill; // Process is waiting to be killed when in the bg; reason @@ -185,6 +186,7 @@ class ProcessRecord { pw.print(prefix); pw.print("curSchedGroup="); pw.print(curSchedGroup); pw.print(" setSchedGroup="); pw.print(setSchedGroup); pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel); + pw.print(" hasShownUi="); pw.println(hasShownUi); pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground); pw.print(" foregroundServices="); pw.print(foregroundServices); pw.print(" forcingToForeground="); pw.println(forcingToForeground); diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index d7d4b03..a5a6d8e 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -36,7 +36,6 @@ import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkUtils; import android.os.Binder; -import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -76,10 +75,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private final static String TAG = "Tethering"; private final static boolean DEBUG = true; - private boolean mBooted = false; - //used to remember if we got connected before boot finished - private boolean mDeferedUsbConnection = false; - // TODO - remove both of these - should be part of interface inspection/selection stuff private String[] mTetherableUsbRegexs; private String[] mTetherableWifiRegexs; @@ -126,10 +121,9 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private Notification mTetheredNotification; - // whether we can tether is the && of these two - they come in as separate - // broadcasts so track them so we can decide what to do when either changes - private boolean mUsbMassStorageOff; // track the status of USB Mass Storage - private boolean mUsbConnected; // track the status of USB connection + private boolean mRndisEnabled; // track the RNDIS function enabled state + private boolean mUsbTetherRequested; // true if USB tethering should be started + // when RNDIS is enabled public Tethering(Context context, INetworkManagementService nmService, Looper looper) { mContext = context; @@ -149,7 +143,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { IntentFilter filter = new IntentFilter(); filter.addAction(UsbManager.ACTION_USB_STATE); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); - filter.addAction(Intent.ACTION_BOOT_COMPLETED); mContext.registerReceiver(mStateReceiver, filter); filter = new IntentFilter(); @@ -158,9 +151,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { filter.addDataScheme("file"); mContext.registerReceiver(mStateReceiver, filter); - mUsbMassStorageOff = !Environment.MEDIA_SHARED.equals( - Environment.getExternalStorageState()); - mDhcpRange = context.getResources().getStringArray( com.android.internal.R.array.config_tether_dhcp_range); if ((mDhcpRange.length == 0) || (mDhcpRange.length % 2 ==1)) { @@ -221,6 +211,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } public void interfaceLinkStateChanged(String iface, boolean up) { + if (DEBUG) Log.d(TAG, "interfaceLinkStateChanged " + iface + ", " + up); + interfaceStatusChanged(iface, up); } private boolean isUsb(String iface) { @@ -243,6 +235,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } return false; } + public void interfaceAdded(String iface) { boolean found = false; boolean usb = false; @@ -288,6 +281,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } + public void limitReached(String limitName, String iface) {} + public int tether(String iface) { Log.d(TAG, "Tethering " + iface); TetherInterfaceSM sm = null; @@ -454,47 +449,28 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } - private void updateUsbStatus() { - boolean enable = mUsbConnected && mUsbMassStorageOff; - - if (mBooted) { - enableUsbIfaces(enable); - } - } - private class StateReceiver extends BroadcastReceiver { public void onReceive(Context content, Intent intent) { String action = intent.getAction(); if (action.equals(UsbManager.ACTION_USB_STATE)) { - mUsbConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED); - updateUsbStatus(); - } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) { - mUsbMassStorageOff = false; - updateUsbStatus(); - } - else if (action.equals(Intent.ACTION_MEDIA_UNSHARED)) { - mUsbMassStorageOff = true; - updateUsbStatus(); + synchronized (Tethering.this) { + boolean usbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false); + mRndisEnabled = intent.getBooleanExtra(UsbManager.USB_FUNCTION_RNDIS, false); + // start tethering if we have a request pending + if (usbConnected && mRndisEnabled && mUsbTetherRequested) { + tetherUsb(true); + } + mUsbTetherRequested = false; + } } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) { if (DEBUG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION"); mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED); - } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { - mBooted = true; - updateUsbStatus(); } } } - // used on cable insert/remove - private void enableUsbIfaces(boolean enable) { - // add/remove USB interfaces when USB is connected/disconnected - for (String intf : mTetherableUsbRegexs) { - if (enable) { - interfaceAdded(intf); - } else { - interfaceRemoved(intf); - } - } + private void tetherUsb(boolean enable) { + if (DEBUG) Log.d(TAG, "tetherUsb " + enable); String[] ifaces = new String[0]; try { @@ -505,83 +481,50 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } for (String iface : ifaces) { if (isUsb(iface)) { - if (enable) { - interfaceAdded(iface); - } else { - interfaceRemoved(iface); + int result = (enable ? tether(iface) : untether(iface)); + if (result == ConnectivityManager.TETHER_ERROR_NO_ERROR) { + return; } } } - } - - // toggled when we enter/leave the fully tethered state - private boolean enableUsbRndis(boolean enabled) { - if (DEBUG) Log.d(TAG, "enableUsbRndis(" + enabled + ")"); - - UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE); - if (usbManager == null) { - Log.d(TAG, "could not get UsbManager"); - return false; - } - try { - if (enabled) { - usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false); - } else { - usbManager.setCurrentFunction(null, false); - } - } catch (Exception e) { - Log.e(TAG, "Error toggling usb RNDIS", e); - return false; - } - return true; + Log.e(TAG, "unable start or stop USB tethering"); } // configured when we start tethering and unconfig'd on error or conclusion private boolean configureUsbIface(boolean enabled) { if (DEBUG) Log.d(TAG, "configureUsbIface(" + enabled + ")"); - if (enabled) { - // must enable RNDIS first to create the interface - enableUsbRndis(enabled); - } - + // toggle the USB interfaces + String[] ifaces = new String[0]; try { - // bring toggle the interfaces - String[] ifaces = new String[0]; - try { - ifaces = mNMService.listInterfaces(); - } catch (Exception e) { - Log.e(TAG, "Error listing Interfaces", e); - return false; - } - for (String iface : ifaces) { - if (isUsb(iface)) { - InterfaceConfiguration ifcg = null; - try { - ifcg = mNMService.getInterfaceConfig(iface); - if (ifcg != null) { - InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR); - ifcg.addr = new LinkAddress(addr, USB_PREFIX_LENGTH); - if (enabled) { - ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up"); - } else { - ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down"); - } - ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", ""); - ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," "); - mNMService.setInterfaceConfig(iface, ifcg); + ifaces = mNMService.listInterfaces(); + } catch (Exception e) { + Log.e(TAG, "Error listing Interfaces", e); + return false; + } + for (String iface : ifaces) { + if (isUsb(iface)) { + InterfaceConfiguration ifcg = null; + try { + ifcg = mNMService.getInterfaceConfig(iface); + if (ifcg != null) { + InetAddress addr = NetworkUtils.numericToInetAddress(USB_NEAR_IFACE_ADDR); + ifcg.addr = new LinkAddress(addr, USB_PREFIX_LENGTH); + if (enabled) { + ifcg.interfaceFlags = ifcg.interfaceFlags.replace("down", "up"); + } else { + ifcg.interfaceFlags = ifcg.interfaceFlags.replace("up", "down"); } - } catch (Exception e) { - Log.e(TAG, "Error configuring interface " + iface, e); - return false; + ifcg.interfaceFlags = ifcg.interfaceFlags.replace("running", ""); + ifcg.interfaceFlags = ifcg.interfaceFlags.replace(" "," "); + mNMService.setInterfaceConfig(iface, ifcg); } + } catch (Exception e) { + Log.e(TAG, "Error configuring interface " + iface, e); + return false; } - } - } finally { - if (!enabled) { - enableUsbRndis(false); } - } + } return true; } @@ -598,6 +541,28 @@ public class Tethering extends INetworkManagementEventObserver.Stub { return mTetherableBluetoothRegexs; } + public int setUsbTethering(boolean enable) { + UsbManager usbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE); + + synchronized (this) { + if (enable) { + if (mRndisEnabled) { + tetherUsb(true); + } else { + mUsbTetherRequested = true; + usbManager.setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false); + } + } else { + tetherUsb(false); + if (mRndisEnabled) { + usbManager.setCurrentFunction(null, false); + } + mUsbTetherRequested = false; + } + } + return ConnectivityManager.TETHER_ERROR_NO_ERROR; + } + public int[] getUpstreamIfaceTypes() { int values[] = new int[mUpstreamIfaceTypes.size()]; Iterator<Integer> iterator = mUpstreamIfaceTypes.iterator(); diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java index 05e95a7..9cb772e 100644 --- a/services/java/com/android/server/connectivity/Vpn.java +++ b/services/java/com/android/server/connectivity/Vpn.java @@ -248,6 +248,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } } + public void limitReached(String limitName, String iface) {} + private void showNotification(VpnConfig config, String label, Bitmap icon) { NotificationManager nm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); @@ -394,7 +396,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { if (mTimer == -1) { mTimer = now; Thread.sleep(1); - } else if (now - mTimer <= 30000) { + } else if (now - mTimer <= 60000) { Thread.sleep(yield ? 200 : 1); } else { mInfo.state = LegacyVpnInfo.STATE_TIMEOUT; diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index c80cd0a..f183f83 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -19,6 +19,7 @@ package com.android.server.usb; import android.app.PendingIntent; import android.app.Notification; import android.app.NotificationManager; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -80,6 +81,7 @@ public class UsbDeviceManager { private static final int MSG_ENABLE_ADB = 1; private static final int MSG_SET_CURRENT_FUNCTION = 2; private static final int MSG_SYSTEM_READY = 3; + private static final int MSG_BOOT_COMPLETED = 4; // Delay for debouncing USB disconnects. // We often get rapid connect/disconnect events when enabling USB functions, @@ -87,7 +89,7 @@ public class UsbDeviceManager { private static final int UPDATE_DELAY = 1000; private UsbHandler mHandler; - private boolean mSystemReady; + private boolean mBootCompleted; private final Context mContext; private final ContentResolver mContentResolver; @@ -141,10 +143,15 @@ public class UsbDeviceManager { Process.THREAD_PRIORITY_BACKGROUND); thread.start(); mHandler = new UsbHandler(thread.getLooper()); + + if (nativeIsStartRequested()) { + if (DEBUG) Slog.d(TAG, "accessory attached at boot"); + setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false); + } } public void systemReady() { - mSystemReady = true; + if (DEBUG) Slog.d(TAG, "systemReady"); mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); @@ -236,15 +243,22 @@ public class UsbDeviceManager { private String mCurrentFunctions; private String mDefaultFunctions; private UsbAccessory mCurrentAccessory; - private boolean mDeferAccessoryAttached; private int mUsbNotificationId; private boolean mAdbNotificationShown; + private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + if (DEBUG) Slog.d(TAG, "boot completed"); + mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED); + } + }; + private static final int NOTIFICATION_NONE = 0; private static final int NOTIFICATION_MTP = 1; private static final int NOTIFICATION_PTP = 2; private static final int NOTIFICATION_INSTALLER = 3; - private static final int NOTIFICATION_ADB = 4; + private static final int NOTIFICATION_ACCESSORY = 4; + private static final int NOTIFICATION_ADB = 5; public UsbHandler(Looper looper) { super(looper); @@ -285,6 +299,9 @@ public class UsbDeviceManager { // Watch for USB configuration changes mUEventObserver.startObserving(USB_STATE_MATCH); mUEventObserver.startObserving(ACCESSORY_START_MATCH); + + mContext.registerReceiver(mBootCompletedReceiver, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); } catch (Exception e) { Slog.e(TAG, "Error initializing UsbHandler", e); } @@ -406,11 +423,9 @@ public class UsbDeviceManager { mCurrentAccessory = new UsbAccessory(strings); Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); // defer accessoryAttached if system is not ready - if (mSystemReady) { + if (mBootCompleted) { mSettingsManager.accessoryAttached(mCurrentAccessory); - } else { - mDeferAccessoryAttached = true; - } + } // else handle in mBootCompletedReceiver } else { Slog.e(TAG, "nativeGetAccessoryStrings failed"); } @@ -421,7 +436,7 @@ public class UsbDeviceManager { setEnabledFunctions(mDefaultFunctions); if (mCurrentAccessory != null) { - if (mSystemReady) { + if (mBootCompleted) { mSettingsManager.accessoryDetached(mCurrentAccessory); } mCurrentAccessory = null; @@ -463,7 +478,7 @@ public class UsbDeviceManager { // restore defaults when USB is disconnected doSetCurrentFunctions(mDefaultFunctions); } - if (mSystemReady) { + if (mBootCompleted) { updateUsbState(); } break; @@ -497,7 +512,10 @@ public class UsbDeviceManager { updateUsbNotification(); updateAdbNotification(); updateUsbState(); - if (mCurrentAccessory != null && mDeferAccessoryAttached) { + break; + case MSG_BOOT_COMPLETED: + mBootCompleted = true; + if (mCurrentAccessory != null) { mSettingsManager.accessoryAttached(mCurrentAccessory); } break; @@ -527,6 +545,10 @@ public class UsbDeviceManager { title = r.getText( com.android.internal.R.string.usb_cd_installer_notification_title); id = NOTIFICATION_INSTALLER; + } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ACCESSORY)) { + title = r.getText( + com.android.internal.R.string.usb_accessory_notification_title); + id = NOTIFICATION_ACCESSORY; } else { Slog.e(TAG, "No known USB function in updateUsbNotification"); } @@ -671,4 +693,5 @@ public class UsbDeviceManager { private native String[] nativeGetAccessoryStrings(); private native ParcelFileDescriptor nativeOpenAccessory(); + private native boolean nativeIsStartRequested(); } diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java index d8fd7fe..36f5dcb 100644 --- a/services/java/com/android/server/wm/BlackFrame.java +++ b/services/java/com/android/server/wm/BlackFrame.java @@ -32,10 +32,12 @@ public class BlackFrame { final int top; final Surface surface; - BlackSurface(SurfaceSession session, int layer, int l, int t, int w, int h) + BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b) throws Surface.OutOfResourcesException { left = l; top = t; + int w = r-l; + int h = b-t; surface = new Surface(session, 0, "BlackSurface", -1, w, h, PixelFormat.OPAQUE, Surface.FX_SURFACE_DIM); if (WindowManagerService.SHOW_TRANSACTIONS || diff --git a/services/jni/com_android_server_UsbDeviceManager.cpp b/services/jni/com_android_server_UsbDeviceManager.cpp index 6954171..40f0dbd 100644 --- a/services/jni/com_android_server_UsbDeviceManager.cpp +++ b/services/jni/com_android_server_UsbDeviceManager.cpp @@ -99,11 +99,26 @@ static jobject android_server_UsbDeviceManager_openAccessory(JNIEnv *env, jobjec gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); } +static jboolean android_server_UsbDeviceManager_isStartRequested(JNIEnv *env, jobject thiz) +{ + int fd = open(DRIVER_NAME, O_RDWR); + if (fd < 0) { + LOGE("could not open %s", DRIVER_NAME); + return false; + } + int result = ioctl(fd, ACCESSORY_IS_START_REQUESTED); + close(fd); + return (result == 1); +} + + static JNINativeMethod method_table[] = { { "nativeGetAccessoryStrings", "()[Ljava/lang/String;", (void*)android_server_UsbDeviceManager_getAccessoryStrings }, { "nativeOpenAccessory", "()Landroid/os/ParcelFileDescriptor;", (void*)android_server_UsbDeviceManager_openAccessory }, + { "nativeIsStartRequested", "()Z", + (void*)android_server_UsbDeviceManager_isStartRequested }, }; int register_android_server_UsbDeviceManager(JNIEnv *env) diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index e0dce1f..5b74fb8 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -586,12 +586,12 @@ status_t SensorService::SensorEventConnection::sendEvents( if (size == -EAGAIN) { // the destination doesn't accept events anymore, it's probably // full. For now, we just drop the events on the floor. - LOGW("dropping %d events on the floor", count); + //LOGW("dropping %d events on the floor", count); return size; } - LOGE_IF(size<0, "dropping %d events on the floor (%s)", - count, strerror(-size)); + //LOGE_IF(size<0, "dropping %d events on the floor (%s)", + // count, strerror(-size)); return size < 0 ? status_t(size) : status_t(NO_ERROR); } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 680814c..4a27701 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1318,9 +1318,6 @@ sp<ISurface> SurfaceFlinger::createSurface( if (surfaceHandle != 0) { params->token = token; params->identity = layer->getIdentity(); - params->width = w; - params->height = h; - params->format = format; if (normalLayer != 0) { Mutex::Autolock _l(mStateLock); mLayerMap.add(layer->getSurfaceBinder(), normalLayer); diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp index 11f61cc..91e010f 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.cpp +++ b/services/surfaceflinger/SurfaceTextureLayer.cpp @@ -60,7 +60,11 @@ status_t SurfaceTextureLayer::queueBuffer(int buf, int64_t timestamp, sp<Layer> layer(mLayer.promote()); if (layer != NULL) { - *outTransform = layer->getOrientation(); + uint32_t orientation = layer->getOrientation(); + if (orientation & Transform::ROT_INVALID) { + orientation = 0; + } + *outTransform = orientation; } return res; |