Merge "Add error reporting for Tethering."
diff --git a/api/current.xml b/api/current.xml
index 1f7be9e..eae20e7 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -24220,6 +24220,17 @@
  visibility="public"
 >
 </field>
+<field name="CURSOR_EXTRA_KEY_IN_PROGRESS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;in_progress&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_DATA_KEY"
  type="java.lang.String"
  transient="false"
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index a447f53..c8d1397 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -674,14 +674,19 @@
     return 0;
 }
 
-void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid)
+void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid,
+        struct stat* statbuf)
 {
     while (path[basepos] != 0) {
         if (path[basepos] == '/') {
             path[basepos] = 0;
-            LOGI("Making directory: %s\n", path);
-            if (mkdir(path, mode) == 0) {
-                chown(path, uid, gid);
+            if (lstat(path, statbuf) < 0) {
+                LOGI("Making directory: %s\n", path);
+                if (mkdir(path, mode) == 0) {
+                    chown(path, uid, gid);
+                } else {
+                    LOGW("Unable to make directory %s: %s\n", path, strerror(errno));
+                }
             }
             path[basepos] = '/';
             basepos++;
@@ -690,8 +695,8 @@
     }
 }
 
-int movefileordir(char* srcpath, char* dstpath, int dstuid, int dstgid,
-        struct stat* statbuf)
+int movefileordir(char* srcpath, char* dstpath, int dstbasepos,
+        int dstuid, int dstgid, struct stat* statbuf)
 {
     DIR *d;
     struct dirent *de;
@@ -706,8 +711,9 @@
     }
     
     if ((statbuf->st_mode&S_IFDIR) == 0) {
+        mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH,
+                dstuid, dstgid, statbuf);
         LOGI("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid);
-        mkinnerdirs(dstpath, dstend-1, S_IRWXU|S_IRWXG|S_IXOTH, dstuid, dstgid);
         if (rename(srcpath, dstpath) >= 0) {
             if (chown(dstpath, dstuid, dstgid) < 0) {
                 LOGE("cannot chown %s: %s\n", dstpath, strerror(errno));
@@ -752,7 +758,7 @@
         strcpy(srcpath+srcend+1, name);
         strcpy(dstpath+dstend+1, name);
         
-        if (movefileordir(srcpath, dstpath, dstuid, dstgid, statbuf) != 0) {
+        if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) {
             res = 1;
         }
         
@@ -834,7 +840,9 @@
                             LOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg);
                             if (!create_move_path(srcpath, PKG_DIR_PREFIX, srcpkg, buf+bufp) &&
                                     !create_move_path(dstpath, PKG_DIR_PREFIX, dstpkg, buf+bufp)) {
-                                movefileordir(srcpath, dstpath, dstuid, dstgid, &s);
+                                movefileordir(srcpath, dstpath,
+                                        strlen(dstpath)-strlen(buf+bufp),
+                                        dstuid, dstgid, &s);
                             }
                         }
                     } else {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 67f9629..0ed572a 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1300,6 +1300,14 @@
     public final static String EXTRA_SELECT_QUERY = "select_query";
 
     /**
+     * Boolean extra data key for a suggestion provider to return in {@link Cursor#getExtras} to
+     * indicate that the search is not complete yet. This can be used by the search UI
+     * to indicate that a search is in progress. The suggestion provider can return partial results
+     * this way and send a change notification on the cursor when more results are available.
+     */
+    public final static String CURSOR_EXTRA_KEY_IN_PROGRESS = "in_progress";
+
+    /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getStringExtra content.Intent.getStringExtra()}
      * to obtain the action message that was defined for a particular search action key and/or
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 07e9793..3e11a3f 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -159,19 +159,23 @@
          * for in app search we show the progress spinner until the cursor is returned with
          * the results.
          */
+        Cursor cursor = null;
         mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
         try {
-            final Cursor cursor = mSearchManager.getSuggestions(mSearchable, query, QUERY_LIMIT);
+            cursor = mSearchManager.getSuggestions(mSearchable, query, QUERY_LIMIT);
             // trigger fill window so the spinner stays up until the results are copied over and
             // closer to being ready
-            if (cursor != null) cursor.getCount();
-            return cursor;
+            if (cursor != null) {
+                cursor.getCount();
+                return cursor;
+            }
         } catch (RuntimeException e) {
             Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
-            return null;
-        } finally {
-            mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
         }
+        // If cursor is null or an exception was thrown, stop the spinner and return null.
+        // changeCursor doesn't get called if cursor is null
+        mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
+        return null;
     }
 
     public void close() {
@@ -180,6 +184,39 @@
         mClosed = true;
     }
 
+    @Override
+    public void notifyDataSetChanged() {
+        if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
+        super.notifyDataSetChanged();
+
+        updateSpinnerState(getCursor());
+    }
+
+    @Override
+    public void notifyDataSetInvalidated() {
+        if (DBG) Log.d(LOG_TAG, "notifyDataSetInvalidated");
+        super.notifyDataSetInvalidated();
+
+        updateSpinnerState(getCursor());
+    }
+
+    private void updateSpinnerState(Cursor cursor) {
+        if (DBG) {
+            Log.d(LOG_TAG, "updateSpinnerState - extra = "
+                + (cursor != null
+                        ? cursor.getExtras().getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)
+                        : null));
+        }
+        // Check if the Cursor indicates that the query is not complete and show the spinner
+        if (cursor != null
+                && cursor.getExtras().getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)) {
+            mSearchDialog.getWindow().getDecorView().post(mStartSpinnerRunnable);
+            return;
+        }
+        // If cursor is null or is done, stop the spinner
+        mSearchDialog.getWindow().getDecorView().post(mStopSpinnerRunnable);
+    }
+
     /**
      * Cache columns.
      */
@@ -202,7 +239,8 @@
                 mText2UrlCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
                 mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
                 mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
-                mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR);
+                mBackgroundColorCol =
+                        c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR);
             }
         } catch (Exception e) {
             Log.e(LOG_TAG, "error changing cursor and caching columns", e);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b07bafcf..7a0337cd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -967,8 +967,11 @@
                 String orig =sa.getNonResourceString(
                         com.android.internal.R.styleable.AndroidManifestOriginalPackage_name);
                 if (!pkg.packageName.equals(orig)) {
-                    pkg.mOriginalPackage = orig;
-                    pkg.mRealPackage = pkg.packageName;
+                    if (pkg.mOriginalPackages == null) {
+                        pkg.mOriginalPackages = new ArrayList<String>();
+                        pkg.mRealPackage = pkg.packageName;
+                    }
+                    pkg.mOriginalPackages.add(orig);
                 }
 
                 sa.recycle();
@@ -2579,7 +2582,7 @@
         public ArrayList<String> usesOptionalLibraries = null;
         public String[] usesLibraryFiles = null;
 
-        public String mOriginalPackage = null;
+        public ArrayList<String> mOriginalPackages = null;
         public String mRealPackage = null;
         public ArrayList<String> mAdoptPermissions = null;
         
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index cd8361c..d280f50 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -202,6 +202,12 @@
     RS_PRIMITIVE_TRIANGLE_FAN
 };
 
+enum RsError {
+    RS_ERROR_NONE,
+    RS_ERROR_BAD_SHADER,
+    RS_ERROR_BAD_SCRIPT
+};
+
 #ifndef NO_RS_FUNCS
 #include "rsgApiFuncDecl.h"
 #endif
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 4d97c0f..cb9937c 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -36,6 +36,11 @@
 	param int32_t bits
 }
 
+ContextGetError {
+	param RsError *err
+	ret const char *
+	}
+
 ContextSetPriority {
 	param int32_t priority
 	}
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index cc3a74fb..d8a9a99 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -178,6 +178,11 @@
     uint32_t ret = runScript(mRootScript.get(), 0);
 
     checkError("runRootScript");
+    if (mError != RS_ERROR_NONE) {
+        // If we have an error condition we stop rendering until
+        // somthing changes that might fix it.
+        ret = 0;
+    }
     return ret;
 }
 
@@ -240,10 +245,13 @@
     }
 }
 
-void Context::setupCheck()
+bool Context::setupCheck()
 {
     if (checkVersion2_0()) {
-        mShaderCache.lookup(this, mVertex.get(), mFragment.get());
+        if (!mShaderCache.lookup(this, mVertex.get(), mFragment.get())) {
+            LOGE("Context::setupCheck() 1 fail");
+            return false;
+        }
 
         mFragmentStore->setupGL2(this, &mStateFragmentStore);
         mFragment->setupGL2(this, &mStateFragment, &mShaderCache);
@@ -256,6 +264,7 @@
         mRaster->setupGL(this, &mStateRaster);
         mVertex->setupGL(this, &mStateVertex);
     }
+    return true;
 }
 
 static bool getProp(const char *str)
@@ -389,6 +398,9 @@
     mUseDepth = useDepth;
     mPaused = false;
     mObjHead = NULL;
+    mError = RS_ERROR_NONE;
+    mErrorMsg = NULL;
+
     memset(&mEGL, 0, sizeof(mEGL));
     memset(&mGL, 0, sizeof(mGL));
     mIsGraphicsContext = isGraphics;
@@ -764,6 +776,23 @@
     mIO.mToClient.shutdown();
 }
 
+const char * Context::getError(RsError *err)
+{
+    *err = mError;
+    mError = RS_ERROR_NONE;
+    if (*err != RS_ERROR_NONE) {
+        return mErrorMsg;
+    }
+    return NULL;
+}
+
+void Context::setError(RsError e, const char *msg)
+{
+    mError = e;
+    mErrorMsg = msg;
+}
+
+
 void Context::dumpDebug() const
 {
     LOGE("RS Context debug %p", this);
@@ -874,6 +903,15 @@
     ObjectBase::dumpAll(rsc);
 }
 
+const char * rsi_ContextGetError(Context *rsc, RsError *e)
+{
+    const char *msg = rsc->getError(e);
+    if (*e != RS_ERROR_NONE) {
+        LOGE("RS Error %i %s", *e, msg);
+    }
+    return msg;
+}
+
 }
 }
 
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 04bd748..82c3687 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -93,7 +93,7 @@
     const ProgramRaster * getRaster() {return mRaster.get();}
     const ProgramVertex * getVertex() {return mVertex.get();}
 
-    void setupCheck();
+    bool setupCheck();
     bool checkDriver() const {return mEGL.mSurface != 0;}
 
     void pause();
@@ -160,6 +160,8 @@
 
     void dumpDebug() const;
     void checkError(const char *) const;
+    const char * getError(RsError *);
+    void setError(RsError e, const char *msg);
 
     mutable const ObjectBase * mObjHead;
 
@@ -211,6 +213,8 @@
     bool mExit;
     bool mUseDepth;
     bool mPaused;
+    RsError mError;
+    const char *mErrorMsg;
 
     pthread_t mThreadId;
     pid_t mNativeThreadId;
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 656a3c3..478a6dc 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -39,6 +39,7 @@
     mInputCount = 0;
     mOutputCount = 0;
     mConstantCount = 0;
+    mIsValid = false;
 }
 
 Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
@@ -216,6 +217,7 @@
                 }
                 glDeleteShader(mShaderID);
                 mShaderID = 0;
+                rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
                 return false;
             }
         }
@@ -224,6 +226,7 @@
     if (rsc->props.mLogShaders) {
         LOGV("--Shader load result %x ", glGetError());
     }
+    mIsValid = true;
     return true;
 }
 
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index a34e89f..86f85fb 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -59,6 +59,8 @@
     String8 getGLSLOutputString() const;
     String8 getGLSLConstantString() const;
 
+    bool isValid() const {return mIsValid;}
+
 protected:
     // Components not listed in "in" will be passed though
     // unless overwritten by components in out.
@@ -68,6 +70,7 @@
     uint32_t mInputCount;
     uint32_t mOutputCount;
     uint32_t mConstantCount;
+    bool mIsValid;
 
     ObjectBaseRef<Allocation> mConstants[MAX_UNIFORMS];
 
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index cb1436b..a33933b 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -96,6 +96,10 @@
 void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot)
 {
     Script *s = static_cast<Script *>(vs);
+    if (s->mEnviroment.mInvokables[slot] == NULL) {
+        rsc->setError(RS_ERROR_BAD_SCRIPT, "Calling invoke on bad script");
+        return;
+    }
     s->setupScript();
     s->mEnviroment.mInvokables[slot]();
 }
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index b7e0b86..1f23773 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -62,6 +62,11 @@
 
 uint32_t ScriptC::run(Context *rsc, uint32_t launchIndex)
 {
+    if (mProgram.mScript == NULL) {
+        rsc->setError(RS_ERROR_BAD_SCRIPT, "Attempted to run bad script");
+        return 0;
+    }
+
     Context::ScriptTLSStruct * tls =
     (Context::ScriptTLSStruct *)pthread_getspecific(Context::gThreadTLSKey);
     rsAssert(tls);
@@ -154,7 +159,9 @@
         ACCchar buf[4096];
         ACCsizei len;
         accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf);
-        LOGV(buf);
+        LOGE(buf);
+        rsc->setError(RS_ERROR_BAD_SCRIPT, "Error compiling user script.");
+        return;
     }
 
     if (s->mProgram.mInit) {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 235c153..202ca3d 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -683,7 +683,9 @@
                         float x2, float y2, float z2)
 {
     GET_TLS();
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
 
     float vtx[] = { x1, y1, z1, x2, y2, z2 };
     VertexArray va;
@@ -700,7 +702,9 @@
 static void SC_drawPoint(float x, float y, float z)
 {
     GET_TLS();
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
 
     float vtx[] = { x, y, z };
 
@@ -725,7 +729,9 @@
                                  float u4, float v4)
 {
     GET_TLS();
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
 
     //LOGE("Quad");
     //LOGE("%4.2f, %4.2f, %4.2f", x1, y1, z1);
@@ -782,7 +788,9 @@
         float cx0, float cy0, float cx1, float cy1)
 {
     GET_TLS();
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
 
     GLint crop[4] = {cx0, cy0, cx1, cy1};
     glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop);
@@ -831,7 +839,9 @@
 {
     GET_TLS();
     SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
     sm->render(rsc);
 }
 
@@ -839,7 +849,9 @@
 {
     GET_TLS();
     SimpleMesh *sm = static_cast<SimpleMesh *>(vsm);
-    rsc->setupCheck();
+    if (!rsc->setupCheck()) {
+        return;
+    }
     sm->renderRange(rsc, start, len);
 }
 
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 3a1f370..4711d1b 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -123,6 +123,8 @@
                 }
             }
             glDeleteProgram(pgm);
+            rsc->setError(RS_ERROR_BAD_SHADER, "Error linking GL Programs");
+            return false;
         }
         if (vtx->isUserProgram()) {
             for (uint32_t ct=0; ct < vtx->getAttribCount(); ct++) {
@@ -146,6 +148,7 @@
         }
     }
 
+    e->mIsValid = true;
     //LOGV("SC made program %i", e->program);
     glUseProgram(e->program);
     mEntryCount++;
diff --git a/libs/rs/rsShaderCache.h b/libs/rs/rsShaderCache.h
index 7aa8183..df99ccc 100644
--- a/libs/rs/rsShaderCache.h
+++ b/libs/rs/rsShaderCache.h
@@ -56,6 +56,7 @@
         int32_t mFragAttribSlots[Program::MAX_ATTRIBS];
         int32_t mFragUniformSlots[Program::MAX_UNIFORMS];
         bool mUserVertexProgram;
+        bool mIsValid;
     } entry_t;
     entry_t *mEntries;
     entry_t *mCurrent;
diff --git a/libs/rs/spec.l b/libs/rs/spec.l
index d81d47e..6a9010fe 100644
--- a/libs/rs/spec.l
+++ b/libs/rs/spec.l
@@ -148,6 +148,9 @@
     BEGIN(api_entry2);
     }
 
+<api_entry2>"*" {
+    currType->ptrLevel ++;
+    }
 
 <api_entry2>"}" {
     apiCount++;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index a36ee85..e586869 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -450,10 +450,20 @@
         VolumeStreamState streamState = mStreamStates[streamType];
         if (streamState.setIndex(index, lastAudible) || force) {
             // Post message to set system volume (it in turn will post a message
-            // to persist). Do not change volume if stream is muted.
-            if (streamState.muteCount() == 0) {
+            // to persist).
+            // If stream is muted or we are in silent mode and stream is affected by ringer mode
+            // and the new volume is not 0, just persist the new volume but do not change
+            // current value
+            if (streamState.muteCount() == 0 &&
+                (mRingerMode == AudioManager.RINGER_MODE_NORMAL ||
+                !isStreamAffectedByRingerMode(streamType) ||
+                index == 0)) {
                 sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
                         streamState, 0);
+            } else {
+                // Post a persist volume msg
+                sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamType,
+                        SENDMSG_REPLACE, 0, 1, streamState, PERSIST_DELAY);
             }
         }
     }
@@ -512,7 +522,7 @@
                 if (!isStreamAffectedByRingerMode(streamType)) continue;
                 // Bring back last audible volume
                 setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
-                                   false, false);
+                                   true, false);
             }
         } else {
             for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
@@ -524,7 +534,7 @@
                     // to non affected by ringer mode. Does not arm to do it for streams that
                     // are not affected as well.
                     setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
-                            false, false);
+                            true, false);
                 }
             }
         }
@@ -1269,14 +1279,18 @@
 
             // Post a persist volume msg
             sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType,
-                    SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY);
+                    SENDMSG_REPLACE, 1, 1, streamState, PERSIST_DELAY);
         }
 
-        private void persistVolume(VolumeStreamState streamState) {
-            System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
-                    (streamState.mIndex + 5)/ 10);
-            System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
+        private void persistVolume(VolumeStreamState streamState, boolean current, boolean lastAudible) {
+            if (current) {
+                System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
+                              (streamState.mIndex + 5)/ 10);
+            }
+            if (lastAudible) {
+                System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
                     (streamState.mLastAudibleIndex + 5) / 10);
+            }
         }
 
         private void persistRingerMode() {
@@ -1361,7 +1375,7 @@
                     break;
 
                 case MSG_PERSIST_VOLUME:
-                    persistVolume((VolumeStreamState) msg.obj);
+                    persistVolume((VolumeStreamState) msg.obj, (msg.arg1 != 0), (msg.arg2 != 0));
                     break;
 
                 case MSG_PERSIST_RINGER_MODE:
@@ -1469,7 +1483,7 @@
                         //  and persist with no delay as there might be registered observers of the persisted
                         //  notification volume.
                         sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
-                                SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0);
+                                SENDMSG_REPLACE, 1, 1, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0);
                     }
                 }
             }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index b41a7d9..664f028 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2372,10 +2372,10 @@
         synchronized (mPackages) {
             // Look to see if we already know about this package.
             String oldName = mSettings.mRenamedPackages.get(pkg.packageName);
-            if (oldName != null && oldName.equals(pkg.mOriginalPackage)) {
+            if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
                 // This package has been renamed to its original name.  Let's
                 // use that.
-                ps = mSettings.peekPackageLP(pkg.mOriginalPackage);
+                ps = mSettings.peekPackageLP(oldName);
             }
             // If there was no original package, see one for the real package name.
             if (ps == null) {
@@ -2645,7 +2645,7 @@
 
         if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
             // Only system apps can use these features.
-            pkg.mOriginalPackage = null;
+            pkg.mOriginalPackages = null;
             pkg.mRealPackage = null;
             pkg.mAdoptPermissions = null;
         }
@@ -2727,22 +2727,22 @@
             }
 
             if (false) {
-                if (pkg.mOriginalPackage != null) {
+                if (pkg.mOriginalPackages != null) {
                     Log.w(TAG, "WAITING FOR DEBUGGER");
                     Debug.waitForDebugger();
-                    Log.i(TAG, "Package " + pkg.packageName + " from original package"
-                            + pkg.mOriginalPackage);
+                    Log.i(TAG, "Package " + pkg.packageName + " from original packages"
+                            + pkg.mOriginalPackages);
                 }
             }
             
             // Check if we are renaming from an original package name.
             PackageSetting origPackage = null;
             String realName = null;
-            if (pkg.mOriginalPackage != null) {
+            if (pkg.mOriginalPackages != null) {
                 // This package may need to be renamed to a previously
                 // installed name.  Let's check on that...
                 String renamed = mSettings.mRenamedPackages.get(pkg.mRealPackage);
-                if (pkg.mOriginalPackage.equals(renamed)) {
+                if (pkg.mOriginalPackages.contains(renamed)) {
                     // This package had originally been installed as the
                     // original name, and we have already taken care of
                     // transitioning to the new one.  Just update the new
@@ -2755,25 +2755,32 @@
                         pkg.setPackageName(renamed);
                     }
                     
-                } else if ((origPackage
-                        = mSettings.peekPackageLP(pkg.mOriginalPackage)) != null) {
-                    // We do have the package already installed under its
-                    // original name...  should we use it?
-                    if (!verifyPackageUpdate(origPackage, pkg)) {
-                        // New package is not compatible with original.
-                        origPackage = null;
-                    } else if (origPackage.sharedUser != null) {
-                        // Make sure uid is compatible between packages.
-                        if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
-                            Log.w(TAG, "Unable to migrate data from " + origPackage.name
-                                    + " to " + pkg.packageName + ": old uid "
-                                    + origPackage.sharedUser.name
-                                    + " differs from " + pkg.mSharedUserId);
-                            origPackage = null;
+                } else {
+                    for (int i=pkg.mOriginalPackages.size()-1; i>=0; i--) {
+                        if ((origPackage=mSettings.peekPackageLP(
+                                pkg.mOriginalPackages.get(i))) != null) {
+                            // We do have the package already installed under its
+                            // original name...  should we use it?
+                            if (!verifyPackageUpdate(origPackage, pkg)) {
+                                // New package is not compatible with original.
+                                origPackage = null;
+                                continue;
+                            } else if (origPackage.sharedUser != null) {
+                                // Make sure uid is compatible between packages.
+                                if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
+                                    Log.w(TAG, "Unable to migrate data from " + origPackage.name
+                                            + " to " + pkg.packageName + ": old uid "
+                                            + origPackage.sharedUser.name
+                                            + " differs from " + pkg.mSharedUserId);
+                                    origPackage = null;
+                                    continue;
+                                }
+                            } else {
+                                if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
+                                        + pkg.packageName + " to old name " + origPackage.name);
+                            }
+                            break;
                         }
-                    } else {
-                        if (DEBUG_UPGRADE) Log.v(TAG, "Renaming new package "
-                                + pkg.packageName + " to old name " + origPackage.name);
                     }
                 }
             }
@@ -5479,13 +5486,14 @@
             // Check if installing already existing package
             if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
                 String oldName = mSettings.mRenamedPackages.get(pkgName);
-                if (oldName != null && oldName.equals(pkg.mOriginalPackage)
+                if (pkg.mOriginalPackages != null
+                        && pkg.mOriginalPackages.contains(oldName)
                         && mPackages.containsKey(oldName)) {
                     // This package is derived from an original package,
                     // and this device has been updating from that original
                     // name.  We must continue using the original name, so
                     // rename the new package here.
-                    pkg.setPackageName(pkg.mOriginalPackage);
+                    pkg.setPackageName(oldName);
                     pkgName = pkg.packageName;
                     replace = true;
                 } else if (mPackages.containsKey(pkgName)) {