Merge "Remember to cancel lingering when a network again satsifies a NetworkRequest." into lmp-mr1-dev
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2df35df..2ef046d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2419,7 +2419,7 @@
                         int res = -1;
                         try {
                             res = mount.mkdirs(getPackageName(), dir.getAbsolutePath());
-                        } catch (RemoteException e) {
+                        } catch (Exception ignored) {
                         }
                         if (res != 0) {
                             Log.w(TAG, "Failed to ensure directory: " + dir);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 5fd697a..c0dca0e 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -604,6 +604,7 @@
         public static final byte CMD_CURRENT_TIME = 5;
         public static final byte CMD_OVERFLOW = 6;
         public static final byte CMD_RESET = 7;
+        public static final byte CMD_SHUTDOWN = 8;
 
         public byte cmd = CMD_NULL;
         
@@ -3529,6 +3530,11 @@
                     pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss",
                             rec.currentTime).toString());
                 }
+            } else if (rec.cmd == HistoryItem.CMD_SHUTDOWN) {
+                if (checkin) {
+                    pw.print(":");
+                }
+                pw.println("SHUTDOWN");
             } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
                 if (checkin) {
                     pw.print(":");
@@ -3849,7 +3855,8 @@
                 if (histStart >= 0 && !printed) {
                     if (rec.cmd == HistoryItem.CMD_CURRENT_TIME
                             || rec.cmd == HistoryItem.CMD_RESET
-                            || rec.cmd == HistoryItem.CMD_START) {
+                            || rec.cmd == HistoryItem.CMD_START
+                            || rec.cmd == HistoryItem.CMD_SHUTDOWN) {
                         printed = true;
                         hprinter.printNextItem(pw, rec, baseTime, checkin,
                                 (flags&DUMP_VERBOSE) != 0);
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 9df8ad5..eff44bd 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -24,6 +24,7 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.UserHandle;
+import android.util.Slog;
 import com.android.internal.os.BackgroundThread;
 
 import java.util.HashSet;
@@ -279,8 +280,8 @@
         mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
                 UserHandle.USER_NULL);
         if (mChangeUserId == UserHandle.USER_NULL) {
-            throw new IllegalArgumentException(
-                    "Intent broadcast does not contain user handle: " + intent);
+            Slog.w("PackageMonitor", "Intent broadcast does not contain user handle: " + intent);
+            return;
         }
         onBeginPackageChanges();
         
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8ceee20..20bb95e 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6955,6 +6955,17 @@
         }
     }
 
+    private void recordShutdownLocked(final long elapsedRealtimeMs, final long uptimeMs) {
+        if (mRecordingHistory) {
+            mHistoryCur.currentTime = System.currentTimeMillis();
+            mLastRecordedClockTime = mHistoryCur.currentTime;
+            mLastRecordedClockRealtime = elapsedRealtimeMs;
+            addHistoryBufferLocked(elapsedRealtimeMs, uptimeMs, HistoryItem.CMD_SHUTDOWN,
+                    mHistoryCur);
+            mHistoryCur.currentTime = 0;
+        }
+    }
+
     // This should probably be exposed in the API, though it's not critical
     private static final int BATTERY_PLUGGED_NONE = 0;
 
@@ -7627,6 +7638,7 @@
     }
 
     public void shutdownLocked() {
+        recordShutdownLocked(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
         writeSyncLocked();
         mShuttingDown = true;
     }
diff --git a/core/java/com/android/internal/util/FastPrintWriter.java b/core/java/com/android/internal/util/FastPrintWriter.java
index c70a243..c74fea0 100644
--- a/core/java/com/android/internal/util/FastPrintWriter.java
+++ b/core/java/com/android/internal/util/FastPrintWriter.java
@@ -15,7 +15,7 @@
 import java.nio.charset.CodingErrorAction;
 
 public class FastPrintWriter extends PrintWriter {
-    private static Writer sDummyWriter = new Writer() {
+    private static class DummyWriter extends Writer {
         @Override
         public void close() throws IOException {
             UnsupportedOperationException ex
@@ -100,7 +100,7 @@
      *             if {@code out} is {@code null}.
      */
     public FastPrintWriter(OutputStream out, boolean autoFlush, int bufferLen) {
-        super(sDummyWriter, autoFlush);
+        super(new DummyWriter(), autoFlush);
         if (out == null) {
             throw new NullPointerException("out is null");
         }
@@ -169,7 +169,7 @@
      *             if {@code wr} is {@code null}.
      */
     public FastPrintWriter(Writer wr, boolean autoFlush, int bufferLen) {
-        super(sDummyWriter, autoFlush);
+        super(new DummyWriter(), autoFlush);
         if (wr == null) {
             throw new NullPointerException("wr is null");
         }
@@ -212,7 +212,7 @@
      *             if {@code pr} is {@code null}.
      */
     public FastPrintWriter(Printer pr, int bufferLen) {
-        super(sDummyWriter, true);
+        super(new DummyWriter(), true);
         if (pr == null) {
             throw new NullPointerException("pr is null");
         }
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 533313a..7361858 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -35,6 +35,7 @@
 #include <cutils/properties.h>
 
 #include <string.h>
+#include <inttypes.h>
 
 #include "android_runtime/AndroidRuntime.h"
 #include "android_runtime/android_hardware_camera2_CameraMetadata.h"
@@ -360,15 +361,18 @@
         realCount = count;
     }
 
-    mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, mByteArray, 0,
+    jobject chainingBuf = mEnv->CallObjectMethod(mInBuf, gInputByteBufferClassInfo.mGetMethod, mByteArray, 0,
             realCount);
+    mEnv->DeleteLocalRef(chainingBuf);
 
     if (mEnv->ExceptionCheck()) {
+        ALOGE("%s: Exception while reading from input into byte buffer.", __FUNCTION__);
         return BAD_VALUE;
     }
 
     mEnv->GetByteArrayRegion(mByteArray, 0, realCount, reinterpret_cast<jbyte*>(buf + offset));
     if (mEnv->ExceptionCheck()) {
+        ALOGE("%s: Exception while reading from byte buffer.", __FUNCTION__);
         return BAD_VALUE;
     }
     return realCount;
@@ -469,15 +473,17 @@
 
     for (uint32_t i = 0; i < mHeight; ++i) {
         size_t rowFillAmt = 0;
-        size_t rowSize = mPixStride;
+        size_t rowSize = mRowStride;
 
         while (rowFillAmt < mRowStride) {
             ssize_t bytesRead = mInput->read(rowBytes, rowFillAmt, rowSize);
             if (bytesRead <= 0) {
                 if (bytesRead == NOT_ENOUGH_DATA || bytesRead == 0) {
+                    ALOGE("%s: Early EOF on row %" PRIu32 ", received bytesRead %zd",
+                            __FUNCTION__, i, bytesRead);
                     jniThrowExceptionFmt(mEnv, "java/io/IOException",
-                            "Early EOF encountered, not enough pixel data for image of size %u",
-                            fullSize);
+                            "Early EOF encountered, not enough pixel data for image of size %"
+                            PRIu32, fullSize);
                     bytesRead = NOT_ENOUGH_DATA;
                 } else {
                     if (!mEnv->ExceptionCheck()) {
diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml
index b70e1b4..9147cbf 100644
--- a/core/res/res/values-mcc302-mnc220/config.xml
+++ b/core/res/res/values-mcc302-mnc220/config.xml
@@ -39,7 +39,6 @@
     <string-array translatable="false" name="config_tether_apndata">
         <item>[ApnSettingV3]TELUS ISP,isp.telus.com,,,,,,,,,302,220,,DUN,,,true,0,,,,,,,gid,54</item>
         <item>[ApnSettingV3]Tethered PC Mobile,isp.mb.com,,,,,,,,,302,220,,DUN,,,true,0,,,,,,,gid,50</item>
-        <item>[ApnSettingV3]Koodo,sp.koodo.com,,,,,,,,,302,220,,DUN,,,true,0,,,,,,,gid,4B</item>
     </string-array>
 
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 69b4e71..0d76c25 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3043,34 +3043,34 @@
     <string name="autofill_region_ignored_re">province|region|other<!-- es -->|provincia<!-- pt-BR, pt-PT -->|bairro|suburb</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_company_re">company|business|organization|organisation|department<!-- de-DE -->|firma|firmenname<!-- es -->|empresa<!-- fr-FR -->|societe|société<!-- it-IT -->|ragione.?sociale<!-- ja-JP -->|会社<!-- ru -->|название.?компании<!-- zh-CN -->|单位|公司</string>
+    <string name="autofill_company_re">company|business|organization|organisation|department<!-- de-DE -->|firma|firmenname<!-- es -->|empresa<!-- fr-FR -->|societe|société<!-- it-IT -->|ragione.?sociale<!-- ja-JP -->|会社<!-- ru -->|название.?компании<!-- zh-CN -->|单位|公司</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_address_line_1_re">address.?line|address1|addr1|street<!-- de-DE -->|strasse|straße|hausnummer|housenumber<!-- en-GB -->|house.?name<!-- es -->|direccion|dirección<!-- fr-FR -->|adresse<!-- it-IT -->|indirizzo<!-- ja-JP -->|住所1<!-- pt-BR, pt-PT -->|morada|endereço<!-- ru -->|Адрес<!-- zh-CN -->|地址</string>
+    <string name="autofill_address_line_1_re">address.?line|address1|addr1|street<!-- de-DE -->|strasse|straße|hausnummer|housenumber<!-- en-GB -->|house.?name<!-- es -->|direccion|dirección<!-- fr-FR -->|adresse<!-- it-IT -->|indirizzo<!-- ja-JP -->|住所1<!-- pt-BR, pt-PT -->|morada|endereço<!-- ru -->|Адрес<!-- zh-CN -->|地址</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_address_line_1_label_re">address<!-- fr-FR -->|adresse<!-- it-IT -->|indirizzo<!-- ja-JP -->|住所<!-- zh-CN -->|地址</string>
+    <string name="autofill_address_line_1_label_re">address<!-- fr-FR -->|adresse<!-- it-IT -->|indirizzo<!-- ja-JP -->|住所<!-- zh-CN -->|地址</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_address_line_2_re">address.?line2|address2|addr2|street|suite|unit<!-- de-DE -->|adresszusatz|ergänzende.?angaben<!-- es -->|direccion2|colonia|adicional<!-- fr-FR -->|addresssuppl|complementnom|appartement<!-- it-IT -->|indirizzo2<!-- ja-JP -->|住所2</string>
+    <string name="autofill_address_line_2_re">address.?line2|address2|addr2|street|suite|unit<!-- de-DE -->|adresszusatz|ergänzende.?angaben<!-- es -->|direccion2|colonia|adicional<!-- fr-FR -->|addresssuppl|complementnom|appartement<!-- it-IT -->|indirizzo2<!-- ja-JP -->|住所2</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_address_line_3_re">address.?line3|address3|addr3|street|line3<!-- es -->|municipio<!-- fr-FR -->|batiment|residence<!-- it-IT -->|indirizzo3</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_country_re">country|location<!-- ja-JP -->|国<!-- zh-CN -->|国家</string>
+    <string name="autofill_country_re">country|location<!-- ja-JP -->|国<!-- zh-CN -->|国家</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_zip_code_re">zip|postal|post code|pcode|^1z$<!-- de-DE -->|postleitzahl<!-- es -->|cp<!-- fr-FR -->|cdp<!-- it-IT -->|cap<!-- ja-JP -->|郵便番号<!-- pt-BR, pt-PT -->|codigo|codpos|cep<!-- ru -->|Почтовый.?Индекс<!--zh-CN -->|邮政编码|邮编<!-- zh-TW -->|郵遞區號</string>
+    <string name="autofill_zip_code_re">zip|postal|post code|pcode|^1z$<!-- de-DE -->|postleitzahl<!-- es -->|cp<!-- fr-FR -->|cdp<!-- it-IT -->|cap<!-- ja-JP -->|郵便番号<!-- pt-BR, pt-PT -->|codigo|codpos|cep<!-- ru -->|Почтовый.?Индекс<!--zh-CN -->|邮政编码|邮编<!-- zh-TW -->|郵遞區號</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_zip_4_re">zip|^-$|post2<!-- pt-BR, pt-PT -->|codpos2</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_city_re">city|town<!-- de-DE -->|ort|stadt<!-- en-AU -->|suburb<!-- es -->|ciudad|provincia|localidad|poblacion<!-- fr-FR -->|ville|commune<!-- it-IT -->|localita<!-- ja-JP -->|市区町村<!-- pt-BR, pt-PT -->|cidade<!-- ru -->|Город<!-- zh-CN -->|市<!-- zh-TW -->|分區</string>
+    <string name="autofill_city_re">city|town<!-- de-DE -->|ort|stadt<!-- en-AU -->|suburb<!-- es -->|ciudad|provincia|localidad|poblacion<!-- fr-FR -->|ville|commune<!-- it-IT -->|localita<!-- ja-JP -->|市区町村<!-- pt-BR, pt-PT -->|cidade<!-- ru -->|Город<!-- zh-CN -->|市<!-- zh-TW -->|分區</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_state_re">state|county|region|province<!-- de-DE -->|land<!-- en-UK -->|county|principality<!-- ja-JP -->|都道府県<!-- pt-BR, pt-PT -->|estado|provincia<!-- ru -->|область<!-- zh-CN -->|省<!-- zh-TW -->|地區</string>
+    <string name="autofill_state_re">state|county|region|province<!-- de-DE -->|land<!-- en-UK -->|county|principality<!-- ja-JP -->|都道府県<!-- pt-BR, pt-PT -->|estado|provincia<!-- ru -->|область<!-- zh-CN -->|省<!-- zh-TW -->|地區</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_address_type_same_as_re">same as</string>
@@ -3085,20 +3085,20 @@
     <string name="autofill_shipping_designator_re">ship</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_email_re">e.?mail<!-- ja-JP -->|メールアドレス<!-- ru -->|Электронной.?Почты<!-- zh-CN -->|邮件|邮箱<!-- zh-TW -->|電郵地址</string>
+    <string name="autofill_email_re">e.?mail<!-- ja-JP -->|メールアドレス<!-- ru -->|Электронной.?Почты<!-- zh-CN -->|邮件|邮箱<!-- zh-TW -->|電郵地址</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_username_re">user.?name|user.?id<!-- de-DE -->|vollständiger.?name<!-- zh-CN -->|用户名</string>
+    <string name="autofill_username_re">user.?name|user.?id<!-- de-DE -->|vollständiger.?name<!-- zh-CN -->|用户名</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_name_re">^name|full.?name|your.?name|customer.?name|firstandlastname<!-- es -->|nombre.*y.*apellidos<!-- fr-FR -->|^nom<!-- ja-JP -->|お名前|氏名<!-- pt-BR, pt-PT -->|^nome<!-- zh-CN -->|姓名</string>
+    <string name="autofill_name_re">^name|full.?name|your.?name|customer.?name|firstandlastname<!-- es -->|nombre.*y.*apellidos<!-- fr-FR -->|^nom<!-- ja-JP -->|お名前|氏名<!-- pt-BR, pt-PT -->|^nome<!-- zh-CN -->|姓名</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_name_specific_re">^name<!-- fr-FR -->|^nom<!-- pt-BR, pt-PT -->|^nome</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
 
-    <string name="autofill_first_name_re">irst.*name|initials|fname|first$<!-- de-DE -->|vorname<!-- es -->|nombre<!-- fr-FR -->|forename|prénom|prenom<!-- ja-JP -->|名<!-- pt-BR, pt-PT -->|nome<!-- ru -->|Имя</string>
+    <string name="autofill_first_name_re">irst.*name|initials|fname|first$<!-- de-DE -->|vorname<!-- es -->|nombre<!-- fr-FR -->|forename|prénom|prenom<!-- ja-JP -->|名<!-- pt-BR, pt-PT -->|nome<!-- ru -->|Имя</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_middle_initial_re">middle.*initial|m\\.i\\.|mi$</string>
@@ -3107,10 +3107,10 @@
     <string name="autofill_middle_name_re">middle.*name|mname|middle$<!-- es -->|apellido.?materno|lastlastname</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_last_name_re">last.*name|lname|surname|last$<!-- de-DE -->|nachname<!-- es -->|apellidos<!-- fr-FR -->|famille|^nom<!-- it-IT -->|cognome<!-- ja-JP -->|姓<!-- pt-BR, pt-PT -->|morada|apelidos|surename|sobrenome<!-- ru -->|Фамилия</string>
+    <string name="autofill_last_name_re">last.*name|lname|surname|last$<!-- de-DE -->|nachname<!-- es -->|apellidos<!-- fr-FR -->|famille|^nom<!-- it-IT -->|cognome<!-- ja-JP -->|姓<!-- pt-BR, pt-PT -->|morada|apelidos|surename|sobrenome<!-- ru -->|Фамилия</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_phone_re">phone<!-- de-DE -->|telefonnummer<!-- es -->|telefono|teléfono<!-- fr-FR -->|telfixe<!-- ja-JP -->|電話<!-- pt-BR, pt-PT -->|telefone|telemovel<!-- ru -->|телефон<!-- zh-CN -->|电话</string>
+    <string name="autofill_phone_re">phone<!-- de-DE -->|telefonnummer<!-- es -->|telefono|teléfono<!-- fr-FR -->|telfixe<!-- ja-JP -->|電話<!-- pt-BR, pt-PT -->|telefone|telemovel<!-- ru -->|телефон<!-- zh-CN -->|电话</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_area_code_re">area.*code|acode|area</string>
@@ -3125,7 +3125,7 @@
     <string name="autofill_phone_extension_re">ext<!-- pt-BR, pt-PT -->|ramal</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_name_on_card_re">card.?holder|name.?on.?card|ccname|owner<!-- de-DE -->|karteninhaber<!-- es -->|nombre.*tarjeta<!-- fr-FR -->|nom.*carte<!-- it-IT -->|nome.*cart<!-- ja-JP -->|名前<!-- ru -->|Имя.*карты<!-- zh-CN -->|信用卡开户名|开户名|持卡人姓名<!-- zh-TW -->|持卡人姓名</string>
+    <string name="autofill_name_on_card_re">card.?holder|name.?on.?card|ccname|owner<!-- de-DE -->|karteninhaber<!-- es -->|nombre.*tarjeta<!-- fr-FR -->|nom.*carte<!-- it-IT -->|nome.*cart<!-- ja-JP -->|名前<!-- ru -->|Имя.*карты<!-- zh-CN -->|信用卡开户名|开户名|持卡人姓名<!-- zh-TW -->|持卡人姓名</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_name_on_card_contextual_re">name</string>
@@ -3134,19 +3134,19 @@
     <string name="autofill_card_cvc_re">verification|card identification|cvn|security code|cvv code|cvc</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_card_number_re">number|card.?#|card.?no|ccnum<!-- de-DE -->|nummer<!-- es -->|credito|numero|número<!-- fr-FR -->|numéro<!-- ja-JP -->|カード番号<!-- ru -->|Номер.*карты<!-- zh-CN -->|信用卡号|信用卡号码<!-- zh-TW -->|信用卡卡號</string>
+    <string name="autofill_card_number_re">number|card.?#|card.?no|ccnum<!-- de-DE -->|nummer<!-- es -->|credito|numero|número<!-- fr-FR -->|numéro<!-- ja-JP -->|カード番号<!-- ru -->|Номер.*карты<!-- zh-CN -->|信用卡号|信用卡号码<!-- zh-TW -->|信用卡卡號</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_expiration_month_re">expir|exp.*month|exp.*date|ccmonth<!-- de-DE -->|gueltig|gültig|monat<!-- es -->|fecha<!-- fr-FR -->|date.*exp<!-- it-IT -->|scadenza<!-- ja-JP -->|有効期限<!-- pt-BR, pt-PT -->|validade<!-- ru -->|Срок действия карты<!-- zh-CN -->|月</string>
+    <string name="autofill_expiration_month_re">expir|exp.*month|exp.*date|ccmonth<!-- de-DE -->|gueltig|gültig|monat<!-- es -->|fecha<!-- fr-FR -->|date.*exp<!-- it-IT -->|scadenza<!-- ja-JP -->|有効期限<!-- pt-BR, pt-PT -->|validade<!-- ru -->|Срок действия карты<!-- zh-CN -->|月</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_expiration_date_re">exp|^/|year<!-- de-DE -->|ablaufdatum|gueltig|gültig|yahr<!-- es -->|fecha<!-- it-IT -->|scadenza<!-- ja-JP -->|有効期限<!-- pt-BR, pt-PT -->|validade<!-- ru -->|Срок действия карты<!-- zh-CN -->|年|有效期</string>
+    <string name="autofill_expiration_date_re">exp|^/|year<!-- de-DE -->|ablaufdatum|gueltig|gültig|yahr<!-- es -->|fecha<!-- it-IT -->|scadenza<!-- ja-JP -->|有効期限<!-- pt-BR, pt-PT -->|validade<!-- ru -->|Срок действия карты<!-- zh-CN -->|年|有效期</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_card_ignored_re">^card</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
-    <string name="autofill_fax_re">fax<!-- fr-FR -->|télécopie|telecopie<!-- ja-JP -->|ファックス<!-- ru -->|факс<!-- zh-CN -->|传真<!-- zh-TW -->|傳真</string>
+    <string name="autofill_fax_re">fax<!-- fr-FR -->|télécopie|telecopie<!-- ja-JP -->|ファックス<!-- ru -->|факс<!-- zh-CN -->|传真<!-- zh-TW -->|傳真</string>
 
     <!-- Do not translate. Regex used by AutoFill. -->
     <string name="autofill_country_code_re">country.*code|ccode|_cc</string>
@@ -3338,7 +3338,7 @@
          It is also used by the home screen's search "widget". It should be short -->
     <string name="search_go">Search</string>
     <!-- Default hint text for the system-wide search UI's text field. [CHAR LIMIT=30] -->
-    <string name="search_hint">Search…</string>
+    <string name="search_hint">Search…</string>
     <!-- SearchView accessibility description for search button [CHAR LIMIT=NONE] -->
     <string name="searchview_description_search">Search</string>
     <!-- SearchView accessibility description for search text field [CHAR LIMIT=NONE] -->
@@ -4811,9 +4811,9 @@
 
     <!-- Printing -->
 
-    <!-- ISO (European standard) A0 media (paper) size: 33.11" × 46.81" -->
+    <!-- ISO (European standard) A0 media (paper) size: 33.11" × 46.81" -->
     <string name="mediasize_iso_a0">ISO A0</string>
-    <!-- ISO (European standard) A1 media (paper) size: 23.39" × 33.11" -->
+    <!-- ISO (European standard) A1 media (paper) size: 23.39" × 33.11" -->
     <string name="mediasize_iso_a1">ISO A1</string>
     <!-- ISO (European standard) A2 media (paper) size: 16.54" x 23.39" -->
     <string name="mediasize_iso_a2">ISO A2</string>
@@ -4880,17 +4880,17 @@
     <!-- ISO (European standard) C10 media (paper) size: 1.10" x 1.57" -->
     <string name="mediasize_iso_c10">ISO C10</string>
 
-    <!-- North America Letter media (paper) size: 8.5" × 11" (279mm x 216mm) -->
+    <!-- North America Letter media (paper) size: 8.5" × 11" (279mm x 216mm) -->
     <string name="mediasize_na_letter">Letter</string>
-    <!-- North America Government Letter media (paper) size: 8.0" × 10.5" (203mm x 267mm) -->
+    <!-- North America Government Letter media (paper) size: 8.0" × 10.5" (203mm x 267mm) -->
     <string name="mediasize_na_gvrnmt_letter">Government Letter</string>
-    <!-- North America Legal media (paper) size: 8.5" × 14" (216mm x 356mm) -->
+    <!-- North America Legal media (paper) size: 8.5" × 14" (216mm x 356mm) -->
     <string name="mediasize_na_legal">Legal</string>
-    <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" (203mm × 127mm) -->
+    <!-- North America Junior Legal media (paper) size: 8.0" × 5.0" (203mm × 127mm) -->
     <string name="mediasize_na_junior_legal">Junior Legal</string>
-    <!-- North America Ledger media (paper) size: 17" × 11" (432mm × 279mm) -->
+    <!-- North America Ledger media (paper) size: 17" × 11" (432mm × 279mm) -->
     <string name="mediasize_na_ledger">Ledger</string>
-    <!-- North America Tabloid media (paper) size: 11" × 17" (279mm × 432mm) -->
+    <!-- North America Tabloid media (paper) size: 11" × 17" (279mm × 432mm) -->
     <string name="mediasize_na_tabloid">Tabloid</string>
 
     <!-- North America Index Card 3x5 media (paper) size: 3" x 5" (76mm x 127mm) -->
@@ -5113,7 +5113,7 @@
     <string name="lock_to_app_unlock_password">Ask for password before unpinning</string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
-    <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
+    <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
 
     <!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active -->
     <string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string>
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 8faa75c..4356a3e 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -106,6 +106,10 @@
     public static final String MIMETYPE_AUDIO_FLAC = "audio/flac";
     public static final String MIMETYPE_AUDIO_MSGSM = "audio/gsm";
     public static final String MIMETYPE_AUDIO_AC3 = "audio/ac3";
+    /**
+     * @hide
+     */
+    public static final String MIMETYPE_AUDIO_EAC3 = "audio/eac3";
 
     /**
      * MIME type for WebVTT subtitle data.
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index 3b1b1d7..e9c80a0 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -102,7 +102,7 @@
     ALOGV("JNIMediaRecorderListener::notify");
 
     JNIEnv *env = AndroidRuntime::getJNIEnv();
-    env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0);
+    env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, NULL);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 8463d94..b59a541 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -329,7 +329,7 @@
             fields.midPostNativeEvent,
             callbackInfo->visualizer_ref,
             NATIVE_EVENT_SERVER_DIED,
-            0, 0, 0);
+            0, 0, NULL);
     }
 }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 78af785..6b7ac8c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -25,6 +25,8 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.net.wifi.WifiManager;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -33,9 +35,12 @@
 import android.provider.Settings;
 import android.util.Log;
 
+import libcore.io.IoUtils;
+
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
 import java.io.CharArrayReader;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -48,11 +53,15 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.util.ArrayList;
+import java.util.BitSet;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.zip.CRC32;
 
 /**
@@ -138,6 +147,7 @@
         String ssid = "";  // equals() and hashCode() need these to be non-null
         String key_mgmt = "";
         boolean certUsed = false;
+        boolean hasWepKey = false;
         final ArrayList<String> rawLines = new ArrayList<String>();
 
         public static Network readFromStream(BufferedReader in) {
@@ -164,9 +174,9 @@
             rawLines.add(line);
 
             // remember the ssid and key_mgmt lines for duplicate culling
-            if (line.startsWith("ssid")) {
+            if (line.startsWith("ssid=")) {
                 ssid = line;
-            } else if (line.startsWith("key_mgmt")) {
+            } else if (line.startsWith("key_mgmt=")) {
                 key_mgmt = line;
             } else if (line.startsWith("client_cert=")) {
                 certUsed = true;
@@ -174,6 +184,8 @@
                 certUsed = true;
             } else if (line.startsWith("ca_path=")) {
                 certUsed = true;
+            } else if (line.startsWith("wep_")) {
+                hasWepKey = true;
             }
         }
 
@@ -193,6 +205,56 @@
             Log.v(TAG, "}");
         }
 
+        // Calculate the equivalent of WifiConfiguration's configKey()
+        public String configKey() {
+            if (ssid == null) {
+                // No SSID => malformed network definition
+                return null;
+            }
+
+            final String bareSsid = ssid.substring(ssid.indexOf('=') + 1);
+
+            final BitSet types = new BitSet();
+            if (key_mgmt == null) {
+                // no key_mgmt specified; this is defined as equivalent to "WPA-PSK WPA-EAP"
+                types.set(KeyMgmt.WPA_PSK);
+                types.set(KeyMgmt.WPA_EAP);
+            } else {
+                // Need to parse the key_mgmt line
+                final String bareKeyMgmt = key_mgmt.substring(key_mgmt.indexOf('=') + 1);
+                String[] typeStrings = bareKeyMgmt.split("\\s+");
+
+                // Parse out all the key management regimes permitted for this network.  The literal
+                // strings here are the standard values permitted in wpa_supplicant.conf.
+                for (int i = 0; i < typeStrings.length; i++) {
+                    final String ktype = typeStrings[i];
+                    if (ktype.equals("WPA-PSK")) {
+                        Log.v(TAG, "  + setting WPA_PSK bit");
+                        types.set(KeyMgmt.WPA_PSK);
+                    } else if (ktype.equals("WPA-EAP")) {
+                        Log.v(TAG, "  + setting WPA_EAP bit");
+                        types.set(KeyMgmt.WPA_EAP);
+                    } else if (ktype.equals("IEEE8021X")) {
+                        Log.v(TAG, "  + setting IEEE8021X bit");
+                        types.set(KeyMgmt.IEEE8021X);
+                    }
+                }
+            }
+
+            // Now build the canonical config key paralleling the WifiConfiguration semantics
+            final String key;
+            if (types.get(KeyMgmt.WPA_PSK)) {
+                key = bareSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK];
+            } else if (types.get(KeyMgmt.WPA_EAP) || types.get(KeyMgmt.IEEE8021X)) {
+                key = bareSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP];
+            } else if (hasWepKey) {
+                key = bareSsid + "WEP";  // hardcoded this way in WifiConfiguration
+            } else {
+                key = bareSsid + KeyMgmt.strings[KeyMgmt.NONE];
+            }
+            return key;
+        }
+
         // Same approach as Pair.equals() and Pair.hashCode()
         @Override
         public boolean equals(Object o) {
@@ -216,6 +278,17 @@
         }
     }
 
+    boolean networkInWhitelist(Network net, List<WifiConfiguration> whitelist) {
+        final String netConfigKey = net.configKey();
+        final int N = whitelist.size();
+        for (int i = 0; i < N; i++) {
+            if (Objects.equals(netConfigKey, whitelist.get(i).configKey(true))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     // Ingest multiple wifi config file fragments, looking for network={} blocks
     // and eliminating duplicates
     class WifiNetworkSettings {
@@ -223,7 +296,7 @@
         final HashSet<Network> mKnownNetworks = new HashSet<Network>();
         final ArrayList<Network> mNetworks = new ArrayList<Network>(8);
 
-        public void readNetworks(BufferedReader in) {
+        public void readNetworks(BufferedReader in, List<WifiConfiguration> whitelist) {
             try {
                 String line;
                 while (in.ready()) {
@@ -232,6 +305,15 @@
                         // Parse out 'network=' decls so we can ignore duplicates
                         if (line.startsWith("network")) {
                             Network net = Network.readFromStream(in);
+                            if (whitelist != null) {
+                                if (!networkInWhitelist(net, whitelist)) {
+                                    if (DEBUG_BACKUP) {
+                                        Log.v(TAG, "Network not in whitelist, skipping: "
+                                                + net.ssid + " / " + net.key_mgmt);
+                                    }
+                                    continue;
+                                }
+                            }
                             if (! mKnownNetworks.contains(net)) {
                                 if (DEBUG_BACKUP) {
                                     Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
@@ -844,24 +926,23 @@
         BufferedReader br = null;
         try {
             File file = new File(filename);
-            if (file.exists()) {
-                br = new BufferedReader(new FileReader(file));
-                StringBuffer relevantLines = new StringBuffer();
-                boolean started = false;
-                String line;
-                while ((line = br.readLine()) != null) {
-                    if (!started && line.startsWith("network")) {
-                        started = true;
-                    }
-                    if (started) {
-                        relevantLines.append(line).append("\n");
-                    }
-                }
-                if (relevantLines.length() > 0) {
-                    return relevantLines.toString().getBytes();
-                } else {
-                    return EMPTY_DATA;
-                }
+            if (!file.exists()) {
+                return EMPTY_DATA;
+            }
+
+            WifiManager wifi = (WifiManager) getSystemService(WIFI_SERVICE);
+            List<WifiConfiguration> configs = wifi.getConfiguredNetworks();
+
+            WifiNetworkSettings fromFile = new WifiNetworkSettings();
+            br = new BufferedReader(new FileReader(file));
+            fromFile.readNetworks(br, configs);
+
+            // Write the parsed networks into a packed byte array
+            if (fromFile.mKnownNetworks.size() > 0) {
+                ByteArrayOutputStream bos = new ByteArrayOutputStream();
+                OutputStreamWriter out = new OutputStreamWriter(bos);
+                fromFile.write(out);
+                return bos.toByteArray();
             } else {
                 return EMPTY_DATA;
             }
@@ -869,12 +950,7 @@
             Log.w(TAG, "Couldn't backup " + filename);
             return EMPTY_DATA;
         } finally {
-            if (br != null) {
-                try {
-                    br.close();
-                } catch (IOException e) {
-                }
-            }
+            IoUtils.closeQuietly(br);
         }
     }
 
@@ -886,7 +962,7 @@
             if (supplicantFile.exists()) {
                 // Retain the existing APs; we'll append the restored ones to them
                 BufferedReader in = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT));
-                supplicantImage.readNetworks(in);
+                supplicantImage.readNetworks(in, null);
                 in.close();
 
                 supplicantFile.delete();
@@ -897,7 +973,7 @@
                 char[] restoredAsBytes = new char[size];
                 for (int i = 0; i < size; i++) restoredAsBytes[i] = (char) bytes[i];
                 BufferedReader in = new BufferedReader(new CharArrayReader(restoredAsBytes));
-                supplicantImage.readNetworks(in);
+                supplicantImage.readNetworks(in, null);
 
                 if (DEBUG_BACKUP) {
                     Log.v(TAG, "Final AP list:");
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 9d4cd99a..e5ace1b 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -103,9 +103,19 @@
     @Override
     public void onStart() {
         enforceChecksumValidity();
+        formatIfOemUnlockEnabled();
         publishBinderService(Context.PERSISTENT_DATA_BLOCK_SERVICE, mService);
     }
 
+    private void formatIfOemUnlockEnabled() {
+        if (doGetOemUnlockEnabled()) {
+            synchronized (mLock) {
+                formatPartitionLocked();
+                doSetOemUnlockEnabledLocked(true);
+            }
+        }
+    }
+
     private void enforceOemUnlockPermission() {
         mContext.enforceCallingOrSelfPermission(
                 Manifest.permission.OEM_UNLOCK_STATE,
@@ -285,6 +295,28 @@
         }
     }
 
+    private boolean doGetOemUnlockEnabled() {
+        DataInputStream inputStream;
+        try {
+            inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
+        } catch (FileNotFoundException e) {
+            Slog.e(TAG, "partition not available");
+            return false;
+        }
+
+        try {
+            synchronized (mLock) {
+                inputStream.skip(getBlockDeviceSize() - 1);
+                return inputStream.readByte() != 0;
+            }
+        } catch (IOException e) {
+            Slog.e(TAG, "unable to access persistent partition", e);
+            return false;
+        } finally {
+            IoUtils.closeQuietly(inputStream);
+        }
+    }
+
     private native long nativeGetBlockDeviceSize(String path);
     private native int nativeWipe(String path);
 
@@ -410,25 +442,7 @@
         @Override
         public boolean getOemUnlockEnabled() {
             enforceOemUnlockPermission();
-            DataInputStream inputStream;
-            try {
-                inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
-            } catch (FileNotFoundException e) {
-                Slog.e(TAG, "partition not available");
-                return false;
-            }
-
-            try {
-                synchronized (mLock) {
-                    inputStream.skip(getBlockDeviceSize() - 1);
-                    return inputStream.readByte() != 0;
-                }
-            } catch (IOException e) {
-                Slog.e(TAG, "unable to access persistent partition", e);
-                return false;
-            } finally {
-                IoUtils.closeQuietly(inputStream);
-            }
+            return doGetOemUnlockEnabled();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index eb89f21..6ad128c 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -205,8 +205,8 @@
             }
 
             if (!parser.getName().equals("permissions") && !parser.getName().equals("config")) {
-                throw new XmlPullParserException("Unexpected start tag: found " + parser.getName() +
-                        ", expected 'permissions' or 'config'");
+                throw new XmlPullParserException("Unexpected start tag in " + permFile
+                        + ": found " + parser.getName() + ", expected 'permissions' or 'config'");
             }
 
             while (true) {
@@ -222,7 +222,7 @@
                         int gid = android.os.Process.getGidForName(gidStr);
                         mGlobalGids = appendInt(mGlobalGids, gid);
                     } else {
-                        Slog.w(TAG, "<group> without gid at "
+                        Slog.w(TAG, "<group> without gid in " + permFile + " at "
                                 + parser.getPositionDescription());
                     }
 
@@ -231,7 +231,7 @@
                 } else if ("permission".equals(name) && !onlyFeatures) {
                     String perm = parser.getAttributeValue(null, "name");
                     if (perm == null) {
-                        Slog.w(TAG, "<permission> without name at "
+                        Slog.w(TAG, "<permission> without name in " + permFile + " at "
                                 + parser.getPositionDescription());
                         XmlUtils.skipCurrentTag(parser);
                         continue;
@@ -242,14 +242,14 @@
                 } else if ("assign-permission".equals(name) && !onlyFeatures) {
                     String perm = parser.getAttributeValue(null, "name");
                     if (perm == null) {
-                        Slog.w(TAG, "<assign-permission> without name at "
+                        Slog.w(TAG, "<assign-permission> without name in " + permFile + " at "
                                 + parser.getPositionDescription());
                         XmlUtils.skipCurrentTag(parser);
                         continue;
                     }
                     String uidStr = parser.getAttributeValue(null, "uid");
                     if (uidStr == null) {
-                        Slog.w(TAG, "<assign-permission> without uid at "
+                        Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at "
                                 + parser.getPositionDescription());
                         XmlUtils.skipCurrentTag(parser);
                         continue;
@@ -257,7 +257,7 @@
                     int uid = Process.getUidForName(uidStr);
                     if (uid < 0) {
                         Slog.w(TAG, "<assign-permission> with unknown uid \""
-                                + uidStr + "\" at "
+                                + uidStr + "  in " + permFile + " at "
                                 + parser.getPositionDescription());
                         XmlUtils.skipCurrentTag(parser);
                         continue;
@@ -275,10 +275,10 @@
                     String lname = parser.getAttributeValue(null, "name");
                     String lfile = parser.getAttributeValue(null, "file");
                     if (lname == null) {
-                        Slog.w(TAG, "<library> without name at "
+                        Slog.w(TAG, "<library> without name in " + permFile + " at "
                                 + parser.getPositionDescription());
                     } else if (lfile == null) {
-                        Slog.w(TAG, "<library> without file at "
+                        Slog.w(TAG, "<library> without file in " + permFile + " at "
                                 + parser.getPositionDescription());
                     } else {
                         //Log.i(TAG, "Got library " + lname + " in " + lfile);
@@ -297,7 +297,7 @@
                         allowed = !"true".equals(notLowRam);
                     }
                     if (fname == null) {
-                        Slog.w(TAG, "<feature> without name at "
+                        Slog.w(TAG, "<feature> without name in " + permFile + " at "
                                 + parser.getPositionDescription());
                     } else if (allowed) {
                         //Log.i(TAG, "Got feature " + fname);
@@ -311,7 +311,7 @@
                 } else if ("unavailable-feature".equals(name)) {
                     String fname = parser.getAttributeValue(null, "name");
                     if (fname == null) {
-                        Slog.w(TAG, "<unavailable-feature> without name at "
+                        Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at "
                                 + parser.getPositionDescription());
                     } else {
                         mUnavailableFeatures.add(fname);
@@ -322,7 +322,7 @@
                 } else if ("allow-in-power-save".equals(name) && !onlyFeatures) {
                     String pkgname = parser.getAttributeValue(null, "package");
                     if (pkgname == null) {
-                        Slog.w(TAG, "<allow-in-power-save> without package at "
+                        Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at "
                                 + parser.getPositionDescription());
                     } else {
                         mAllowInPowerSave.add(pkgname);
@@ -333,7 +333,7 @@
                 } else if ("fixed-ime-app".equals(name) && !onlyFeatures) {
                     String pkgname = parser.getAttributeValue(null, "package");
                     if (pkgname == null) {
-                        Slog.w(TAG, "<fixed-ime-app> without package at "
+                        Slog.w(TAG, "<fixed-ime-app> without package in " + permFile + " at "
                                 + parser.getPositionDescription());
                     } else {
                         mFixedImeApps.add(pkgname);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index f02a815..d199c3f 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -751,6 +751,9 @@
                 }
             }
 
+            mAm.startAssociationLocked(callerApp.uid, callerApp.processName,
+                    s.appInfo.uid, s.name, s.processName);
+
             AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
             ConnectionRecord c = new ConnectionRecord(b, activity,
                     connection, flags, clientLabel, clientIntent);
@@ -1445,10 +1448,10 @@
 
         boolean created = false;
         try {
-            String nameTerm;
-            int lastPeriod = r.shortName.lastIndexOf('.');
-            nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
             if (LOG_SERVICE_START_STOP) {
+                String nameTerm;
+                int lastPeriod = r.shortName.lastIndexOf('.');
+                nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
                 EventLogTags.writeAmCreateService(
                         r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
             }
@@ -1746,6 +1749,8 @@
             }
         }
 
+        mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name);
+
         if (b.connections.size() == 0) {
             b.intent.apps.remove(b.client);
         }
@@ -2367,7 +2372,8 @@
             if (proc.executingServices.size() == 0 || proc.thread == null) {
                 return;
             }
-            long maxTime = SystemClock.uptimeMillis() -
+            final long now = SystemClock.uptimeMillis();
+            final long maxTime =  now -
                     (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
             ServiceRecord timeout = null;
             long nextTime = 0;
@@ -2383,7 +2389,21 @@
             }
             if (timeout != null && mAm.mLruProcesses.contains(proc)) {
                 Slog.w(TAG, "Timeout executing service: " + timeout);
-                anrMessage = "Executing service " + timeout.shortName;
+                StringBuilder sb = new StringBuilder();
+                sb.append("sxecuting service ");
+                sb.append(timeout.shortName);
+                sb.append(" (execStart=");
+                TimeUtils.formatDuration(now-timeout.executingStart, sb);
+                sb.append(", nesting=");
+                sb.append(timeout.executeNesting);
+                sb.append(", fg=");
+                sb.append(proc.execServicesFg);
+                sb.append(", create=");
+                TimeUtils.formatDuration(now-timeout.createTime, sb);
+                sb.append(", proc=");
+                sb.append(timeout.app != null ? timeout.app.toShortString() : "null");
+                sb.append(")");
+                anrMessage = sb.toString();
             } else {
                 Message msg = mAm.mHandler.obtainMessage(
                         ActivityManagerService.SERVICE_TIMEOUT_MSG);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ed16d2e..4b7fb2b 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -749,6 +749,38 @@
 
     final ActiveServices mServices;
 
+    final static class Association {
+        final int mSourceUid;
+        final String mSourceProcess;
+        final int mTargetUid;
+        final ComponentName mTargetComponent;
+        final String mTargetProcess;
+
+        int mCount;
+        long mTime;
+
+        int mNesting;
+        long mStartTime;
+
+        Association(int sourceUid, String sourceProcess, int targetUid,
+                ComponentName targetComponent, String targetProcess) {
+            mSourceUid = sourceUid;
+            mSourceProcess = sourceProcess;
+            mTargetUid = targetUid;
+            mTargetComponent = targetComponent;
+            mTargetProcess = targetProcess;
+        }
+    }
+
+    /**
+     * When service association tracking is enabled, this is all of the associations we
+     * have seen.  Mapping is target uid -> target component -> source uid -> source process name
+     * -> association data.
+     */
+    final SparseArray<ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>>>
+            mAssociations = new SparseArray<>();
+    boolean mTrackingAssociations;
+
     /**
      * Backup/restore process management
      */
@@ -2071,6 +2103,8 @@
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
             ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
 
+        mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));
+
         mConfiguration.setToDefaults();
         mConfiguration.setLocale(Locale.getDefault());
 
@@ -2964,6 +2998,10 @@
                 instructionSet = VMRuntime.getInstructionSet(app.info.primaryCpuAbi);
             }
 
+            app.gids = gids;
+            app.requiredAbi = requiredAbi;
+            app.instructionSet = instructionSet;
+
             // Start the process.  It will either succeed and return a result containing
             // the PID of the new process, or else throw a RuntimeException.
             boolean isActivityProcess = (entryPoint == null);
@@ -2994,7 +3032,11 @@
             StringBuilder buf = mStringBuilder;
             buf.setLength(0);
             buf.append("Start proc ");
+            buf.append(startResult.pid);
+            buf.append(':');
             buf.append(app.processName);
+            buf.append('/');
+            UserHandle.formatUid(buf, uid);
             if (!isActivityProcess) {
                 buf.append(" [");
                 buf.append(entryPoint);
@@ -3006,23 +3048,6 @@
                 buf.append(" ");
                 buf.append(hostingNameStr);
             }
-            buf.append(": pid=");
-            buf.append(startResult.pid);
-            buf.append(" uid=");
-            buf.append(uid);
-            buf.append(" gids={");
-            if (gids != null) {
-                for (int gi=0; gi<gids.length; gi++) {
-                    if (gi != 0) buf.append(", ");
-                    buf.append(gids[gi]);
-
-                }
-            }
-            buf.append("}");
-            if (requiredAbi != null) {
-                buf.append(" abi=");
-                buf.append(requiredAbi);
-            }
             Slog.i(TAG, buf.toString());
             app.setPid(startResult.pid);
             app.usingWrapper = startResult.usingWrapper;
@@ -5293,7 +5318,6 @@
             int callingPid = Binder.getCallingPid();
             if (callingPid == Process.myPid()) {
                 //  Yeah, um, no.
-                Slog.w(TAG, "Can't addPackageDependency on system process");
                 return;
             }
             ProcessRecord proc;
@@ -9082,6 +9106,7 @@
             }
             cpr.connections.add(conn);
             r.conProviders.add(conn);
+            startAssociationLocked(r.uid, r.processName, cpr.uid, cpr.name, cpr.info.processName);
             return conn;
         }
         cpr.addExternalProcessHandleLocked(externalProcessToken);
@@ -9105,6 +9130,7 @@
             if (conn.stableCount == 0 && conn.unstableCount == 0) {
                 cpr.connections.remove(conn);
                 conn.client.conProviders.remove(conn);
+                stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name);
                 return true;
             }
             return false;
@@ -12320,9 +12346,18 @@
                 dumpAll = true;
             } else if ("-c".equals(opt)) {
                 dumpClient = true;
+            } else if ("-p".equals(opt)) {
+                if (opti < args.length) {
+                    dumpPackage = args[opti];
+                    opti++;
+                } else {
+                    pw.println("Error: -p option requires package argument");
+                    return;
+                }
+                dumpClient = true;
             } else if ("-h".equals(opt)) {
                 pw.println("Activity manager dump options:");
-                pw.println("  [-a] [-c] [-h] [cmd] ...");
+                pw.println("  [-a] [-c] [-p package] [-h] [cmd] ...");
                 pw.println("  cmd may be one of:");
                 pw.println("    a[ctivities]: activity stack state");
                 pw.println("    r[recents]: recent activities state");
@@ -12333,17 +12368,21 @@
                 pw.println("    prov[iders] [COMP_SPEC ...]: content provider state");
                 pw.println("    provider [COMP_SPEC]: provider client-side state");
                 pw.println("    s[ervices] [COMP_SPEC ...]: service state");
+                pw.println("    as[sociations]: tracked app associations");
                 pw.println("    service [COMP_SPEC]: service client-side state");
                 pw.println("    package [PACKAGE_NAME]: all state related to given package");
                 pw.println("    all: dump all activities");
                 pw.println("    top: dump the top activity");
                 pw.println("    write: write all pending state to storage");
+                pw.println("    track-associations: enable association tracking");
+                pw.println("    untrack-associations: disable and clear association tracking");
                 pw.println("  cmd may also be a COMP_SPEC to dump activities.");
                 pw.println("  COMP_SPEC may be a component name (com.foo/.myApp),");
                 pw.println("    a partial substring in a component name, a");
                 pw.println("    hex object identifier.");
                 pw.println("  -a: include all available server state.");
                 pw.println("  -c: include client state.");
+                pw.println("  -p: limit output to given package.");
                 return;
             } else {
                 pw.println("Unknown argument: " + opt + "; use -h for help");
@@ -12358,11 +12397,11 @@
             opti++;
             if ("activities".equals(cmd) || "a".equals(cmd)) {
                 synchronized (this) {
-                    dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, null);
+                    dumpActivitiesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
                 }
             } else if ("recents".equals(cmd) || "r".equals(cmd)) {
                 synchronized (this) {
-                    dumpRecentsLocked(fd, pw, args, opti, true, null);
+                    dumpRecentsLocked(fd, pw, args, opti, true, dumpPackage);
                 }
             } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
                 String[] newArgs;
@@ -12371,14 +12410,14 @@
                     name = null;
                     newArgs = EMPTY_STRING_ARRAY;
                 } else {
-                    name = args[opti];
+                    dumpPackage = args[opti];
                     opti++;
                     newArgs = new String[args.length - opti];
                     if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
                             args.length - opti);
                 }
                 synchronized (this) {
-                    dumpBroadcastsLocked(fd, pw, args, opti, true, name);
+                    dumpBroadcastsLocked(fd, pw, args, opti, true, dumpPackage);
                 }
             } else if ("intents".equals(cmd) || "i".equals(cmd)) {
                 String[] newArgs;
@@ -12387,14 +12426,14 @@
                     name = null;
                     newArgs = EMPTY_STRING_ARRAY;
                 } else {
-                    name = args[opti];
+                    dumpPackage = args[opti];
                     opti++;
                     newArgs = new String[args.length - opti];
                     if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
                             args.length - opti);
                 }
                 synchronized (this) {
-                    dumpPendingIntentsLocked(fd, pw, args, opti, true, name);
+                    dumpPendingIntentsLocked(fd, pw, args, opti, true, dumpPackage);
                 }
             } else if ("processes".equals(cmd) || "p".equals(cmd)) {
                 String[] newArgs;
@@ -12403,14 +12442,14 @@
                     name = null;
                     newArgs = EMPTY_STRING_ARRAY;
                 } else {
-                    name = args[opti];
+                    dumpPackage = args[opti];
                     opti++;
                     newArgs = new String[args.length - opti];
                     if (args.length > 2) System.arraycopy(args, opti, newArgs, 0,
                             args.length - opti);
                 }
                 synchronized (this) {
-                    dumpProcessesLocked(fd, pw, args, opti, true, name);
+                    dumpProcessesLocked(fd, pw, args, opti, true, dumpPackage);
                 }
             } else if ("oom".equals(cmd) || "o".equals(cmd)) {
                 synchronized (this) {
@@ -12468,14 +12507,39 @@
                     opti = 0;
                     more = true;
                 }
+            } else if ("associations".equals(cmd) || "as".equals(cmd)) {
+                synchronized (this) {
+                    dumpAssociationsLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
+                }
             } else if ("services".equals(cmd) || "s".equals(cmd)) {
                 synchronized (this) {
-                    mServices.dumpServicesLocked(fd, pw, args, opti, true, dumpClient, null);
+                    mServices.dumpServicesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
                 }
             } else if ("write".equals(cmd)) {
                 mTaskPersister.flush();
                 pw.println("All tasks persisted.");
                 return;
+            } else if ("track-associations".equals(cmd)) {
+                synchronized (this) {
+                    if (!mTrackingAssociations) {
+                        mTrackingAssociations = true;
+                        pw.println("Association tracking started.");
+                    } else {
+                        pw.println("Association tracking already enabled.");
+                    }
+                }
+                return;
+            } else if ("untrack-associations".equals(cmd)) {
+                synchronized (this) {
+                    if (mTrackingAssociations) {
+                        mTrackingAssociations = false;
+                        mAssociations.clear();
+                        pw.println("Association tracking stopped.");
+                    } else {
+                        pw.println("Association tracking not running.");
+                    }
+                }
+                return;
             } else {
                 // Dumping a single activity?
                 if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) {
@@ -12517,6 +12581,13 @@
                 pw.println("-------------------------------------------------------------------------------");
             }
             dumpActivitiesLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
+            if (mAssociations.size() > 0) {
+                pw.println();
+                if (dumpAll) {
+                    pw.println("-------------------------------------------------------------------------------");
+                }
+                dumpAssociationsLocked(fd, pw, args, opti, dumpAll, dumpClient, dumpPackage);
+            }
             pw.println();
             if (dumpAll) {
                 pw.println("-------------------------------------------------------------------------------");
@@ -12591,6 +12662,78 @@
         }
     }
 
+    void dumpAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+            int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
+        pw.println("ACTIVITY MANAGER ASSOCIATIONS (dumpsys activity associations)");
+
+        int dumpUid = 0;
+        if (dumpPackage != null) {
+            IPackageManager pm = AppGlobals.getPackageManager();
+            try {
+                dumpUid = pm.getPackageUid(dumpPackage, 0);
+            } catch (RemoteException e) {
+            }
+        }
+
+        boolean printedAnything = false;
+
+        final long now = SystemClock.uptimeMillis();
+
+        for (int i1=0, N1=mAssociations.size(); i1<N1; i1++) {
+            ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> targetComponents
+                    = mAssociations.valueAt(i1);
+            for (int i2=0, N2=targetComponents.size(); i2<N2; i2++) {
+                SparseArray<ArrayMap<String, Association>> sourceUids
+                        = targetComponents.valueAt(i2);
+                for (int i3=0, N3=sourceUids.size(); i3<N3; i3++) {
+                    ArrayMap<String, Association> sourceProcesses = sourceUids.valueAt(i3);
+                    for (int i4=0, N4=sourceProcesses.size(); i4<N4; i4++) {
+                        Association ass = sourceProcesses.valueAt(i4);
+                        if (dumpPackage != null) {
+                            if (!ass.mTargetComponent.getPackageName().equals(dumpPackage)
+                                    && UserHandle.getAppId(ass.mSourceUid) != dumpUid) {
+                                continue;
+                            }
+                        }
+                        printedAnything = true;
+                        pw.print("  ");
+                        pw.print(ass.mTargetProcess);
+                        pw.print("/");
+                        UserHandle.formatUid(pw, ass.mTargetUid);
+                        pw.print(" <- ");
+                        pw.print(ass.mSourceProcess);
+                        pw.print("/");
+                        UserHandle.formatUid(pw, ass.mSourceUid);
+                        pw.println();
+                        pw.print("    via ");
+                        pw.print(ass.mTargetComponent.flattenToShortString());
+                        pw.println();
+                        pw.print("    ");
+                        long dur = ass.mTime;
+                        if (ass.mNesting > 0) {
+                            dur += now - ass.mStartTime;
+                        }
+                        TimeUtils.formatDuration(dur, pw);
+                        pw.print(" (");
+                        pw.print(ass.mCount);
+                        pw.println(" times)");
+                        if (ass.mNesting > 0) {
+                            pw.print("    ");
+                            pw.print(" Currently active: ");
+                            TimeUtils.formatDuration(now - ass.mStartTime, pw);
+                            pw.println();
+                        }
+                    }
+                }
+            }
+
+        }
+
+        if (!printedAnything) {
+            pw.println("  (nothing)");
+        }
+    }
+
     void dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage) {
         boolean needSep = false;
@@ -14687,7 +14830,9 @@
                 // In the protocol here, we don't expect the client to correctly
                 // clean up this connection, we'll just remove it.
                 cpr.connections.remove(i);
-                conn.client.conProviders.remove(conn);
+                if (conn.client.conProviders.remove(conn)) {
+                    stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.name);
+                }
             }
         }
 
@@ -14773,6 +14918,8 @@
             for (int i=0; i<app.conProviders.size(); i++) {
                 ContentProviderConnection conn = app.conProviders.get(i);
                 conn.provider.connections.remove(conn);
+                stopAssociationLocked(app.uid, app.processName, conn.provider.uid,
+                        conn.provider.name);
             }
             app.conProviders.clear();
         }
@@ -16715,6 +16862,69 @@
         return null;
     }
 
+    Association startAssociationLocked(int sourceUid, String sourceProcess, int targetUid,
+            ComponentName targetComponent, String targetProcess) {
+        if (!mTrackingAssociations) {
+            return null;
+        }
+        ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> components
+                = mAssociations.get(targetUid);
+        if (components == null) {
+            components = new ArrayMap<>();
+            mAssociations.put(targetUid, components);
+        }
+        SparseArray<ArrayMap<String, Association>> sourceUids = components.get(targetComponent);
+        if (sourceUids == null) {
+            sourceUids = new SparseArray<>();
+            components.put(targetComponent, sourceUids);
+        }
+        ArrayMap<String, Association> sourceProcesses = sourceUids.get(sourceUid);
+        if (sourceProcesses == null) {
+            sourceProcesses = new ArrayMap<>();
+            sourceUids.put(sourceUid, sourceProcesses);
+        }
+        Association ass = sourceProcesses.get(sourceProcess);
+        if (ass == null) {
+            ass = new Association(sourceUid, sourceProcess, targetUid, targetComponent,
+                    targetProcess);
+            sourceProcesses.put(sourceProcess, ass);
+        }
+        ass.mCount++;
+        ass.mNesting++;
+        if (ass.mNesting == 1) {
+            ass.mStartTime = SystemClock.uptimeMillis();
+        }
+        return ass;
+    }
+
+    void stopAssociationLocked(int sourceUid, String sourceProcess, int targetUid,
+            ComponentName targetComponent) {
+        if (!mTrackingAssociations) {
+            return;
+        }
+        ArrayMap<ComponentName, SparseArray<ArrayMap<String, Association>>> components
+                = mAssociations.get(targetUid);
+        if (components == null) {
+            return;
+        }
+        SparseArray<ArrayMap<String, Association>> sourceUids = components.get(targetComponent);
+        if (sourceUids == null) {
+            return;
+        }
+        ArrayMap<String, Association> sourceProcesses = sourceUids.get(sourceUid);
+        if (sourceProcesses == null) {
+            return;
+        }
+        Association ass = sourceProcesses.get(sourceProcess);
+        if (ass == null || ass.mNesting <= 0) {
+            return;
+        }
+        ass.mNesting--;
+        if (ass.mNesting == 0) {
+            ass.mTime += SystemClock.uptimeMillis() - ass.mStartTime;
+        }
+    }
+
     private final int computeOomAdjLocked(ProcessRecord app, int cachedAdj, ProcessRecord TOP_APP,
             boolean doingAll, long now) {
         if (mAdjSeq == app.adjSeq) {
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 0dc163b..d1682b8 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -108,50 +108,46 @@
         for (Map.Entry<String, Class<?>> entry : map.entrySet()) {
             String setting = entry.getKey();
             Class<?> type = entry.getValue();
-            try {
-                if (type == String.class) {
-                    final String value;
-                    if (map == sSecureSettingToTypeMap) {
-                        value = Settings.Secure.getString(context.getContentResolver(), setting);
-                    } else if (map == sSystemSettingToTypeMap) {
-                        value = Settings.System.getString(context.getContentResolver(), setting);
-                    } else {
-                        value = Settings.Global.getString(context.getContentResolver(), setting);
-                    }
-                    snapshot.putString(setting, value);
-                } else if (type == int.class) {
-                    final int value;
-                    if (map == sSecureSettingToTypeMap) {
-                        value = Settings.Secure.getInt(context.getContentResolver(), setting);
-                    } else if (map == sSystemSettingToTypeMap) {
-                        value = Settings.System.getInt(context.getContentResolver(), setting);
-                    } else {
-                        value = Settings.Global.getInt(context.getContentResolver(), setting);
-                    }
-                    snapshot.putInt(setting, value);
-                } else if (type == float.class) {
-                    final float value;
-                    if (map == sSecureSettingToTypeMap) {
-                        value = Settings.Secure.getFloat(context.getContentResolver(), setting);
-                    } else if (map == sSystemSettingToTypeMap) {
-                        value = Settings.System.getFloat(context.getContentResolver(), setting);
-                    } else {
-                        value = Settings.Global.getFloat(context.getContentResolver(), setting);
-                    }
-                    snapshot.putFloat(setting, value);
-                } else if (type == long.class) {
-                    final long value;
-                    if (map == sSecureSettingToTypeMap) {
-                        value = Settings.Secure.getLong(context.getContentResolver(), setting);
-                    } else if (map == sSystemSettingToTypeMap) {
-                        value = Settings.System.getLong(context.getContentResolver(), setting);
-                    } else {
-                        value = Settings.Global.getLong(context.getContentResolver(), setting);
-                    }
-                    snapshot.putLong(setting, value);
+            if (type == String.class) {
+                final String value;
+                if (map == sSecureSettingToTypeMap) {
+                    value = Settings.Secure.getString(context.getContentResolver(), setting);
+                } else if (map == sSystemSettingToTypeMap) {
+                    value = Settings.System.getString(context.getContentResolver(), setting);
+                } else {
+                    value = Settings.Global.getString(context.getContentResolver(), setting);
                 }
-            } catch (SettingNotFoundException snfe) {
-                Log.w(LOG_TAG, "Cannot find setting \"" + setting + "\"", snfe);
+                snapshot.putString(setting, value);
+            } else if (type == int.class) {
+                final int value;
+                if (map == sSecureSettingToTypeMap) {
+                    value = Settings.Secure.getInt(context.getContentResolver(), setting, 0);
+                } else if (map == sSystemSettingToTypeMap) {
+                    value = Settings.System.getInt(context.getContentResolver(), setting, 0);
+                } else {
+                    value = Settings.Global.getInt(context.getContentResolver(), setting, 0);
+                }
+                snapshot.putInt(setting, value);
+            } else if (type == float.class) {
+                final float value;
+                if (map == sSecureSettingToTypeMap) {
+                    value = Settings.Secure.getFloat(context.getContentResolver(), setting, 0);
+                } else if (map == sSystemSettingToTypeMap) {
+                    value = Settings.System.getFloat(context.getContentResolver(), setting, 0);
+                } else {
+                    value = Settings.Global.getFloat(context.getContentResolver(), setting, 0);
+                }
+                snapshot.putFloat(setting, value);
+            } else if (type == long.class) {
+                final long value;
+                if (map == sSecureSettingToTypeMap) {
+                    value = Settings.Secure.getLong(context.getContentResolver(), setting, 0);
+                } else if (map == sSystemSettingToTypeMap) {
+                    value = Settings.System.getLong(context.getContentResolver(), setting, 0);
+                } else {
+                    value = Settings.Global.getLong(context.getContentResolver(), setting, 0);
+                }
+                snapshot.putLong(setting, value);
             }
         }
     }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 7c48f3e..a6c616a 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -64,6 +64,9 @@
     ProcessStats.ProcessState baseProcessTracker;
     BatteryStatsImpl.Uid.Proc curProcBatteryStats;
     int pid;                    // The process of this application; 0 if none
+    int[] gids;                 // The gids this process was launched with
+    String requiredAbi;         // The ABI this process was launched with
+    String instructionSet;      // The instruction set this process was launched with
     boolean starting;           // True if the process is being started
     long lastActivityTime;      // For managing the LRU list
     long lastPssTime;           // Last time we retrieved PSS data
@@ -183,7 +186,17 @@
         if (uid != info.uid) {
             pw.print(" ISOLATED uid="); pw.print(uid);
         }
-        pw.println();
+        pw.print(" gids={");
+        if (gids != null) {
+            for (int gi=0; gi<gids.length; gi++) {
+                if (gi != 0) pw.print(", ");
+                pw.print(gids[gi]);
+
+            }
+        }
+        pw.println("}");
+        pw.print(prefix); pw.print("requiredAbi="); pw.print(requiredAbi);
+                pw.print(" instructionSet="); pw.println(instructionSet);
         if (info.className != null) {
             pw.print(prefix); pw.print("class="); pw.println(info.className);
         }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 64d77c1..ab53fbc 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -168,7 +168,6 @@
 
     @Override
     protected void onServiceAdded(ManagedServiceInfo info) {
-        Slog.d(TAG, "onServiceAdded " + info);
         final IConditionProvider provider = provider(info);
         try {
             provider.onConnected();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 825627f..02cacd9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -683,6 +683,9 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+            if (action == null) {
+                return;
+            }
 
             boolean queryRestart = false;
             boolean queryRemove = false;
@@ -1829,7 +1832,7 @@
                     // can to avoid extracting signals.
                     handleGroupedNotificationLocked(r, old, callingUid, callingPid);
                     boolean ignoreNotification =
-                            removeUnusedGroupedNotificationLocked(r, callingUid, callingPid);
+                            removeUnusedGroupedNotificationLocked(r, old, callingUid, callingPid);
 
                     // This conditional is a dirty hack to limit the logging done on
                     //     behalf of the download manager without affecting other apps.
@@ -1966,7 +1969,8 @@
      *
      * <p>Returns true if the given notification is a child of a group with a
      * summary, which means that SysUI will never show it, and hence the new
-     * notification can be safely ignored.</p>
+     * notification can be safely ignored. Also cancels any previous instance
+     * of the ignored notification.</p>
      *
      * <p>For summaries, cancels all children of that group, as SysUI will
      * never show them anymore.</p>
@@ -1974,7 +1978,7 @@
      * @return true if the given notification can be ignored as an optimization
      */
     private boolean removeUnusedGroupedNotificationLocked(NotificationRecord r,
-            int callingUid, int callingPid) {
+            NotificationRecord old, int callingUid, int callingPid) {
         // No optimizations are possible if listeners want groups.
         if (mListeners.notificationGroupsDesired()) {
             return false;
@@ -1992,6 +1996,13 @@
                 Slog.d(TAG, "Ignoring group child " + sbn.getKey() + " due to existing summary "
                         + summary.getKey());
             }
+            // Make sure we don't leave an old version of the notification around.
+            if (old != null) {
+                if (DBG) {
+                    Slog.d(TAG, "Canceling old version of ignored group child " + sbn.getKey());
+                }
+                cancelNotificationLocked(old, false, REASON_GROUP_OPTIMIZATION);
+            }
             return true;
         } else if (isSummary) {
             // Summary -> cancel children
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index be3251c..d484b8f 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -320,6 +320,9 @@
         checkManageUsersPermission("get the profile parent");
         synchronized (mPackagesLock) {
             UserInfo profile = getUserInfoLocked(userHandle);
+            if (profile == null) {
+                return null;
+            }
             int parentUserId = profile.profileGroupId;
             if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) {
                 return null;
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f859fd2..da25c533 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -304,10 +304,11 @@
             pw.print(prefix); pw.print("inPendingTransaction=");
                     pw.println(inPendingTransaction);
         }
-        if (startingData != null || removed || firstWindowDrawn) {
+        if (startingData != null || removed || firstWindowDrawn || mDeferRemoval) {
             pw.print(prefix); pw.print("startingData="); pw.print(startingData);
                     pw.print(" removed="); pw.print(removed);
-                    pw.print(" firstWindowDrawn="); pw.println(firstWindowDrawn);
+                    pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn);
+                    pw.print(" mDeferRemoval="); pw.println(mDeferRemoval);
         }
         if (startingWindow != null || startingView != null
                 || startingDisplayed || startingMoved) {
diff --git a/services/core/java/com/android/server/wm/StackTapPointerEventListener.java b/services/core/java/com/android/server/wm/StackTapPointerEventListener.java
index 19d8ab3..8938358 100644
--- a/services/core/java/com/android/server/wm/StackTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/StackTapPointerEventListener.java
@@ -57,6 +57,7 @@
                 if (mPointerId >= 0) {
                     int index = motionEvent.findPointerIndex(mPointerId);
                     if ((motionEvent.getEventTime() - motionEvent.getDownTime()) > TAP_TIMEOUT_MSEC
+                            || index < 0
                             || (motionEvent.getX(index) - mDownX) > mMotionSlop
                             || (motionEvent.getY(index) - mDownY) > mMotionSlop) {
                         mPointerId = -1;
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a60be3b..b49b87c 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -68,6 +68,6 @@
 
     @Override
     public String toString() {
-        return "{taskId=" + taskId + " appTokens=" + mAppTokens + "}";
+        return "{taskId=" + taskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2750941..4d0169d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5200,8 +5200,17 @@
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + taskId);
         EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, taskId, "removeTask");
         task.mDeferRemoval = false;
-        task.mStack.removeTask(task);
+        stack.removeTask(task);
         mTaskIdToTask.delete(task.taskId);
+
+        final ArrayList<AppWindowToken> exitingApps = stack.mExitingAppTokens;
+        for (int appNdx = exitingApps.size() - 1; appNdx >= 0; --appNdx) {
+            final AppWindowToken wtoken = exitingApps.get(appNdx);
+            if (wtoken.groupId == taskId) {
+                wtoken.mDeferRemoval = false;
+                exitingApps.remove(appNdx);
+            }
+        }
     }
 
     public void removeTask(int taskId) {