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);
     }
 
     /*