Merge "b/3307761 Clean up the flag mIsHandlingMultiTouch." into honeycomb-mr1
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index c79a458..495fa21 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -77,8 +77,8 @@
void grantAccessoryPermission(in UsbAccessory accessory, int uid);
/* Returns true if the USB manager has default preferences or permissions for the package */
- boolean hasDefaults(String packageName, int uid);
+ boolean hasDefaults(String packageName);
/* Clears default preferences and permissions for the package */
- oneway void clearDefaults(String packageName, int uid);
+ oneway void clearDefaults(String packageName);
}
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index 6cd9178..7d66caa 100644
--- a/core/java/android/hardware/usb/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -109,6 +109,14 @@
}
@Override
+ public int hashCode() {
+ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+ (mModel == null ? 0 : mModel.hashCode()) ^
+ (mType == null ? 0 : mType.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()));
+ }
+
+ @Override
public String toString() {
return "UsbAccessory[mManufacturer=" + mManufacturer +
", mModel=" + mModel +
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index 37bd82b..39254b38 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -270,6 +270,11 @@
}
@Override
+ public int hashCode() {
+ return mName.hashCode();
+ }
+
+ @Override
public String toString() {
return "UsbDevice[mName=" + mName + ",mVendorId=" + mVendorId +
",mProductId=" + mProductId + ",mClass=" + mClass +
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 9f1b8ea..e80c744 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -100,7 +100,7 @@
*
* This intent is sent when a USB accessory is detached.
* <ul>
- * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory}
+ * <li> {@link #EXTRA_ACCESSORY} containing the {@link UsbAccessory}
* for the attached accessory that was detached
* </ul>
*/
@@ -180,10 +180,8 @@
/**
* Name of extra added to the {@link android.app.PendingIntent}
- * passed into
- * {#requestPermission(android.content.Context, android.hardware.usb.UsbDevice, android.app.PendingIntent)}
- * or
- * {#requestPermission(android.content.Context, android.hardware.usb.UsbAccessory, android.app.PendingIntent)}
+ * passed into {@link #requestPermission(UsbDevice, PendingIntent)}
+ * or {@link #requestPermission(UsbAccessory, PendingIntent)}
* containing a boolean value indicating whether the user granted permission or not.
*/
public static final String EXTRA_PERMISSION_GRANTED = "permission";
@@ -281,6 +279,9 @@
/**
* Returns true if the caller has permission to access the device.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission(UsbDevice, PendingIntent)} or
+ * by the user choosing the caller as the default application for the device.
*
* @param device to check permissions for
* @return true if caller has permission
@@ -296,6 +297,9 @@
/**
* Returns true if the caller has permission to access the accessory.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission(UsbAccessory, PendingIntent)} or
+ * by the user choosing the caller as the default application for the accessory.
*
* @param accessory to check permissions for
* @return true if caller has permission
@@ -310,10 +314,13 @@
}
/**
- * Requests permission for the given package to access the device.
+ * Requests temporary permission for the given package to access the device.
* This may result in a system dialog being displayed to the user
* if permission had not already been granted.
* Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * If successful, this grants the caller permission to access the device only
+ * until the device is disconnected.
+ *
* The following extras will be added to pi:
* <ul>
* <li> {@link #EXTRA_DEVICE} containing the device passed into this call
@@ -333,10 +340,13 @@
}
/**
- * Requests permission for the given package to access the accessory.
+ * Requests temporary permission for the given package to access the accessory.
* This may result in a system dialog being displayed to the user
* if permission had not already been granted.
* Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * If successful, this grants the caller permission to access the device only
+ * until the device is disconnected.
+ *
* The following extras will be added to pi:
* <ul>
* <li> {@link #EXTRA_ACCESSORY} containing the accessory passed into this call
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 942425af..716a215 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -1008,14 +1008,15 @@
final Point viewSize = drawData.mViewSize;
updateZoomRange(viewState, viewSize.x, drawData.mMinPrefWidth);
setupZoomOverviewWidth(drawData, mWebView.getViewWidth());
+ final float overviewScale = getZoomOverviewScale();
if (!mMinZoomScaleFixed) {
- mMinZoomScale = getZoomOverviewScale();
+ mMinZoomScale = (mInitialScale > 0) ?
+ Math.min(mInitialScale, overviewScale) : overviewScale;
mMaxZoomScale = Math.max(mMaxZoomScale, mMinZoomScale);
}
if (!mWebView.drawHistory()) {
float scale;
- final float overviewScale = getZoomOverviewScale();
WebSettings settings = mWebView.getSettings();
if (mInitialScale > 0) {
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index f78f83c..b6619ab 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -315,7 +315,11 @@
}
// get the pointer to where we'll record the audio
- recordBuff = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+ // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+ // a way that it becomes much more efficient. When doing so, we will have to prevent the
+ // AudioSystem callback to be called while in critical section (in case of media server
+ // process crash for instance)
+ recordBuff = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
if (recordBuff == NULL) {
LOGE("Error retrieving destination for recorded audio data, can't record");
@@ -327,7 +331,7 @@
ssize_t readSize = lpRecorder->read(recordBuff + offsetInBytes,
sizeInBytes > (jint)recorderBuffSize ?
(jint)recorderBuffSize : sizeInBytes );
- env->ReleasePrimitiveArrayCritical(javaAudioData, recordBuff, 0);
+ env->ReleaseByteArrayElements(javaAudioData, recordBuff, 0);
return (jint) readSize;
}
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 8409adc..44d2a52 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -530,8 +530,12 @@
}
// get the pointer for the audio data from the java array
+ // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+ // a way that it becomes much more efficient. When doing so, we will have to prevent the
+ // AudioSystem callback to be called while in critical section (in case of media server
+ // process crash for instance)
if (javaAudioData) {
- cAudioData = (jbyte *)env->GetPrimitiveArrayCritical(javaAudioData, NULL);
+ cAudioData = (jbyte *)env->GetByteArrayElements(javaAudioData, NULL);
if (cAudioData == NULL) {
LOGE("Error retrieving source of audio data to play, can't play");
return 0; // out of memory or no data to load
@@ -543,7 +547,7 @@
jint written = writeToTrack(lpTrack, javaAudioFormat, cAudioData, offsetInBytes, sizeInBytes);
- env->ReleasePrimitiveArrayCritical(javaAudioData, cAudioData, 0);
+ env->ReleaseByteArrayElements(javaAudioData, cAudioData, 0);
//LOGV("write wrote %d (tried %d) bytes in the native AudioTrack with offset %d",
// (int)written, (int)(sizeInBytes), (int)offsetInBytes);
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 5f7cd90..293764d 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -346,12 +346,14 @@
};
bool processAudioBuffer(const sp<ClientRecordThread>& thread);
- status_t openRecord(uint32_t sampleRate,
+ status_t openRecord_l(uint32_t sampleRate,
int format,
int channelCount,
int frameCount,
uint32_t flags,
audio_io_handle_t input);
+ audio_io_handle_t getInput_l();
+ status_t restoreRecord_l(audio_track_cblk_t*& cblk);
sp<IAudioRecord> mAudioRecord;
sp<IMemory> mCblkMemory;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 813a905..3e346db 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -437,7 +437,7 @@
};
bool processAudioBuffer(const sp<AudioTrackThread>& thread);
- status_t createTrack(int streamType,
+ status_t createTrack_l(int streamType,
uint32_t sampleRate,
int format,
int channelCount,
@@ -446,6 +446,10 @@
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
bool enforceFrameCount);
+ void flush_l();
+ status_t setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount);
+ audio_io_handle_t getOutput_l();
+ status_t restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart);
sp<IAudioTrack> mAudioTrack;
sp<IMemory> mCblkMemory;
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index c6990bf..4610135 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -31,6 +31,7 @@
#define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP init time
#define MAX_RUN_TIMEOUT_MS 1000
#define WAIT_PERIOD_MS 10
+#define RESTORE_TIMEOUT_MS 5000 // Maximum waiting time for a track to be restored
#define CBLK_UNDERRUN_MSK 0x0001
#define CBLK_UNDERRUN_ON 0x0001 // underrun (out) or overrrun (in) indication
@@ -47,6 +48,12 @@
#define CBLK_DISABLED_MSK 0x0010
#define CBLK_DISABLED_ON 0x0010 // track disabled by AudioFlinger due to underrun:
#define CBLK_DISABLED_OFF 0x0000 // must be re-started
+#define CBLK_RESTORING_MSK 0x0020
+#define CBLK_RESTORING_ON 0x0020 // track is being restored after invalidation
+#define CBLK_RESTORING_OFF 0x0000 // by AudioFlinger
+#define CBLK_RESTORED_MSK 0x0040
+#define CBLK_RESTORED_ON 0x0040 // track has been restored after invalidation
+#define CBLK_RESTORED_OFF 0x0040 // by AudioFlinger
struct audio_track_cblk_t
{
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 5a73d2d..fd12e19 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -805,7 +805,7 @@
if (mode != mMode) {
// automatically handle audio focus for mode changes
- handleFocusForCalls(mMode, mode);
+ handleFocusForCalls(mMode, mode, cb);
if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
mMode = mode;
@@ -864,7 +864,7 @@
}
/** pre-condition: oldMode != newMode */
- private void handleFocusForCalls(int oldMode, int newMode) {
+ private void handleFocusForCalls(int oldMode, int newMode, IBinder cb) {
// if ringing
if (newMode == AudioSystem.MODE_RINGTONE) {
// if not ringing silently
@@ -872,8 +872,8 @@
if (ringVolume > 0) {
// request audio focus for the communication focus entry
requestAudioFocus(AudioManager.STREAM_RING,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
- null, null /* both allowed to be null only for this clientId */,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
+ null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
IN_VOICE_COMM_FOCUS_ID /*clientId*/);
}
@@ -884,8 +884,8 @@
// request audio focus for the communication focus entry
// (it's ok if focus was already requested during ringing)
requestAudioFocus(AudioManager.STREAM_RING,
- AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
- null, null /* both allowed to be null only for this clientId */,
+ AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, cb,
+ null /* IAudioFocusDispatcher allowed to be null only for this clientId */,
IN_VOICE_COMM_FOCUS_ID /*clientId*/);
}
// if exiting call
@@ -2547,10 +2547,9 @@
// the main stream type for the audio focus request is currently not used. It may
// potentially be used to handle multiple stream type-dependent audio focuses.
- // we need a valid binder callback for clients other than the AudioService's phone
- // state listener
- if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId) && ((cb == null) || !cb.pingBinder())) {
- Log.i(TAG, " AudioFocus DOA client for requestAudioFocus(), exiting");
+ // we need a valid binder callback for clients
+ if (!cb.pingBinder()) {
+ Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
}
@@ -2591,17 +2590,14 @@
}//synchronized(mAudioFocusLock)
// handle the potential premature death of the new holder of the focus
- // (premature death == death before abandoning focus) for a client which is not the
- // AudioService's phone state listener
- if (!IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
- // Register for client death notification
- AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
- try {
- cb.linkToDeath(afdh, 0);
- } catch (RemoteException e) {
- // client has already died!
- Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
- }
+ // (premature death == death before abandoning focus)
+ // Register for client death notification
+ AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
+ try {
+ cb.linkToDeath(afdh, 0);
+ } catch (RemoteException e) {
+ // client has already died!
+ Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death");
}
return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 1d6ffa0..a18bedb2 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -128,6 +128,9 @@
{
LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
+
+ AutoMutex lock(mLock);
+
if (mAudioRecord != 0) {
return INVALID_OPERATION;
}
@@ -183,7 +186,7 @@
mSessionId = sessionId;
// create the IAudioRecord
- status = openRecord(sampleRate, format, channelCount,
+ status = openRecord_l(sampleRate, format, channelCount,
frameCount, flags, input);
if (status != NO_ERROR) {
return status;
@@ -282,21 +285,31 @@
}
AutoMutex lock(mLock);
+ // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioRecord> audioRecord = mAudioRecord;
+ sp <IMemory> iMem = mCblkMemory;
+ audio_track_cblk_t* cblk = mCblk;
if (mActive == 0) {
mActive = 1;
- ret = mAudioRecord->start();
- if (ret == DEAD_OBJECT) {
- LOGV("start() dead IAudioRecord: creating a new one");
- ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount,
- mFrameCount, mFlags, getInput());
- if (ret == NO_ERROR) {
- ret = mAudioRecord->start();
+
+ cblk->lock.lock();
+ if (!(cblk->flags & CBLK_INVALID_MSK)) {
+ cblk->lock.unlock();
+ ret = mAudioRecord->start();
+ cblk->lock.lock();
+ if (ret == DEAD_OBJECT) {
+ cblk->flags |= CBLK_INVALID_MSK;
}
}
+ if (cblk->flags & CBLK_INVALID_MSK) {
+ ret = restoreRecord_l(cblk);
+ }
+ cblk->lock.unlock();
if (ret == NO_ERROR) {
- mNewPosition = mCblk->user + mUpdatePeriod;
- mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
- mCblk->waitTimeMs = 0;
+ mNewPosition = cblk->user + mUpdatePeriod;
+ cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ cblk->waitTimeMs = 0;
if (t != 0) {
t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
@@ -353,6 +366,7 @@
uint32_t AudioRecord::getSampleRate()
{
+ AutoMutex lock(mLock);
return mCblk->sampleRate;
}
@@ -400,6 +414,7 @@
{
if (position == 0) return BAD_VALUE;
+ AutoMutex lock(mLock);
*position = mCblk->user;
return NO_ERROR;
@@ -415,7 +430,8 @@
// -------------------------------------------------------------------------
-status_t AudioRecord::openRecord(
+// must be called with mLock held
+status_t AudioRecord::openRecord_l(
uint32_t sampleRate,
int format,
int channelCount,
@@ -459,6 +475,7 @@
status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
+ AutoMutex lock(mLock);
int active;
status_t result;
audio_track_cblk_t* cblk = mCblk;
@@ -483,7 +500,19 @@
cblk->lock.unlock();
return WOULD_BLOCK;
}
- result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+ if (!(cblk->flags & CBLK_INVALID_MSK)) {
+ mLock.unlock();
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
+ cblk->lock.unlock();
+ mLock.lock();
+ if (mActive == 0) {
+ return status_t(STOPPED);
+ }
+ cblk->lock.lock();
+ }
+ if (cblk->flags & CBLK_INVALID_MSK) {
+ goto create_new_record;
+ }
if (__builtin_expect(result!=NO_ERROR, false)) {
cblk->waitTimeMs += waitTimeMs;
if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) {
@@ -491,16 +520,17 @@
"user=%08x, server=%08x", cblk->user, cblk->server);
cblk->lock.unlock();
result = mAudioRecord->start();
- if (result == DEAD_OBJECT) {
- LOGW("obtainBuffer() dead IAudioRecord: creating a new one");
- result = openRecord(cblk->sampleRate, mFormat, mChannelCount,
- mFrameCount, mFlags, getInput());
- if (result == NO_ERROR) {
- cblk = mCblk;
- mAudioRecord->start();
- }
- }
cblk->lock.lock();
+ if (result == DEAD_OBJECT) {
+ cblk->flags |= CBLK_INVALID_MSK;
+create_new_record:
+ result = AudioRecord::restoreRecord_l(cblk);
+ }
+ if (result != NO_ERROR) {
+ LOGW("obtainBuffer create Track error %d", result);
+ cblk->lock.unlock();
+ return result;
+ }
cblk->waitTimeMs = 0;
}
if (--waitCount == 0) {
@@ -540,12 +570,19 @@
void AudioRecord::releaseBuffer(Buffer* audioBuffer)
{
- audio_track_cblk_t* cblk = mCblk;
- cblk->stepUser(audioBuffer->frameCount);
+ AutoMutex lock(mLock);
+ mCblk->stepUser(audioBuffer->frameCount);
}
audio_io_handle_t AudioRecord::getInput()
{
+ AutoMutex lock(mLock);
+ return getInput_l();
+}
+
+// must be called with mLock held
+audio_io_handle_t AudioRecord::getInput_l()
+{
mInput = AudioSystem::getInput(mInputSource,
mCblk->sampleRate,
mFormat, mChannels,
@@ -573,6 +610,12 @@
return BAD_VALUE;
}
+ mLock.lock();
+ // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioRecord> audioRecord = mAudioRecord;
+ sp <IMemory> iMem = mCblkMemory;
+ mLock.unlock();
do {
@@ -613,9 +656,17 @@
uint32_t frames = mRemainingFrames;
size_t readSize;
+ mLock.lock();
+ // acquire a strong reference on the IAudioRecord and IMemory so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioRecord> audioRecord = mAudioRecord;
+ sp <IMemory> iMem = mCblkMemory;
+ audio_track_cblk_t* cblk = mCblk;
+ mLock.unlock();
+
// Manage marker callback
if (!mMarkerReached && (mMarkerPosition > 0)) {
- if (mCblk->user >= mMarkerPosition) {
+ if (cblk->user >= mMarkerPosition) {
mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
mMarkerReached = true;
}
@@ -623,7 +674,7 @@
// Manage new position callback
if (mUpdatePeriod > 0) {
- while (mCblk->user >= mNewPosition) {
+ while (cblk->user >= mNewPosition) {
mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
mNewPosition += mUpdatePeriod;
}
@@ -669,11 +720,11 @@
// Manage overrun callback
- if (mActive && (mCblk->framesAvailable_l() == 0)) {
- LOGV("Overrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags);
- if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+ if (mActive && (cblk->framesAvailable() == 0)) {
+ LOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
+ if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
mCbf(EVENT_OVERRUN, mUserData, 0);
- mCblk->flags |= CBLK_UNDERRUN_ON;
+ cblk->flags |= CBLK_UNDERRUN_ON;
}
}
@@ -685,6 +736,69 @@
return true;
}
+// must be called with mLock and cblk.lock held. Callers must also hold strong references on
+// the IAudioRecord and IMemory in case they are recreated here.
+// If the IAudioRecord is successfully restored, the cblk pointer is updated
+status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
+{
+ status_t result;
+
+ if (!(cblk->flags & CBLK_RESTORING_MSK)) {
+ LOGW("dead IAudioRecord, creating a new one");
+
+ cblk->flags |= CBLK_RESTORING_ON;
+ // signal old cblk condition so that other threads waiting for available buffers stop
+ // waiting now
+ cblk->cv.broadcast();
+ cblk->lock.unlock();
+
+ // if the new IAudioRecord is created, openRecord_l() will modify the
+ // following member variables: mAudioRecord, mCblkMemory and mCblk.
+ // It will also delete the strong references on previous IAudioRecord and IMemory
+ result = openRecord_l(cblk->sampleRate, mFormat, mChannelCount,
+ mFrameCount, mFlags, getInput_l());
+ if (result == NO_ERROR) {
+ result = mAudioRecord->start();
+ }
+ if (result != NO_ERROR) {
+ mActive = false;
+ }
+
+ // signal old cblk condition for other threads waiting for restore completion
+ cblk->lock.lock();
+ cblk->flags |= CBLK_RESTORED_MSK;
+ cblk->cv.broadcast();
+ cblk->lock.unlock();
+ } else {
+ if (!(cblk->flags & CBLK_RESTORED_MSK)) {
+ LOGW("dead IAudioRecord, waiting for a new one to be created");
+ mLock.unlock();
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
+ cblk->lock.unlock();
+ mLock.lock();
+ } else {
+ LOGW("dead IAudioRecord, already restored");
+ result = NO_ERROR;
+ cblk->lock.unlock();
+ }
+ if (result != NO_ERROR || mActive == 0) {
+ result = status_t(STOPPED);
+ }
+ }
+ LOGV("restoreRecord_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
+ result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
+
+ if (result == NO_ERROR) {
+ // from now on we switch to the newly created cblk
+ cblk = mCblk;
+ }
+ cblk->lock.lock();
+
+ LOGW_IF(result != NO_ERROR, "restoreRecord_l() error %d", result);
+
+ return result;
+}
+
// =========================================================================
AudioRecord::ClientRecordThread::ClientRecordThread(AudioRecord& receiver, bool bCanCallJava)
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c1bed59..8d8f67b 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -148,6 +148,7 @@
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
+ AutoMutex lock(mLock);
if (mAudioTrack != 0) {
LOGE("Track already in use");
return INVALID_OPERATION;
@@ -211,8 +212,15 @@
mAuxEffectId = 0;
// create the IAudioTrack
- status_t status = createTrack(streamType, sampleRate, format, channelCount,
- frameCount, flags, sharedBuffer, output, true);
+ status_t status = createTrack_l(streamType,
+ sampleRate,
+ format,
+ channelCount,
+ frameCount,
+ flags,
+ sharedBuffer,
+ output,
+ true);
if (status != NO_ERROR) {
return status;
@@ -312,37 +320,38 @@
}
AutoMutex lock(mLock);
+ // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioTrack> audioTrack = mAudioTrack;
+ sp <IMemory> iMem = mCblkMemory;
+ audio_track_cblk_t* cblk = mCblk;
+
if (mActive == 0) {
mActive = 1;
- mNewPosition = mCblk->server + mUpdatePeriod;
- mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
- mCblk->waitTimeMs = 0;
- mCblk->flags &= ~CBLK_DISABLED_ON;
+ mNewPosition = cblk->server + mUpdatePeriod;
+ cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
+ cblk->waitTimeMs = 0;
+ cblk->flags &= ~CBLK_DISABLED_ON;
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
}
- if (mCblk->flags & CBLK_INVALID_MSK) {
- LOGW("start() track %p invalidated, creating a new one", this);
- // no need to clear the invalid flag as this cblk will not be used anymore
- // force new track creation
- status = DEAD_OBJECT;
- } else {
+ LOGV("start %p before lock cblk %p", this, mCblk);
+ cblk->lock.lock();
+ if (!(cblk->flags & CBLK_INVALID_MSK)) {
+ cblk->lock.unlock();
status = mAudioTrack->start();
- }
- if (status == DEAD_OBJECT) {
- LOGV("start() dead IAudioTrack: creating a new one");
- status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
- mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
- if (status == NO_ERROR) {
- status = mAudioTrack->start();
- if (status == NO_ERROR) {
- mNewPosition = mCblk->server + mUpdatePeriod;
- }
+ cblk->lock.lock();
+ if (status == DEAD_OBJECT) {
+ cblk->flags |= CBLK_INVALID_MSK;
}
}
+ if (cblk->flags & CBLK_INVALID_MSK) {
+ status = restoreTrack_l(cblk, true);
+ }
+ cblk->lock.unlock();
if (status != NO_ERROR) {
LOGV("start() failed");
mActive = 0;
@@ -375,14 +384,14 @@
mAudioTrack->stop();
// Cancel loops (If we are in the middle of a loop, playback
// would not stop until loopCount reaches 0).
- setLoop(0, 0, 0);
+ setLoop_l(0, 0, 0);
// the playback head position will reset to 0, so if a marker is set, we need
// to activate it again
mMarkerReached = false;
// Force flush if a shared buffer is used otherwise audioflinger
// will not stop before end of buffer is reached.
if (mSharedBuffer != 0) {
- flush();
+ flush_l();
}
if (t != 0) {
t->requestExit();
@@ -403,6 +412,13 @@
void AudioTrack::flush()
{
+ AutoMutex lock(mLock);
+ flush_l();
+}
+
+// must be called with mLock held
+void AudioTrack::flush_l()
+{
LOGV("flush");
// clear playback marker and periodic update counter
@@ -445,6 +461,7 @@
return BAD_VALUE;
}
+ AutoMutex lock(mLock);
mVolume[LEFT] = left;
mVolume[RIGHT] = right;
@@ -470,6 +487,7 @@
if (level > 1.0f) {
return BAD_VALUE;
}
+ AutoMutex lock(mLock);
mSendLevel = level;
@@ -495,17 +513,26 @@
// Resampler implementation limits input sampling rate to 2 x output sampling rate.
if (rate <= 0 || rate > afSamplingRate*2 ) return BAD_VALUE;
+ AutoMutex lock(mLock);
mCblk->sampleRate = rate;
return NO_ERROR;
}
uint32_t AudioTrack::getSampleRate()
{
+ AutoMutex lock(mLock);
return mCblk->sampleRate;
}
status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
{
+ AutoMutex lock(mLock);
+ return setLoop_l(loopStart, loopEnd, loopCount);
+}
+
+// must be called with mLock held
+status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount)
+{
audio_track_cblk_t* cblk = mCblk;
Mutex::Autolock _l(cblk->lock);
@@ -540,6 +567,7 @@
status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount)
{
+ AutoMutex lock(mLock);
if (loopStart != 0) {
*loopStart = mCblk->loopStart;
}
@@ -599,6 +627,7 @@
status_t AudioTrack::setPosition(uint32_t position)
{
+ AutoMutex lock(mLock);
Mutex::Autolock _l(mCblk->lock);
if (!stopped()) return INVALID_OPERATION;
@@ -614,7 +643,7 @@
status_t AudioTrack::getPosition(uint32_t *position)
{
if (position == 0) return BAD_VALUE;
-
+ AutoMutex lock(mLock);
*position = mCblk->server;
return NO_ERROR;
@@ -622,9 +651,11 @@
status_t AudioTrack::reload()
{
+ AutoMutex lock(mLock);
+
if (!stopped()) return INVALID_OPERATION;
- flush();
+ flush_l();
mCblk->stepUser(mCblk->frameCount);
@@ -633,6 +664,13 @@
audio_io_handle_t AudioTrack::getOutput()
{
+ AutoMutex lock(mLock);
+ return getOutput_l();
+}
+
+// must be called with mLock held
+audio_io_handle_t AudioTrack::getOutput_l()
+{
return AudioSystem::getOutput((AudioSystem::stream_type)mStreamType,
mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
}
@@ -654,7 +692,8 @@
// -------------------------------------------------------------------------
-status_t AudioTrack::createTrack(
+// must be called with mLock held
+status_t AudioTrack::createTrack_l(
int streamType,
uint32_t sampleRate,
int format,
@@ -774,6 +813,7 @@
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
{
+ AutoMutex lock(mLock);
int active;
status_t result;
audio_track_cblk_t* cblk = mCblk;
@@ -800,12 +840,17 @@
return WOULD_BLOCK;
}
if (!(cblk->flags & CBLK_INVALID_MSK)) {
+ mLock.unlock();
result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs));
- }
- if (cblk->flags & CBLK_INVALID_MSK) {
- LOGW("obtainBuffer() track %p invalidated, creating a new one", this);
- // no need to clear the invalid flag as this cblk will not be used anymore
cblk->lock.unlock();
+ mLock.lock();
+ if (mActive == 0) {
+ return status_t(STOPPED);
+ }
+ cblk->lock.lock();
+ }
+
+ if (cblk->flags & CBLK_INVALID_MSK) {
goto create_new_track;
}
if (__builtin_expect(result!=NO_ERROR, false)) {
@@ -819,18 +864,17 @@
//unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
result = mAudioTrack->start();
- if (result == DEAD_OBJECT) {
- LOGW("obtainBuffer() dead IAudioTrack: creating a new one");
-create_new_track:
- result = createTrack(mStreamType, cblk->sampleRate, mFormat, mChannelCount,
- mFrameCount, mFlags, mSharedBuffer, getOutput(), false);
- if (result == NO_ERROR) {
- cblk = mCblk;
- cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
- mAudioTrack->start();
- }
- }
cblk->lock.lock();
+ if (result == DEAD_OBJECT) {
+ cblk->flags |= CBLK_INVALID_MSK;
+create_new_track:
+ result = restoreTrack_l(cblk, false);
+ }
+ if (result != NO_ERROR) {
+ LOGW("obtainBuffer create Track error %d", result);
+ cblk->lock.unlock();
+ return result;
+ }
}
cblk->waitTimeMs = 0;
}
@@ -848,7 +892,7 @@
}
// restart track if it was disabled by audioflinger due to previous underrun
- if (cblk->flags & CBLK_DISABLED_MSK) {
+ if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
cblk->flags &= ~CBLK_DISABLED_ON;
LOGW("obtainBuffer() track %p disabled, restarting", this);
mAudioTrack->start();
@@ -883,8 +927,8 @@
void AudioTrack::releaseBuffer(Buffer* audioBuffer)
{
- audio_track_cblk_t* cblk = mCblk;
- cblk->stepUser(audioBuffer->frameCount);
+ AutoMutex lock(mLock);
+ mCblk->stepUser(audioBuffer->frameCount);
}
// -------------------------------------------------------------------------
@@ -903,6 +947,13 @@
LOGV("write %p: %d bytes, mActive=%d", this, userSize, mActive);
+ // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+ // while we are accessing the cblk
+ mLock.lock();
+ sp <IAudioTrack> audioTrack = mAudioTrack;
+ sp <IMemory> iMem = mCblkMemory;
+ mLock.unlock();
+
ssize_t written = 0;
const int8_t *src = (const int8_t *)buffer;
Buffer audioBuffer;
@@ -953,21 +1004,29 @@
uint32_t frames;
size_t writtenSize;
+ mLock.lock();
+ // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed
+ // while we are accessing the cblk
+ sp <IAudioTrack> audioTrack = mAudioTrack;
+ sp <IMemory> iMem = mCblkMemory;
+ audio_track_cblk_t* cblk = mCblk;
+ mLock.unlock();
+
// Manage underrun callback
- if (mActive && (mCblk->framesReady() == 0)) {
- LOGV("Underrun user: %x, server: %x, flags %04x", mCblk->user, mCblk->server, mCblk->flags);
- if ((mCblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
+ if (mActive && (cblk->framesReady() == 0)) {
+ LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags);
+ if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) {
mCbf(EVENT_UNDERRUN, mUserData, 0);
- if (mCblk->server == mCblk->frameCount) {
+ if (cblk->server == cblk->frameCount) {
mCbf(EVENT_BUFFER_END, mUserData, 0);
}
- mCblk->flags |= CBLK_UNDERRUN_ON;
+ cblk->flags |= CBLK_UNDERRUN_ON;
if (mSharedBuffer != 0) return false;
}
}
// Manage loop end callback
- while (mLoopCount > mCblk->loopCount) {
+ while (mLoopCount > cblk->loopCount) {
int loopCount = -1;
mLoopCount--;
if (mLoopCount >= 0) loopCount = mLoopCount;
@@ -977,7 +1036,7 @@
// Manage marker callback
if (!mMarkerReached && (mMarkerPosition > 0)) {
- if (mCblk->server >= mMarkerPosition) {
+ if (cblk->server >= mMarkerPosition) {
mCbf(EVENT_MARKER, mUserData, (void *)&mMarkerPosition);
mMarkerReached = true;
}
@@ -985,7 +1044,7 @@
// Manage new position callback
if (mUpdatePeriod > 0) {
- while (mCblk->server >= mNewPosition) {
+ while (cblk->server >= mNewPosition) {
mCbf(EVENT_NEW_POS, mUserData, (void *)&mNewPosition);
mNewPosition += mUpdatePeriod;
}
@@ -1068,6 +1127,84 @@
return true;
}
+// must be called with mLock and cblk.lock held. Callers must also hold strong references on
+// the IAudioTrack and IMemory in case they are recreated here.
+// If the IAudioTrack is successfully restored, the cblk pointer is updated
+status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
+{
+ status_t result;
+
+ if (!(cblk->flags & CBLK_RESTORING_MSK)) {
+ LOGW("dead IAudioTrack, creating a new one from %s",
+ fromStart ? "start()" : "obtainBuffer()");
+
+ cblk->flags |= CBLK_RESTORING_ON;
+ // signal old cblk condition so that other threads waiting for available buffers stop
+ // waiting now
+ cblk->cv.broadcast();
+ cblk->lock.unlock();
+
+ // if the new IAudioTrack is created, createTrack_l() will modify the
+ // following member variables: mAudioTrack, mCblkMemory and mCblk.
+ // It will also delete the strong references on previous IAudioTrack and IMemory
+ result = createTrack_l(mStreamType,
+ cblk->sampleRate,
+ mFormat,
+ mChannelCount,
+ mFrameCount,
+ mFlags,
+ mSharedBuffer,
+ getOutput_l(),
+ false);
+
+ if (result == NO_ERROR) {
+ if (!fromStart) {
+ mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
+ }
+ result = mAudioTrack->start();
+ if (fromStart && result == NO_ERROR) {
+ mNewPosition = mCblk->server + mUpdatePeriod;
+ }
+ }
+ if (result != NO_ERROR) {
+ mActive = false;
+ }
+
+ // signal old cblk condition for other threads waiting for restore completion
+ cblk->lock.lock();
+ cblk->flags |= CBLK_RESTORED_MSK;
+ cblk->cv.broadcast();
+ cblk->lock.unlock();
+ } else {
+ if (!(cblk->flags & CBLK_RESTORED_MSK)) {
+ LOGW("dead IAudioTrack, waiting for a new one");
+ mLock.unlock();
+ result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
+ cblk->lock.unlock();
+ mLock.lock();
+ } else {
+ LOGW("dead IAudioTrack, already restored");
+ result = NO_ERROR;
+ cblk->lock.unlock();
+ }
+ if (result != NO_ERROR || mActive == 0) {
+ result = status_t(STOPPED);
+ }
+ }
+ LOGV("restoreTrack_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
+ result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
+
+ if (result == NO_ERROR) {
+ // from now on we switch to the newly created cblk
+ cblk = mCblk;
+ }
+ cblk->lock.lock();
+
+ LOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d", result);
+
+ return result;
+}
+
status_t AudioTrack::dump(int fd, const Vector<String16>& args) const
{
@@ -1197,7 +1334,9 @@
this->server = s;
- cv.signal();
+ if (!(flags & CBLK_INVALID_MSK)) {
+ cv.signal();
+ }
lock.unlock();
return true;
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index adc49ae..3c6c427 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -62,6 +62,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -99,9 +100,6 @@
/* Chipset supports background scan */
private final boolean mBackgroundScanSupported;
- // true if the user enabled Wifi while in airplane mode
- private AtomicBoolean mAirplaneModeOverwridden = new AtomicBoolean(false);
-
private final LockList mLocks = new LockList();
// some wifi lock statistics
private int mFullHighPerfLocksAcquired;
@@ -144,6 +142,14 @@
private static final String ACTION_DEVICE_IDLE =
"com.android.server.WifiManager.action.DEVICE_IDLE";
+ private static final int WIFI_DISABLED = 0;
+ private static final int WIFI_ENABLED = 1;
+ /* Wifi enabled while in airplane mode */
+ private static final int WIFI_ENABLED_AIRPLANE_OVERRIDE = 2;
+
+ private AtomicInteger mWifiState = new AtomicInteger(WIFI_DISABLED);
+ private AtomicBoolean mAirplaneModeOn = new AtomicBoolean(false);
+
private boolean mIsReceiverRegistered = false;
@@ -338,11 +344,11 @@
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // clear our flag indicating the user has overwridden airplane mode
- mAirplaneModeOverwridden.set(false);
- // on airplane disable, restore Wifi if the saved state indicates so
- if (!isAirplaneModeOn() && testAndClearWifiSavedState()) {
- persistWifiEnabled(true);
+ mAirplaneModeOn.set(isAirplaneModeOn());
+ /* On airplane mode disable, restore wifi state if necessary */
+ if (!mAirplaneModeOn.get() && (testAndClearWifiSavedState() ||
+ mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE)) {
+ persistWifiEnabled(true);
}
updateWifiState();
}
@@ -402,9 +408,10 @@
* This function is used only at boot time
*/
public void checkAndStartWifi() {
- /* Start if Wi-Fi is enabled or the saved state indicates Wi-Fi was on */
- boolean wifiEnabled = !isAirplaneModeOn()
- && (getPersistedWifiEnabled() || testAndClearWifiSavedState());
+ mAirplaneModeOn.set(isAirplaneModeOn());
+ mWifiState.set(getPersistedWifiState());
+ /* Start if Wi-Fi should be enabled or the saved state indicates Wi-Fi was on */
+ boolean wifiEnabled = shouldWifiBeEnabled() || testAndClearWifiSavedState();
Slog.i(TAG, "WifiService starting up with Wi-Fi " +
(wifiEnabled ? "enabled" : "disabled"));
setWifiEnabled(wifiEnabled);
@@ -423,21 +430,39 @@
return (wifiSavedState == 1);
}
- private boolean getPersistedWifiEnabled() {
+ private int getPersistedWifiState() {
final ContentResolver cr = mContext.getContentResolver();
try {
- return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON) == 1;
+ return Settings.Secure.getInt(cr, Settings.Secure.WIFI_ON);
} catch (Settings.SettingNotFoundException e) {
- Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, 0);
- return false;
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, WIFI_DISABLED);
+ return WIFI_DISABLED;
+ }
+ }
+
+ private boolean shouldWifiBeEnabled() {
+ if (mAirplaneModeOn.get()) {
+ return mWifiState.get() == WIFI_ENABLED_AIRPLANE_OVERRIDE;
+ } else {
+ return mWifiState.get() != WIFI_DISABLED;
}
}
private void persistWifiEnabled(boolean enabled) {
final ContentResolver cr = mContext.getContentResolver();
- Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, enabled ? 1 : 0);
+ if (enabled) {
+ if (isAirplaneModeOn() && isAirplaneToggleable()) {
+ mWifiState.set(WIFI_ENABLED_AIRPLANE_OVERRIDE);
+ } else {
+ mWifiState.set(WIFI_ENABLED);
+ }
+ } else {
+ mWifiState.set(WIFI_DISABLED);
+ }
+ Settings.Secure.putInt(cr, Settings.Secure.WIFI_ON, mWifiState.get());
}
+
/**
* see {@link android.net.wifi.WifiManager#pingSupplicant()}
* @return {@code true} if the operation succeeds, {@code false} otherwise
@@ -490,11 +515,6 @@
Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
}
- // set a flag if the user is enabling Wifi while in airplane mode
- if (enable && isAirplaneModeOn() && isAirplaneToggleable()) {
- mAirplaneModeOverwridden.set(true);
- }
-
if (enable) {
reportStartWorkSource();
}
@@ -1037,11 +1057,8 @@
}
private void updateWifiState() {
- boolean wifiEnabled = getPersistedWifiEnabled();
- boolean airplaneMode = isAirplaneModeOn() && !mAirplaneModeOverwridden.get();
boolean lockHeld = mLocks.hasLocks();
int strongestLockMode = WifiManager.WIFI_MODE_FULL;
- boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
if (lockHeld) {
@@ -1053,11 +1070,11 @@
}
/* Disable tethering when airplane mode is enabled */
- if (airplaneMode) {
+ if (mAirplaneModeOn.get()) {
mWifiStateMachine.setWifiApEnabled(null, false);
}
- if (wifiShouldBeEnabled) {
+ if (shouldWifiBeEnabled()) {
if (wifiShouldBeStarted) {
reportStartWorkSource();
mWifiStateMachine.setWifiEnabled(true);
diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
index 29e6f94..25eac6f 100644
--- a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
@@ -35,7 +35,7 @@
import android.os.FileUtils;
import android.os.Process;
import android.util.Log;
-import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.util.Xml;
import com.android.internal.content.PackageMonitor;
@@ -65,16 +65,16 @@
private final Context mContext;
- // maps UID to user approved USB devices
- private final SparseArray<ArrayList<DeviceFilter>> mDevicePermissionMap =
- new SparseArray<ArrayList<DeviceFilter>>();
- // maps UID to user approved USB accessories
- private final SparseArray<ArrayList<AccessoryFilter>> mAccessoryPermissionMap =
- new SparseArray<ArrayList<AccessoryFilter>>();
+ // Temporary mapping USB device name to list of UIDs with permissions for the device
+ private final HashMap<String, SparseBooleanArray> mDevicePermissionMap =
+ new HashMap<String, SparseBooleanArray>();
+ // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
+ private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
+ new HashMap<UsbAccessory, SparseBooleanArray>();
// Maps DeviceFilter to user preferred application package
private final HashMap<DeviceFilter, String> mDevicePreferenceMap =
new HashMap<DeviceFilter, String>();
- // Maps DeviceFilter to user preferred application package
+ // Maps AccessoryFilter to user preferred application package
private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
new HashMap<AccessoryFilter, String>();
@@ -354,15 +354,6 @@
}
}
}
-
- public void onUidRemoved(int uid) {
- synchronized (mLock) {
- // clear all permissions for the UID
- if (clearUidDefaultsLocked(uid)) {
- writeSettingsLocked();
- }
- }
- }
}
MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
@@ -374,44 +365,6 @@
mPackageMonitor.register(context, true);
}
- private void readDevicePermission(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int uid = -1;
- ArrayList<DeviceFilter> filters = new ArrayList<DeviceFilter>();
- int count = parser.getAttributeCount();
- for (int i = 0; i < count; i++) {
- if ("uid".equals(parser.getAttributeName(i))) {
- uid = Integer.parseInt(parser.getAttributeValue(i));
- break;
- }
- }
- XmlUtils.nextElement(parser);
- while ("usb-device".equals(parser.getName())) {
- filters.add(DeviceFilter.read(parser));
- XmlUtils.nextElement(parser);
- }
- mDevicePermissionMap.put(uid, filters);
- }
-
- private void readAccessoryPermission(XmlPullParser parser)
- throws XmlPullParserException, IOException {
- int uid = -1;
- ArrayList<AccessoryFilter> filters = new ArrayList<AccessoryFilter>();
- int count = parser.getAttributeCount();
- for (int i = 0; i < count; i++) {
- if ("uid".equals(parser.getAttributeName(i))) {
- uid = Integer.parseInt(parser.getAttributeValue(i));
- break;
- }
- }
- XmlUtils.nextElement(parser);
- while ("usb-accessory".equals(parser.getName())) {
- filters.add(AccessoryFilter.read(parser));
- XmlUtils.nextElement(parser);
- }
- mAccessoryPermissionMap.put(uid, filters);
- }
-
private void readPreference(XmlPullParser parser)
throws XmlPullParserException, IOException {
String packageName = null;
@@ -443,11 +396,7 @@
XmlUtils.nextElement(parser);
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
String tagName = parser.getName();
- if ("device-permission".equals(tagName)) {
- readDevicePermission(parser);
- } else if ("accessory-permission".equals(tagName)) {
- readAccessoryPermission(parser);
- } else if ("preference".equals(tagName)) {
+ if ("preference".equals(tagName)) {
readPreference(parser);
} else {
XmlUtils.nextElement(parser);
@@ -480,32 +429,6 @@
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, "settings");
- int count = mDevicePermissionMap.size();
- for (int i = 0; i < count; i++) {
- int uid = mDevicePermissionMap.keyAt(i);
- ArrayList<DeviceFilter> filters = mDevicePermissionMap.valueAt(i);
- serializer.startTag(null, "device-permission");
- serializer.attribute(null, "uid", Integer.toString(uid));
- int filterCount = filters.size();
- for (int j = 0; j < filterCount; j++) {
- filters.get(j).write(serializer);
- }
- serializer.endTag(null, "device-permission");
- }
-
- count = mAccessoryPermissionMap.size();
- for (int i = 0; i < count; i++) {
- int uid = mAccessoryPermissionMap.keyAt(i);
- ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
- serializer.startTag(null, "accessory-permission");
- serializer.attribute(null, "uid", Integer.toString(uid));
- int filterCount = filters.size();
- for (int j = 0; j < filterCount; j++) {
- filters.get(j).write(serializer);
- }
- serializer.endTag(null, "accessory-permission");
- }
-
for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
serializer.startTag(null, "preference");
serializer.attribute(null, "package", mDevicePreferenceMap.get(filter));
@@ -621,6 +544,9 @@
}
public void deviceDetached(UsbDevice device) {
+ // clear temporary permissions for the device
+ mDevicePermissionMap.remove(device.getDeviceName());
+
Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
Log.d(TAG, "usbDeviceRemoved, sending " + intent);
@@ -644,6 +570,16 @@
resolveActivity(intent, matches, defaultPackage, null, accessory);
}
+ public void accessoryDetached(UsbAccessory accessory) {
+ // clear temporary permissions for the accessory
+ mAccessoryPermissionMap.remove(accessory);
+
+ Intent intent = new Intent(
+ UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ mContext.sendBroadcast(intent);
+ }
+
private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
String defaultPackage, UsbDevice device, UsbAccessory accessory) {
int count = matches.size();
@@ -659,13 +595,6 @@
rInfo.activityInfo.applicationInfo != null &&
(rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
defaultRI = rInfo;
- int uid = rInfo.activityInfo.applicationInfo.uid;
- // grant permission
- if (device != null) {
- grantDevicePermission(device, uid);
- } else if (accessory != null) {
- grantAccessoryPermission(accessory, uid);
- }
}
}
@@ -682,6 +611,13 @@
}
if (defaultRI != null) {
+ // grant permission for default activity
+ if (device != null) {
+ grantDevicePermission(device, defaultRI.activityInfo.applicationInfo.uid);
+ } else if (accessory != null) {
+ grantAccessoryPermission(accessory, defaultRI.activityInfo.applicationInfo.uid);
+ }
+
// start default activity directly
try {
intent.setComponent(
@@ -711,47 +647,24 @@
}
}
- public void accessoryDetached(UsbAccessory accessory) {
- Intent intent = new Intent(
- UsbManager.ACTION_USB_ACCESSORY_DETACHED);
- intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
- mContext.sendBroadcast(intent);
- }
-
public boolean hasPermission(UsbDevice device) {
synchronized (mLock) {
- ArrayList<DeviceFilter> filterList =
- mDevicePermissionMap.get(Binder.getCallingUid());
- if (filterList != null) {
- int count = filterList.size();
- for (int i = 0; i < count; i++) {
- DeviceFilter filter = filterList.get(i);
- if (filter.equals(device)) {
- // permission allowed
- return true;
- }
- }
+ SparseBooleanArray uidList = mDevicePermissionMap.get(device.getDeviceName());
+ if (uidList == null) {
+ return false;
}
+ return uidList.get(Binder.getCallingUid());
}
- return false;
}
public boolean hasPermission(UsbAccessory accessory) {
synchronized (mLock) {
- ArrayList<AccessoryFilter> filterList =
- mAccessoryPermissionMap.get(Binder.getCallingUid());
- if (filterList != null) {
- int count = filterList.size();
- for (int i = 0; i < count; i++) {
- AccessoryFilter filter = filterList.get(i);
- if (filter.equals(accessory)) {
- // permission allowed
- return true;
- }
- }
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ if (uidList == null) {
+ return false;
}
+ return uidList.get(Binder.getCallingUid());
}
- return false;
}
public void checkPermission(UsbDevice device) {
@@ -873,73 +786,43 @@
public void grantDevicePermission(UsbDevice device, int uid) {
synchronized (mLock) {
- ArrayList<DeviceFilter> filterList = mDevicePermissionMap.get(uid);
- if (filterList == null) {
- filterList = new ArrayList<DeviceFilter>();
- mDevicePermissionMap.put(uid, filterList);
- } else {
- int count = filterList.size();
- for (int i = 0; i < count; i++) {
- if (filterList.get(i).equals(device)) return;
- }
+ String deviceName = device.getDeviceName();
+ SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
+ if (uidList == null) {
+ uidList = new SparseBooleanArray(1);
+ mDevicePermissionMap.put(deviceName, uidList);
}
- filterList.add(new DeviceFilter(device));
- writeSettingsLocked();
+ uidList.put(uid, true);
}
}
public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
synchronized (mLock) {
- ArrayList<AccessoryFilter> filterList = mAccessoryPermissionMap.get(uid);
- if (filterList == null) {
- filterList = new ArrayList<AccessoryFilter>();
- mAccessoryPermissionMap.put(uid, filterList);
- } else {
- int count = filterList.size();
- for (int i = 0; i < count; i++) {
- if (filterList.get(i).equals(accessory)) return;
- }
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ if (uidList == null) {
+ uidList = new SparseBooleanArray(1);
+ mAccessoryPermissionMap.put(accessory, uidList);
}
- filterList.add(new AccessoryFilter(accessory));
- writeSettingsLocked();
+ uidList.put(uid, true);
}
}
- public boolean hasDefaults(String packageName, int uid) {
+ public boolean hasDefaults(String packageName) {
synchronized (mLock) {
- if (mDevicePermissionMap.get(uid) != null) return true;
- if (mAccessoryPermissionMap.get(uid) != null) return true;
if (mDevicePreferenceMap.values().contains(packageName)) return true;
if (mAccessoryPreferenceMap.values().contains(packageName)) return true;
return false;
}
}
- public void clearDefaults(String packageName, int uid) {
+ public void clearDefaults(String packageName) {
synchronized (mLock) {
- boolean packageCleared = clearPackageDefaultsLocked(packageName);
- boolean uidCleared = clearUidDefaultsLocked(uid);
- if (packageCleared || uidCleared) {
+ if (clearPackageDefaultsLocked(packageName)) {
writeSettingsLocked();
}
}
}
- private boolean clearUidDefaultsLocked(int uid) {
- boolean cleared = false;
- int index = mDevicePermissionMap.indexOfKey(uid);
- if (index >= 0) {
- mDevicePermissionMap.removeAt(index);
- cleared = true;
- }
- index = mAccessoryPermissionMap.indexOfKey(uid);
- if (index >= 0) {
- mAccessoryPermissionMap.removeAt(index);
- cleared = true;
- }
- return cleared;
- }
-
private boolean clearPackageDefaultsLocked(String packageName) {
boolean cleared = false;
synchronized (mLock) {
@@ -972,24 +855,24 @@
public void dump(FileDescriptor fd, PrintWriter pw) {
synchronized (mLock) {
pw.println(" Device permissions:");
- int count = mDevicePermissionMap.size();
- for (int i = 0; i < count; i++) {
- int uid = mDevicePermissionMap.keyAt(i);
- pw.println(" " + "uid " + uid + ":");
- ArrayList<DeviceFilter> filters = mDevicePermissionMap.valueAt(i);
- for (DeviceFilter filter : filters) {
- pw.println(" " + filter);
+ for (String deviceName : mDevicePermissionMap.keySet()) {
+ pw.print(" " + deviceName + ": ");
+ SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName);
+ int count = uidList.size();
+ for (int i = 0; i < count; i++) {
+ pw.print(Integer.toString(uidList.keyAt(i)) + " ");
}
+ pw.println("");
}
pw.println(" Accessory permissions:");
- count = mAccessoryPermissionMap.size();
- for (int i = 0; i < count; i++) {
- int uid = mAccessoryPermissionMap.keyAt(i);
- pw.println(" " + "uid " + uid + ":");
- ArrayList<AccessoryFilter> filters = mAccessoryPermissionMap.valueAt(i);
- for (AccessoryFilter filter : filters) {
- pw.println(" " + filter);
+ for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
+ pw.print(" " + accessory + ": ");
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ int count = uidList.size();
+ for (int i = 0; i < count; i++) {
+ pw.print(Integer.toString(uidList.keyAt(i)) + " ");
}
+ pw.println("");
}
pw.println(" Device preferences:");
for (DeviceFilter filter : mDevicePreferenceMap.keySet()) {
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index d0a2492..71f2a9b 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -483,14 +483,14 @@
mDeviceManager.grantAccessoryPermission(accessory, uid);
}
- public boolean hasDefaults(String packageName, int uid) {
+ public boolean hasDefaults(String packageName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- return mDeviceManager.hasDefaults(packageName, uid);
+ return mDeviceManager.hasDefaults(packageName);
}
- public void clearDefaults(String packageName, int uid) {
+ public void clearDefaults(String packageName) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
- mDeviceManager.clearDefaults(packageName, uid);
+ mDeviceManager.clearDefaults(packageName);
}
/*