Merge "Expose an update_engine API that verifies the given payload metadata."
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 711c12d..2a67b75 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,6 +1,7 @@
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
                   -fw core/java/android/
+                      graphics/java/android
                       core/tests/coretests/src/android/
                       packages/PrintRecommendationService/
                       packages/PrintSpooler/
diff --git a/api/current.txt b/api/current.txt
index 3944b45..54f0e15 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23371,6 +23371,7 @@
     method public android.media.MediaDrm.CryptoSession getCryptoSession(byte[], java.lang.String, java.lang.String);
     method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.HashMap<java.lang.String, java.lang.String>) throws android.media.NotProvisionedException;
     method public int getMaxHdcpLevel();
+    method public static int getMaxSecurityLevel();
     method public int getMaxSessionCount();
     method public android.os.PersistableBundle getMetrics();
     method public int getOpenSessionCount();
@@ -23384,6 +23385,7 @@
     method public static boolean isCryptoSchemeSupported(java.util.UUID);
     method public static boolean isCryptoSchemeSupported(java.util.UUID, java.lang.String);
     method public byte[] openSession() throws android.media.NotProvisionedException, android.media.ResourceBusyException;
+    method public byte[] openSession(int) throws android.media.NotProvisionedException, android.media.ResourceBusyException;
     method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.NotProvisionedException;
     method public void provideProvisionResponse(byte[]) throws android.media.DeniedByServerException;
     method public java.util.HashMap<java.lang.String, java.lang.String> queryKeyStatus(byte[]);
@@ -23399,7 +23401,6 @@
     method public void setOnKeyStatusChangeListener(android.media.MediaDrm.OnKeyStatusChangeListener, android.os.Handler);
     method public void setPropertyByteArray(java.lang.String, byte[]);
     method public void setPropertyString(java.lang.String, java.lang.String);
-    method public void setSecurityLevel(byte[], int);
     field public static final deprecated int EVENT_KEY_EXPIRED = 3; // 0x3
     field public static final int EVENT_KEY_REQUIRED = 2; // 0x2
     field public static final deprecated int EVENT_PROVISION_REQUIRED = 1; // 0x1
@@ -36774,6 +36775,13 @@
     field public static final java.lang.String ADDRESS = "address";
   }
 
+  public static final class Telephony.CarrierIdentification implements android.provider.BaseColumns {
+    method public static android.net.Uri getUriForSubscriptionId(int);
+    field public static final java.lang.String CID = "carrier_id";
+    field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String NAME = "carrier_name";
+  }
+
   public static final class Telephony.Carriers implements android.provider.BaseColumns {
     field public static final java.lang.String APN = "apn";
     field public static final java.lang.String AUTH_TYPE = "authtype";
@@ -44903,6 +44911,7 @@
     method public abstract int getAttributeListValue(int, java.lang.String[], int);
     method public abstract java.lang.String getAttributeName(int);
     method public abstract int getAttributeNameResource(int);
+    method public default java.lang.String getAttributeNamespace(int);
     method public abstract int getAttributeResourceValue(java.lang.String, java.lang.String, int);
     method public abstract int getAttributeResourceValue(int, int);
     method public abstract int getAttributeUnsignedIntValue(java.lang.String, java.lang.String, int);
@@ -50364,7 +50373,7 @@
     method public final void logSelectionModifiedEvent(int, int);
     method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextClassification);
     method public final void logSelectionModifiedEvent(int, int, android.view.textclassifier.TextSelection);
-    method public final void logSelectionStartedEvent(int);
+    method public final void logSelectionStartedEvent(int, int);
     method public abstract void writeEvent(android.view.textclassifier.logging.SelectionEvent);
     field public static final int OUT_OF_BOUNDS = 2147483647; // 0x7fffffff
     field public static final int OUT_OF_BOUNDS_NEGATIVE = -2147483648; // 0x80000000
@@ -50394,6 +50403,7 @@
     method public int getEventIndex();
     method public long getEventTime();
     method public int getEventType();
+    method public int getInvocationMethod();
     method public java.lang.String getPackageName();
     method public java.lang.String getSessionId();
     method public java.lang.String getSignature();
@@ -50418,6 +50428,8 @@
     field public static final int EVENT_SELECTION_STARTED = 1; // 0x1
     field public static final int EVENT_SMART_SELECTION_MULTI = 4; // 0x4
     field public static final int EVENT_SMART_SELECTION_SINGLE = 3; // 0x3
+    field public static final int INVOCATION_LINK = 2; // 0x2
+    field public static final int INVOCATION_MANUAL = 1; // 0x1
   }
 
 }
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index 03faa92..f53befe 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -142,7 +142,7 @@
 PrivacyBuffer::clear()
 {
     mSize = 0;
-    mProto = ProtoOutputStream();
+    mProto.clear();
 }
 
 size_t
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index 90158a0..8eea944 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -242,7 +242,8 @@
 LOCAL_SRC_FILES := $(statsd_common_src) \
                    benchmark/main.cpp \
                    benchmark/hello_world_benchmark.cpp \
-                   benchmark/log_event_benchmark.cpp
+                   benchmark/log_event_benchmark.cpp \
+                   benchmark/stats_write_benchmark.cpp
 
 LOCAL_C_INCLUDES := $(statsd_common_c_includes)
 
@@ -261,7 +262,8 @@
     $(statsd_common_static_libraries)
 
 LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries) \
-    libgtest_prod
+    libgtest_prod \
+    libstatslog
 
 LOCAL_PROTOC_OPTIMIZE_TYPE := lite
 
diff --git a/cmds/statsd/AndroidTest.xml b/cmds/statsd/AndroidTest.xml
new file mode 100644
index 0000000..afe30a2
--- /dev/null
+++ b/cmds/statsd/AndroidTest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Config for statsd_test">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="statsd_test->/data/nativetest/statsd_test" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/nativetest" />
+        <option name="module-name" value="statsd_test" />
+    </test>
+</configuration>
\ No newline at end of file
diff --git a/cmds/statsd/benchmark/stats_write_benchmark.cpp b/cmds/statsd/benchmark/stats_write_benchmark.cpp
new file mode 100644
index 0000000..f5a0cd5
--- /dev/null
+++ b/cmds/statsd/benchmark/stats_write_benchmark.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "benchmark/benchmark.h"
+#include <statslog.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+static void BM_StatsWrite(benchmark::State& state) {
+    const char* reason = "test";
+    int64_t boot_end_time = 1234567;
+    int64_t total_duration = 100;
+    int64_t bootloader_duration = 10;
+    int64_t time_since_last_boot = 99999999;
+    while (state.KeepRunning()) {
+        android::util::stats_write(
+                android::util::BOOT_SEQUENCE_REPORTED, reason, reason,
+                boot_end_time, total_duration, bootloader_duration, time_since_last_boot);
+        total_duration++;
+    }
+}
+BENCHMARK(BM_StatsWrite);
+
+}  //  namespace statsd
+}  //  namespace os
+}  //  namespace android
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
index 63f6e2a..ba16ec83 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp
@@ -19,7 +19,6 @@
 
 #include "AnomalyTracker.h"
 #include "external/Perfetto.h"
-#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
 #include "guardrail/StatsdStats.h"
 #include "subscriber/IncidentdReporter.h"
 #include "subscriber/SubscriberReporter.h"
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 0578e06..936a2ef1 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -59,9 +59,7 @@
                                metric.links().end());
         mConditionSliced = true;
     }
-
-    startNewProtoOutputStreamLocked();
-
+    mProto = std::make_unique<ProtoOutputStream>();
     VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(),
          (long long)mBucketSizeNs, (long long)mStartTimeNs);
 }
@@ -70,10 +68,6 @@
     VLOG("~EventMetricProducer() called");
 }
 
-void EventMetricProducer::startNewProtoOutputStreamLocked() {
-    mProto = std::make_unique<ProtoOutputStream>();
-}
-
 void EventMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eventTime) {
 }
 
@@ -113,7 +107,7 @@
     protoOutput->write(FIELD_TYPE_MESSAGE | FIELD_ID_EVENT_METRICS,
                        reinterpret_cast<char*>(buffer.get()->data()), buffer.get()->size());
 
-    startNewProtoOutputStreamLocked();
+    mProto->clear();
 }
 
 void EventMetricProducer::onConditionChangedLocked(const bool conditionMet,
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 935f206..394ed23 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -40,9 +40,6 @@
 
     virtual ~EventMetricProducer();
 
-protected:
-    void startNewProtoOutputStreamLocked();
-
 private:
     void onMatchedLogEventInternalLocked(
             const size_t matcherIndex, const MetricDimensionKey& eventKey,
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 71de479..7b70f59 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -37,9 +37,11 @@
 Landroid/app/ActivityThread;->currentApplication()Landroid/app/Application;
 Landroid/app/ActivityThread;->currentPackageName()Ljava/lang/String;
 Landroid/app/ActivityThread;->currentProcessName()Ljava/lang/String;
+Landroid/app/ActivityThread;->getActivity(Landroid/os/IBinder;)Landroid/app/Activity;
 Landroid/app/ActivityThread;->getApplication()Landroid/app/Application;
 Landroid/app/ActivityThread;->getApplicationThread()Landroid/app/ActivityThread$ApplicationThread;
 Landroid/app/ActivityThread;->getHandler()Landroid/os/Handler;
+Landroid/app/ActivityThread;->getInstrumentation()Landroid/app/Instrumentation;
 Landroid/app/ActivityThread;->getPackageManager()Landroid/content/pm/IPackageManager;
 Landroid/app/ActivityThread;->getProcessName()Ljava/lang/String;
 Landroid/app/ActivityThread$H;->BIND_SERVICE:I
@@ -282,13 +284,28 @@
 Landroid/content/pm/UserInfo;->id:I
 Landroid/content/pm/UserInfo;->isPrimary()Z
 Landroid/content/res/AssetManager;->addAssetPath(Ljava/lang/String;)I
+Landroid/content/res/AssetManager;->addAssetPaths([Ljava/lang/String;)[I
+Landroid/content/res/AssetManager;->applyStyle(JIIJ[IIJJ)V
+Landroid/content/res/AssetManager;->getArraySize(I)I
 Landroid/content/res/AssetManager;->getAssignedPackageIdentifiers()Landroid/util/SparseArray;
+Landroid/content/res/AssetManager;->getCookieName(I)Ljava/lang/String;
 Landroid/content/res/AssetManager;->getResourceBagText(II)Ljava/lang/CharSequence;
+Landroid/content/res/AssetManager;->loadResourceBagValue(IILandroid/util/TypedValue;Z)I
+Landroid/content/res/AssetManager;->loadResourceValue(ISLandroid/util/TypedValue;Z)I
+Landroid/content/res/AssetManager;->loadThemeAttributeValue(JILandroid/util/TypedValue;Z)I
 Landroid/content/res/AssetManager;->mObject:J
+Landroid/content/res/AssetManager;->openNonAssetFdNative(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;
 Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;I)Ljava/io/InputStream;
 Landroid/content/res/AssetManager;->openNonAsset(ILjava/lang/String;)Ljava/io/InputStream;
 Landroid/content/res/AssetManager;->openNonAsset(Ljava/lang/String;I)Ljava/io/InputStream;
 Landroid/content/res/AssetManager;->openNonAsset(Ljava/lang/String;)Ljava/io/InputStream;
+Landroid/content/res/AssetManager;->openNonAssetNative(ILjava/lang/String;I)J
+Landroid/content/res/AssetManager;->openXmlAssetNative(ILjava/lang/String;)J
+Landroid/content/res/AssetManager;->resolveAttrs(JII[I[I[I[I)Z
+Landroid/content/res/AssetManager;->retrieveArray(I[I)I
+Landroid/content/res/AssetManager;->retrieveAttributes(J[I[I[I)Z
+Landroid/content/res/AssetManager;->STYLE_NUM_ENTRIES:I
+Landroid/content/res/AssetManager;->STYLE_RESOURCE_ID:I
 Landroid/content/res/DrawableCache;->getInstance(JLandroid/content/res/Resources;Landroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
 Landroid/content/res/Resources;->getCompatibilityInfo()Landroid/content/res/CompatibilityInfo;
 Landroid/content/res/ResourcesImpl;->mAccessLock:Ljava/lang/Object;
@@ -318,6 +335,7 @@
 Landroid/content/res/TypedArray;->mTheme:Landroid/content/res/Resources$Theme;
 Landroid/content/res/TypedArray;->mValue:Landroid/util/TypedValue;
 Landroid/content/res/TypedArray;->mXml:Landroid/content/res/XmlBlock$Parser;
+Landroid/content/res/XmlBlock;->close()V
 Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParser;
 Landroid/content/res/XmlBlock$Parser;->mParseState:J
 Landroid/content/SyncStatusInfo;->lastSuccessTime:J
@@ -557,6 +575,7 @@
 Landroid/net/TrafficStats;->setThreadStatsTagBackup()V
 Landroid/net/TrafficStats;->setThreadStatsTagRestore()V
 Landroid/net/TrafficStats;->setThreadStatsUid(I)V
+Landroid/net/WebAddress;-><init>(Ljava/lang/String;)V
 Landroid/net/WifiKey;-><init>(Ljava/lang/String;Ljava/lang/String;)V
 Landroid/net/wifi/p2p/WifiP2pGroup;->getNetworkId()I
 Landroid/net/wifi/p2p/WifiP2pGroupList;->getGroupList()Ljava/util/Collection;
@@ -600,6 +619,7 @@
 Landroid/net/wifi/WifiScanner;->startScan(Landroid/net/wifi/WifiScanner$ScanSettings;Landroid/net/wifi/WifiScanner$ScanListener;Landroid/os/WorkSource;)V
 Landroid/net/wifi/WifiScanner;->startScan(Landroid/net/wifi/WifiScanner$ScanSettings;Landroid/net/wifi/WifiScanner$ScanListener;)V
 Landroid/net/wifi/WifiScanner;->stopBackgroundScan(Landroid/net/wifi/WifiScanner$ScanListener;)V
+Landroid/net/wifi/WifiSsid;->NONE:Ljava/lang/String;
 Landroid/nfc/NfcAdapter;->addNfcUnlockHandler(Landroid/nfc/NfcAdapter$NfcUnlockHandler;[Ljava/lang/String;)Z
 Landroid/nfc/NfcAdapter;->disable()Z
 Landroid/nfc/NfcAdapter;->enable()Z
@@ -859,6 +879,7 @@
 Landroid/service/voice/VoiceInteractionService;->isKeyphraseAndLocaleSupportedForHotword(Ljava/lang/String;Ljava/util/Locale;)Z
 Landroid/service/wallpaper/WallpaperService$Engine;->setFixedSizeAllowed(Z)V
 Landroid/speech/tts/TextToSpeech;->getCurrentEngine()Ljava/lang/String;
+Landroid/system/StructTimeval;->fromMillis(J)Landroid/system/StructTimeval;
 Landroid/telecom/AudioState;->getRoute()I
 Landroid/telecom/AudioState;->getSupportedRouteMask()I
 Landroid/telecom/AudioState;->isMuted()Z
@@ -953,6 +974,7 @@
 Landroid/text/SpannableStringInternal;->setSpan(Ljava/lang/Object;III)V
 Landroid/text/SpannableStringInternal;->setSpan(Ljava/lang/Object;IIIZ)V
 Landroid/text/SpannableStringInternal;->START:I
+Landroid/text/StaticLayout;-><init>(Ljava/lang/CharSequence;IILandroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZLandroid/text/TextUtils$TruncateAt;II)V
 Landroid/text/StaticLayout;->mColumns:I
 Landroid/text/StaticLayout;->mLineCount:I
 Landroid/text/StaticLayout;->mLines:[I
@@ -1001,6 +1023,7 @@
 Landroid/view/LayoutInflater;->mFactory:Landroid/view/LayoutInflater$Factory;
 Landroid/view/LayoutInflater;->mFactorySet:Z
 Landroid/view/LayoutInflater;->sConstructorMap:Ljava/util/HashMap;
+Landroid/view/LayoutInflater;->setPrivateFactory(Landroid/view/LayoutInflater$Factory2;)V
 Landroid/view/MotionEvent;->HISTORY_CURRENT:I
 Landroid/view/MotionEvent;->mNativePtr:J
 Landroid/view/MotionEvent;->nativeGetRawAxisValue(JIII)F
@@ -1073,6 +1096,7 @@
 Landroid/view/View;->mScrollX:I
 Landroid/view/View;->mScrollY:I
 Landroid/view/View;->mStartActivityRequestWho:Ljava/lang/String;
+Landroid/view/View;->mTag:Ljava/lang/Object;
 Landroid/view/View;->mTop:I
 Landroid/view/View;->mUnscaledDrawingCache:Landroid/graphics/Bitmap;
 Landroid/view/View;->notifySubtreeAccessibilityStateChangedIfNeeded()V
@@ -1111,20 +1135,72 @@
 Landroid/view/Window;->mAppName:Ljava/lang/String;
 Landroid/view/Window;->mAppToken:Landroid/os/IBinder;
 Landroid/view/Window;->mHardwareAccelerated:Z
+Landroid/webkit/FindActionModeCallback;->findAll()V
+Landroid/webkit/FindActionModeCallback;-><init>(Landroid/content/Context;)V
+Landroid/webkit/FindActionModeCallback;->setText(Ljava/lang/String;)V
+Landroid/webkit/FindActionModeCallback;->setWebView(Landroid/webkit/WebView;)V
+Landroid/webkit/FindActionModeCallback;->showSoftInput()V
+Landroid/webkit/GeolocationPermissions;-><init>()V
+Landroid/webkit/HttpAuthHandler;-><init>()V
+Landroid/webkit/JsDialogHelper;-><init>(Landroid/webkit/JsPromptResult;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
+Landroid/webkit/JsDialogHelper;->showDialog(Landroid/content/Context;)V
+Landroid/webkit/JsPromptResult;->getStringResult()Ljava/lang/String;
+Landroid/webkit/JsPromptResult;-><init>(Landroid/webkit/JsResult$ResultReceiver;)V
+Landroid/webkit/SslErrorHandler;-><init>()V
+Landroid/webkit/TokenBindingService;-><init>()V
+Landroid/webkit/TokenBindingService$TokenBindingKey;-><init>()V
+Landroid/webkit/WebChromeClient;->openFileChooser(Landroid/webkit/ValueCallback;Ljava/lang/String;Ljava/lang/String;)V
+Landroid/webkit/WebMessagePort;-><init>()V
+Landroid/webkit/WebResourceError;-><init>()V
+Landroid/webkit/WebResourceResponse;-><init>(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/util/Map;Ljava/io/InputStream;)V
+Landroid/webkit/WebSettings;->getAcceptThirdPartyCookies()Z
+Landroid/webkit/WebSettings;->setAcceptThirdPartyCookies(Z)V
 Landroid/webkit/WebSettings;->setNavDump(Z)V
 Landroid/webkit/WebSettings;->setPluginsEnabled(Z)V
+Landroid/webkit/WebStorage;-><init>()V
+Landroid/webkit/WebStorage$Origin;-><init>(Ljava/lang/String;JJ)V
 Landroid/webkit/WebView;->debugDump()V
+Landroid/webkit/WebViewDelegate;->addWebViewAssetPath(Landroid/content/Context;)V
+Landroid/webkit/WebViewDelegate;->callDrawGlFunction(Landroid/graphics/Canvas;JLjava/lang/Runnable;)V
+Landroid/webkit/WebViewDelegate;->callDrawGlFunction(Landroid/graphics/Canvas;J)V
+Landroid/webkit/WebViewDelegate;->canInvokeDrawGlFunctor(Landroid/view/View;)Z
+Landroid/webkit/WebViewDelegate;->detachDrawGlFunctor(Landroid/view/View;J)V
+Landroid/webkit/WebViewDelegate;->getApplication()Landroid/app/Application;
+Landroid/webkit/WebViewDelegate;->getDataDirectorySuffix()Ljava/lang/String;
+Landroid/webkit/WebViewDelegate;->getErrorString(Landroid/content/Context;I)Ljava/lang/String;
+Landroid/webkit/WebViewDelegate;->getPackageId(Landroid/content/res/Resources;Ljava/lang/String;)I
+Landroid/webkit/WebViewDelegate;->invokeDrawGlFunctor(Landroid/view/View;JZ)V
+Landroid/webkit/WebViewDelegate;->isMultiProcessEnabled()Z
+Landroid/webkit/WebViewDelegate;->isTraceTagEnabled()Z
+Landroid/webkit/WebViewDelegate;->setOnTraceEnabledChangeListener(Landroid/webkit/WebViewDelegate$OnTraceEnabledChangeListener;)V
 Landroid/webkit/WebView;->disablePlatformNotifications()V
 Landroid/webkit/WebView;->emulateShiftHeld()V
 Landroid/webkit/WebView;->enablePlatformNotifications()V
 Landroid/webkit/WebViewFactory;->getLoadedPackageInfo()Landroid/content/pm/PackageInfo;
 Landroid/webkit/WebViewFactory;->getProvider()Landroid/webkit/WebViewFactoryProvider;
+Landroid/webkit/WebViewFactory;->loadWebViewNativeLibraryFromPackage(Ljava/lang/String;Ljava/lang/ClassLoader;)I
 Landroid/webkit/WebViewFactory;->sPackageInfo:Landroid/content/pm/PackageInfo;
 Landroid/webkit/WebView;->getVisibleTitleHeight()I
 Landroid/webkit/WebView;->getWebViewProvider()Landroid/webkit/WebViewProvider;
+Landroid/webkit/WebView$HitTestResult;-><init>()V
+Landroid/webkit/WebView$HitTestResult;->setExtra(Ljava/lang/String;)V
+Landroid/webkit/WebView$HitTestResult;->setType(I)V
 Landroid/webkit/WebView;->isPaused()Z
 Landroid/webkit/WebView;->mProvider:Landroid/webkit/WebViewProvider;
 Landroid/webkit/WebView;->notifyFindDialogDismissed()V
+Landroid/webkit/WebView$PrivateAccess;->overScrollBy(IIIIIIIIZ)V
+Landroid/webkit/WebView$PrivateAccess;->setMeasuredDimension(II)V
+Landroid/webkit/WebView$PrivateAccess;->super_dispatchKeyEvent(Landroid/view/KeyEvent;)Z
+Landroid/webkit/WebView$PrivateAccess;->super_getScrollBarStyle()I
+Landroid/webkit/WebView$PrivateAccess;->super_onDrawVerticalScrollBar(Landroid/graphics/Canvas;Landroid/graphics/drawable/Drawable;IIII)V
+Landroid/webkit/WebView$PrivateAccess;->super_onGenericMotionEvent(Landroid/view/MotionEvent;)Z
+Landroid/webkit/WebView$PrivateAccess;->super_performAccessibilityAction(ILandroid/os/Bundle;)Z
+Landroid/webkit/WebView$PrivateAccess;->super_performLongClick()Z
+Landroid/webkit/WebView$PrivateAccess;->super_requestFocus(ILandroid/graphics/Rect;)Z
+Landroid/webkit/WebView$PrivateAccess;->super_scrollTo(II)V
+Landroid/webkit/WebView$PrivateAccess;->super_setFrame(IIII)Z
+Landroid/webkit/WebView$PrivateAccess;->super_setLayoutParams(Landroid/view/ViewGroup$LayoutParams;)V
+Landroid/webkit/WebView$PrivateAccess;->super_startActivityForResult(Landroid/content/Intent;I)V
 Landroid/webkit/WebView;->restorePicture(Landroid/os/Bundle;Ljava/io/File;)Z
 Landroid/webkit/WebView;->savePicture(Landroid/os/Bundle;Ljava/io/File;)Z
 Landroid/webkit/WebView;->sEnforceThreadChecking:Z
@@ -1379,6 +1455,7 @@
 Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
 Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
 Ldalvik/system/CloseGuard;->warnIfOpen()V
+Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
 Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
 Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
 Ldalvik/system/DexFile;->openDexFile(Ljava/lang/String;Ljava/lang/String;ILjava/lang/ClassLoader;[Ldalvik/system/DexPathList$Element;)Ljava/lang/Object;
@@ -1398,6 +1475,7 @@
 Ldalvik/system/VMRuntime;->newNonMovableArray(Ljava/lang/Class;I)Ljava/lang/Object;
 Ldalvik/system/VMRuntime;->registerNativeAllocation(I)V
 Ldalvik/system/VMRuntime;->registerNativeFree(I)V
+Ldalvik/system/VMRuntime;->runFinalization(J)V
 Ldalvik/system/VMRuntime;->setMinimumHeapSize(J)J
 Ldalvik/system/VMRuntime;->setTargetHeapUtilization(F)F
 Ldalvik/system/VMRuntime;->trackExternalAllocation(J)Z
@@ -1418,13 +1496,39 @@
 Ljava/lang/Daemons$FinalizerDaemon;->finalizingObject:Ljava/lang/Object;
 Ljava/lang/Daemons$FinalizerDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerDaemon;
 Ljava/lang/Daemons$FinalizerWatchdogDaemon;->INSTANCE:Ljava/lang/Daemons$FinalizerWatchdogDaemon;
+Ljava/lang/Daemons;->requestHeapTrim()V
+Ljava/lang/Daemons;->start()V
+Ljava/lang/Daemons;->stop()V
+Ljava/lang/ref/FinalizerReference;->add(Ljava/lang/Object;)V
+Ljava/lang/reflect/Executable;->artMethod:J
+Ljava/lang/reflect/Parameter;-><init>(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V
+Ljava/lang/ref/ReferenceQueue;->add(Ljava/lang/ref/Reference;)V
 Ljava/lang/Runtime;->loadLibrary(Ljava/lang/String;Ljava/lang/ClassLoader;)V
 Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V
 Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;
+Ljava/lang/String;-><init>(II[C)V
+Ljava/lang/Thread;->daemon:Z
+Ljava/lang/Thread;->dispatchUncaughtException(Ljava/lang/Throwable;)V
+Ljava/lang/ThreadGroup;->add(Ljava/lang/Thread;)V
+Ljava/lang/ThreadGroup;->groups:[Ljava/lang/ThreadGroup;
+Ljava/lang/Thread;->group:Ljava/lang/ThreadGroup;
+Ljava/lang/ThreadGroup;->mainThreadGroup:Ljava/lang/ThreadGroup;
+Ljava/lang/ThreadGroup;->name:Ljava/lang/String;
+Ljava/lang/ThreadGroup;->ngroups:I
 Ljava/lang/ThreadGroup;->parent:Ljava/lang/ThreadGroup;
 Ljava/lang/ThreadGroup;->systemThreadGroup:Ljava/lang/ThreadGroup;
+Ljava/lang/ThreadGroup;->threadTerminated(Ljava/lang/Thread;)V
 Ljava/lang/Thread;->inheritableThreadLocals:Ljava/lang/ThreadLocal$ThreadLocalMap;
+Ljava/lang/Thread;-><init>(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V
+Ljava/lang/Thread;->lock:Ljava/lang/Object;
+Ljava/lang/Thread;->name:Ljava/lang/String;
+Ljava/lang/Thread;->nativePeer:J
+Ljava/lang/Thread;->priority:I
+Ljava/lang/Throwable;->backtrace:Ljava/lang/Object;
+Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
 Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
+Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
+Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
 Ljava/net/Authenticator;->theAuthenticator:Ljava/net/Authenticator;
 Ljava/net/DatagramSocket;->impl:Ljava/net/DatagramSocketImpl;
 Ljava/net/InetAddress;->clearDnsCache()V
@@ -1432,9 +1536,18 @@
 Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress;
 Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
 Ljava/net/URI;->host:Ljava/lang/String;
+Ljava/nio/Buffer;->address:J
+Ljava/nio/Buffer;->capacity:I
+Ljava/nio/Buffer;->limit:I
+Ljava/nio/ByteBuffer;->hb:[B
+Ljava/nio/ByteBuffer;->isReadOnly:Z
+Ljava/nio/ByteBuffer;->offset:I
 Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z
+Ljava/nio/DirectByteBuffer;-><init>(JI)V
 Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
 Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
+Ljava/util/ArrayList;->elementData:[Ljava/lang/Object;
+Ljava/util/ArrayList;->size:I
 Ljava/util/ArrayList$SubList;->parent:Ljava/util/AbstractList;
 Ljava/util/ArrayList$SubList;->parentOffset:I
 Ljava/util/ArrayList$SubList;->size:I
@@ -1444,6 +1557,7 @@
 Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
 Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
 Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
+Llibcore/util/ZoneInfo;->mTransitions:[J
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
 Lorg/json/JSONArray;->values:Ljava/util/List;
 Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index aca8d48..0bc510a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6362,8 +6362,6 @@
         } else {
             writer.print(prefix); writer.println("No AutofillManager");
         }
-
-        ResourcesManager.getInstance().dump(prefix, writer);
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 5ee7ede..4626cb2 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -348,4 +348,9 @@
      * Returns is the caller has the same uid as the Recents component
      */
     public abstract boolean isCallerRecents(int callingUid);
+
+    /**
+     * Whether an UID is active or idle.
+     */
+    public abstract boolean isUidActive(int uid);
 }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index b96e028..fb11272 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -21,7 +21,6 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ActivityInfo;
-import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.content.res.CompatResources;
 import android.content.res.CompatibilityInfo;
@@ -35,7 +34,6 @@
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.Log;
-import android.util.LruCache;
 import android.util.Pair;
 import android.util.Slog;
 import android.view.Display;
@@ -43,13 +41,9 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.IndentingPrintWriter;
 
-import java.io.IOException;
-import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Objects;
 import java.util.WeakHashMap;
 import java.util.function.Predicate;
@@ -65,7 +59,12 @@
      * Predicate that returns true if a WeakReference is gc'ed.
      */
     private static final Predicate<WeakReference<Resources>> sEmptyReferencePredicate =
-            weakRef -> weakRef == null || weakRef.get() == null;
+            new Predicate<WeakReference<Resources>>() {
+                @Override
+                public boolean test(WeakReference<Resources> weakRef) {
+                    return weakRef == null || weakRef.get() == null;
+                }
+            };
 
     /**
      * The global compatibility settings.
@@ -90,48 +89,6 @@
      */
     private final ArrayList<WeakReference<Resources>> mResourceReferences = new ArrayList<>();
 
-    private static class ApkKey {
-        public final String path;
-        public final boolean sharedLib;
-        public final boolean overlay;
-
-        ApkKey(String path, boolean sharedLib, boolean overlay) {
-            this.path = path;
-            this.sharedLib = sharedLib;
-            this.overlay = overlay;
-        }
-
-        @Override
-        public int hashCode() {
-            int result = 1;
-            result = 31 * result + this.path.hashCode();
-            result = 31 * result + Boolean.hashCode(this.sharedLib);
-            result = 31 * result + Boolean.hashCode(this.overlay);
-            return result;
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof ApkKey)) {
-                return false;
-            }
-            ApkKey other = (ApkKey) obj;
-            return this.path.equals(other.path) && this.sharedLib == other.sharedLib
-                    && this.overlay == other.overlay;
-        }
-    }
-
-    /**
-     * The ApkAssets we are caching and intend to hold strong references to.
-     */
-    private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(15);
-
-    /**
-     * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't
-     * in our LRU cache. Bonus resources :)
-     */
-    private final ArrayMap<ApkKey, WeakReference<ApkAssets>> mCachedApkAssets = new ArrayMap<>();
-
     /**
      * Resources and base configuration override associated with an Activity.
      */
@@ -303,41 +260,6 @@
         }
     }
 
-    private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay)
-            throws IOException {
-        final ApkKey newKey = new ApkKey(path, sharedLib, overlay);
-        ApkAssets apkAssets = mLoadedApkAssets.get(newKey);
-        if (apkAssets != null) {
-            return apkAssets;
-        }
-
-        // Optimistically check if this ApkAssets exists somewhere else.
-        final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey);
-        if (apkAssetsRef != null) {
-            apkAssets = apkAssetsRef.get();
-            if (apkAssets != null) {
-                mLoadedApkAssets.put(newKey, apkAssets);
-                return apkAssets;
-            } else {
-                // Clean up the reference.
-                mCachedApkAssets.remove(newKey);
-            }
-        }
-
-        // We must load this from disk.
-        if (overlay) {
-            final String idmapPath = "/data/resource-cache/"
-                    + path.substring(1).replace('/', '@')
-                    + "@idmap";
-            apkAssets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/);
-        } else {
-            apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib);
-        }
-        mLoadedApkAssets.put(newKey, apkAssets);
-        mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets));
-        return apkAssets;
-    }
-
     /**
      * Creates an AssetManager from the paths within the ResourcesKey.
      *
@@ -348,15 +270,13 @@
     */
     @VisibleForTesting
     protected @Nullable AssetManager createAssetManager(@NonNull final ResourcesKey key) {
-        final ArrayList<ApkAssets> apkAssets = new ArrayList<>();
+        AssetManager assets = new AssetManager();
 
         // resDir can be null if the 'android' package is creating a new Resources object.
         // This is fine, since each AssetManager automatically loads the 'android' package
         // already.
         if (key.mResDir != null) {
-            try {
-                apkAssets.add(loadApkAssets(key.mResDir, false /*sharedLib*/, false /*overlay*/));
-            } catch (IOException e) {
+            if (assets.addAssetPath(key.mResDir) == 0) {
                 Log.e(TAG, "failed to add asset path " + key.mResDir);
                 return null;
             }
@@ -364,10 +284,7 @@
 
         if (key.mSplitResDirs != null) {
             for (final String splitResDir : key.mSplitResDirs) {
-                try {
-                    apkAssets.add(loadApkAssets(splitResDir, false /*sharedLib*/,
-                            false /*overlay*/));
-                } catch (IOException e) {
+                if (assets.addAssetPath(splitResDir) == 0) {
                     Log.e(TAG, "failed to add split asset path " + splitResDir);
                     return null;
                 }
@@ -376,13 +293,7 @@
 
         if (key.mOverlayDirs != null) {
             for (final String idmapPath : key.mOverlayDirs) {
-                try {
-                    apkAssets.add(loadApkAssets(idmapPath, false /*sharedLib*/, true /*overlay*/));
-                } catch (IOException e) {
-                    Log.w(TAG, "failed to add overlay path " + idmapPath);
-
-                    // continue.
-                }
+                assets.addOverlayPath(idmapPath);
             }
         }
 
@@ -391,77 +302,16 @@
                 if (libDir.endsWith(".apk")) {
                     // Avoid opening files we know do not have resources,
                     // like code-only .jar files.
-                    try {
-                        apkAssets.add(loadApkAssets(libDir, true /*sharedLib*/, false /*overlay*/));
-                    } catch (IOException e) {
+                    if (assets.addAssetPathAsSharedLibrary(libDir) == 0) {
                         Log.w(TAG, "Asset path '" + libDir +
                                 "' does not exist or contains no resources.");
-
-                        // continue.
                     }
                 }
             }
         }
-
-        AssetManager assets = new AssetManager();
-        assets.setApkAssets(apkAssets.toArray(new ApkAssets[apkAssets.size()]),
-                false /*invalidateCaches*/);
         return assets;
     }
 
-    private static <T> int countLiveReferences(Collection<WeakReference<T>> collection) {
-        int count = 0;
-        for (WeakReference<T> ref : collection) {
-            final T value = ref != null ? ref.get() : null;
-            if (value != null) {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    /**
-     * @hide
-     */
-    public void dump(String prefix, PrintWriter printWriter) {
-        synchronized (this) {
-            IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
-            for (int i = 0; i < prefix.length() / 2; i++) {
-                pw.increaseIndent();
-            }
-
-            pw.println("ResourcesManager:");
-            pw.increaseIndent();
-            pw.print("cached apks: total=");
-            pw.print(mLoadedApkAssets.size());
-            pw.print(" created=");
-            pw.print(mLoadedApkAssets.createCount());
-            pw.print(" evicted=");
-            pw.print(mLoadedApkAssets.evictionCount());
-            pw.print(" hit=");
-            pw.print(mLoadedApkAssets.hitCount());
-            pw.print(" miss=");
-            pw.print(mLoadedApkAssets.missCount());
-            pw.print(" max=");
-            pw.print(mLoadedApkAssets.maxSize());
-            pw.println();
-
-            pw.print("total apks: ");
-            pw.println(countLiveReferences(mCachedApkAssets.values()));
-
-            pw.print("resources: ");
-
-            int references = countLiveReferences(mResourceReferences);
-            for (ActivityResources activityResources : mActivityResourceReferences.values()) {
-                references += countLiveReferences(activityResources.activityResources);
-            }
-            pw.println(references);
-
-            pw.print("resource impls: ");
-            pw.println(countLiveReferences(mResourceImpls.values()));
-        }
-    }
-
     private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) {
         Configuration config;
         final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY);
@@ -780,16 +630,28 @@
 
                 // We will create the ResourcesImpl object outside of holding this lock.
             }
+        }
 
-            // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
-            ResourcesImpl resourcesImpl = createResourcesImpl(key);
-            if (resourcesImpl == null) {
-                return null;
+        // If we're here, we didn't find a suitable ResourcesImpl to use, so create one now.
+        ResourcesImpl resourcesImpl = createResourcesImpl(key);
+        if (resourcesImpl == null) {
+            return null;
+        }
+
+        synchronized (this) {
+            ResourcesImpl existingResourcesImpl = findResourcesImplForKeyLocked(key);
+            if (existingResourcesImpl != null) {
+                if (DEBUG) {
+                    Slog.d(TAG, "- got beat! existing impl=" + existingResourcesImpl
+                            + " new impl=" + resourcesImpl);
+                }
+                resourcesImpl.getAssets().close();
+                resourcesImpl = existingResourcesImpl;
+            } else {
+                // Add this ResourcesImpl to the cache.
+                mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
             }
 
-            // Add this ResourcesImpl to the cache.
-            mResourceImpls.put(key, new WeakReference<>(resourcesImpl));
-
             final Resources resources;
             if (activityToken != null) {
                 resources = getOrCreateResourcesForActivityLocked(activityToken, classLoader,
diff --git a/core/java/android/app/timezone/RulesManager.java b/core/java/android/app/timezone/RulesManager.java
index 0a38eb9..dc79256 100644
--- a/core/java/android/app/timezone/RulesManager.java
+++ b/core/java/android/app/timezone/RulesManager.java
@@ -68,6 +68,23 @@
     private static final String TAG = "timezone.RulesManager";
     private static final boolean DEBUG = false;
 
+    /**
+     * The action of the intent that the Android system will broadcast when a time zone rules update
+     * operation has been successfully staged  (i.e. to be applied next reboot) or unstaged.
+     *
+     * <p>See {@link #EXTRA_OPERATION_STAGED}
+     *
+     * <p>This is a protected intent that can only be sent by the system.
+     */
+    public static final String ACTION_RULES_UPDATE_OPERATION =
+            "com.android.intent.action.timezone.RULES_UPDATE_OPERATION";
+
+    /**
+     * The key for a boolean extra for the {@link #ACTION_RULES_UPDATE_OPERATION} intent used to
+     * indicate whether the operation was a "stage" or an "unstage".
+     */
+    public static final String EXTRA_OPERATION_STAGED = "staged";
+
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "SUCCESS", "ERROR_" }, value = {
             SUCCESS,
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 377942a..dda4167 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -54,7 +54,6 @@
 import android.content.pm.split.DefaultSplitAssetLoader;
 import android.content.pm.split.SplitAssetDependencyLoader;
 import android.content.pm.split.SplitAssetLoader;
-import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -1287,6 +1286,7 @@
      */
     @Deprecated
     public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
+        final AssetManager assets = newConfiguredAssetManager();
         final PackageLite lite = parseMonolithicPackageLite(apkFile, flags);
         if (mOnlyCoreApps) {
             if (!lite.coreApp) {
@@ -1295,9 +1295,8 @@
             }
         }
 
-        final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
         try {
-            final Package pkg = parseBaseApk(apkFile, assetLoader.getBaseAssetManager(), flags);
+            final Package pkg = parseBaseApk(apkFile, assets, flags);
             pkg.setCodePath(apkFile.getCanonicalPath());
             pkg.setUse32bitAbi(lite.use32bitAbi);
             return pkg;
@@ -1305,10 +1304,28 @@
             throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
                     "Failed to get path: " + apkFile, e);
         } finally {
-            IoUtils.closeQuietly(assetLoader);
+            IoUtils.closeQuietly(assets);
         }
     }
 
+    private static int loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
+            throws PackageParserException {
+        if ((flags & PARSE_MUST_BE_APK) != 0 && !isApkPath(apkPath)) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "Invalid package file: " + apkPath);
+        }
+
+        // The AssetManager guarantees uniqueness for asset paths, so if this asset path
+        // already exists in the AssetManager, addAssetPath will only return the cookie
+        // assigned to it.
+        int cookie = assets.addAssetPath(apkPath);
+        if (cookie == 0) {
+            throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Failed adding asset path: " + apkPath);
+        }
+        return cookie;
+    }
+
     private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
             throws PackageParserException {
         final String apkPath = apkFile.getAbsolutePath();
@@ -1324,15 +1341,13 @@
 
         if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath);
 
+        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
+
+        Resources res = null;
         XmlResourceParser parser = null;
         try {
-            final int cookie = assets.findCookieForPath(apkPath);
-            if (cookie == 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                        "Failed adding asset path: " + apkPath);
-            }
+            res = new Resources(assets, mMetrics, null);
             parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
-            final Resources res = new Resources(assets, mMetrics, null);
 
             final String[] outError = new String[1];
             final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
@@ -1367,18 +1382,15 @@
 
         if (DEBUG_JAR) Slog.d(TAG, "Scanning split APK: " + apkPath);
 
+        final int cookie = loadApkIntoAssetManager(assets, apkPath, flags);
+
         final Resources res;
         XmlResourceParser parser = null;
         try {
-            // This must always succeed, as the path has been added to the AssetManager before.
-            final int cookie = assets.findCookieForPath(apkPath);
-            if (cookie == 0) {
-                throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
-                        "Failed adding asset path: " + apkPath);
-            }
-
-            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
             res = new Resources(assets, mMetrics, null);
+            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    Build.VERSION.RESOURCES_SDK_INT);
+            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
 
             final String[] outError = new String[1];
             pkg = parseSplitApk(pkg, res, parser, flags, splitIndex, outError);
@@ -1580,19 +1592,21 @@
             int flags) throws PackageParserException {
         final String apkPath = fd != null ? debugPathName : apkFile.getAbsolutePath();
 
+        AssetManager assets = null;
         XmlResourceParser parser = null;
         try {
-            final ApkAssets apkAssets;
-            try {
-                apkAssets = fd != null
-                        ? ApkAssets.loadFromFd(fd, debugPathName, false, false)
-                        : ApkAssets.loadFromPath(apkPath);
-            } catch (IOException e) {
+            assets = newConfiguredAssetManager();
+            int cookie = fd != null
+                    ? assets.addAssetFd(fd, debugPathName) : assets.addAssetPath(apkPath);
+            if (cookie == 0) {
                 throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                         "Failed to parse " + apkPath);
             }
 
-            parser = apkAssets.openXml(ANDROID_MANIFEST_FILENAME);
+            final DisplayMetrics metrics = new DisplayMetrics();
+            metrics.setToDefaults();
+
+            parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);
 
             final SigningDetails signingDetails;
             if ((flags & PARSE_COLLECT_CERTIFICATES) != 0) {
@@ -1619,7 +1633,7 @@
                     "Failed to parse " + apkPath, e);
         } finally {
             IoUtils.closeQuietly(parser);
-            // TODO(b/72056911): Implement and call close() on ApkAssets.
+            IoUtils.closeQuietly(assets);
         }
     }
 
diff --git a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
index 9e3a8f4..99eb470 100644
--- a/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
+++ b/core/java/android/content/pm/split/DefaultSplitAssetLoader.java
@@ -15,13 +15,10 @@
  */
 package android.content.pm.split;
 
-import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
 
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.ParseFlags;
-import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.os.Build;
 
@@ -29,8 +26,6 @@
 
 import libcore.io.IoUtils;
 
-import java.io.IOException;
-
 /**
  * Loads the base and split APKs into a single AssetManager.
  * @hide
@@ -38,66 +33,68 @@
 public class DefaultSplitAssetLoader implements SplitAssetLoader {
     private final String mBaseCodePath;
     private final String[] mSplitCodePaths;
-    private final @ParseFlags int mFlags;
+    private final int mFlags;
+
     private AssetManager mCachedAssetManager;
 
-    public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) {
+    public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) {
         mBaseCodePath = pkg.baseCodePath;
         mSplitCodePaths = pkg.splitCodePaths;
         mFlags = flags;
     }
 
-    private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
-            throws PackageParserException {
-        if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
-                    "Invalid package file: " + path);
+    private static void loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
+            throws PackageParser.PackageParserException {
+        if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(apkPath)) {
+            throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                    "Invalid package file: " + apkPath);
         }
 
-        try {
-            return ApkAssets.loadFromPath(path);
-        } catch (IOException e) {
-            throw new PackageParserException(INSTALL_FAILED_INVALID_APK,
-                    "Failed to load APK at path " + path, e);
+        if (assets.addAssetPath(apkPath) == 0) {
+            throw new PackageParser.PackageParserException(
+                    INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                    "Failed adding asset path: " + apkPath);
         }
     }
 
     @Override
-    public AssetManager getBaseAssetManager() throws PackageParserException {
+    public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
         if (mCachedAssetManager != null) {
             return mCachedAssetManager;
         }
 
-        ApkAssets[] apkAssets = new ApkAssets[(mSplitCodePaths != null
-                ? mSplitCodePaths.length : 0) + 1];
+        AssetManager assets = new AssetManager();
+        try {
+            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    Build.VERSION.RESOURCES_SDK_INT);
+            loadApkIntoAssetManager(assets, mBaseCodePath, mFlags);
 
-        // Load the base.
-        int splitIdx = 0;
-        apkAssets[splitIdx++] = loadApkAssets(mBaseCodePath, mFlags);
+            if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
+                for (String apkPath : mSplitCodePaths) {
+                    loadApkIntoAssetManager(assets, apkPath, mFlags);
+                }
+            }
 
-        // Load any splits.
-        if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
-            for (String apkPath : mSplitCodePaths) {
-                apkAssets[splitIdx++] = loadApkAssets(apkPath, mFlags);
+            mCachedAssetManager = assets;
+            assets = null;
+            return mCachedAssetManager;
+        } finally {
+            if (assets != null) {
+                IoUtils.closeQuietly(assets);
             }
         }
-
-        AssetManager assets = new AssetManager();
-        assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                Build.VERSION.RESOURCES_SDK_INT);
-        assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
-
-        mCachedAssetManager = assets;
-        return mCachedAssetManager;
     }
 
     @Override
-    public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException {
+    public AssetManager getSplitAssetManager(int splitIdx)
+            throws PackageParser.PackageParserException {
         return getBaseAssetManager();
     }
 
     @Override
     public void close() throws Exception {
-        IoUtils.closeQuietly(mCachedAssetManager);
+        if (mCachedAssetManager != null) {
+            IoUtils.closeQuietly(mCachedAssetManager);
+        }
     }
 }
diff --git a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
index 58eaabf..16023f0 100644
--- a/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
+++ b/core/java/android/content/pm/split/SplitAssetDependencyLoader.java
@@ -15,21 +15,17 @@
  */
 package android.content.pm.split;
 
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
 
 import android.annotation.NonNull;
-import android.content.pm.PackageManager;
 import android.content.pm.PackageParser;
-import android.content.pm.PackageParser.PackageParserException;
-import android.content.pm.PackageParser.ParseFlags;
-import android.content.res.ApkAssets;
 import android.content.res.AssetManager;
 import android.os.Build;
 import android.util.SparseArray;
 
 import libcore.io.IoUtils;
 
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 
@@ -38,15 +34,17 @@
  * is to be used when an application opts-in to isolated split loading.
  * @hide
  */
-public class SplitAssetDependencyLoader extends SplitDependencyLoader<PackageParserException>
+public class SplitAssetDependencyLoader
+        extends SplitDependencyLoader<PackageParser.PackageParserException>
         implements SplitAssetLoader {
     private final String[] mSplitPaths;
-    private final @ParseFlags int mFlags;
-    private final ApkAssets[][] mCachedSplitApks;
-    private final AssetManager[] mCachedAssetManagers;
+    private final int mFlags;
+
+    private String[][] mCachedPaths;
+    private AssetManager[] mCachedAssetManagers;
 
     public SplitAssetDependencyLoader(PackageParser.PackageLite pkg,
-            SparseArray<int[]> dependencies, @ParseFlags int flags) {
+            SparseArray<int[]> dependencies, int flags) {
         super(dependencies);
 
         // The base is inserted into index 0, so we need to shift all the splits by 1.
@@ -55,7 +53,7 @@
         System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length);
 
         mFlags = flags;
-        mCachedSplitApks = new ApkAssets[mSplitPaths.length][];
+        mCachedPaths = new String[mSplitPaths.length][];
         mCachedAssetManagers = new AssetManager[mSplitPaths.length];
     }
 
@@ -64,60 +62,58 @@
         return mCachedAssetManagers[splitIdx] != null;
     }
 
-    private static ApkAssets loadApkAssets(String path, @ParseFlags int flags)
-            throws PackageParserException {
-        if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(path)) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
-                    "Invalid package file: " + path);
-        }
-
-        try {
-            return ApkAssets.loadFromPath(path);
-        } catch (IOException e) {
-            throw new PackageParserException(PackageManager.INSTALL_FAILED_INVALID_APK,
-                    "Failed to load APK at path " + path, e);
-        }
-    }
-
-    private static AssetManager createAssetManagerWithAssets(ApkAssets[] apkAssets) {
+    private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags)
+            throws PackageParser.PackageParserException {
         final AssetManager assets = new AssetManager();
-        assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                Build.VERSION.RESOURCES_SDK_INT);
-        assets.setApkAssets(apkAssets, false /*invalidateCaches*/);
-        return assets;
+        try {
+            assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                    Build.VERSION.RESOURCES_SDK_INT);
+
+            for (String assetPath : assetPaths) {
+                if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 &&
+                        !PackageParser.isApkPath(assetPath)) {
+                    throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
+                            "Invalid package file: " + assetPath);
+                }
+
+                if (assets.addAssetPath(assetPath) == 0) {
+                    throw new PackageParser.PackageParserException(
+                            INSTALL_PARSE_FAILED_BAD_MANIFEST,
+                            "Failed adding asset path: " + assetPath);
+                }
+            }
+            return assets;
+        } catch (Throwable e) {
+            IoUtils.closeQuietly(assets);
+            throw e;
+        }
     }
 
     @Override
     protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices,
-            int parentSplitIdx) throws PackageParserException {
-        final ArrayList<ApkAssets> assets = new ArrayList<>();
-
-        // Include parent ApkAssets.
+            int parentSplitIdx) throws PackageParser.PackageParserException {
+        final ArrayList<String> assetPaths = new ArrayList<>();
         if (parentSplitIdx >= 0) {
-            Collections.addAll(assets, mCachedSplitApks[parentSplitIdx]);
+            Collections.addAll(assetPaths, mCachedPaths[parentSplitIdx]);
         }
 
-        // Include this ApkAssets.
-        assets.add(loadApkAssets(mSplitPaths[splitIdx], mFlags));
-
-        // Load and include all config splits for this feature.
+        assetPaths.add(mSplitPaths[splitIdx]);
         for (int configSplitIdx : configSplitIndices) {
-            assets.add(loadApkAssets(mSplitPaths[configSplitIdx], mFlags));
+            assetPaths.add(mSplitPaths[configSplitIdx]);
         }
-
-        // Cache the results.
-        mCachedSplitApks[splitIdx] = assets.toArray(new ApkAssets[assets.size()]);
-        mCachedAssetManagers[splitIdx] = createAssetManagerWithAssets(mCachedSplitApks[splitIdx]);
+        mCachedPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]);
+        mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedPaths[splitIdx],
+                mFlags);
     }
 
     @Override
-    public AssetManager getBaseAssetManager() throws PackageParserException {
+    public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
         loadDependenciesForSplit(0);
         return mCachedAssetManagers[0];
     }
 
     @Override
-    public AssetManager getSplitAssetManager(int idx) throws PackageParserException {
+    public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException {
         // Since we insert the base at position 0, and PackageParser keeps splits separate from
         // the base, we need to adjust the index.
         loadDependenciesForSplit(idx + 1);
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
deleted file mode 100644
index fd664bc..0000000
--- a/core/java/android/content/res/ApkAssets.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.content.res;
-
-import android.annotation.NonNull;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-/**
- * The loaded, immutable, in-memory representation of an APK.
- *
- * The main implementation is native C++ and there is very little API surface exposed here. The APK
- * is mainly accessed via {@link AssetManager}.
- *
- * Since the ApkAssets instance is immutable, it can be reused and shared across AssetManagers,
- * making the creation of AssetManagers very cheap.
- * @hide
- */
-public final class ApkAssets {
-    @GuardedBy("this") private final long mNativePtr;
-    @GuardedBy("this") private StringBlock mStringBlock;
-
-    /**
-     * Creates a new ApkAssets instance from the given path on disk.
-     *
-     * @param path The path to an APK on disk.
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadFromPath(@NonNull String path) throws IOException {
-        return new ApkAssets(path, false /*system*/, false /*forceSharedLib*/, false /*overlay*/);
-    }
-
-    /**
-     * Creates a new ApkAssets instance from the given path on disk.
-     *
-     * @param path The path to an APK on disk.
-     * @param system When true, the APK is loaded as a system APK (framework).
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system)
-            throws IOException {
-        return new ApkAssets(path, system, false /*forceSharedLib*/, false /*overlay*/);
-    }
-
-    /**
-     * Creates a new ApkAssets instance from the given path on disk.
-     *
-     * @param path The path to an APK on disk.
-     * @param system When true, the APK is loaded as a system APK (framework).
-     * @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
-     *                           loaded as a shared library.
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadFromPath(@NonNull String path, boolean system,
-            boolean forceSharedLibrary) throws IOException {
-        return new ApkAssets(path, system, forceSharedLibrary, false /*overlay*/);
-    }
-
-    /**
-     * Creates a new ApkAssets instance from the given file descriptor. Not for use by applications.
-     *
-     * Performs a dup of the underlying fd, so you must take care of still closing
-     * the FileDescriptor yourself (and can do that whenever you want).
-     *
-     * @param fd The FileDescriptor of an open, readable APK.
-     * @param friendlyName The friendly name used to identify this ApkAssets when logging.
-     * @param system When true, the APK is loaded as a system APK (framework).
-     * @param forceSharedLibrary When true, any packages within the APK with package ID 0x7f are
-     *                           loaded as a shared library.
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadFromFd(@NonNull FileDescriptor fd,
-            @NonNull String friendlyName, boolean system, boolean forceSharedLibrary)
-            throws IOException {
-        return new ApkAssets(fd, friendlyName, system, forceSharedLibrary);
-    }
-
-    /**
-     * Creates a new ApkAssets instance from the IDMAP at idmapPath. The overlay APK path
-     * is encoded within the IDMAP.
-     *
-     * @param idmapPath Path to the IDMAP of an overlay APK.
-     * @param system When true, the APK is loaded as a system APK (framework).
-     * @return a new instance of ApkAssets.
-     * @throws IOException if a disk I/O error or parsing error occurred.
-     */
-    public static @NonNull ApkAssets loadOverlayFromPath(@NonNull String idmapPath, boolean system)
-            throws IOException {
-        return new ApkAssets(idmapPath, system, false /*forceSharedLibrary*/, true /*overlay*/);
-    }
-
-    private ApkAssets(@NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
-            throws IOException {
-        Preconditions.checkNotNull(path, "path");
-        mNativePtr = nativeLoad(path, system, forceSharedLib, overlay);
-        mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
-    }
-
-    private ApkAssets(@NonNull FileDescriptor fd, @NonNull String friendlyName, boolean system,
-            boolean forceSharedLib) throws IOException {
-        Preconditions.checkNotNull(fd, "fd");
-        Preconditions.checkNotNull(friendlyName, "friendlyName");
-        mNativePtr = nativeLoadFromFd(fd, friendlyName, system, forceSharedLib);
-        mStringBlock = new StringBlock(nativeGetStringBlock(mNativePtr), true /*useSparse*/);
-    }
-
-    @NonNull String getAssetPath() {
-        synchronized (this) {
-            return nativeGetAssetPath(mNativePtr);
-        }
-    }
-
-    CharSequence getStringFromPool(int idx) {
-        synchronized (this) {
-            return mStringBlock.get(idx);
-        }
-    }
-
-    /**
-     * Retrieve a parser for a compiled XML file. This is associated with a single APK and
-     * <em>NOT</em> a full AssetManager. This means that shared-library references will not be
-     * dynamically assigned runtime package IDs.
-     *
-     * @param fileName The path to the file within the APK.
-     * @return An XmlResourceParser.
-     * @throws IOException if the file was not found or an error occurred retrieving it.
-     */
-    public @NonNull XmlResourceParser openXml(@NonNull String fileName) throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
-        synchronized (this) {
-            long nativeXmlPtr = nativeOpenXml(mNativePtr, fileName);
-            try (XmlBlock block = new XmlBlock(null, nativeXmlPtr)) {
-                XmlResourceParser parser = block.newParser();
-                // If nativeOpenXml doesn't throw, it will always return a valid native pointer,
-                // which makes newParser always return non-null. But let's be paranoid.
-                if (parser == null) {
-                    throw new AssertionError("block.newParser() returned a null parser");
-                }
-                return parser;
-            }
-        }
-    }
-
-    /**
-     * Returns false if the underlying APK was changed since this ApkAssets was loaded.
-     */
-    public boolean isUpToDate() {
-        synchronized (this) {
-            return nativeIsUpToDate(mNativePtr);
-        }
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        nativeDestroy(mNativePtr);
-    }
-
-    private static native long nativeLoad(
-            @NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
-            throws IOException;
-    private static native long nativeLoadFromFd(@NonNull FileDescriptor fd,
-            @NonNull String friendlyName, boolean system, boolean forceSharedLib)
-            throws IOException;
-    private static native void nativeDestroy(long ptr);
-    private static native @NonNull String nativeGetAssetPath(long ptr);
-    private static native long nativeGetStringBlock(long ptr);
-    private static native boolean nativeIsUpToDate(long ptr);
-    private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
-}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index bb90700..5f8a34d 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -18,11 +18,9 @@
 
 import android.annotation.AnyRes;
 import android.annotation.ArrayRes;
-import android.annotation.AttrRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
-import android.annotation.StyleRes;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration.NativeConfig;
 import android.os.ParcelFileDescriptor;
@@ -31,19 +29,11 @@
 import android.util.TypedValue;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
-import libcore.io.IoUtils;
-
-import java.io.BufferedReader;
-import java.io.FileInputStream;
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.channels.FileLock;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 
 /**
@@ -54,19 +44,7 @@
  * bytes.
  */
 public final class AssetManager implements AutoCloseable {
-    private static final String TAG = "AssetManager";
-    private static final boolean DEBUG_REFS = false;
-
-    private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk";
-
-    private static final Object sSync = new Object();
-
-    private static final ApkAssets[] sEmptyApkAssets = new ApkAssets[0];
-
-    // Not private for LayoutLib's BridgeAssetManager.
-    @GuardedBy("sSync") static AssetManager sSystem = null;
-
-    @GuardedBy("sSync") private static ApkAssets[] sSystemApkAssets = new ApkAssets[0];
+    /* modes used when opening an asset */
 
     /**
      * Mode for {@link #open(String, int)}: no specific information about how
@@ -89,335 +67,88 @@
      */
     public static final int ACCESS_BUFFER = 3;
 
-    @GuardedBy("this") private final TypedValue mValue = new TypedValue();
-    @GuardedBy("this") private final long[] mOffsets = new long[2];
+    private static final String TAG = "AssetManager";
+    private static final boolean localLOGV = false || false;
+    
+    private static final boolean DEBUG_REFS = false;
+    
+    private static final Object sSync = new Object();
+    /*package*/ static AssetManager sSystem = null;
 
-    // Pointer to native implementation, stuffed inside a long.
-    @GuardedBy("this") private long mObject;
+    private final TypedValue mValue = new TypedValue();
+    private final long[] mOffsets = new long[2];
+    
+    // For communication with native code.
+    private long mObject;
 
-    // The loaded asset paths.
-    @GuardedBy("this") private ApkAssets[] mApkAssets;
-
-    // Debug/reference counting implementation.
-    @GuardedBy("this") private boolean mOpen = true;
-    @GuardedBy("this") private int mNumRefs = 1;
-    @GuardedBy("this") private HashMap<Long, RuntimeException> mRefStacks;
-
+    private StringBlock mStringBlocks[] = null;
+    
+    private int mNumRefs = 1;
+    private boolean mOpen = true;
+    private HashMap<Long, RuntimeException> mRefStacks;
+ 
     /**
      * Create a new AssetManager containing only the basic system assets.
      * Applications will not generally use this method, instead retrieving the
      * appropriate asset manager with {@link Resources#getAssets}.    Not for
      * use by applications.
-     * @hide
+     * {@hide}
      */
     public AssetManager() {
-        final ApkAssets[] assets;
-        synchronized (sSync) {
-            createSystemAssetsInZygoteLocked();
-            assets = sSystemApkAssets;
-        }
-
-        mObject = nativeCreate();
-        if (DEBUG_REFS) {
-            mNumRefs = 0;
-            incRefsLocked(hashCode());
-        }
-
-        // Always set the framework resources.
-        setApkAssets(assets, false /*invalidateCaches*/);
-    }
-
-    /**
-     * Private constructor that doesn't call ensureSystemAssets.
-     * Used for the creation of system assets.
-     */
-    @SuppressWarnings("unused")
-    private AssetManager(boolean sentinel) {
-        mObject = nativeCreate();
-        if (DEBUG_REFS) {
-            mNumRefs = 0;
-            incRefsLocked(hashCode());
-        }
-    }
-
-    /**
-     * This must be called from Zygote so that system assets are shared by all applications.
-     */
-    @GuardedBy("sSync")
-    private static void createSystemAssetsInZygoteLocked() {
-        if (sSystem != null) {
-            return;
-        }
-
-        // Make sure that all IDMAPs are up to date.
-        nativeVerifySystemIdmaps();
-
-        try {
-            ArrayList<ApkAssets> apkAssets = new ArrayList<>();
-            apkAssets.add(ApkAssets.loadFromPath(FRAMEWORK_APK_PATH, true /*system*/));
-            loadStaticRuntimeOverlays(apkAssets);
-
-            sSystemApkAssets = apkAssets.toArray(new ApkAssets[apkAssets.size()]);
-            sSystem = new AssetManager(true /*sentinel*/);
-            sSystem.setApkAssets(sSystemApkAssets, false /*invalidateCaches*/);
-        } catch (IOException e) {
-            throw new IllegalStateException("Failed to create system AssetManager", e);
-        }
-    }
-
-    /**
-     * Loads the static runtime overlays declared in /data/resource-cache/overlays.list.
-     * Throws an exception if the file is corrupt or if loading the APKs referenced by the file
-     * fails. Returns quietly if the overlays.list file doesn't exist.
-     * @param outApkAssets The list to fill with the loaded ApkAssets.
-     */
-    private static void loadStaticRuntimeOverlays(ArrayList<ApkAssets> outApkAssets)
-            throws IOException {
-        final FileInputStream fis;
-        try {
-            fis = new FileInputStream("/data/resource-cache/overlays.list");
-        } catch (FileNotFoundException e) {
-            // We might not have any overlays, this is fine. We catch here since ApkAssets
-            // loading can also fail with the same exception, which we would want to propagate.
-            Log.i(TAG, "no overlays.list file found");
-            return;
-        }
-
-        try {
-            // Acquire a lock so that any idmap scanning doesn't impact the current set.
-            // The order of this try-with-resources block matters. We must release the lock, and
-            // then close the file streams when exiting the block.
-            try (final BufferedReader br = new BufferedReader(new InputStreamReader(fis));
-                 final FileLock flock = fis.getChannel().lock(0, Long.MAX_VALUE, true /*shared*/)) {
-                for (String line; (line = br.readLine()) != null; ) {
-                    final String idmapPath = line.split(" ")[1];
-                    outApkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, true /*system*/));
-                }
+        synchronized (this) {
+            if (DEBUG_REFS) {
+                mNumRefs = 0;
+                incRefsLocked(this.hashCode());
             }
-        } finally {
-            // When BufferedReader is closed above, FileInputStream is closed as well. But let's be
-            // paranoid.
-            IoUtils.closeQuietly(fis);
+            init(false);
+            if (localLOGV) Log.v(TAG, "New asset manager: " + this);
+            ensureSystemAssets();
         }
     }
 
+    private static void ensureSystemAssets() {
+        synchronized (sSync) {
+            if (sSystem == null) {
+                AssetManager system = new AssetManager(true);
+                system.makeStringBlocks(null);
+                sSystem = system;
+            }
+        }
+    }
+    
+    private AssetManager(boolean isSystem) {
+        if (DEBUG_REFS) {
+            synchronized (this) {
+                mNumRefs = 0;
+                incRefsLocked(this.hashCode());
+            }
+        }
+        init(true);
+        if (localLOGV) Log.v(TAG, "New asset manager: " + this);
+    }
+
     /**
      * Return a global shared asset manager that provides access to only
      * system assets (no application assets).
-     * @hide
+     * {@hide}
      */
     public static AssetManager getSystem() {
-        synchronized (sSync) {
-            createSystemAssetsInZygoteLocked();
-            return sSystem;
-        }
+        ensureSystemAssets();
+        return sSystem;
     }
 
     /**
      * Close this asset manager.
      */
-    @Override
     public void close() {
-        synchronized (this) {
-            if (!mOpen) {
-                return;
-            }
-
-            mOpen = false;
-            decRefsLocked(hashCode());
-        }
-    }
-
-    /**
-     * Changes the asset paths in this AssetManager. This replaces the {@link #addAssetPath(String)}
-     * family of methods.
-     *
-     * @param apkAssets The new set of paths.
-     * @param invalidateCaches Whether to invalidate any caches. This should almost always be true.
-     *                         Set this to false if you are appending new resources
-     *                         (not new configurations).
-     * @hide
-     */
-    public void setApkAssets(@NonNull ApkAssets[] apkAssets, boolean invalidateCaches) {
-        Preconditions.checkNotNull(apkAssets, "apkAssets");
-
-        // Copy the apkAssets, but prepend the system assets (framework + overlays).
-        final ApkAssets[] newApkAssets = new ApkAssets[apkAssets.length + sSystemApkAssets.length];
-        System.arraycopy(sSystemApkAssets, 0, newApkAssets, 0, sSystemApkAssets.length);
-        System.arraycopy(apkAssets, 0, newApkAssets, sSystemApkAssets.length, apkAssets.length);
-
-        synchronized (this) {
-            ensureOpenLocked();
-            mApkAssets = newApkAssets;
-            nativeSetApkAssets(mObject, mApkAssets, invalidateCaches);
-            if (invalidateCaches) {
-                // Invalidate all caches.
-                invalidateCachesLocked(-1);
-            }
-        }
-    }
-
-    /**
-     * Invalidates the caches in this AssetManager according to the bitmask `diff`.
-     *
-     * @param diff The bitmask of changes generated by {@link Configuration#diff(Configuration)}.
-     * @see ActivityInfo.Config
-     */
-    private void invalidateCachesLocked(int diff) {
-        // TODO(adamlesinski): Currently there are no caches to invalidate in Java code.
-    }
-
-    /**
-     * Returns the set of ApkAssets loaded by this AssetManager. If the AssetManager is closed, this
-     * returns a 0-length array.
-     * @hide
-     */
-    public @NonNull ApkAssets[] getApkAssets() {
-        synchronized (this) {
+        synchronized(this) {
+            //System.out.println("Release: num=" + mNumRefs
+            //                   + ", released=" + mReleased);
             if (mOpen) {
-                return mApkAssets;
+                mOpen = false;
+                decRefsLocked(this.hashCode());
             }
         }
-        return sEmptyApkAssets;
-    }
-
-    /**
-     * Returns a cookie for use with the other APIs of AssetManager.
-     * @return 0 if the path was not found, otherwise a positive integer cookie representing
-     * this path in the AssetManager.
-     * @hide
-     */
-    public int findCookieForPath(@NonNull String path) {
-        Preconditions.checkNotNull(path, "path");
-        synchronized (this) {
-            ensureValidLocked();
-            final int count = mApkAssets.length;
-            for (int i = 0; i < count; i++) {
-                if (path.equals(mApkAssets[i].getAssetPath())) {
-                    return i + 1;
-                }
-            }
-        }
-        return 0;
-    }
-
-    /**
-     * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
-     * @hide
-     */
-    @Deprecated
-    public int addAssetPath(String path) {
-        return addAssetPathInternal(path, false /*overlay*/, false /*appAsLib*/);
-    }
-
-    /**
-     * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
-     * @hide
-     */
-    @Deprecated
-    public int addAssetPathAsSharedLibrary(String path) {
-        return addAssetPathInternal(path, false /*overlay*/, true /*appAsLib*/);
-    }
-
-    /**
-     * @deprecated Use {@link #setApkAssets(ApkAssets[], boolean)}
-     * @hide
-     */
-    @Deprecated
-    public int addOverlayPath(String path) {
-        return addAssetPathInternal(path, true /*overlay*/, false /*appAsLib*/);
-    }
-
-    private int addAssetPathInternal(String path, boolean overlay, boolean appAsLib) {
-        Preconditions.checkNotNull(path, "path");
-        synchronized (this) {
-            ensureOpenLocked();
-            final int count = mApkAssets.length;
-            for (int i = 0; i < count; i++) {
-                if (mApkAssets[i].getAssetPath().equals(path)) {
-                    return i + 1;
-                }
-            }
-
-            final ApkAssets assets;
-            try {
-                if (overlay) {
-                    // TODO(b/70343104): This hardcoded path will be removed once
-                    // addAssetPathInternal is deleted.
-                    final String idmapPath = "/data/resource-cache/"
-                            + path.substring(1).replace('/', '@')
-                            + "@idmap";
-                    assets = ApkAssets.loadOverlayFromPath(idmapPath, false /*system*/);
-                } else {
-                    assets = ApkAssets.loadFromPath(path, false /*system*/, appAsLib);
-                }
-            } catch (IOException e) {
-                return 0;
-            }
-
-            final ApkAssets[] newApkAssets = Arrays.copyOf(mApkAssets, count + 1);
-            newApkAssets[count] = assets;
-            setApkAssets(newApkAssets, true);
-            return count + 1;
-        }
-    }
-
-    /**
-     * Ensures that the native implementation has not been destroyed.
-     * The AssetManager may have been closed, but references to it still exist
-     * and therefore the native implementation is not destroyed.
-     */
-    @GuardedBy("this")
-    private void ensureValidLocked() {
-        if (mObject == 0) {
-            throw new RuntimeException("AssetManager has been destroyed");
-        }
-    }
-
-    /**
-     * Ensures that the AssetManager has not been explicitly closed. If this method passes,
-     * then this implies that ensureValidLocked() also passes.
-     */
-    @GuardedBy("this")
-    private void ensureOpenLocked() {
-        // If mOpen is true, this implies that mObject != 0.
-        if (!mOpen) {
-            throw new RuntimeException("AssetManager has been closed");
-        }
-    }
-
-    /**
-     * Populates {@code outValue} with the data associated a particular
-     * resource identifier for the current configuration.
-     *
-     * @param resId the resource identifier to load
-     * @param densityDpi the density bucket for which to load the resource
-     * @param outValue the typed value in which to put the data
-     * @param resolveRefs {@code true} to resolve references, {@code false}
-     *                    to leave them unresolved
-     * @return {@code true} if the data was loaded into {@code outValue},
-     *         {@code false} otherwise
-     */
-    boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
-            boolean resolveRefs) {
-        Preconditions.checkNotNull(outValue, "outValue");
-        synchronized (this) {
-            ensureValidLocked();
-            final int cookie = nativeGetResourceValue(
-                    mObject, resId, (short) densityDpi, outValue, resolveRefs);
-            if (cookie <= 0) {
-                return false;
-            }
-
-            // Convert the changing configurations flags populated by native code.
-            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
-                    outValue.changingConfigurations);
-
-            if (outValue.type == TypedValue.TYPE_STRING) {
-                outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data);
-            }
-            return true;
-        }
     }
 
     /**
@@ -427,7 +158,8 @@
      * @param resId the resource identifier to load
      * @return the string value, or {@code null}
      */
-    @Nullable CharSequence getResourceText(@StringRes int resId) {
+    @Nullable
+    final CharSequence getResourceText(@StringRes int resId) {
         synchronized (this) {
             final TypedValue outValue = mValue;
             if (getResourceValue(resId, 0, outValue, true)) {
@@ -442,15 +174,15 @@
      * identifier for the current configuration.
      *
      * @param resId the resource identifier to load
-     * @param bagEntryId the index into the bag to load
+     * @param bagEntryId
      * @return the string value, or {@code null}
      */
-    @Nullable CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
+    @Nullable
+    final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) {
         synchronized (this) {
-            ensureValidLocked();
             final TypedValue outValue = mValue;
-            final int cookie = nativeGetResourceBagValue(mObject, resId, bagEntryId, outValue);
-            if (cookie <= 0) {
+            final int block = loadResourceBagValue(resId, bagEntryId, outValue, true);
+            if (block < 0) {
                 return null;
             }
 
@@ -459,49 +191,12 @@
                     outValue.changingConfigurations);
 
             if (outValue.type == TypedValue.TYPE_STRING) {
-                return mApkAssets[cookie - 1].getStringFromPool(outValue.data);
+                return mStringBlocks[block].get(outValue.data);
             }
             return outValue.coerceToString();
         }
     }
 
-    int getResourceArraySize(@ArrayRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceArraySize(mObject, resId);
-        }
-    }
-
-    /**
-     * Populates `outData` with array elements of `resId`. `outData` is normally
-     * used with
-     * {@link TypedArray}.
-     *
-     * Each logical element in `outData` is {@link TypedArray#STYLE_NUM_ENTRIES}
-     * long,
-     * with the indices of the data representing the type, value, asset cookie,
-     * resource ID,
-     * configuration change mask, and density of the element.
-     *
-     * @param resId The resource ID of an array resource.
-     * @param outData The array to populate with data.
-     * @return The length of the array.
-     *
-     * @see TypedArray#STYLE_TYPE
-     * @see TypedArray#STYLE_DATA
-     * @see TypedArray#STYLE_ASSET_COOKIE
-     * @see TypedArray#STYLE_RESOURCE_ID
-     * @see TypedArray#STYLE_CHANGING_CONFIGURATIONS
-     * @see TypedArray#STYLE_DENSITY
-     */
-    int getResourceArray(@ArrayRes int resId, @NonNull int[] outData) {
-        Preconditions.checkNotNull(outData, "outData");
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceArray(mObject, resId, outData);
-        }
-    }
-
     /**
      * Retrieves the string array associated with a particular resource
      * identifier for the current configuration.
@@ -509,10 +204,39 @@
      * @param resId the resource identifier of the string array
      * @return the string array, or {@code null}
      */
-    @Nullable String[] getResourceStringArray(@ArrayRes int resId) {
+    @Nullable
+    final String[] getResourceStringArray(@ArrayRes int resId) {
+        return getArrayStringResource(resId);
+    }
+
+    /**
+     * Populates {@code outValue} with the data associated a particular
+     * resource identifier for the current configuration.
+     *
+     * @param resId the resource identifier to load
+     * @param densityDpi the density bucket for which to load the resource
+     * @param outValue the typed value in which to put the data
+     * @param resolveRefs {@code true} to resolve references, {@code false}
+     *                    to leave them unresolved
+     * @return {@code true} if the data was loaded into {@code outValue},
+     *         {@code false} otherwise
+     */
+    final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue,
+            boolean resolveRefs) {
         synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceStringArray(mObject, resId);
+            final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs);
+            if (block < 0) {
+                return false;
+            }
+
+            // Convert the changing configurations flags populated by native code.
+            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+                    outValue.changingConfigurations);
+
+            if (outValue.type == TypedValue.TYPE_STRING) {
+                outValue.string = mStringBlocks[block].get(outValue.data);
+            }
+            return true;
         }
     }
 
@@ -522,48 +246,26 @@
      *
      * @param resId the resource id of the string array
      */
-    @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) {
+    final @Nullable CharSequence[] getResourceTextArray(@ArrayRes int resId) {
         synchronized (this) {
-            ensureValidLocked();
-            final int[] rawInfoArray = nativeGetResourceStringArrayInfo(mObject, resId);
+            final int[] rawInfoArray = getArrayStringInfo(resId);
             if (rawInfoArray == null) {
                 return null;
             }
-
             final int rawInfoArrayLen = rawInfoArray.length;
             final int infoArrayLen = rawInfoArrayLen / 2;
+            int block;
+            int index;
             final CharSequence[] retArray = new CharSequence[infoArrayLen];
             for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
-                int cookie = rawInfoArray[i];
-                int index = rawInfoArray[i + 1];
-                retArray[j] = (index >= 0 && cookie > 0)
-                        ? mApkAssets[cookie - 1].getStringFromPool(index) : null;
+                block = rawInfoArray[i];
+                index = rawInfoArray[i + 1];
+                retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
             }
             return retArray;
         }
     }
 
-    @Nullable int[] getResourceIntArray(@ArrayRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceIntArray(mObject, resId);
-        }
-    }
-
-    /**
-     * Get the attributes for a style resource. These are the &lt;item&gt;
-     * elements in
-     * a &lt;style&gt; resource.
-     * @param resId The resource ID of the style
-     * @return An array of attribute IDs.
-     */
-    @AttrRes int[] getStyleAttributes(@StyleRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetStyleAttributes(mObject, resId);
-        }
-    }
-
     /**
      * Populates {@code outValue} with the data associated with a particular
      * resource identifier for the current configuration. Resolves theme
@@ -577,88 +279,73 @@
      * @return {@code true} if the data was loaded into {@code outValue},
      *         {@code false} otherwise
      */
-    boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
+    final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue,
             boolean resolveRefs) {
-        Preconditions.checkNotNull(outValue, "outValue");
+        final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs);
+        if (block < 0) {
+            return false;
+        }
+
+        // Convert the changing configurations flags populated by native code.
+        outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
+                outValue.changingConfigurations);
+
+        if (outValue.type == TypedValue.TYPE_STRING) {
+            final StringBlock[] blocks = ensureStringBlocks();
+            outValue.string = blocks[block].get(outValue.data);
+        }
+        return true;
+    }
+
+    /**
+     * Ensures the string blocks are loaded.
+     *
+     * @return the string blocks
+     */
+    @NonNull
+    final StringBlock[] ensureStringBlocks() {
         synchronized (this) {
-            ensureValidLocked();
-            final int cookie = nativeThemeGetAttributeValue(mObject, theme, resId, outValue,
-                    resolveRefs);
-            if (cookie <= 0) {
-                return false;
+            if (mStringBlocks == null) {
+                makeStringBlocks(sSystem.mStringBlocks);
             }
+            return mStringBlocks;
+        }
+    }
 
-            // Convert the changing configurations flags populated by native code.
-            outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
-                    outValue.changingConfigurations);
-
-            if (outValue.type == TypedValue.TYPE_STRING) {
-                outValue.string = mApkAssets[cookie - 1].getStringFromPool(outValue.data);
+    /*package*/ final void makeStringBlocks(StringBlock[] seed) {
+        final int seedNum = (seed != null) ? seed.length : 0;
+        final int num = getStringBlockCount();
+        mStringBlocks = new StringBlock[num];
+        if (localLOGV) Log.v(TAG, "Making string blocks for " + this
+                + ": " + num);
+        for (int i=0; i<num; i++) {
+            if (i < seedNum) {
+                mStringBlocks[i] = seed[i];
+            } else {
+                mStringBlocks[i] = new StringBlock(getNativeStringBlock(i), true);
             }
-            return true;
         }
     }
 
-    void dumpTheme(long theme, int priority, String tag, String prefix) {
+    /*package*/ final CharSequence getPooledStringForCookie(int cookie, int id) {
         synchronized (this) {
-            ensureValidLocked();
-            nativeThemeDump(mObject, theme, priority, tag, prefix);
+            // Cookies map to string blocks starting at 1.
+            return mStringBlocks[cookie - 1].get(id);
         }
     }
 
-    @Nullable String getResourceName(@AnyRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceName(mObject, resId);
-        }
-    }
-
-    @Nullable String getResourcePackageName(@AnyRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourcePackageName(mObject, resId);
-        }
-    }
-
-    @Nullable String getResourceTypeName(@AnyRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceTypeName(mObject, resId);
-        }
-    }
-
-    @Nullable String getResourceEntryName(@AnyRes int resId) {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetResourceEntryName(mObject, resId);
-        }
-    }
-
-    @AnyRes int getResourceIdentifier(@NonNull String name, @Nullable String defType,
-            @Nullable String defPackage) {
-        synchronized (this) {
-            ensureValidLocked();
-            // name is checked in JNI.
-            return nativeGetResourceIdentifier(mObject, name, defType, defPackage);
-        }
-    }
-
-    CharSequence getPooledStringForCookie(int cookie, int id) {
-        // Cookies map to ApkAssets starting at 1.
-        return getApkAssets()[cookie - 1].getStringFromPool(id);
-    }
-
     /**
      * Open an asset using ACCESS_STREAMING mode.  This provides access to
      * files that have been bundled with an application as assets -- that is,
      * files placed in to the "assets" directory.
      * 
-     * @param fileName The name of the asset to open.  This name can be hierarchical.
+     * @param fileName The name of the asset to open.  This name can be
+     *                 hierarchical.
      * 
      * @see #open(String, int)
      * @see #list
      */
-    public @NonNull InputStream open(@NonNull String fileName) throws IOException {
+    public final InputStream open(String fileName) throws IOException {
         return open(fileName, ACCESS_STREAMING);
     }
 
@@ -668,7 +355,8 @@
      * with an application as assets -- that is, files placed in to the
      * "assets" directory.
      * 
-     * @param fileName The name of the asset to open.  This name can be hierarchical.
+     * @param fileName The name of the asset to open.  This name can be
+     *                 hierarchical.
      * @param accessMode Desired access mode for retrieving the data.
      * 
      * @see #ACCESS_UNKNOWN
@@ -678,40 +366,34 @@
      * @see #open(String)
      * @see #list
      */
-    public @NonNull InputStream open(@NonNull String fileName, int accessMode) throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    public final InputStream open(String fileName, int accessMode)
+        throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final long asset = nativeOpenAsset(mObject, fileName, accessMode);
-            if (asset == 0) {
-                throw new FileNotFoundException("Asset file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            final AssetInputStream assetInputStream = new AssetInputStream(asset);
-            incRefsLocked(assetInputStream.hashCode());
-            return assetInputStream;
+            long asset = openAsset(fileName, accessMode);
+            if (asset != 0) {
+                AssetInputStream res = new AssetInputStream(asset);
+                incRefsLocked(res.hashCode());
+                return res;
+            }
         }
+        throw new FileNotFoundException("Asset file: " + fileName);
     }
 
-    /**
-     * Open an uncompressed asset by mmapping it and returning an {@link AssetFileDescriptor}.
-     * This provides access to files that have been bundled with an application as assets -- that
-     * is, files placed in to the "assets" directory.
-     *
-     * The asset must be uncompressed, or an exception will be thrown.
-     *
-     * @param fileName The name of the asset to open.  This name can be hierarchical.
-     * @return An open AssetFileDescriptor.
-     */
-    public @NonNull AssetFileDescriptor openFd(@NonNull String fileName) throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    public final AssetFileDescriptor openFd(String fileName)
+            throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final ParcelFileDescriptor pfd = nativeOpenAssetFd(mObject, fileName, mOffsets);
-            if (pfd == null) {
-                throw new FileNotFoundException("Asset file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
+            ParcelFileDescriptor pfd = openAssetFd(fileName, mOffsets);
+            if (pfd != null) {
+                return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
+            }
         }
+        throw new FileNotFoundException("Asset file: " + fileName);
     }
 
     /**
@@ -726,121 +408,90 @@
      * 
      * @see #open
      */
-    public @Nullable String[] list(@NonNull String path) throws IOException {
-        Preconditions.checkNotNull(path, "path");
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeList(mObject, path);
-        }
-    }
+    public native final String[] list(String path)
+        throws IOException;
 
     /**
+     * {@hide}
      * Open a non-asset file as an asset using ACCESS_STREAMING mode.  This
      * provides direct access to all of the files included in an application
      * package (not only its assets).  Applications should not normally use
      * this.
-     *
-     * @param fileName Name of the asset to retrieve.
-     *
+     * 
      * @see #open(String)
-     * @hide
      */
-    public @NonNull InputStream openNonAsset(@NonNull String fileName) throws IOException {
+    public final InputStream openNonAsset(String fileName) throws IOException {
         return openNonAsset(0, fileName, ACCESS_STREAMING);
     }
 
     /**
+     * {@hide}
      * Open a non-asset file as an asset using a specific access mode.  This
      * provides direct access to all of the files included in an application
      * package (not only its assets).  Applications should not normally use
      * this.
-     *
-     * @param fileName Name of the asset to retrieve.
-     * @param accessMode Desired access mode for retrieving the data.
-     *
-     * @see #ACCESS_UNKNOWN
-     * @see #ACCESS_STREAMING
-     * @see #ACCESS_RANDOM
-     * @see #ACCESS_BUFFER
+     * 
      * @see #open(String, int)
-     * @hide
      */
-    public @NonNull InputStream openNonAsset(@NonNull String fileName, int accessMode)
-            throws IOException {
+    public final InputStream openNonAsset(String fileName, int accessMode)
+        throws IOException {
         return openNonAsset(0, fileName, accessMode);
     }
 
     /**
+     * {@hide}
      * Open a non-asset in a specified package.  Not for use by applications.
-     *
+     * 
      * @param cookie Identifier of the package to be opened.
      * @param fileName Name of the asset to retrieve.
-     * @hide
      */
-    public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName)
-            throws IOException {
+    public final InputStream openNonAsset(int cookie, String fileName)
+        throws IOException {
         return openNonAsset(cookie, fileName, ACCESS_STREAMING);
     }
 
     /**
+     * {@hide}
      * Open a non-asset in a specified package.  Not for use by applications.
-     *
+     * 
      * @param cookie Identifier of the package to be opened.
      * @param fileName Name of the asset to retrieve.
      * @param accessMode Desired access mode for retrieving the data.
-     * @hide
      */
-    public @NonNull InputStream openNonAsset(int cookie, @NonNull String fileName, int accessMode)
-            throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    public final InputStream openNonAsset(int cookie, String fileName, int accessMode)
+        throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final long asset = nativeOpenNonAsset(mObject, cookie, fileName, accessMode);
-            if (asset == 0) {
-                throw new FileNotFoundException("Asset absolute file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            final AssetInputStream assetInputStream = new AssetInputStream(asset);
-            incRefsLocked(assetInputStream.hashCode());
-            return assetInputStream;
+            long asset = openNonAssetNative(cookie, fileName, accessMode);
+            if (asset != 0) {
+                AssetInputStream res = new AssetInputStream(asset);
+                incRefsLocked(res.hashCode());
+                return res;
+            }
         }
+        throw new FileNotFoundException("Asset absolute file: " + fileName);
     }
 
-    /**
-     * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}.
-     * This provides direct access to all of the files included in an application
-     * package (not only its assets).  Applications should not normally use this.
-     *
-     * The asset must not be compressed, or an exception will be thrown.
-     *
-     * @param fileName Name of the asset to retrieve.
-     */
-    public @NonNull AssetFileDescriptor openNonAssetFd(@NonNull String fileName)
+    public final AssetFileDescriptor openNonAssetFd(String fileName)
             throws IOException {
         return openNonAssetFd(0, fileName);
     }
-
-    /**
-     * Open a non-asset as an asset by mmapping it and returning an {@link AssetFileDescriptor}.
-     * This provides direct access to all of the files included in an application
-     * package (not only its assets).  Applications should not normally use this.
-     *
-     * The asset must not be compressed, or an exception will be thrown.
-     *
-     * @param cookie Identifier of the package to be opened.
-     * @param fileName Name of the asset to retrieve.
-     */
-    public @NonNull AssetFileDescriptor openNonAssetFd(int cookie, @NonNull String fileName)
-            throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    
+    public final AssetFileDescriptor openNonAssetFd(int cookie,
+            String fileName) throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final ParcelFileDescriptor pfd =
-                    nativeOpenNonAssetFd(mObject, cookie, fileName, mOffsets);
-            if (pfd == null) {
-                throw new FileNotFoundException("Asset absolute file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
+            ParcelFileDescriptor pfd = openNonAssetFdNative(cookie,
+                    fileName, mOffsets);
+            if (pfd != null) {
+                return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
+            }
         }
+        throw new FileNotFoundException("Asset absolute file: " + fileName);
     }
     
     /**
@@ -848,7 +499,7 @@
      * 
      * @param fileName The name of the file to retrieve.
      */
-    public @NonNull XmlResourceParser openXmlResourceParser(@NonNull String fileName)
+    public final XmlResourceParser openXmlResourceParser(String fileName)
             throws IOException {
         return openXmlResourceParser(0, fileName);
     }
@@ -859,265 +510,270 @@
      * @param cookie Identifier of the package to be opened.
      * @param fileName The name of the file to retrieve.
      */
-    public @NonNull XmlResourceParser openXmlResourceParser(int cookie, @NonNull String fileName)
-            throws IOException {
-        try (XmlBlock block = openXmlBlockAsset(cookie, fileName)) {
-            XmlResourceParser parser = block.newParser();
-            // If openXmlBlockAsset doesn't throw, it will always return an XmlBlock object with
-            // a valid native pointer, which makes newParser always return non-null. But let's
-            // be paranoid.
-            if (parser == null) {
-                throw new AssertionError("block.newParser() returned a null parser");
-            }
-            return parser;
-        }
+    public final XmlResourceParser openXmlResourceParser(int cookie,
+            String fileName) throws IOException {
+        XmlBlock block = openXmlBlockAsset(cookie, fileName);
+        XmlResourceParser rp = block.newParser();
+        block.close();
+        return rp;
     }
 
     /**
-     * Retrieve a non-asset as a compiled XML file.  Not for use by applications.
+     * {@hide}
+     * Retrieve a non-asset as a compiled XML file.  Not for use by
+     * applications.
      * 
      * @param fileName The name of the file to retrieve.
-     * @hide
      */
-    @NonNull XmlBlock openXmlBlockAsset(@NonNull String fileName) throws IOException {
+    /*package*/ final XmlBlock openXmlBlockAsset(String fileName)
+            throws IOException {
         return openXmlBlockAsset(0, fileName);
     }
 
     /**
+     * {@hide}
      * Retrieve a non-asset as a compiled XML file.  Not for use by
      * applications.
      * 
      * @param cookie Identifier of the package to be opened.
      * @param fileName Name of the asset to retrieve.
-     * @hide
      */
-    @NonNull XmlBlock openXmlBlockAsset(int cookie, @NonNull String fileName) throws IOException {
-        Preconditions.checkNotNull(fileName, "fileName");
+    /*package*/ final XmlBlock openXmlBlockAsset(int cookie, String fileName)
+        throws IOException {
         synchronized (this) {
-            ensureOpenLocked();
-            final long xmlBlock = nativeOpenXmlAsset(mObject, cookie, fileName);
-            if (xmlBlock == 0) {
-                throw new FileNotFoundException("Asset XML file: " + fileName);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
             }
-            final XmlBlock block = new XmlBlock(this, xmlBlock);
-            incRefsLocked(block.hashCode());
-            return block;
+            long xmlBlock = openXmlAssetNative(cookie, fileName);
+            if (xmlBlock != 0) {
+                XmlBlock res = new XmlBlock(this, xmlBlock);
+                incRefsLocked(res.hashCode());
+                return res;
+            }
         }
+        throw new FileNotFoundException("Asset XML file: " + fileName);
     }
 
-    void xmlBlockGone(int id) {
+    /*package*/ void xmlBlockGone(int id) {
         synchronized (this) {
             decRefsLocked(id);
         }
     }
 
-    void applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
-            @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress,
-            long outIndicesAddress) {
-        Preconditions.checkNotNull(inAttrs, "inAttrs");
+    /*package*/ final long createTheme() {
         synchronized (this) {
-            // Need to synchronize on AssetManager because we will be accessing
-            // the native implementation of AssetManager.
-            ensureValidLocked();
-            nativeApplyStyle(mObject, themePtr, defStyleAttr, defStyleRes,
-                    parser != null ? parser.mParseState : 0, inAttrs, outValuesAddress,
-                    outIndicesAddress);
+            if (!mOpen) {
+                throw new RuntimeException("Assetmanager has been closed");
+            }
+            long res = newTheme();
+            incRefsLocked(res);
+            return res;
         }
     }
 
-    boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
-            @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues,
-            @NonNull int[] outIndices) {
-        Preconditions.checkNotNull(inAttrs, "inAttrs");
-        Preconditions.checkNotNull(outValues, "outValues");
-        Preconditions.checkNotNull(outIndices, "outIndices");
+    /*package*/ final void releaseTheme(long theme) {
         synchronized (this) {
-            // Need to synchronize on AssetManager because we will be accessing
-            // the native implementation of AssetManager.
-            ensureValidLocked();
-            return nativeResolveAttrs(mObject,
-                    themePtr, defStyleAttr, defStyleRes, inValues, inAttrs, outValues, outIndices);
+            deleteTheme(theme);
+            decRefsLocked(theme);
         }
     }
 
-    boolean retrieveAttributes(@NonNull XmlBlock.Parser parser, @NonNull int[] inAttrs,
-            @NonNull int[] outValues, @NonNull int[] outIndices) {
-        Preconditions.checkNotNull(parser, "parser");
-        Preconditions.checkNotNull(inAttrs, "inAttrs");
-        Preconditions.checkNotNull(outValues, "outValues");
-        Preconditions.checkNotNull(outIndices, "outIndices");
-        synchronized (this) {
-            // Need to synchronize on AssetManager because we will be accessing
-            // the native implementation of AssetManager.
-            ensureValidLocked();
-            return nativeRetrieveAttributes(
-                    mObject, parser.mParseState, inAttrs, outValues, outIndices);
-        }
-    }
-
-    long createTheme() {
-        synchronized (this) {
-            ensureValidLocked();
-            long themePtr = nativeThemeCreate(mObject);
-            incRefsLocked(themePtr);
-            return themePtr;
-        }
-    }
-
-    void releaseTheme(long themePtr) {
-        synchronized (this) {
-            nativeThemeDestroy(themePtr);
-            decRefsLocked(themePtr);
-        }
-    }
-
-    void applyStyleToTheme(long themePtr, @StyleRes int resId, boolean force) {
-        synchronized (this) {
-            // Need to synchronize on AssetManager because we will be accessing
-            // the native implementation of AssetManager.
-            ensureValidLocked();
-            nativeThemeApplyStyle(mObject, themePtr, resId, force);
-        }
-    }
-
-    @Override
     protected void finalize() throws Throwable {
-        if (DEBUG_REFS && mNumRefs != 0) {
-            Log.w(TAG, "AssetManager " + this + " finalized with non-zero refs: " + mNumRefs);
-            if (mRefStacks != null) {
-                for (RuntimeException e : mRefStacks.values()) {
-                    Log.w(TAG, "Reference from here", e);
+        try {
+            if (DEBUG_REFS && mNumRefs != 0) {
+                Log.w(TAG, "AssetManager " + this
+                        + " finalized with non-zero refs: " + mNumRefs);
+                if (mRefStacks != null) {
+                    for (RuntimeException e : mRefStacks.values()) {
+                        Log.w(TAG, "Reference from here", e);
+                    }
                 }
             }
-        }
-
-        if (mObject != 0) {
-            nativeDestroy(mObject);
+            destroy();
+        } finally {
+            super.finalize();
         }
     }
-
-    /* No Locking is needed for AssetInputStream because an AssetInputStream is not-thread
-    safe and it does not rely on AssetManager once it has been created. It completely owns the
-    underlying Asset. */
+    
     public final class AssetInputStream extends InputStream {
-        private long mAssetNativePtr;
-        private long mLength;
-        private long mMarkPos;
-
         /**
          * @hide
          */
         public final int getAssetInt() {
             throw new UnsupportedOperationException();
         }
-
         /**
          * @hide
          */
         public final long getNativeAsset() {
-            return mAssetNativePtr;
+            return mAsset;
         }
-
-        private AssetInputStream(long assetNativePtr) {
-            mAssetNativePtr = assetNativePtr;
-            mLength = nativeAssetGetLength(assetNativePtr);
+        private AssetInputStream(long asset)
+        {
+            mAsset = asset;
+            mLength = getAssetLength(asset);
         }
-
-        @Override
         public final int read() throws IOException {
-            ensureOpen();
-            return nativeAssetReadChar(mAssetNativePtr);
+            return readAssetChar(mAsset);
         }
-
-        @Override
-        public final int read(@NonNull byte[] b) throws IOException {
-            ensureOpen();
-            Preconditions.checkNotNull(b, "b");
-            return nativeAssetRead(mAssetNativePtr, b, 0, b.length);
-        }
-
-        @Override
-        public final int read(@NonNull byte[] b, int off, int len) throws IOException {
-            ensureOpen();
-            Preconditions.checkNotNull(b, "b");
-            return nativeAssetRead(mAssetNativePtr, b, off, len);
-        }
-
-        @Override
-        public final long skip(long n) throws IOException {
-            ensureOpen();
-            long pos = nativeAssetSeek(mAssetNativePtr, 0, 0);
-            if ((pos + n) > mLength) {
-                n = mLength - pos;
-            }
-            if (n > 0) {
-                nativeAssetSeek(mAssetNativePtr, n, 0);
-            }
-            return n;
-        }
-
-        @Override
-        public final int available() throws IOException {
-            ensureOpen();
-            final long len = nativeAssetGetRemainingLength(mAssetNativePtr);
-            return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) len;
-        }
-
-        @Override
         public final boolean markSupported() {
             return true;
         }
-
-        @Override
-        public final void mark(int readlimit) {
-            ensureOpen();
-            mMarkPos = nativeAssetSeek(mAssetNativePtr, 0, 0);
+        public final int available() throws IOException {
+            long len = getAssetRemainingLength(mAsset);
+            return len > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)len;
         }
-
-        @Override
-        public final void reset() throws IOException {
-            ensureOpen();
-            nativeAssetSeek(mAssetNativePtr, mMarkPos, -1);
-        }
-
-        @Override
         public final void close() throws IOException {
-            if (mAssetNativePtr != 0) {
-                nativeAssetDestroy(mAssetNativePtr);
-                mAssetNativePtr = 0;
-
-                synchronized (AssetManager.this) {
+            synchronized (AssetManager.this) {
+                if (mAsset != 0) {
+                    destroyAsset(mAsset);
+                    mAsset = 0;
                     decRefsLocked(hashCode());
                 }
             }
         }
+        public final void mark(int readlimit) {
+            mMarkPos = seekAsset(mAsset, 0, 0);
+        }
+        public final void reset() throws IOException {
+            seekAsset(mAsset, mMarkPos, -1);
+        }
+        public final int read(byte[] b) throws IOException {
+            return readAsset(mAsset, b, 0, b.length);
+        }
+        public final int read(byte[] b, int off, int len) throws IOException {
+            return readAsset(mAsset, b, off, len);
+        }
+        public final long skip(long n) throws IOException {
+            long pos = seekAsset(mAsset, 0, 0);
+            if ((pos+n) > mLength) {
+                n = mLength-pos;
+            }
+            if (n > 0) {
+                seekAsset(mAsset, n, 0);
+            }
+            return n;
+        }
 
-        @Override
-        protected void finalize() throws Throwable {
+        protected void finalize() throws Throwable
+        {
             close();
         }
 
-        private void ensureOpen() {
-            if (mAssetNativePtr == 0) {
-                throw new IllegalStateException("AssetInputStream is closed");
-            }
+        private long mAsset;
+        private long mLength;
+        private long mMarkPos;
+    }
+
+    /**
+     * Add an additional set of assets to the asset manager.  This can be
+     * either a directory or ZIP file.  Not for use by applications.  Returns
+     * the cookie of the added asset, or 0 on failure.
+     * {@hide}
+     */
+    public final int addAssetPath(String path) {
+        return  addAssetPathInternal(path, false);
+    }
+
+    /**
+     * Add an application assets to the asset manager and loading it as shared library.
+     * This can be either a directory or ZIP file.  Not for use by applications.  Returns
+     * the cookie of the added asset, or 0 on failure.
+     * {@hide}
+     */
+    public final int addAssetPathAsSharedLibrary(String path) {
+        return addAssetPathInternal(path, true);
+    }
+
+    private final int addAssetPathInternal(String path, boolean appAsLib) {
+        synchronized (this) {
+            int res = addAssetPathNative(path, appAsLib);
+            makeStringBlocks(mStringBlocks);
+            return res;
         }
     }
 
+    private native final int addAssetPathNative(String path, boolean appAsLib);
+
+    /**
+     * Add an additional set of assets to the asset manager from an already open
+     * FileDescriptor.  Not for use by applications.
+     * This does not give full AssetManager functionality for these assets,
+     * since the origin of the file is not known for purposes of sharing,
+     * overlay resolution, and other features.  However it does allow you
+     * to do simple access to the contents of the given fd as an apk file.
+     * Performs a dup of the underlying fd, so you must take care of still closing
+     * the FileDescriptor yourself (and can do that whenever you want).
+     * Returns the cookie of the added asset, or 0 on failure.
+     * {@hide}
+     */
+    public int addAssetFd(FileDescriptor fd, String debugPathName) {
+        return addAssetFdInternal(fd, debugPathName, false);
+    }
+
+    private int addAssetFdInternal(FileDescriptor fd, String debugPathName,
+            boolean appAsLib) {
+        synchronized (this) {
+            int res = addAssetFdNative(fd, debugPathName, appAsLib);
+            makeStringBlocks(mStringBlocks);
+            return res;
+        }
+    }
+
+    private native int addAssetFdNative(FileDescriptor fd, String debugPathName,
+            boolean appAsLib);
+
+    /**
+     * Add a set of assets to overlay an already added set of assets.
+     *
+     * This is only intended for application resources. System wide resources
+     * are handled before any Java code is executed.
+     *
+     * {@hide}
+     */
+
+    public final int addOverlayPath(String idmapPath) {
+        synchronized (this) {
+            int res = addOverlayPathNative(idmapPath);
+            makeStringBlocks(mStringBlocks);
+            return res;
+        }
+    }
+
+    /**
+     * See addOverlayPath.
+     *
+     * {@hide}
+     */
+    public native final int addOverlayPathNative(String idmapPath);
+
+    /**
+     * Add multiple sets of assets to the asset manager at once.  See
+     * {@link #addAssetPath(String)} for more information.  Returns array of
+     * cookies for each added asset with 0 indicating failure, or null if
+     * the input array of paths is null.
+     * {@hide}
+     */
+    public final int[] addAssetPaths(String[] paths) {
+        if (paths == null) {
+            return null;
+        }
+
+        int[] cookies = new int[paths.length];
+        for (int i = 0; i < paths.length; i++) {
+            cookies[i] = addAssetPath(paths[i]);
+        }
+
+        return cookies;
+    }
+
     /**
      * Determine whether the state in this asset manager is up-to-date with
      * the files on the filesystem.  If false is returned, you need to
      * instantiate a new AssetManager class to see the new data.
-     * @hide
+     * {@hide}
      */
-    public boolean isUpToDate() {
-        for (ApkAssets apkAssets : getApkAssets()) {
-            if (!apkAssets.isUpToDate()) {
-                return false;
-            }
-        }
-        return true;
-    }
+    public native final boolean isUpToDate();
 
     /**
      * Get the locales that this asset manager contains data for.
@@ -1130,12 +786,7 @@
      * are of the form {@code ll_CC} where {@code ll} is a two letter language code,
      * and {@code CC} is a two letter country code.
      */
-    public String[] getLocales() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetLocales(mObject, false /*excludeSystem*/);
-        }
-    }
+    public native final String[] getLocales();
 
     /**
      * Same as getLocales(), except that locales that are only provided by the system (i.e. those
@@ -1145,58 +796,132 @@
      * assets support Cherokee and French, getLocales() would return
      * [Cherokee, English, French, German], while getNonSystemLocales() would return
      * [Cherokee, French].
-     * @hide
+     * {@hide}
      */
-    public String[] getNonSystemLocales() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetLocales(mObject, true /*excludeSystem*/);
-        }
-    }
+    public native final String[] getNonSystemLocales();
+
+    /** {@hide} */
+    public native final Configuration[] getSizeConfigurations();
 
     /**
-     * @hide
-     */
-    Configuration[] getSizeConfigurations() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetSizeConfigurations(mObject);
-        }
-    }
-
-    /**
-     * Change the configuration used when retrieving resources.  Not for use by
+     * Change the configuation used when retrieving resources.  Not for use by
      * applications.
-     * @hide
+     * {@hide}
      */
-    public void setConfiguration(int mcc, int mnc, @Nullable String locale, int orientation,
-            int touchscreen, int density, int keyboard, int keyboardHidden, int navigation,
-            int screenWidth, int screenHeight, int smallestScreenWidthDp, int screenWidthDp,
-            int screenHeightDp, int screenLayout, int uiMode, int colorMode, int majorVersion) {
-        synchronized (this) {
-            ensureValidLocked();
-            nativeSetConfiguration(mObject, mcc, mnc, locale, orientation, touchscreen, density,
-                    keyboard, keyboardHidden, navigation, screenWidth, screenHeight,
-                    smallestScreenWidthDp, screenWidthDp, screenHeightDp, screenLayout, uiMode,
-                    colorMode, majorVersion);
-        }
-    }
+    public native final void setConfiguration(int mcc, int mnc, String locale,
+            int orientation, int touchscreen, int density, int keyboard,
+            int keyboardHidden, int navigation, int screenWidth, int screenHeight,
+            int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp,
+            int screenLayout, int uiMode, int colorMode, int majorVersion);
 
     /**
-     * @hide
+     * Retrieve the resource identifier for the given resource name.
      */
-    public SparseArray<String> getAssignedPackageIdentifiers() {
-        synchronized (this) {
-            ensureValidLocked();
-            return nativeGetAssignedPackageIdentifiers(mObject);
-        }
-    }
+    /*package*/ native final int getResourceIdentifier(String name,
+                                                       String defType,
+                                                       String defPackage);
+
+    /*package*/ native final String getResourceName(int resid);
+    /*package*/ native final String getResourcePackageName(int resid);
+    /*package*/ native final String getResourceTypeName(int resid);
+    /*package*/ native final String getResourceEntryName(int resid);
+    
+    private native final long openAsset(String fileName, int accessMode);
+    private final native ParcelFileDescriptor openAssetFd(String fileName,
+            long[] outOffsets) throws IOException;
+    private native final long openNonAssetNative(int cookie, String fileName,
+            int accessMode);
+    private native ParcelFileDescriptor openNonAssetFdNative(int cookie,
+            String fileName, long[] outOffsets) throws IOException;
+    private native final void destroyAsset(long asset);
+    private native final int readAssetChar(long asset);
+    private native final int readAsset(long asset, byte[] b, int off, int len);
+    private native final long seekAsset(long asset, long offset, int whence);
+    private native final long getAssetLength(long asset);
+    private native final long getAssetRemainingLength(long asset);
+
+    /** Returns true if the resource was found, filling in mRetStringBlock and
+     *  mRetData. */
+    private native final int loadResourceValue(int ident, short density, TypedValue outValue,
+            boolean resolve);
+    /** Returns true if the resource was found, filling in mRetStringBlock and
+     *  mRetData. */
+    private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
+                                               boolean resolve);
+    /*package*/ static final int STYLE_NUM_ENTRIES = 6;
+    /*package*/ static final int STYLE_TYPE = 0;
+    /*package*/ static final int STYLE_DATA = 1;
+    /*package*/ static final int STYLE_ASSET_COOKIE = 2;
+    /*package*/ static final int STYLE_RESOURCE_ID = 3;
+
+    /* Offset within typed data array for native changingConfigurations. */
+    static final int STYLE_CHANGING_CONFIGURATIONS = 4;
+
+    /*package*/ static final int STYLE_DENSITY = 5;
+    /*package*/ native static final void applyStyle(long theme,
+            int defStyleAttr, int defStyleRes, long xmlParser,
+            int[] inAttrs, int length, long outValuesAddress, long outIndicesAddress);
+    /*package*/ native static final boolean resolveAttrs(long theme,
+            int defStyleAttr, int defStyleRes, int[] inValues,
+            int[] inAttrs, int[] outValues, int[] outIndices);
+    /*package*/ native final boolean retrieveAttributes(
+            long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
+    /*package*/ native final int getArraySize(int resource);
+    /*package*/ native final int retrieveArray(int resource, int[] outValues);
+    private native final int getStringBlockCount();
+    private native final long getNativeStringBlock(int block);
+
+    /**
+     * {@hide}
+     */
+    public native final String getCookieName(int cookie);
+
+    /**
+     * {@hide}
+     */
+    public native final SparseArray<String> getAssignedPackageIdentifiers();
+
+    /**
+     * {@hide}
+     */
+    public native static final int getGlobalAssetCount();
+    
+    /**
+     * {@hide}
+     */
+    public native static final String getAssetAllocations();
+    
+    /**
+     * {@hide}
+     */
+    public native static final int getGlobalAssetManagerCount();
+    
+    private native final long newTheme();
+    private native final void deleteTheme(long theme);
+    /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
+    /*package*/ native static final void copyTheme(long dest, long source);
+    /*package*/ native static final void clearTheme(long theme);
+    /*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
+                                                                TypedValue outValue,
+                                                                boolean resolve);
+    /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
+    /*package*/ native static final @NativeConfig int getThemeChangingConfigurations(long theme);
+
+    private native final long openXmlAssetNative(int cookie, String fileName);
+
+    private native final String[] getArrayStringResource(int arrayRes);
+    private native final int[] getArrayStringInfo(int arrayRes);
+    /*package*/ native final int[] getArrayIntResource(int arrayRes);
+    /*package*/ native final int[] getStyleAttributes(int themeRes);
+
+    private native final void init(boolean isSystem);
+    private native final void destroy();
 
     @GuardedBy("this")
-    private void incRefsLocked(long id) {
+    private final void incRefsLocked(long id) {
         if (DEBUG_REFS) {
             if (mRefStacks == null) {
-                mRefStacks = new HashMap<>();
+                mRefStacks = new HashMap<Long, RuntimeException>();
             }
             RuntimeException ex = new RuntimeException();
             ex.fillInStackTrace();
@@ -1206,117 +931,15 @@
     }
 
     @GuardedBy("this")
-    private void decRefsLocked(long id) {
+    private final void decRefsLocked(long id) {
         if (DEBUG_REFS && mRefStacks != null) {
             mRefStacks.remove(id);
         }
         mNumRefs--;
-        if (mNumRefs == 0 && mObject != 0) {
-            nativeDestroy(mObject);
-            mObject = 0;
-            mApkAssets = sEmptyApkAssets;
+        //System.out.println("Dec streams: mNumRefs=" + mNumRefs
+        //                   + " mReleased=" + mReleased);
+        if (mNumRefs == 0) {
+            destroy();
         }
     }
-
-    // AssetManager setup native methods.
-    private static native long nativeCreate();
-    private static native void nativeDestroy(long ptr);
-    private static native void nativeSetApkAssets(long ptr, @NonNull ApkAssets[] apkAssets,
-            boolean invalidateCaches);
-    private static native void nativeSetConfiguration(long ptr, int mcc, int mnc,
-            @Nullable String locale, int orientation, int touchscreen, int density, int keyboard,
-            int keyboardHidden, int navigation, int screenWidth, int screenHeight,
-            int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp, int screenLayout,
-            int uiMode, int colorMode, int majorVersion);
-    private static native @NonNull SparseArray<String> nativeGetAssignedPackageIdentifiers(
-            long ptr);
-
-    // File native methods.
-    private static native @Nullable String[] nativeList(long ptr, @NonNull String path)
-            throws IOException;
-    private static native long nativeOpenAsset(long ptr, @NonNull String fileName, int accessMode);
-    private static native @Nullable ParcelFileDescriptor nativeOpenAssetFd(long ptr,
-            @NonNull String fileName, long[] outOffsets) throws IOException;
-    private static native long nativeOpenNonAsset(long ptr, int cookie, @NonNull String fileName,
-            int accessMode);
-    private static native @Nullable ParcelFileDescriptor nativeOpenNonAssetFd(long ptr, int cookie,
-            @NonNull String fileName, @NonNull long[] outOffsets) throws IOException;
-    private static native long nativeOpenXmlAsset(long ptr, int cookie, @NonNull String fileName);
-
-    // Primitive resource native methods.
-    private static native int nativeGetResourceValue(long ptr, @AnyRes int resId, short density,
-            @NonNull TypedValue outValue, boolean resolveReferences);
-    private static native int nativeGetResourceBagValue(long ptr, @AnyRes int resId, int bagEntryId,
-            @NonNull TypedValue outValue);
-
-    private static native @Nullable @AttrRes int[] nativeGetStyleAttributes(long ptr,
-            @StyleRes int resId);
-    private static native @Nullable String[] nativeGetResourceStringArray(long ptr,
-            @ArrayRes int resId);
-    private static native @Nullable int[] nativeGetResourceStringArrayInfo(long ptr,
-            @ArrayRes int resId);
-    private static native @Nullable int[] nativeGetResourceIntArray(long ptr, @ArrayRes int resId);
-    private static native int nativeGetResourceArraySize(long ptr, @ArrayRes int resId);
-    private static native int nativeGetResourceArray(long ptr, @ArrayRes int resId,
-            @NonNull int[] outValues);
-
-    // Resource name/ID native methods.
-    private static native @AnyRes int nativeGetResourceIdentifier(long ptr, @NonNull String name,
-            @Nullable String defType, @Nullable String defPackage);
-    private static native @Nullable String nativeGetResourceName(long ptr, @AnyRes int resid);
-    private static native @Nullable String nativeGetResourcePackageName(long ptr,
-            @AnyRes int resid);
-    private static native @Nullable String nativeGetResourceTypeName(long ptr, @AnyRes int resid);
-    private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid);
-    private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem);
-    private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr);
-
-    // Style attribute retrieval native methods.
-    private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr,
-            @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs,
-            long outValuesAddress, long outIndicesAddress);
-    private static native boolean nativeResolveAttrs(long ptr, long themePtr,
-            @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable int[] inValues,
-            @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices);
-    private static native boolean nativeRetrieveAttributes(long ptr, long xmlParserPtr,
-            @NonNull int[] inAttrs, @NonNull int[] outValues, @NonNull int[] outIndices);
-
-    // Theme related native methods
-    private static native long nativeThemeCreate(long ptr);
-    private static native void nativeThemeDestroy(long themePtr);
-    private static native void nativeThemeApplyStyle(long ptr, long themePtr, @StyleRes int resId,
-            boolean force);
-    static native void nativeThemeCopy(long destThemePtr, long sourceThemePtr);
-    static native void nativeThemeClear(long themePtr);
-    private static native int nativeThemeGetAttributeValue(long ptr, long themePtr,
-            @AttrRes int resId, @NonNull TypedValue outValue, boolean resolve);
-    private static native void nativeThemeDump(long ptr, long themePtr, int priority, String tag,
-            String prefix);
-    static native @NativeConfig int nativeThemeGetChangingConfigurations(long themePtr);
-
-    // AssetInputStream related native methods.
-    private static native void nativeAssetDestroy(long assetPtr);
-    private static native int nativeAssetReadChar(long assetPtr);
-    private static native int nativeAssetRead(long assetPtr, byte[] b, int off, int len);
-    private static native long nativeAssetSeek(long assetPtr, long offset, int whence);
-    private static native long nativeAssetGetLength(long assetPtr);
-    private static native long nativeAssetGetRemainingLength(long assetPtr);
-
-    private static native void nativeVerifySystemIdmaps();
-
-    // Global debug native methods.
-    /**
-     * @hide
-     */
-    public static native int getGlobalAssetCount();
-
-    /**
-     * @hide
-     */
-    public static native String getAssetAllocations();
-
-    /**
-     * @hide
-     */
-    public static native int getGlobalAssetManagerCount();
 }
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index d813382..ad85e71 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -590,7 +590,7 @@
      */
     @NonNull
     public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
-        int[] res = mResourcesImpl.getAssets().getResourceIntArray(id);
+        int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
         if (res != null) {
             return res;
         }
@@ -613,13 +613,13 @@
     @NonNull
     public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
         final ResourcesImpl impl = mResourcesImpl;
-        int len = impl.getAssets().getResourceArraySize(id);
+        int len = impl.getAssets().getArraySize(id);
         if (len < 0) {
             throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
         }
         
         TypedArray array = TypedArray.obtain(this, len);
-        array.mLength = impl.getAssets().getResourceArray(id, array.mData);
+        array.mLength = impl.getAssets().retrieveArray(id, array.mData);
         array.mIndices[0] = 0;
         
         return array;
@@ -1794,7 +1794,8 @@
         // out the attributes from the XML file (applying type information
         // contained in the resources and such).
         XmlBlock.Parser parser = (XmlBlock.Parser)set;
-        mResourcesImpl.getAssets().retrieveAttributes(parser, attrs, array.mData, array.mIndices);
+        mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
+                array.mData, array.mIndices);
 
         array.mXml = parser;
 
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 08a1613..91dd7ee 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -168,6 +168,7 @@
         mDisplayAdjustments = displayAdjustments;
         mConfiguration.setToDefaults();
         updateConfiguration(config, metrics, displayAdjustments.getCompatibilityInfo());
+        mAssets.ensureStringBlocks();
     }
 
     public DisplayAdjustments getDisplayAdjustments() {
@@ -1274,7 +1275,8 @@
 
         void applyStyle(int resId, boolean force) {
             synchronized (mKey) {
-                mAssets.applyStyleToTheme(mTheme, resId, force);
+                AssetManager.applyThemeStyle(mTheme, resId, force);
+
                 mThemeResId = resId;
                 mKey.append(resId, force);
             }
@@ -1283,7 +1285,7 @@
         void setTo(ThemeImpl other) {
             synchronized (mKey) {
                 synchronized (other.mKey) {
-                    AssetManager.nativeThemeCopy(mTheme, other.mTheme);
+                    AssetManager.copyTheme(mTheme, other.mTheme);
 
                     mThemeResId = other.mThemeResId;
                     mKey.setTo(other.getKey());
@@ -1306,10 +1308,12 @@
                 // out the attributes from the XML file (applying type information
                 // contained in the resources and such).
                 final XmlBlock.Parser parser = (XmlBlock.Parser) set;
-                mAssets.applyStyle(mTheme, defStyleAttr, defStyleRes, parser, attrs,
-                        array.mDataAddress, array.mIndicesAddress);
+                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+                        parser != null ? parser.mParseState : 0,
+                        attrs, attrs.length, array.mDataAddress, array.mIndicesAddress);
                 array.mTheme = wrapper;
                 array.mXml = parser;
+
                 return array;
             }
         }
@@ -1326,7 +1330,7 @@
                 }
 
                 final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
-                mAssets.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
                 array.mTheme = wrapper;
                 array.mXml = null;
                 return array;
@@ -1346,14 +1350,14 @@
         @Config int getChangingConfigurations() {
             synchronized (mKey) {
                 final @NativeConfig int nativeChangingConfig =
-                        AssetManager.nativeThemeGetChangingConfigurations(mTheme);
+                        AssetManager.getThemeChangingConfigurations(mTheme);
                 return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
             }
         }
 
         public void dump(int priority, String tag, String prefix) {
             synchronized (mKey) {
-                mAssets.dumpTheme(mTheme, priority, tag, prefix);
+                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
             }
         }
 
@@ -1382,13 +1386,13 @@
          */
         void rebase() {
             synchronized (mKey) {
-                AssetManager.nativeThemeClear(mTheme);
+                AssetManager.clearTheme(mTheme);
 
                 // Reapply the same styles in the same order.
                 for (int i = 0; i < mKey.mCount; i++) {
                     final int resId = mKey.mResId[i];
                     final boolean force = mKey.mForce[i];
-                    mAssets.applyStyleToTheme(mTheme, resId, force);
+                    AssetManager.applyThemeStyle(mTheme, resId, force);
                 }
             }
         }
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index cbb3c6d..f33c751 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -61,15 +61,6 @@
         return attrs;
     }
 
-    // STYLE_ prefixed constants are offsets within the typed data array.
-    static final int STYLE_NUM_ENTRIES = 6;
-    static final int STYLE_TYPE = 0;
-    static final int STYLE_DATA = 1;
-    static final int STYLE_ASSET_COOKIE = 2;
-    static final int STYLE_RESOURCE_ID = 3;
-    static final int STYLE_CHANGING_CONFIGURATIONS = 4;
-    static final int STYLE_DENSITY = 5;
-
     private final Resources mResources;
     private DisplayMetrics mMetrics;
     private AssetManager mAssets;
@@ -87,7 +78,7 @@
 
     private void resize(int len) {
         mLength = len;
-        final int dataLen = len * STYLE_NUM_ENTRIES;
+        final int dataLen = len * AssetManager.STYLE_NUM_ENTRIES;
         final int indicesLen = len + 1;
         final VMRuntime runtime = VMRuntime.getRuntime();
         if (mDataAddress == 0 || mData.length < dataLen) {
@@ -175,9 +166,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return null;
         } else if (type == TypedValue.TYPE_STRING) {
@@ -212,9 +203,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return null;
         } else if (type == TypedValue.TYPE_STRING) {
@@ -251,13 +242,14 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_STRING) {
-            final int cookie = data[index + STYLE_ASSET_COOKIE];
+            final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
             if (cookie < 0) {
-                return mXml.getPooledString(data[index + STYLE_DATA]).toString();
+                return mXml.getPooledString(
+                    data[index+AssetManager.STYLE_DATA]).toString();
             }
         }
         return null;
@@ -282,11 +274,11 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         final @Config int changingConfigs = ActivityInfo.activityInfoConfigNativeToJava(
-                data[index + STYLE_CHANGING_CONFIGURATIONS]);
+                data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
         if ((changingConfigs & ~allowedChangingConfigs) != 0) {
             return null;
         }
@@ -328,14 +320,14 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA] != 0;
+            return data[index+AssetManager.STYLE_DATA] != 0;
         }
 
         final TypedValue v = mValue;
@@ -367,14 +359,14 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         }
 
         final TypedValue v = mValue;
@@ -404,16 +396,16 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_FLOAT) {
-            return Float.intBitsToFloat(data[index + STYLE_DATA]);
+            return Float.intBitsToFloat(data[index+AssetManager.STYLE_DATA]);
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         }
 
         final TypedValue v = mValue;
@@ -454,15 +446,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_STRING) {
             final TypedValue value = mValue;
             if (getValueAt(index, value)) {
@@ -506,7 +498,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
                         "Failed to resolve attribute at index " + index + ": " + value);
@@ -541,7 +533,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
                         "Failed to resolve attribute at index " + index + ": " + value);
@@ -572,15 +564,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -620,14 +612,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimension(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimension(
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -668,14 +661,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimensionPixelOffset(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimensionPixelOffset(
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -717,14 +711,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimensionPixelSize(
+                data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -760,15 +755,16 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimensionPixelSize(
+                data[index+AssetManager.STYLE_DATA], mMetrics);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -799,14 +795,15 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type >= TypedValue.TYPE_FIRST_INT
                 && type <= TypedValue.TYPE_LAST_INT) {
-            return data[index + STYLE_DATA];
+            return data[index+AssetManager.STYLE_DATA];
         } else if (type == TypedValue.TYPE_DIMENSION) {
-            return TypedValue.complexToDimensionPixelSize(data[index + STYLE_DATA], mMetrics);
+            return TypedValue.complexToDimensionPixelSize(
+                    data[index + AssetManager.STYLE_DATA], mMetrics);
         }
 
         return defValue;
@@ -836,14 +833,15 @@
         }
 
         final int attrIndex = index;
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
 
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return defValue;
         } else if (type == TypedValue.TYPE_FRACTION) {
-            return TypedValue.complexToFraction(data[index + STYLE_DATA], base, pbase);
+            return TypedValue.complexToFraction(
+                data[index+AssetManager.STYLE_DATA], base, pbase);
         } else if (type == TypedValue.TYPE_ATTRIBUTE) {
             final TypedValue value = mValue;
             getValueAt(index, value);
@@ -876,10 +874,10 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        if (data[index + STYLE_TYPE] != TypedValue.TYPE_NULL) {
-            final int resid = data[index + STYLE_RESOURCE_ID];
+        if (data[index+AssetManager.STYLE_TYPE] != TypedValue.TYPE_NULL) {
+            final int resid = data[index+AssetManager.STYLE_RESOURCE_ID];
             if (resid != 0) {
                 return resid;
             }
@@ -904,10 +902,10 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        if (data[index + STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
-            return data[index + STYLE_DATA];
+        if (data[index + AssetManager.STYLE_TYPE] == TypedValue.TYPE_ATTRIBUTE) {
+            return data[index + AssetManager.STYLE_DATA];
         }
         return defValue;
     }
@@ -941,7 +939,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
                         "Failed to resolve attribute at index " + index + ": " + value);
@@ -977,7 +975,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             if (value.type == TypedValue.TYPE_ATTRIBUTE) {
                 throw new UnsupportedOperationException(
                         "Failed to resolve attribute at index " + index + ": " + value);
@@ -1008,7 +1006,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             return mResources.getTextArray(value.resourceId);
         }
         return null;
@@ -1029,7 +1027,7 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        return getValueAt(index * STYLE_NUM_ENTRIES, outValue);
+        return getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, outValue);
     }
 
     /**
@@ -1045,8 +1043,8 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
-        return mData[index + STYLE_TYPE];
+        index *= AssetManager.STYLE_NUM_ENTRIES;
+        return mData[index + AssetManager.STYLE_TYPE];
     }
 
     /**
@@ -1065,9 +1063,9 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         return type != TypedValue.TYPE_NULL;
     }
 
@@ -1086,11 +1084,11 @@
             throw new RuntimeException("Cannot make calls to a recycled instance!");
         }
 
-        index *= STYLE_NUM_ENTRIES;
+        index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         return type != TypedValue.TYPE_NULL
-                || data[index + STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
+                || data[index+AssetManager.STYLE_DATA] == TypedValue.DATA_NULL_EMPTY;
     }
 
     /**
@@ -1111,7 +1109,7 @@
         }
 
         final TypedValue value = mValue;
-        if (getValueAt(index * STYLE_NUM_ENTRIES, value)) {
+        if (getValueAt(index*AssetManager.STYLE_NUM_ENTRIES, value)) {
             return value;
         }
         return null;
@@ -1183,16 +1181,16 @@
         final int[] data = mData;
         final int N = length();
         for (int i = 0; i < N; i++) {
-            final int index = i * STYLE_NUM_ENTRIES;
-            if (data[index + STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
+            final int index = i * AssetManager.STYLE_NUM_ENTRIES;
+            if (data[index + AssetManager.STYLE_TYPE] != TypedValue.TYPE_ATTRIBUTE) {
                 // Not an attribute, ignore.
                 continue;
             }
 
             // Null the entry so that we can safely call getZzz().
-            data[index + STYLE_TYPE] = TypedValue.TYPE_NULL;
+            data[index + AssetManager.STYLE_TYPE] = TypedValue.TYPE_NULL;
 
-            final int attr = data[index + STYLE_DATA];
+            final int attr = data[index + AssetManager.STYLE_DATA];
             if (attr == 0) {
                 // Useless data, ignore.
                 continue;
@@ -1233,44 +1231,45 @@
         final int[] data = mData;
         final int N = length();
         for (int i = 0; i < N; i++) {
-            final int index = i * STYLE_NUM_ENTRIES;
-            final int type = data[index + STYLE_TYPE];
+            final int index = i * AssetManager.STYLE_NUM_ENTRIES;
+            final int type = data[index + AssetManager.STYLE_TYPE];
             if (type == TypedValue.TYPE_NULL) {
                 continue;
             }
             changingConfig |= ActivityInfo.activityInfoConfigNativeToJava(
-                    data[index + STYLE_CHANGING_CONFIGURATIONS]);
+                    data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
         }
         return changingConfig;
     }
 
     private boolean getValueAt(int index, TypedValue outValue) {
         final int[] data = mData;
-        final int type = data[index + STYLE_TYPE];
+        final int type = data[index+AssetManager.STYLE_TYPE];
         if (type == TypedValue.TYPE_NULL) {
             return false;
         }
         outValue.type = type;
-        outValue.data = data[index + STYLE_DATA];
-        outValue.assetCookie = data[index + STYLE_ASSET_COOKIE];
-        outValue.resourceId = data[index + STYLE_RESOURCE_ID];
+        outValue.data = data[index+AssetManager.STYLE_DATA];
+        outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
+        outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
         outValue.changingConfigurations = ActivityInfo.activityInfoConfigNativeToJava(
-                data[index + STYLE_CHANGING_CONFIGURATIONS]);
-        outValue.density = data[index + STYLE_DENSITY];
+                data[index + AssetManager.STYLE_CHANGING_CONFIGURATIONS]);
+        outValue.density = data[index+AssetManager.STYLE_DENSITY];
         outValue.string = (type == TypedValue.TYPE_STRING) ? loadStringValueAt(index) : null;
         return true;
     }
 
     private CharSequence loadStringValueAt(int index) {
         final int[] data = mData;
-        final int cookie = data[index + STYLE_ASSET_COOKIE];
+        final int cookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
         if (cookie < 0) {
             if (mXml != null) {
-                return mXml.getPooledString(data[index + STYLE_DATA]);
+                return mXml.getPooledString(
+                    data[index+AssetManager.STYLE_DATA]);
             }
             return null;
         }
-        return mAssets.getPooledStringForCookie(cookie, data[index + STYLE_DATA]);
+        return mAssets.getPooledStringForCookie(cookie, data[index+AssetManager.STYLE_DATA]);
     }
 
     /** @hide */
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index d4ccffb..e6b95741 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -16,7 +16,6 @@
 
 package android.content.res;
 
-import android.annotation.Nullable;
 import android.util.TypedValue;
 
 import com.android.internal.util.XmlUtils;
@@ -34,7 +33,7 @@
  * 
  * {@hide}
  */
-final class XmlBlock implements AutoCloseable {
+final class XmlBlock {
     private static final boolean DEBUG=false;
 
     public XmlBlock(byte[] data) {
@@ -49,7 +48,6 @@
         mStrings = new StringBlock(nativeGetStringBlock(mNative), false);
     }
 
-    @Override
     public void close() {
         synchronized (this) {
             if (mOpen) {
@@ -480,13 +478,13 @@
      *  are doing!  The given native object must exist for the entire lifetime
      *  of this newly creating XmlBlock.
      */
-    XmlBlock(@Nullable AssetManager assets, long xmlBlock) {
+    XmlBlock(AssetManager assets, long xmlBlock) {
         mAssets = assets;
         mNative = xmlBlock;
         mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false);
     }
 
-    private @Nullable final AssetManager mAssets;
+    private final AssetManager mAssets;
     private final long mNative;
     /*package*/ final StringBlock mStrings;
     private boolean mOpen = true;
diff --git a/core/java/android/content/res/XmlResourceParser.java b/core/java/android/content/res/XmlResourceParser.java
index 6be9b9e..86f4ba6 100644
--- a/core/java/android/content/res/XmlResourceParser.java
+++ b/core/java/android/content/res/XmlResourceParser.java
@@ -27,6 +27,8 @@
  * it is done reading the resource.
  */
 public interface XmlResourceParser extends XmlPullParser, AttributeSet, AutoCloseable {
+    String getAttributeNamespace (int index);
+
     /**
      * Close this parser. Calls on the interface are no longer valid after this call.
      */
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 24a078f..b6098477 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -19,6 +19,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
@@ -761,6 +762,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress,
             @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork)
             throws ResourceUnavailableException, IOException {
@@ -780,6 +782,7 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
     public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction,
             IpSecTransform transform) throws IOException {
         try {
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 0829b4a..38759a9 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -21,6 +21,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.os.Binder;
@@ -266,6 +267,10 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
+    })
     public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback,
             int intervalSeconds, @NonNull Handler handler) throws IOException {
         checkNotNull(userCallback);
@@ -305,6 +310,10 @@
      * @hide
      */
     @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.NETWORK_STACK,
+            android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD
+    })
     public void stopNattKeepalive() {
         synchronized (mKeepaliveCallback) {
             if (mKeepalive == null) {
@@ -449,6 +458,7 @@
          * @hide
          */
         @SystemApi
+        @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
         public IpSecTransform buildTunnelModeTransform(
                 @NonNull InetAddress sourceAddress,
                 @NonNull IpSecManager.SecurityParameterIndex spi)
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 670f794..4a97640 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -61,18 +61,27 @@
     /**
      * The name of the socket used to communicate with the primary zygote.
      */
-    private final String mSocket;
+    private final LocalSocketAddress mSocket;
 
     /**
      * The name of the secondary (alternate ABI) zygote socket.
      */
-    private final String mSecondarySocket;
+    private final LocalSocketAddress mSecondarySocket;
 
     public ZygoteProcess(String primarySocket, String secondarySocket) {
+        this(new LocalSocketAddress(primarySocket, LocalSocketAddress.Namespace.RESERVED),
+                new LocalSocketAddress(secondarySocket, LocalSocketAddress.Namespace.RESERVED));
+    }
+
+    public ZygoteProcess(LocalSocketAddress primarySocket, LocalSocketAddress secondarySocket) {
         mSocket = primarySocket;
         mSecondarySocket = secondarySocket;
     }
 
+    public LocalSocketAddress getPrimarySocketAddress() {
+        return mSocket;
+    }
+
     /**
      * State for communicating with the zygote process.
      */
@@ -92,14 +101,13 @@
             this.abiList = abiList;
         }
 
-        public static ZygoteState connect(String socketAddress) throws IOException {
+        public static ZygoteState connect(LocalSocketAddress address) throws IOException {
             DataInputStream zygoteInputStream = null;
             BufferedWriter zygoteWriter = null;
             final LocalSocket zygoteSocket = new LocalSocket();
 
             try {
-                zygoteSocket.connect(new LocalSocketAddress(socketAddress,
-                        LocalSocketAddress.Namespace.RESERVED));
+                zygoteSocket.connect(address);
 
                 zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
 
@@ -115,8 +123,8 @@
             }
 
             String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
-            Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: "
-                    + abiListString);
+            Log.i("Zygote", "Process: zygote socket " + address.getNamespace() + "/"
+                    + address.getName() + " opened, supported ABIS: " + abiListString);
 
             return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
                     Arrays.asList(abiListString.split(",")));
@@ -514,9 +522,19 @@
      * @param socketName The name of the socket to connect to.
      */
     public static void waitForConnectionToZygote(String socketName) {
+        final LocalSocketAddress address =
+                new LocalSocketAddress(socketName, LocalSocketAddress.Namespace.RESERVED);
+        waitForConnectionToZygote(address);
+    }
+
+    /**
+     * Try connecting to the Zygote over and over again until we hit a time-out.
+     * @param address The name of the socket to connect to.
+     */
+    public static void waitForConnectionToZygote(LocalSocketAddress address) {
         for (int n = 20; n >= 0; n--) {
             try {
-                final ZygoteState zs = ZygoteState.connect(socketName);
+                final ZygoteState zs = ZygoteState.connect(address);
                 zs.close();
                 return;
             } catch (IOException ioe) {
@@ -529,6 +547,6 @@
             } catch (InterruptedException ie) {
             }
         }
-        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + socketName);
+        Slog.wtf(LOG_TAG, "Failed to connect to Zygote through socket " + address.getName());
     }
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 84996e0..a183895 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12089,11 +12089,22 @@
                 "zram_enabled";
 
         /**
-         * Whether smart replies in notifications are enabled.
+         * Configuration flags for smart replies in notifications.
+         * This is encoded as a key=value list, separated by commas. Ex:
+         *
+         * "enabled=1,max_squeeze_remeasure_count=3"
+         *
+         * The following keys are supported:
+         *
+         * <pre>
+         * enabled                         (boolean)
+         * max_squeeze_remeasure_attempts  (int)
+         * </pre>
+         * @see com.android.systemui.statusbar.policy.SmartReplyConstants
          * @hide
          */
-        public static final String ENABLE_SMART_REPLIES_IN_NOTIFICATIONS =
-                "enable_smart_replies_in_notifications";
+        public static final String SMART_REPLIES_IN_NOTIFICATIONS_FLAGS =
+                "smart_replies_in_notifications_flags";
 
         /**
          * If nonzero, crashes in foreground processes will bring up a dialog.
diff --git a/core/java/android/util/AttributeSet.java b/core/java/android/util/AttributeSet.java
index eb8c168..7f327c7 100644
--- a/core/java/android/util/AttributeSet.java
+++ b/core/java/android/util/AttributeSet.java
@@ -17,6 +17,8 @@
 package android.util;
 
 
+import org.xmlpull.v1.XmlPullParser;
+
 /**
  * A collection of attributes, as found associated with a tag in an XML
  * document.  Often you will not want to use this interface directly, instead
@@ -54,18 +56,42 @@
  * compiled XML resource that is not available in a normal XML file, such
  * as {@link #getAttributeNameResource(int)} which returns the resource
  * identifier associated with a particular XML attribute name.
+ *
+ * @see XmlPullParser
  */
 public interface AttributeSet {
     /**
      * Returns the number of attributes available in the set.
-     * 
+     *
+     * <p>See also {@link XmlPullParser#getAttributeCount XmlPullParser.getAttributeCount()},
+     * which this method corresponds to when parsing a compiled XML file.</p>
+     *
      * @return A positive integer, or 0 if the set is empty.
      */
     public int getAttributeCount();
 
     /**
+     * Returns the namespace of the specified attribute.
+     *
+     * <p>See also {@link XmlPullParser#getAttributeNamespace XmlPullParser.getAttributeNamespace()},
+     * which this method corresponds to when parsing a compiled XML file.</p>
+     *
+     * @param index Index of the desired attribute, 0...count-1.
+     *
+     * @return A String containing the namespace of the attribute, or null if th
+     *         attribute cannot be found.
+     */
+    default String getAttributeNamespace (int index) {
+        // This is a new method since the first interface definition, so add stub impl.
+        return null;
+    }
+
+    /**
      * Returns the name of the specified attribute.
-     * 
+     *
+     * <p>See also {@link XmlPullParser#getAttributeName XmlPullParser.getAttributeName()},
+     * which this method corresponds to when parsing a compiled XML file.</p>
+     *
      * @param index Index of the desired attribute, 0...count-1.
      * 
      * @return A String containing the name of the attribute, or null if the
diff --git a/core/java/android/util/ByteStringUtils.java b/core/java/android/util/ByteStringUtils.java
index 333208d..f6460ad 100644
--- a/core/java/android/util/ByteStringUtils.java
+++ b/core/java/android/util/ByteStringUtils.java
@@ -22,61 +22,63 @@
  * @hide
  */
 public final class ByteStringUtils {
-  private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+    private static final char[] HEX_LOWERCASE_ARRAY = "0123456789abcdef".toCharArray();
+    private static final char[] HEX_UPPERCASE_ARRAY = "0123456789ABCDEF".toCharArray();
 
-  private ByteStringUtils() {
+    private ByteStringUtils() {
     /* hide constructor */
-  }
-
-  /**
-   * Returns the hex encoded string representation of bytes.
-   * @param bytes Byte array to encode.
-   * @return Hex encoded string representation of bytes.
-   */
-  public static String toHexString(byte[] bytes) {
-    if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
-      return null;
     }
 
-    final int byteLength = bytes.length;
-    final int charCount = 2 * byteLength;
-    final char[] chars = new char[charCount];
+    /**
+     * Returns the hex encoded string representation of bytes.
+     * @param bytes Byte array to encode.
+     * @return Hex encoded string representation of bytes.
+     */
+    public static String toHexString(byte[] bytes) {
+        if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
+            return null;
+        }
 
-    for (int i = 0; i < byteLength; i++) {
-      final int byteHex = bytes[i] & 0xFF;
-      chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
-      chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
-    }
-    return new String(chars);
-  }
+        final int byteLength = bytes.length;
+        final int charCount = 2 * byteLength;
+        final char[] chars = new char[charCount];
 
-  /**
-   * Returns the decoded byte array representation of str.
-   * @param str Hex encoded string to decode.
-   * @return Decoded byte array representation of str.
-   */
-  public static byte[] fromHexToByteArray(String str) {
-    if (str == null || str.length() == 0 || str.length() % 2 != 0) {
-      return null;
+        for (int i = 0; i < byteLength; i++) {
+            final int byteHex = bytes[i] & 0xFF;
+            chars[i * 2] = HEX_UPPERCASE_ARRAY[byteHex >>> 4];
+            chars[i * 2 + 1] = HEX_UPPERCASE_ARRAY[byteHex & 0x0F];
+        }
+        return new String(chars);
     }
 
-    final char[] chars = str.toCharArray();
-    final int charLength = chars.length;
-    final byte[] bytes = new byte[charLength / 2];
+    /**
+     * Returns the decoded byte array representation of str.
+     * @param str Hex encoded string to decode.
+     * @return Decoded byte array representation of str.
+     */
+    public static byte[] fromHexToByteArray(String str) {
+        if (str == null || str.length() == 0 || str.length() % 2 != 0) {
+            return null;
+        }
 
-    for (int i = 0; i < bytes.length; i++) {
-      bytes[i] =
-          (byte)(((getIndex(chars[i * 2]) << 4) & 0xF0) | (getIndex(chars[i * 2 + 1]) & 0x0F));
-    }
-    return bytes;
-  }
+        final char[] chars = str.toCharArray();
+        final int charLength = chars.length;
+        final byte[] bytes = new byte[charLength / 2];
 
-  private static int getIndex(char c) {
-    for (int i = 0; i < HEX_ARRAY.length; i++) {
-      if (HEX_ARRAY[i] == c) {
-        return i;
-      }
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] =
+                    (byte) (((getIndex(chars[i * 2]) << 4) & 0xF0)
+                            | (getIndex(chars[i * 2 + 1]) & 0x0F));
+        }
+        return bytes;
     }
-    return -1;
-  }
+
+    private static int getIndex(char c) {
+        for (int i = 0; i < HEX_UPPERCASE_ARRAY.length; i++) {
+            if (HEX_UPPERCASE_ARRAY[i] == c || HEX_LOWERCASE_ARRAY[i] == c) {
+                return i;
+            }
+        }
+        return -1;
+    }
 }
diff --git a/core/java/android/util/XmlPullAttributes.java b/core/java/android/util/XmlPullAttributes.java
index 6c8bb39..cb35eb5 100644
--- a/core/java/android/util/XmlPullAttributes.java
+++ b/core/java/android/util/XmlPullAttributes.java
@@ -34,6 +34,10 @@
         return mParser.getAttributeCount();
     }
 
+    public String getAttributeNamespace (int index) {
+        return mParser.getAttributeNamespace(index);
+    }
+
     public String getAttributeName(int index) {
         return mParser.getAttributeName(index);
     }
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 191c270..dee267d 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -774,8 +774,9 @@
      */
     public void removeAccessibilityServicesStateChangeListener(
             @NonNull AccessibilityServicesStateChangeListener listener) {
-        // Final CopyOnWriteArrayList - no lock needed.
-        mServicesStateChangeListeners.remove(listener);
+        synchronized (mLock) {
+            mServicesStateChangeListeners.remove(listener);
+        }
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index a6a2a94..8fe1d8f 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.drawable.BitmapDrawable;
@@ -378,7 +379,7 @@
         final List<Drawable> drawables = new ArrayList<>(bitmaps.size());
         for (Bitmap bitmap : bitmaps) {
             if (bitmap != null) {
-                drawables.add(new BitmapDrawable(null, bitmap));
+                drawables.add(new BitmapDrawable(Resources.getSystem(), bitmap));
             } else {
                 drawables.add(null);
             }
@@ -681,7 +682,8 @@
     private TextClassification(Parcel in) {
         mText = in.readString();
         mPrimaryIcon = in.readInt() == 0
-                ? null : new BitmapDrawable(null, Bitmap.CREATOR.createFromParcel(in));
+                ? null
+                : new BitmapDrawable(Resources.getSystem(), Bitmap.CREATOR.createFromParcel(in));
         mPrimaryLabel = in.readString();
         mPrimaryIntent = in.readInt() == 0 ? null : Intent.CREATOR.createFromParcel(in);
         mPrimaryOnClickListener = null;  // not parcelable
diff --git a/core/java/android/view/textclassifier/logging/DefaultLogger.java b/core/java/android/view/textclassifier/logging/DefaultLogger.java
index 03a6d3a..f510879 100644
--- a/core/java/android/view/textclassifier/logging/DefaultLogger.java
+++ b/core/java/android/view/textclassifier/logging/DefaultLogger.java
@@ -80,7 +80,7 @@
         Preconditions.checkNotNull(event);
         final LogMaker log = new LogMaker(MetricsEvent.TEXT_SELECTION_SESSION)
                 .setType(getLogType(event))
-                .setSubtype(MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL)
+                .setSubtype(getLogSubType(event))
                 .setPackageName(event.getPackageName())
                 .addTaggedData(START_EVENT_DELTA, event.getDurationSinceSessionStart())
                 .addTaggedData(PREV_EVENT_DELTA, event.getDurationSincePreviousEvent())
@@ -137,6 +137,17 @@
         }
     }
 
+    private static int getLogSubType(SelectionEvent event) {
+        switch (event.getInvocationMethod()) {
+            case SelectionEvent.INVOCATION_MANUAL:
+                return MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL;
+            case SelectionEvent.INVOCATION_LINK:
+                return MetricsEvent.TEXT_SELECTION_INVOCATION_LINK;
+            default:
+                return MetricsEvent.TEXT_SELECTION_INVOCATION_UNKNOWN;
+        }
+    }
+
     private static String getLogTypeString(int logType) {
         switch (logType) {
             case MetricsEvent.ACTION_TEXT_SELECTION_OVERTYPE:
@@ -176,6 +187,17 @@
         }
     }
 
+    private static String getLogSubTypeString(int logSubType) {
+        switch (logSubType) {
+            case MetricsEvent.TEXT_SELECTION_INVOCATION_MANUAL:
+                return "MANUAL";
+            case MetricsEvent.TEXT_SELECTION_INVOCATION_LINK:
+                return "LINK";
+            default:
+                return UNKNOWN;
+        }
+    }
+
     private static void debugLog(LogMaker log) {
         if (!DEBUG_LOG_ENABLED) return;
 
@@ -193,6 +215,7 @@
         final String model = Objects.toString(log.getTaggedData(MODEL_NAME), UNKNOWN);
         final String entity = Objects.toString(log.getTaggedData(ENTITY_TYPE), UNKNOWN);
         final String type = getLogTypeString(log.getType());
+        final String subType = getLogSubTypeString(log.getSubtype());
         final int smartStart = Integer.parseInt(
                 Objects.toString(log.getTaggedData(SMART_START), ZERO));
         final int smartEnd = Integer.parseInt(
@@ -202,8 +225,9 @@
         final int eventEnd = Integer.parseInt(
                 Objects.toString(log.getTaggedData(EVENT_END), ZERO));
 
-        Log.d(LOG_TAG, String.format("%2d: %s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
-                index, type, entity, eventStart, eventEnd, smartStart, smartEnd, widget, model));
+        Log.d(LOG_TAG, String.format("%2d: %s/%s/%s, range=%d,%d - smart_range=%d,%d (%s/%s)",
+                index, type, subType, entity, eventStart, eventEnd, smartStart, smartEnd, widget,
+                model));
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/logging/Logger.java b/core/java/android/view/textclassifier/logging/Logger.java
index 40e4d8c..4448b2b 100644
--- a/core/java/android/view/textclassifier/logging/Logger.java
+++ b/core/java/android/view/textclassifier/logging/Logger.java
@@ -71,6 +71,7 @@
     public static final String WIDGET_CUSTOM_UNSELECTABLE_TEXTVIEW = "nosel-customview";
     public static final String WIDGET_UNKNOWN = "unknown";
 
+    private @SelectionEvent.InvocationMethod int mInvocationMethod;
     private SelectionEvent mPrevEvent;
     private SelectionEvent mSmartEvent;
     private SelectionEvent mStartEvent;
@@ -124,16 +125,19 @@
     /**
      * Logs a "selection started" event.
      *
+     * @param invocationMethod  the way the selection was triggered
      * @param start  the token index of the selected token
      */
-    public final void logSelectionStartedEvent(int start) {
+    public final void logSelectionStartedEvent(
+            @SelectionEvent.InvocationMethod int invocationMethod, int start) {
         if (mConfig == null) {
             return;
         }
 
+        mInvocationMethod = invocationMethod;
         logEvent(new SelectionEvent(
                 start, start + 1, SelectionEvent.EVENT_SELECTION_STARTED,
-                TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
+                TextClassifier.TYPE_UNKNOWN, mInvocationMethod, NO_SIGNATURE, mConfig));
     }
 
     /**
@@ -152,7 +156,7 @@
 
         logEvent(new SelectionEvent(
                 start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
-                TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
+                TextClassifier.TYPE_UNKNOWN, mInvocationMethod, NO_SIGNATURE, mConfig));
     }
 
     /**
@@ -179,7 +183,7 @@
         final String signature = classification.getSignature();
         logEvent(new SelectionEvent(
                 start, end, SelectionEvent.EVENT_SELECTION_MODIFIED,
-                entityType, signature, mConfig));
+                entityType, mInvocationMethod, signature, mConfig));
     }
 
     /**
@@ -213,7 +217,8 @@
                 ? selection.getEntity(0)
                 : TextClassifier.TYPE_UNKNOWN;
         final String signature = selection.getSignature();
-        logEvent(new SelectionEvent(start, end, eventType, entityType, signature, mConfig));
+        logEvent(new SelectionEvent(start, end, eventType, entityType, mInvocationMethod, signature,
+                mConfig));
     }
 
     /**
@@ -234,7 +239,8 @@
         }
 
         logEvent(new SelectionEvent(
-                start, end, actionType, TextClassifier.TYPE_UNKNOWN, NO_SIGNATURE, mConfig));
+                start, end, actionType, TextClassifier.TYPE_UNKNOWN, mInvocationMethod,
+                NO_SIGNATURE, mConfig));
     }
 
     /**
@@ -265,7 +271,8 @@
                 ? classification.getEntity(0)
                 : TextClassifier.TYPE_UNKNOWN;
         final String signature = classification.getSignature();
-        logEvent(new SelectionEvent(start, end, actionType, entityType, signature, mConfig));
+        logEvent(new SelectionEvent(start, end, actionType, entityType, mInvocationMethod,
+                signature, mConfig));
     }
 
     private void logEvent(@NonNull SelectionEvent event) {
diff --git a/core/java/android/view/textclassifier/logging/SelectionEvent.java b/core/java/android/view/textclassifier/logging/SelectionEvent.java
index f40b655..a8de308 100644
--- a/core/java/android/view/textclassifier/logging/SelectionEvent.java
+++ b/core/java/android/view/textclassifier/logging/SelectionEvent.java
@@ -98,6 +98,16 @@
     /** Something else other than User or the default TextClassifier triggered a selection. */
     public static final int EVENT_AUTO_SELECTION = 5;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({INVOCATION_MANUAL, INVOCATION_LINK})
+    public @interface InvocationMethod {}
+
+    /** Selection was invoked by the user long pressing, double tapping, or dragging to select. */
+    public static final int INVOCATION_MANUAL = 1;
+    /** Selection was invoked by the user tapping on a link. */
+    public static final int INVOCATION_LINK = 2;
+
     private final int mAbsoluteStart;
     private final int mAbsoluteEnd;
     private final @EventType int mEventType;
@@ -105,6 +115,7 @@
     @Nullable private final String mWidgetVersion;
     private final String mPackageName;
     private final String mWidgetType;
+    private final @InvocationMethod int mInvocationMethod;
 
     // These fields should only be set by creator of a SelectionEvent.
     private String mSignature;
@@ -121,7 +132,7 @@
     SelectionEvent(
             int start, int end,
             @EventType int eventType, @EntityType String entityType,
-            String signature, Logger.Config config) {
+            @InvocationMethod int invocationMethod, String signature, Logger.Config config) {
         Preconditions.checkArgument(end >= start, "end cannot be less than start");
         mAbsoluteStart = start;
         mAbsoluteEnd = end;
@@ -132,6 +143,7 @@
         mWidgetVersion = config.getWidgetVersion();
         mPackageName = Preconditions.checkNotNull(config.getPackageName());
         mWidgetType = Preconditions.checkNotNull(config.getWidgetType());
+        mInvocationMethod = invocationMethod;
     }
 
     int getAbsoluteStart() {
@@ -180,6 +192,13 @@
     }
 
     /**
+     * Returns the way the selection mode was invoked.
+     */
+    public @InvocationMethod int getInvocationMethod() {
+        return mInvocationMethod;
+    }
+
+    /**
      * Returns the signature of the text classifier result associated with this event.
      */
     public String getSignature() {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 41ceb30..9988661 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -4186,7 +4186,7 @@
                         primaryHorizontal,
                         layout.getLineTop(line),
                         primaryHorizontal,
-                        layout.getLineBottom(line) - layout.getLineBottom(line) + mHandleHeight);
+                        layout.getLineBottom(line) + mHandleHeight);
             }
             // Take TextView's padding and scroll into account.
             int textHorizontalOffset = mTextView.viewportToContentHorizontalOffset();
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index e7a4c02..6ab09d6 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -111,7 +111,8 @@
         mSelectionTracker.onOriginalSelection(
                 getText(mTextView),
                 mTextView.getSelectionStart(),
-                mTextView.getSelectionEnd());
+                mTextView.getSelectionEnd(),
+                false /*isLink*/);
         cancelAsyncTask();
         if (skipTextClassification()) {
             startSelectionActionMode(null);
@@ -134,7 +135,11 @@
      * Starts Link ActionMode.
      */
     public void startLinkActionModeAsync(TextLinks.TextLink textLink) {
-        //TODO: tracking/logging
+        mSelectionTracker.onOriginalSelection(
+                getText(mTextView),
+                mTextView.getSelectionStart(),
+                mTextView.getSelectionEnd(),
+                true /*isLink*/);
         cancelAsyncTask();
         if (skipTextClassification()) {
             startLinkActionMode(null);
@@ -487,7 +492,8 @@
         /**
          * Called when the original selection happens, before smart selection is triggered.
          */
-        public void onOriginalSelection(CharSequence text, int selectionStart, int selectionEnd) {
+        public void onOriginalSelection(
+                CharSequence text, int selectionStart, int selectionEnd, boolean isLink) {
             // If we abandoned a selection and created a new one very shortly after, we may still
             // have a pending request to log ABANDON, which we flush here.
             mDelayedLogAbandon.flush();
@@ -496,7 +502,8 @@
             mOriginalEnd = mSelectionEnd = selectionEnd;
             mAllowReset = false;
             maybeInvalidateLogger();
-            mLogger.logSelectionStarted(text, selectionStart);
+            mLogger.logSelectionStarted(text, selectionStart,
+                    isLink ? SelectionEvent.INVOCATION_LINK : SelectionEvent.INVOCATION_MANUAL);
         }
 
         /**
@@ -679,7 +686,9 @@
             return Logger.WIDGET_UNSELECTABLE_TEXTVIEW;
         }
 
-        public void logSelectionStarted(CharSequence text, int index) {
+        public void logSelectionStarted(
+                CharSequence text, int index,
+                @SelectionEvent.InvocationMethod int invocationMethod) {
             try {
                 Preconditions.checkNotNull(text);
                 Preconditions.checkArgumentInRange(index, 0, text.length(), "index");
@@ -688,7 +697,7 @@
                 }
                 mTokenIterator.setText(mText);
                 mStartIndex = index;
-                mLogger.logSelectionStartedEvent(0);
+                mLogger.logSelectionStartedEvent(invocationMethod, 0);
             } catch (Exception e) {
                 // Avoid crashes due to logging.
                 Log.d(LOG_TAG, e.getMessage());
diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java
index d5b6def..64bdc6e1 100644
--- a/core/java/com/android/internal/widget/ViewPager.java
+++ b/core/java/com/android/internal/widget/ViewPager.java
@@ -31,6 +31,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.MathUtils;
+import android.view.AbsSavedState;
 import android.view.FocusFinder;
 import android.view.Gravity;
 import android.view.KeyEvent;
@@ -1198,16 +1199,12 @@
      * state, in which case it should implement a subclass of this which
      * contains that state.
      */
-    public static class SavedState extends BaseSavedState {
+    public static class SavedState extends AbsSavedState {
         int position;
         Parcelable adapterState;
         ClassLoader loader;
 
-        public SavedState(Parcel source) {
-            super(source);
-        }
-
-        public SavedState(Parcelable superState) {
+        public SavedState(@NonNull Parcelable superState) {
             super(superState);
         }
 
@@ -1225,10 +1222,15 @@
                     + " position=" + position + "}";
         }
 
-        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
+            @Override
+            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
+                return new SavedState(in, loader);
+            }
+
             @Override
             public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
+                return new SavedState(in, null);
             }
             @Override
             public SavedState[] newArray(int size) {
@@ -1237,7 +1239,7 @@
         };
 
         SavedState(Parcel in, ClassLoader loader) {
-            super(in);
+            super(in, loader);
             if (loader == null) {
                 loader = getClass().getClassLoader();
             }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 78a3e13..33f80ce 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -110,8 +110,8 @@
         "android_util_AssetManager.cpp",
         "android_util_Binder.cpp",
         "android_util_EventLog.cpp",
-        "android_util_Log.cpp",
         "android_util_MemoryIntArray.cpp",
+        "android_util_Log.cpp",
         "android_util_PathParser.cpp",
         "android_util_Process.cpp",
         "android_util_StringBlock.cpp",
@@ -191,7 +191,6 @@
         "android_backup_FileBackupHelperBase.cpp",
         "android_backup_BackupHelperDispatcher.cpp",
         "android_app_backup_FullBackup.cpp",
-        "android_content_res_ApkAssets.cpp",
         "android_content_res_ObbScanner.cpp",
         "android_content_res_Configuration.cpp",
         "android_animation_PropertyValuesHolder.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 4a032c4..d202173 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -123,7 +123,6 @@
 extern int register_android_util_PathParser(JNIEnv* env);
 extern int register_android_content_StringBlock(JNIEnv* env);
 extern int register_android_content_XmlBlock(JNIEnv* env);
-extern int register_android_content_res_ApkAssets(JNIEnv* env);
 extern int register_android_graphics_Canvas(JNIEnv* env);
 extern int register_android_graphics_CanvasProperty(JNIEnv* env);
 extern int register_android_graphics_ColorFilter(JNIEnv* env);
@@ -1347,7 +1346,6 @@
     REG_JNI(register_android_content_AssetManager),
     REG_JNI(register_android_content_StringBlock),
     REG_JNI(register_android_content_XmlBlock),
-    REG_JNI(register_android_content_res_ApkAssets),
     REG_JNI(register_android_text_AndroidCharacter),
     REG_JNI(register_android_text_Hyphenator),
     REG_JNI(register_android_text_MeasuredParagraph),
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index ed032c7..48aef4a 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -28,7 +28,7 @@
 #include <nativehelper/ScopedUtfChars.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_util_AssetManager.h>
-#include <androidfw/AssetManager2.h>
+#include <androidfw/AssetManager.h>
 #include "Utils.h"
 #include "FontUtils.h"
 
@@ -205,8 +205,7 @@
     NPE_CHECK_RETURN_ZERO(env, jpath);
 
     NativeFamilyBuilder* builder = reinterpret_cast<NativeFamilyBuilder*>(builderPtr);
-
-    Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(env, jassetMgr);
+    AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
     if (NULL == mgr) {
         builder->axes.clear();
         return false;
@@ -218,33 +217,27 @@
         return false;
     }
 
-    std::unique_ptr<Asset> asset;
-    {
-      ScopedLock<AssetManager2> locked_mgr(*mgr);
-      if (isAsset) {
-          asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
-      } else if (cookie > 0) {
-          // Valid java cookies are 1-based, but AssetManager cookies are 0-based.
-          asset = locked_mgr->OpenNonAsset(str.c_str(), static_cast<ApkAssetsCookie>(cookie - 1),
-                  Asset::ACCESS_BUFFER);
-      } else {
-          asset = locked_mgr->OpenNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
-      }
+    Asset* asset;
+    if (isAsset) {
+        asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    } else {
+        asset = cookie ? mgr->openNonAsset(static_cast<int32_t>(cookie), str.c_str(),
+                Asset::ACCESS_BUFFER) : mgr->openNonAsset(str.c_str(), Asset::ACCESS_BUFFER);
     }
 
-    if (nullptr == asset) {
+    if (NULL == asset) {
         builder->axes.clear();
         return false;
     }
 
     const void* buf = asset->getBuffer(false);
     if (NULL == buf) {
+        delete asset;
         builder->axes.clear();
         return false;
     }
 
-    sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset,
-            asset.release()));
+    sk_sp<SkData> data(SkData::MakeWithProc(buf, asset->getLength(), releaseAsset, asset));
     return addSkTypeface(builder, std::move(data), ttcIndex, weight, isItalic);
 }
 
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 49a24a3..09e37e1 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -361,7 +361,7 @@
     code->sdkVersion = sdkVersion;
 
     code->javaAssetManager = env->NewGlobalRef(jAssetMgr);
-    code->assetManager = NdkAssetManagerForJavaObject(env, jAssetMgr);
+    code->assetManager = assetManagerForJavaObject(env, jAssetMgr);
 
     if (obbDir != NULL) {
         dirStr = env->GetStringUTFChars(obbDir, NULL);
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
deleted file mode 100644
index c0f151b..0000000
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "android-base/macros.h"
-#include "android-base/stringprintf.h"
-#include "android-base/unique_fd.h"
-#include "androidfw/ApkAssets.h"
-#include "utils/misc.h"
-
-#include "core_jni_helpers.h"
-#include "jni.h"
-#include "nativehelper/ScopedUtfChars.h"
-
-using ::android::base::unique_fd;
-
-namespace android {
-
-static jlong NativeLoad(JNIEnv* env, jclass /*clazz*/, jstring java_path, jboolean system,
-                        jboolean force_shared_lib, jboolean overlay) {
-  ScopedUtfChars path(env, java_path);
-  if (path.c_str() == nullptr) {
-    return 0;
-  }
-
-  std::unique_ptr<const ApkAssets> apk_assets;
-  if (overlay) {
-    apk_assets = ApkAssets::LoadOverlay(path.c_str(), system);
-  } else if (force_shared_lib) {
-    apk_assets = ApkAssets::LoadAsSharedLibrary(path.c_str(), system);
-  } else {
-    apk_assets = ApkAssets::Load(path.c_str(), system);
-  }
-
-  if (apk_assets == nullptr) {
-    std::string error_msg = base::StringPrintf("Failed to load asset path %s", path.c_str());
-    jniThrowException(env, "java/io/IOException", error_msg.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(apk_assets.release());
-}
-
-static jlong NativeLoadFromFd(JNIEnv* env, jclass /*clazz*/, jobject file_descriptor,
-                              jstring friendly_name, jboolean system, jboolean force_shared_lib) {
-  ScopedUtfChars friendly_name_utf8(env, friendly_name);
-  if (friendly_name_utf8.c_str() == nullptr) {
-    return 0;
-  }
-
-  int fd = jniGetFDFromFileDescriptor(env, file_descriptor);
-  if (fd < 0) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
-    return 0;
-  }
-
-  unique_fd dup_fd(::dup(fd));
-  if (dup_fd < 0) {
-    jniThrowIOException(env, errno);
-    return 0;
-  }
-
-  std::unique_ptr<const ApkAssets> apk_assets = ApkAssets::LoadFromFd(std::move(dup_fd),
-                                                                      friendly_name_utf8.c_str(),
-                                                                      system, force_shared_lib);
-  if (apk_assets == nullptr) {
-    std::string error_msg = base::StringPrintf("Failed to load asset path %s from fd %d",
-                                               friendly_name_utf8.c_str(), dup_fd.get());
-    jniThrowException(env, "java/io/IOException", error_msg.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(apk_assets.release());
-}
-
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  delete reinterpret_cast<ApkAssets*>(ptr);
-}
-
-static jstring NativeGetAssetPath(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  return env->NewStringUTF(apk_assets->GetPath().c_str());
-}
-
-static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool());
-}
-
-static jboolean NativeIsUpToDate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  (void)apk_assets;
-  return JNI_TRUE;
-}
-
-static jlong NativeOpenXml(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring file_name) {
-  ScopedUtfChars path_utf8(env, file_name);
-  if (path_utf8.c_str() == nullptr) {
-    return 0;
-  }
-
-  const ApkAssets* apk_assets = reinterpret_cast<const ApkAssets*>(ptr);
-  std::unique_ptr<Asset> asset = apk_assets->Open(path_utf8.c_str(),
-                                                  Asset::AccessMode::ACCESS_RANDOM);
-  if (asset == nullptr) {
-    jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
-    return 0;
-  }
-
-  // DynamicRefTable is only needed when looking up resource references. Opening an XML file
-  // directly from an ApkAssets has no notion of proper resource references.
-  std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
-  status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
-  asset.reset();
-
-  if (err != NO_ERROR) {
-    jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
-    return 0;
-  }
-  return reinterpret_cast<jlong>(xml_tree.release());
-}
-
-// JNI registration.
-static const JNINativeMethod gApkAssetsMethods[] = {
-    {"nativeLoad", "(Ljava/lang/String;ZZZ)J", (void*)NativeLoad},
-    {"nativeLoadFromFd", "(Ljava/io/FileDescriptor;Ljava/lang/String;ZZ)J",
-        (void*)NativeLoadFromFd},
-    {"nativeDestroy", "(J)V", (void*)NativeDestroy},
-    {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
-    {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
-    {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
-    {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
-};
-
-int register_android_content_res_ApkAssets(JNIEnv* env) {
-  return RegisterMethodsOrDie(env, "android/content/res/ApkAssets", gApkAssetsMethods,
-                              arraysize(gApkAssetsMethods));
-}
-
-}  // namespace android
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 2334e03..683b4c4 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1,1433 +1,1851 @@
-/*
- * Copyright 2006, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/libs/android_runtime/android_util_AssetManager.cpp
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
 
 #define LOG_TAG "asset"
 
+#include <android_runtime/android_util_AssetManager.h>
+
 #include <inttypes.h>
 #include <linux/capability.h>
 #include <stdio.h>
-#include <sys/stat.h>
-#include <sys/system_properties.h>
 #include <sys/types.h>
 #include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/system_properties.h>
 
 #include <private/android_filesystem_config.h> // for AID_SYSTEM
 
-#include "android-base/logging.h"
-#include "android-base/properties.h"
-#include "android-base/stringprintf.h"
-#include "android_runtime/android_util_AssetManager.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "android_util_Binder.h"
 #include "androidfw/Asset.h"
 #include "androidfw/AssetManager.h"
-#include "androidfw/AssetManager2.h"
 #include "androidfw/AttributeResolution.h"
-#include "androidfw/MutexGuard.h"
 #include "androidfw/ResourceTypes.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_util_Binder.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
-#include "nativehelper/JNIHelp.h"
-#include "nativehelper/ScopedPrimitiveArray.h"
-#include "nativehelper/ScopedStringChars.h"
-#include "nativehelper/ScopedUtfChars.h"
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedUtfChars.h>
 #include "utils/Log.h"
-#include "utils/String8.h"
 #include "utils/misc.h"
+#include "utils/String8.h"
 
 extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap);
 extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
 
-using ::android::base::StringPrintf;
 
 namespace android {
 
+static const bool kThrowOnBadId = false;
+
 // ----------------------------------------------------------------------------
 
-static struct typedvalue_offsets_t {
-  jfieldID mType;
-  jfieldID mData;
-  jfieldID mString;
-  jfieldID mAssetCookie;
-  jfieldID mResourceId;
-  jfieldID mChangingConfigurations;
-  jfieldID mDensity;
+static struct typedvalue_offsets_t
+{
+    jfieldID mType;
+    jfieldID mData;
+    jfieldID mString;
+    jfieldID mAssetCookie;
+    jfieldID mResourceId;
+    jfieldID mChangingConfigurations;
+    jfieldID mDensity;
 } gTypedValueOffsets;
 
-static struct assetfiledescriptor_offsets_t {
-  jfieldID mFd;
-  jfieldID mStartOffset;
-  jfieldID mLength;
+static struct assetfiledescriptor_offsets_t
+{
+    jfieldID mFd;
+    jfieldID mStartOffset;
+    jfieldID mLength;
 } gAssetFileDescriptorOffsets;
 
-static struct assetmanager_offsets_t {
-  jfieldID mObject;
+static struct assetmanager_offsets_t
+{
+    jfieldID mObject;
 } gAssetManagerOffsets;
 
-static struct {
-  jfieldID native_ptr;
-} gApkAssetsFields;
-
-static struct sparsearray_offsets_t {
-  jclass classObject;
-  jmethodID constructor;
-  jmethodID put;
+static struct sparsearray_offsets_t
+{
+    jclass classObject;
+    jmethodID constructor;
+    jmethodID put;
 } gSparseArrayOffsets;
 
-static struct configuration_offsets_t {
-  jclass classObject;
-  jmethodID constructor;
-  jfieldID mSmallestScreenWidthDpOffset;
-  jfieldID mScreenWidthDpOffset;
-  jfieldID mScreenHeightDpOffset;
+static struct configuration_offsets_t
+{
+    jclass classObject;
+    jmethodID constructor;
+    jfieldID mSmallestScreenWidthDpOffset;
+    jfieldID mScreenWidthDpOffset;
+    jfieldID mScreenHeightDpOffset;
 } gConfigurationOffsets;
 
-jclass g_stringClass = nullptr;
+jclass g_stringClass = NULL;
 
 // ----------------------------------------------------------------------------
 
-// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
-constexpr inline static jint ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
-  return cookie != kInvalidCookie ? static_cast<jint>(cookie + 1) : -1;
-}
+static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+                      const Res_value& value, uint32_t ref, ssize_t block,
+                      uint32_t typeSpecFlags, ResTable_config* config = NULL);
 
-constexpr inline static ApkAssetsCookie JavaCookieToApkAssetsCookie(jint cookie) {
-  return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
+jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
+               const Res_value& value, uint32_t ref, ssize_t block,
+               uint32_t typeSpecFlags, ResTable_config* config)
+{
+    env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
+    env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
+                     static_cast<jint>(table->getTableCookie(block)));
+    env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
+    env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
+    env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
+    env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
+            typeSpecFlags);
+    if (config != NULL) {
+        env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
+    }
+    return block;
 }
 
 // This is called by zygote (running as user root) as part of preloadResources.
-static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
-  switch (pid_t pid = fork()) {
-    case -1:
-      PLOG(ERROR) << "failed to fork for idmap";
-      break;
+static void verifySystemIdmaps()
+{
+    pid_t pid;
+    char system_id[10];
 
-    // child
-    case 0: {
-      struct __user_cap_header_struct capheader;
-      struct __user_cap_data_struct capdata;
+    snprintf(system_id, sizeof(system_id), "%d", AID_SYSTEM);
 
-      memset(&capheader, 0, sizeof(capheader));
-      memset(&capdata, 0, sizeof(capdata));
+    switch (pid = fork()) {
+        case -1:
+            ALOGE("failed to fork for idmap: %s", strerror(errno));
+            break;
+        case 0: // child
+            {
+                struct __user_cap_header_struct capheader;
+                struct __user_cap_data_struct capdata;
 
-      capheader.version = _LINUX_CAPABILITY_VERSION;
-      capheader.pid = 0;
+                memset(&capheader, 0, sizeof(capheader));
+                memset(&capdata, 0, sizeof(capdata));
 
-      if (capget(&capheader, &capdata) != 0) {
-        PLOG(ERROR) << "capget";
-        exit(1);
-      }
+                capheader.version = _LINUX_CAPABILITY_VERSION;
+                capheader.pid = 0;
 
-      capdata.effective = capdata.permitted;
-      if (capset(&capheader, &capdata) != 0) {
-        PLOG(ERROR) << "capset";
-        exit(1);
-      }
+                if (capget(&capheader, &capdata) != 0) {
+                    ALOGE("capget: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      if (setgid(AID_SYSTEM) != 0) {
-        PLOG(ERROR) << "setgid";
-        exit(1);
-      }
+                capdata.effective = capdata.permitted;
+                if (capset(&capheader, &capdata) != 0) {
+                    ALOGE("capset: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      if (setuid(AID_SYSTEM) != 0) {
-        PLOG(ERROR) << "setuid";
-        exit(1);
-      }
+                if (setgid(AID_SYSTEM) != 0) {
+                    ALOGE("setgid: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      // Generic idmap parameters
-      const char* argv[8];
-      int argc = 0;
-      struct stat st;
+                if (setuid(AID_SYSTEM) != 0) {
+                    ALOGE("setuid: %s\n", strerror(errno));
+                    exit(1);
+                }
 
-      memset(argv, 0, sizeof(argv));
-      argv[argc++] = AssetManager::IDMAP_BIN;
-      argv[argc++] = "--scan";
-      argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
-      argv[argc++] = AssetManager::TARGET_APK_PATH;
-      argv[argc++] = AssetManager::IDMAP_DIR;
+                // Generic idmap parameters
+                const char* argv[8];
+                int argc = 0;
+                struct stat st;
 
-      // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
-      // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
-      std::string overlay_theme_path = base::GetProperty(AssetManager::OVERLAY_THEME_DIR_PROPERTY,
-                                                         "");
-      if (!overlay_theme_path.empty()) {
-        overlay_theme_path = std::string(AssetManager::OVERLAY_DIR) + "/" + overlay_theme_path;
-        if (stat(overlay_theme_path.c_str(), &st) == 0) {
-          argv[argc++] = overlay_theme_path.c_str();
-        }
-      }
+                memset(argv, NULL, sizeof(argv));
+                argv[argc++] = AssetManager::IDMAP_BIN;
+                argv[argc++] = "--scan";
+                argv[argc++] = AssetManager::TARGET_PACKAGE_NAME;
+                argv[argc++] = AssetManager::TARGET_APK_PATH;
+                argv[argc++] = AssetManager::IDMAP_DIR;
 
-      if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
-        argv[argc++] = AssetManager::OVERLAY_DIR;
-      }
+                // Directories to scan for overlays: if OVERLAY_THEME_DIR_PROPERTY is defined,
+                // use OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in addition to OVERLAY_DIR.
+                char subdir[PROP_VALUE_MAX];
+                int len = __system_property_get(AssetManager::OVERLAY_THEME_DIR_PROPERTY, subdir);
+                if (len > 0) {
+                    String8 overlayPath = String8(AssetManager::OVERLAY_DIR) + "/" + subdir;
+                    if (stat(overlayPath.string(), &st) == 0) {
+                        argv[argc++] = overlayPath.string();
+                    }
+                }
+                if (stat(AssetManager::OVERLAY_DIR, &st) == 0) {
+                    argv[argc++] = AssetManager::OVERLAY_DIR;
+                }
 
-      if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
-        argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
-      }
+                if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
+                    argv[argc++] = AssetManager::PRODUCT_OVERLAY_DIR;
+                }
 
-      // Finally, invoke idmap (if any overlay directory exists)
-      if (argc > 5) {
-        execv(AssetManager::IDMAP_BIN, (char* const*)argv);
-        PLOG(ERROR) << "failed to execv for idmap";
-        exit(1); // should never get here
-      } else {
-        exit(0);
-      }
-  } break;
-
-  // parent
-  default:
-    waitpid(pid, nullptr, 0);
-    break;
-  }
+                // Finally, invoke idmap (if any overlay directory exists)
+                if (argc > 5) {
+                    execv(AssetManager::IDMAP_BIN, (char* const*)argv);
+                    ALOGE("failed to execv for idmap: %s", strerror(errno));
+                    exit(1); // should never get here
+                } else {
+                    exit(0);
+                }
+            }
+            break;
+        default: // parent
+            waitpid(pid, NULL, 0);
+            break;
+    }
 }
 
-static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
-                      uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
-                   ApkAssetsCookieToJavaCookie(cookie));
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
-  env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
-  env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
-  if (config != nullptr) {
-    env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
-  }
-  return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
-}
 
 // ----------------------------------------------------------------------------
 
-// Let the opaque type AAssetManager refer to a guarded AssetManager2 instance.
-struct GuardedAssetManager : public ::AAssetManager {
-  Guarded<AssetManager2> guarded_assetmanager;
-};
-
-::AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
-  jlong assetmanager_handle = env->GetLongField(jassetmanager, gAssetManagerOffsets.mObject);
-  ::AAssetManager* am = reinterpret_cast<::AAssetManager*>(assetmanager_handle);
-  if (am == nullptr) {
+// this guy is exported to other jni routines
+AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
+{
+    jlong amHandle = env->GetLongField(obj, gAssetManagerOffsets.mObject);
+    AssetManager* am = reinterpret_cast<AssetManager*>(amHandle);
+    if (am != NULL) {
+        return am;
+    }
     jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
-    return nullptr;
-  }
-  return am;
+    return NULL;
 }
 
-Guarded<AssetManager2>* AssetManagerForNdkAssetManager(::AAssetManager* assetmanager) {
-  if (assetmanager == nullptr) {
-    return nullptr;
-  }
-  return &reinterpret_cast<GuardedAssetManager*>(assetmanager)->guarded_assetmanager;
-}
-
-Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager) {
-  return AssetManagerForNdkAssetManager(NdkAssetManagerForJavaObject(env, jassetmanager));
-}
-
-static Guarded<AssetManager2>& AssetManagerFromLong(jlong ptr) {
-  return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
-}
-
-static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
-                                          jlongArray out_offsets) {
-  off64_t start_offset, length;
-  int fd = asset->openFileDescriptor(&start_offset, &length);
-  asset.reset();
-
-  if (fd < 0) {
-    jniThrowException(env, "java/io/FileNotFoundException",
-                      "This file can not be opened as a file descriptor; it is probably "
-                      "compressed");
-    return nullptr;
-  }
-
-  jlong* offsets = reinterpret_cast<jlong*>(env->GetPrimitiveArrayCritical(out_offsets, 0));
-  if (offsets == nullptr) {
-    close(fd);
-    return nullptr;
-  }
-
-  offsets[0] = start_offset;
-  offsets[1] = length;
-
-  env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0);
-
-  jobject file_desc = jniCreateFileDescriptor(env, fd);
-  if (file_desc == nullptr) {
-    close(fd);
-    return nullptr;
-  }
-  return newParcelFileDescriptor(env, file_desc);
-}
-
-static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) {
-  return Asset::getGlobalCount();
-}
-
-static jobject NativeGetAssetAllocations(JNIEnv* env, jobject /*clazz*/) {
-  String8 alloc = Asset::getAssetAllocations();
-  if (alloc.length() <= 0) {
-    return nullptr;
-  }
-  return env->NewStringUTF(alloc.string());
-}
-
-static jint NativeGetGlobalAssetManagerCount(JNIEnv* /*env*/, jobject /*clazz*/) {
-  // TODO(adamlesinski): Switch to AssetManager2.
-  return AssetManager::getGlobalCount();
-}
-
-static jlong NativeCreate(JNIEnv* /*env*/, jclass /*clazz*/) {
-  // AssetManager2 needs to be protected by a lock. To avoid cache misses, we allocate the lock and
-  // AssetManager2 in a contiguous block (GuardedAssetManager).
-  return reinterpret_cast<jlong>(new GuardedAssetManager());
-}
-
-static void NativeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  delete reinterpret_cast<GuardedAssetManager*>(ptr);
-}
-
-static void NativeSetApkAssets(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                               jobjectArray apk_assets_array, jboolean invalidate_caches) {
-  const jsize apk_assets_len = env->GetArrayLength(apk_assets_array);
-  std::vector<const ApkAssets*> apk_assets;
-  apk_assets.reserve(apk_assets_len);
-  for (jsize i = 0; i < apk_assets_len; i++) {
-    jobject obj = env->GetObjectArrayElement(apk_assets_array, i);
-    if (obj == nullptr) {
-      std::string msg = StringPrintf("ApkAssets at index %d is null", i);
-      jniThrowNullPointerException(env, msg.c_str());
-      return;
+static jlong android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
+                                                jstring fileName, jint mode)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
     }
 
-    jlong apk_assets_native_ptr = env->GetLongField(obj, gApkAssetsFields.native_ptr);
-    if (env->ExceptionCheck()) {
-      return;
-    }
-    apk_assets.push_back(reinterpret_cast<const ApkAssets*>(apk_assets_native_ptr));
-  }
+    ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
 
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  assetmanager->SetApkAssets(apk_assets, invalidate_caches);
-}
-
-static void NativeSetConfiguration(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint mcc, jint mnc,
-                                   jstring locale, jint orientation, jint touchscreen, jint density,
-                                   jint keyboard, jint keyboard_hidden, jint navigation,
-                                   jint screen_width, jint screen_height,
-                                   jint smallest_screen_width_dp, jint screen_width_dp,
-                                   jint screen_height_dp, jint screen_layout, jint ui_mode,
-                                   jint color_mode, jint major_version) {
-  ResTable_config configuration;
-  memset(&configuration, 0, sizeof(configuration));
-  configuration.mcc = static_cast<uint16_t>(mcc);
-  configuration.mnc = static_cast<uint16_t>(mnc);
-  configuration.orientation = static_cast<uint8_t>(orientation);
-  configuration.touchscreen = static_cast<uint8_t>(touchscreen);
-  configuration.density = static_cast<uint16_t>(density);
-  configuration.keyboard = static_cast<uint8_t>(keyboard);
-  configuration.inputFlags = static_cast<uint8_t>(keyboard_hidden);
-  configuration.navigation = static_cast<uint8_t>(navigation);
-  configuration.screenWidth = static_cast<uint16_t>(screen_width);
-  configuration.screenHeight = static_cast<uint16_t>(screen_height);
-  configuration.smallestScreenWidthDp = static_cast<uint16_t>(smallest_screen_width_dp);
-  configuration.screenWidthDp = static_cast<uint16_t>(screen_width_dp);
-  configuration.screenHeightDp = static_cast<uint16_t>(screen_height_dp);
-  configuration.screenLayout = static_cast<uint8_t>(screen_layout);
-  configuration.uiMode = static_cast<uint8_t>(ui_mode);
-  configuration.colorMode = static_cast<uint8_t>(color_mode);
-  configuration.sdkVersion = static_cast<uint16_t>(major_version);
-
-  if (locale != nullptr) {
-    ScopedUtfChars locale_utf8(env, locale);
-    CHECK(locale_utf8.c_str() != nullptr);
-    configuration.setBcp47Locale(locale_utf8.c_str());
-  }
-
-  // Constants duplicated from Java class android.content.res.Configuration.
-  static const jint kScreenLayoutRoundMask = 0x300;
-  static const jint kScreenLayoutRoundShift = 8;
-
-  // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
-  // in C++. We must extract the round qualifier out of the Java screenLayout and put it
-  // into screenLayout2.
-  configuration.screenLayout2 =
-      static_cast<uint8_t>((screen_layout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  assetmanager->SetConfiguration(configuration);
-}
-
-static jobject NativeGetAssignedPackageIdentifiers(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-
-  jobject sparse_array =
-        env->NewObject(gSparseArrayOffsets.classObject, gSparseArrayOffsets.constructor);
-
-  if (sparse_array == nullptr) {
-    // An exception is pending.
-    return nullptr;
-  }
-
-  assetmanager->ForEachPackage([&](const std::string& package_name, uint8_t package_id) {
-    jstring jpackage_name = env->NewStringUTF(package_name.c_str());
-    if (jpackage_name == nullptr) {
-      // An exception is pending.
-      return;
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Empty file name");
+        return -1;
     }
 
-    env->CallVoidMethod(sparse_array, gSparseArrayOffsets.put, static_cast<jint>(package_id),
-                        jpackage_name);
-  });
-  return sparse_array;
-}
-
-static jobjectArray NativeList(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring path) {
-  ScopedUtfChars path_utf8(env, path);
-  if (path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<AssetDir> asset_dir =
-      assetmanager->OpenDir(path_utf8.c_str());
-  if (asset_dir == nullptr) {
-    jniThrowException(env, "java/io/FileNotFoundException", path_utf8.c_str());
-    return nullptr;
-  }
-
-  const size_t file_count = asset_dir->getFileCount();
-
-  jobjectArray array = env->NewObjectArray(file_count, g_stringClass, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  for (size_t i = 0; i < file_count; i++) {
-    jstring java_string = env->NewStringUTF(asset_dir->getFileName(i).string());
-
-    // Check for errors creating the strings (if malformed or no memory).
-    if (env->ExceptionCheck()) {
-     return nullptr;
+    if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+        && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+        return -1;
     }
 
-    env->SetObjectArrayElement(array, i, java_string);
+    Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
 
-    // If we have a large amount of string in our array, we might overflow the
-    // local reference table of the VM.
-    env->DeleteLocalRef(java_string);
-  }
-  return array;
-}
-
-static jlong NativeOpenAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
-                             jint access_mode) {
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
-
-  if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
-      access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
-    return 0;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset =
-      assetmanager->Open(asset_path_utf8.c_str(), static_cast<Asset::AccessMode>(access_mode));
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(asset.release());
-}
-
-static jobject NativeOpenAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring asset_path,
-                                 jlongArray out_offsets) {
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset = assetmanager->Open(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return nullptr;
-  }
-  return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
-}
-
-static jlong NativeOpenNonAsset(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
-                                jstring asset_path, jint access_mode) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
-
-  if (access_mode != Asset::ACCESS_UNKNOWN && access_mode != Asset::ACCESS_RANDOM &&
-      access_mode != Asset::ACCESS_STREAMING && access_mode != Asset::ACCESS_BUFFER) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
-    return 0;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie,
-                                       static_cast<Asset::AccessMode>(access_mode));
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(),
-                                       static_cast<Asset::AccessMode>(access_mode));
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-  return reinterpret_cast<jlong>(asset.release());
-}
-
-static jobject NativeOpenNonAssetFd(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint jcookie,
-                                    jstring asset_path, jlongArray out_offsets) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return nullptr;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM);
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return nullptr;
-  }
-  return ReturnParcelFileDescriptor(env, std::move(asset), out_offsets);
-}
-
-static jlong NativeOpenXmlAsset(JNIEnv* env, jobject /*clazz*/, jlong ptr, jint jcookie,
-                                jstring asset_path) {
-  ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
-  ScopedUtfChars asset_path_utf8(env, asset_path);
-  if (asset_path_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::unique_ptr<Asset> asset;
-  if (cookie != kInvalidCookie) {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), cookie, Asset::ACCESS_RANDOM);
-  } else {
-    asset = assetmanager->OpenNonAsset(asset_path_utf8.c_str(), Asset::ACCESS_RANDOM, &cookie);
-  }
-
-  if (!asset) {
-    jniThrowException(env, "java/io/FileNotFoundException", asset_path_utf8.c_str());
-    return 0;
-  }
-
-  // May be nullptr.
-  const DynamicRefTable* dynamic_ref_table = assetmanager->GetDynamicRefTableForCookie(cookie);
-
-  std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(dynamic_ref_table);
-  status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
-  asset.reset();
-
-  if (err != NO_ERROR) {
-    jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
-    return 0;
-  }
-  return reinterpret_cast<jlong>(xml_tree.release());
-}
-
-static jint NativeGetResourceValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
-                                   jshort density, jobject typed_value,
-                                   jboolean resolve_references) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Res_value value;
-  ResTable_config selected_config;
-  uint32_t flags;
-  ApkAssetsCookie cookie =
-      assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
-                                static_cast<uint16_t>(density), &value, &selected_config, &flags);
-  if (cookie == kInvalidCookie) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-
-  uint32_t ref = static_cast<uint32_t>(resid);
-  if (resolve_references) {
-    cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-    }
-  }
-  return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
-}
-
-static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
-                                      jint bag_entry_id, jobject typed_value) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-
-  uint32_t type_spec_flags = bag->type_spec_flags;
-  ApkAssetsCookie cookie = kInvalidCookie;
-  const Res_value* bag_value = nullptr;
-  for (const ResolvedBag::Entry& entry : bag) {
-    if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
-      cookie = entry.cookie;
-      bag_value = &entry.value;
-
-      // Keep searching (the old implementation did that).
-    }
-  }
-
-  if (cookie == kInvalidCookie) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-
-  Res_value value = *bag_value;
-  uint32_t ref = static_cast<uint32_t>(resid);
-  ResTable_config selected_config;
-  cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
-  if (cookie == kInvalidCookie) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-  return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
-}
-
-static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return nullptr;
-  }
-
-  jintArray array = env->NewIntArray(bag->entry_count);
-  if (env->ExceptionCheck()) {
-    return nullptr;
-  }
-
-  for (uint32_t i = 0; i < bag->entry_count; i++) {
-    jint attr_resid = bag->entries[i].key;
-    env->SetIntArrayRegion(array, i, 1, &attr_resid);
-  }
-  return array;
-}
-
-static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                                                 jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return nullptr;
-  }
-
-  jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  for (uint32_t i = 0; i < bag->entry_count; i++) {
-    const ResolvedBag::Entry& entry = bag->entries[i];
-
-    // Resolve any references to their final value.
-    Res_value value = entry.value;
-    ResTable_config selected_config;
-    uint32_t flags;
-    uint32_t ref;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      return nullptr;
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return -1;
     }
 
-    if (value.dataType == Res_value::TYPE_STRING) {
-      const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
-      const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
+    //printf("Created Asset Stream: %p\n", a);
 
-      jstring java_string = nullptr;
-      size_t str_len;
-      const char* str_utf8 = pool->string8At(value.data, &str_len);
-      if (str_utf8 != nullptr) {
-        java_string = env->NewStringUTF(str_utf8);
-      } else {
-        const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
-        java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
-      }
-
-      // Check for errors creating the strings (if malformed or no memory).
-      if (env->ExceptionCheck()) {
-        return nullptr;
-      }
-
-      env->SetObjectArrayElement(array, i, java_string);
-
-      // If we have a large amount of string in our array, we might overflow the
-      // local reference table of the VM.
-      env->DeleteLocalRef(java_string);
-    }
-  }
-  return array;
+    return reinterpret_cast<jlong>(a);
 }
 
-static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                                                  jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return nullptr;
-  }
+static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
+{
+    off64_t startOffset, length;
+    int fd = a->openFileDescriptor(&startOffset, &length);
+    delete a;
 
-  jintArray array = env->NewIntArray(bag->entry_count * 2);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
-  if (buffer == nullptr) {
-    return nullptr;
-  }
-
-  for (size_t i = 0; i < bag->entry_count; i++) {
-    const ResolvedBag::Entry& entry = bag->entries[i];
-    Res_value value = entry.value;
-    ResTable_config selected_config;
-    uint32_t flags;
-    uint32_t ref;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
-      return nullptr;
+    if (fd < 0) {
+        jniThrowException(env, "java/io/FileNotFoundException",
+                "This file can not be opened as a file descriptor; it is probably compressed");
+        return NULL;
     }
 
-    jint string_index = -1;
-    if (value.dataType == Res_value::TYPE_STRING) {
-      string_index = static_cast<jint>(value.data);
+    jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
+    if (offsets == NULL) {
+        close(fd);
+        return NULL;
     }
 
-    buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
-    buffer[(i * 2) + 1] = string_index;
-  }
-  env->ReleasePrimitiveArrayCritical(array, buffer, 0);
-  return array;
+    offsets[0] = startOffset;
+    offsets[1] = length;
+
+    env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
+
+    jobject fileDesc = jniCreateFileDescriptor(env, fd);
+    if (fileDesc == NULL) {
+        close(fd);
+        return NULL;
+    }
+
+    return newParcelFileDescriptor(env, fileDesc);
 }
 
-static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return nullptr;
-  }
-
-  jintArray array = env->NewIntArray(bag->entry_count);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(array, nullptr));
-  if (buffer == nullptr) {
-    return nullptr;
-  }
-
-  for (size_t i = 0; i < bag->entry_count; i++) {
-    const ResolvedBag::Entry& entry = bag->entries[i];
-    Res_value value = entry.value;
-    ResTable_config selected_config;
-    uint32_t flags;
-    uint32_t ref;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
-      return nullptr;
+static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
+                                                jstring fileName, jlongArray outOffsets)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
     }
 
-    if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
-      buffer[i] = static_cast<jint>(value.data);
-    }
-  }
-  env->ReleasePrimitiveArrayCritical(array, buffer, 0);
-  return array;
-}
+    ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
 
-static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return -1;
-  }
-  return static_cast<jint>(bag->entry_count);
-}
-
-static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
-                                   jintArray out_data) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
-  if (bag == nullptr) {
-    return -1;
-  }
-
-  const jsize out_data_length = env->GetArrayLength(out_data);
-  if (env->ExceptionCheck()) {
-    return -1;
-  }
-
-  if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
-    jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
-    return -1;
-  }
-
-  jint* buffer = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_data, nullptr));
-  if (buffer == nullptr) {
-    return -1;
-  }
-
-  jint* cursor = buffer;
-  for (size_t i = 0; i < bag->entry_count; i++) {
-    const ResolvedBag::Entry& entry = bag->entries[i];
-    Res_value value = entry.value;
-    ResTable_config selected_config;
-    selected_config.density = 0;
-    uint32_t flags = bag->type_spec_flags;
-    uint32_t ref;
-    ApkAssetsCookie cookie =
-        assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
-      return -1;
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
     }
 
-    // Deal with the special @null value -- it turns back to TYPE_NULL.
-    if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
-      value.dataType = Res_value::TYPE_NULL;
-      value.data = Res_value::DATA_NULL_UNDEFINED;
+    Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
     }
 
-    cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
-    cursor[STYLE_DATA] = static_cast<jint>(value.data);
-    cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
-    cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
-    cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
-    cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
-    cursor += STYLE_NUM_ENTRIES;
-  }
-  env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
-  return static_cast<jint>(bag->entry_count);
+    //printf("Created Asset Stream: %p\n", a);
+
+    return returnParcelFileDescriptor(env, a, outOffsets);
 }
 
-static jint NativeGetResourceIdentifier(JNIEnv* env, jclass /*clazz*/, jlong ptr, jstring name,
-                                        jstring def_type, jstring def_package) {
-  ScopedUtfChars name_utf8(env, name);
-  if (name_utf8.c_str() == nullptr) {
-    // This will throw NPE.
-    return 0;
-  }
-
-  std::string type;
-  if (def_type != nullptr) {
-    ScopedUtfChars type_utf8(env, def_type);
-    CHECK(type_utf8.c_str() != nullptr);
-    type = type_utf8.c_str();
-  }
-
-  std::string package;
-  if (def_package != nullptr) {
-    ScopedUtfChars package_utf8(env, def_package);
-    CHECK(package_utf8.c_str() != nullptr);
-    package = package_utf8.c_str();
-  }
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
-}
-
-static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  AssetManager2::ResourceName name;
-  if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
-    return nullptr;
-  }
-
-  std::string result;
-  if (name.package != nullptr) {
-    result.append(name.package, name.package_len);
-  }
-
-  if (name.type != nullptr || name.type16 != nullptr) {
-    if (!result.empty()) {
-      result += ":";
+static jlong android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName,
+                                                         jint mode)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
     }
 
-    if (name.type != nullptr) {
-      result.append(name.type, name.type_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
-    }
-  }
+    ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
 
-  if (name.entry != nullptr || name.entry16 != nullptr) {
-    if (!result.empty()) {
-      result += "/";
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return -1;
     }
 
-    if (name.entry != nullptr) {
-      result.append(name.entry, name.entry_len);
-    } else {
-      result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
-    }
-  }
-  return env->NewStringUTF(result.c_str());
-}
-
-static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  AssetManager2::ResourceName name;
-  if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
-    return nullptr;
-  }
-
-  if (name.package != nullptr) {
-    return env->NewStringUTF(name.package);
-  }
-  return nullptr;
-}
-
-static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  AssetManager2::ResourceName name;
-  if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
-    return nullptr;
-  }
-
-  if (name.type != nullptr) {
-    return env->NewStringUTF(name.type);
-  } else if (name.type16 != nullptr) {
-    return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
-  }
-  return nullptr;
-}
-
-static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  AssetManager2::ResourceName name;
-  if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
-    return nullptr;
-  }
-
-  if (name.entry != nullptr) {
-    return env->NewStringUTF(name.entry);
-  } else if (name.entry16 != nullptr) {
-    return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
-  }
-  return nullptr;
-}
-
-static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr,
-                                     jboolean exclude_system) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::set<std::string> locales =
-      assetmanager->GetResourceLocales(exclude_system, true /*merge_equivalent_languages*/);
-
-  jobjectArray array = env->NewObjectArray(locales.size(), g_stringClass, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  size_t idx = 0;
-  for (const std::string& locale : locales) {
-    jstring java_string = env->NewStringUTF(locale.c_str());
-    if (java_string == nullptr) {
-      return nullptr;
-    }
-    env->SetObjectArrayElement(array, idx++, java_string);
-    env->DeleteLocalRef(java_string);
-  }
-  return array;
-}
-
-static jobject ConstructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
-  jobject result =
-      env->NewObject(gConfigurationOffsets.classObject, gConfigurationOffsets.constructor);
-  if (result == nullptr) {
-    return nullptr;
-  }
-
-  env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
-                   config.smallestScreenWidthDp);
-  env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
-  env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
-  return result;
-}
-
-static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  std::set<ResTable_config> configurations =
-      assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
-
-  jobjectArray array =
-      env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
-  if (array == nullptr) {
-    return nullptr;
-  }
-
-  size_t idx = 0;
-  for (const ResTable_config& configuration : configurations) {
-    jobject java_configuration = ConstructConfigurationObject(env, configuration);
-    if (java_configuration == nullptr) {
-      return nullptr;
+    if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
+        && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
+        return -1;
     }
 
-    env->SetObjectArrayElement(array, idx++, java_configuration);
-    env->DeleteLocalRef(java_configuration);
-  }
-  return array;
+    Asset* a = cookie
+        ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(),
+                (Asset::AccessMode)mode)
+        : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return -1;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return reinterpret_cast<jlong>(a);
 }
 
-static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                             jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
-                             jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
+static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName,
+                                                         jlongArray outOffsets)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
 
-  ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
-  uint32_t* out_values = reinterpret_cast<uint32_t*>(out_values_ptr);
-  uint32_t* out_indices = reinterpret_cast<uint32_t*>(out_indices_ptr);
+    ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
 
-  jsize attrs_len = env->GetArrayLength(java_attrs);
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return;
-  }
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
+    }
 
-  ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
-             static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
-             out_values, out_indices);
-  env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+    Asset* a = cookie
+        ? am->openNonAsset(static_cast<int32_t>(cookie), fileName8.c_str(), Asset::ACCESS_RANDOM)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
+    }
+
+    //printf("Created Asset Stream: %p\n", a);
+
+    return returnParcelFileDescriptor(env, a, outOffsets);
 }
 
-static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                   jint def_style_attr, jint def_style_resid, jintArray java_values,
-                                   jintArray java_attrs, jintArray out_java_values,
-                                   jintArray out_java_indices) {
-  const jsize attrs_len = env->GetArrayLength(java_attrs);
-  const jsize out_values_len = env->GetArrayLength(out_java_values);
-  if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
-    return JNI_FALSE;
-  }
-
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return JNI_FALSE;
-  }
-
-  jint* values = nullptr;
-  jsize values_len = 0;
-  if (java_values != nullptr) {
-    values_len = env->GetArrayLength(java_values);
-    values = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_values, nullptr));
-    if (values == nullptr) {
-      env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-      return JNI_FALSE;
+static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
+                                                   jstring fileName)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
     }
-  }
 
-  jint* out_values =
-      reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
-  if (out_values == nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-    if (values != nullptr) {
-      env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return NULL;
     }
-    return JNI_FALSE;
-  }
 
-  jint* out_indices = nullptr;
-  if (out_java_indices != nullptr) {
-    jsize out_indices_len = env->GetArrayLength(out_java_indices);
-    if (out_indices_len > attrs_len) {
-      out_indices =
-          reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
-      if (out_indices == nullptr) {
-        env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-        if (values != nullptr) {
-          env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
+    AssetDir* dir = am->openDir(fileName8.c_str());
+
+    if (dir == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return NULL;
+    }
+
+    size_t N = dir->getFileCount();
+
+    jobjectArray array = env->NewObjectArray(dir->getFileCount(),
+                                                g_stringClass, NULL);
+    if (array == NULL) {
+        delete dir;
+        return NULL;
+    }
+
+    for (size_t i=0; i<N; i++) {
+        const String8& name = dir->getFileName(i);
+        jstring str = env->NewStringUTF(name.string());
+        if (str == NULL) {
+            delete dir;
+            return NULL;
         }
-        env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+        env->SetObjectArrayElement(array, i, str);
+        env->DeleteLocalRef(str);
+    }
+
+    delete dir;
+
+    return array;
+}
+
+static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
+                                                      jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+    //printf("Destroying Asset Stream: %p\n", a);
+
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return;
+    }
+
+    delete a;
+}
+
+static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
+                                                       jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
+    }
+
+    uint8_t b;
+    ssize_t res = a->read(&b, 1);
+    return res == 1 ? b : -1;
+}
+
+static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
+                                                jlong assetHandle, jbyteArray bArray,
+                                                jint off, jint len)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+    if (a == NULL || bArray == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
+    }
+
+    if (len == 0) {
+        return 0;
+    }
+
+    jsize bLen = env->GetArrayLength(bArray);
+    if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
+        return -1;
+    }
+
+    jbyte* b = env->GetByteArrayElements(bArray, NULL);
+    ssize_t res = a->read(b+off, len);
+    env->ReleaseByteArrayElements(bArray, b, 0);
+
+    if (res > 0) return static_cast<jint>(res);
+
+    if (res < 0) {
+        jniThrowException(env, "java/io/IOException", "");
+    }
+    return -1;
+}
+
+static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
+                                                 jlong assetHandle,
+                                                 jlong offset, jint whence)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
+    }
+
+    return a->seek(
+        offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
+}
+
+static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
+                                                      jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
+    }
+
+    return a->getLength();
+}
+
+static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
+                                                               jlong assetHandle)
+{
+    Asset* a = reinterpret_cast<Asset*>(assetHandle);
+
+    if (a == NULL) {
+        jniThrowNullPointerException(env, "asset");
+        return -1;
+    }
+
+    return a->getRemainingLength();
+}
+
+static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
+                                                       jstring path, jboolean appAsLib)
+{
+    ScopedUtfChars path8(env, path);
+    if (path8.c_str() == NULL) {
+        return 0;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    int32_t cookie;
+    bool res = am->addAssetPath(String8(path8.c_str()), &cookie, appAsLib);
+
+    return (res) ? static_cast<jint>(cookie) : 0;
+}
+
+static jint android_content_AssetManager_addOverlayPath(JNIEnv* env, jobject clazz,
+                                                     jstring idmapPath)
+{
+    ScopedUtfChars idmapPath8(env, idmapPath);
+    if (idmapPath8.c_str() == NULL) {
+        return 0;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    int32_t cookie;
+    bool res = am->addOverlayPath(String8(idmapPath8.c_str()), &cookie);
+
+    return (res) ? (jint)cookie : 0;
+}
+
+static jint android_content_AssetManager_addAssetFd(JNIEnv* env, jobject clazz,
+                                                    jobject fileDescriptor, jstring debugPathName,
+                                                    jboolean appAsLib)
+{
+    ScopedUtfChars debugPathName8(env, debugPathName);
+
+    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+    if (fd < 0) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Bad FileDescriptor");
+        return 0;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    int dupfd = ::dup(fd);
+    if (dupfd < 0) {
+        jniThrowIOException(env, errno);
+        return 0;
+    }
+
+    int32_t cookie;
+    bool res = am->addAssetFd(dupfd, String8(debugPathName8.c_str()), &cookie, appAsLib);
+
+    return (res) ? static_cast<jint>(cookie) : 0;
+}
+
+static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_TRUE;
+    }
+    return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
+}
+
+static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
+{
+    Vector<String8> locales;
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    am->getLocales(&locales, includeSystemLocales);
+
+    const int N = locales.size();
+
+    jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    for (int i=0; i<N; i++) {
+        jstring str = env->NewStringUTF(locales[i].string());
+        if (str == NULL) {
+            return NULL;
+        }
+        env->SetObjectArrayElement(result, i, str);
+        env->DeleteLocalRef(str);
+    }
+
+    return result;
+}
+
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, true /* include system locales */);
+}
+
+static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, false /* don't include system locales */);
+}
+
+static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
+    jobject result = env->NewObject(gConfigurationOffsets.classObject,
+            gConfigurationOffsets.constructor);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    env->SetIntField(result, gConfigurationOffsets.mSmallestScreenWidthDpOffset,
+            config.smallestScreenWidthDp);
+    env->SetIntField(result, gConfigurationOffsets.mScreenWidthDpOffset, config.screenWidthDp);
+    env->SetIntField(result, gConfigurationOffsets.mScreenHeightDpOffset, config.screenHeightDp);
+
+    return result;
+}
+
+static jobjectArray getSizeConfigurationsInternal(JNIEnv* env,
+        const Vector<ResTable_config>& configs) {
+    const int N = configs.size();
+    jobjectArray result = env->NewObjectArray(N, gConfigurationOffsets.classObject, NULL);
+    if (result == NULL) {
+        return NULL;
+    }
+
+    for (int i=0; i<N; i++) {
+        jobject config = constructConfigurationObject(env, configs[i]);
+        if (config == NULL) {
+            env->DeleteLocalRef(result);
+            return NULL;
+        }
+
+        env->SetObjectArrayElement(result, i, config);
+        env->DeleteLocalRef(config);
+    }
+
+    return result;
+}
+
+static jobjectArray android_content_AssetManager_getSizeConfigurations(JNIEnv* env, jobject clazz) {
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    const ResTable& res(am->getResources());
+    Vector<ResTable_config> configs;
+    res.getConfigurations(&configs, false /* ignoreMipmap */, true /* ignoreAndroidPackage */);
+
+    return getSizeConfigurationsInternal(env, configs);
+}
+
+static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
+                                                          jint mcc, jint mnc,
+                                                          jstring locale, jint orientation,
+                                                          jint touchscreen, jint density,
+                                                          jint keyboard, jint keyboardHidden,
+                                                          jint navigation,
+                                                          jint screenWidth, jint screenHeight,
+                                                          jint smallestScreenWidthDp,
+                                                          jint screenWidthDp, jint screenHeightDp,
+                                                          jint screenLayout, jint uiMode,
+                                                          jint colorMode, jint sdkVersion)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return;
+    }
+
+    ResTable_config config;
+    memset(&config, 0, sizeof(config));
+
+    const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
+
+    // Constants duplicated from Java class android.content.res.Configuration.
+    static const jint kScreenLayoutRoundMask = 0x300;
+    static const jint kScreenLayoutRoundShift = 8;
+
+    config.mcc = (uint16_t)mcc;
+    config.mnc = (uint16_t)mnc;
+    config.orientation = (uint8_t)orientation;
+    config.touchscreen = (uint8_t)touchscreen;
+    config.density = (uint16_t)density;
+    config.keyboard = (uint8_t)keyboard;
+    config.inputFlags = (uint8_t)keyboardHidden;
+    config.navigation = (uint8_t)navigation;
+    config.screenWidth = (uint16_t)screenWidth;
+    config.screenHeight = (uint16_t)screenHeight;
+    config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
+    config.screenWidthDp = (uint16_t)screenWidthDp;
+    config.screenHeightDp = (uint16_t)screenHeightDp;
+    config.screenLayout = (uint8_t)screenLayout;
+    config.uiMode = (uint8_t)uiMode;
+    config.colorMode = (uint8_t)colorMode;
+    config.sdkVersion = (uint16_t)sdkVersion;
+    config.minorVersion = 0;
+
+    // In Java, we use a 32bit integer for screenLayout, while we only use an 8bit integer
+    // in C++. We must extract the round qualifier out of the Java screenLayout and put it
+    // into screenLayout2.
+    config.screenLayout2 =
+            (uint8_t)((screenLayout & kScreenLayoutRoundMask) >> kScreenLayoutRoundShift);
+
+    am->setConfiguration(config, locale8);
+
+    if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
+}
+
+static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
+                                                            jstring name,
+                                                            jstring defType,
+                                                            jstring defPackage)
+{
+    ScopedStringChars name16(env, name);
+    if (name16.get() == NULL) {
+        return 0;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    const char16_t* defType16 = reinterpret_cast<const char16_t*>(defType)
+        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defType, NULL))
+        : NULL;
+    jsize defTypeLen = defType
+        ? env->GetStringLength(defType) : 0;
+    const char16_t* defPackage16 = reinterpret_cast<const char16_t*>(defPackage)
+        ? reinterpret_cast<const char16_t*>(env->GetStringChars(defPackage,
+                                                                NULL))
+        : NULL;
+    jsize defPackageLen = defPackage
+        ? env->GetStringLength(defPackage) : 0;
+
+    jint ident = am->getResources().identifierForName(
+        reinterpret_cast<const char16_t*>(name16.get()), name16.size(),
+        defType16, defTypeLen, defPackage16, defPackageLen);
+
+    if (defPackage16) {
+        env->ReleaseStringChars(defPackage,
+                                reinterpret_cast<const jchar*>(defPackage16));
+    }
+    if (defType16) {
+        env->ReleaseStringChars(defType,
+                                reinterpret_cast<const jchar*>(defType16));
+    }
+
+    return ident;
+}
+
+static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
+                                                            jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    String16 str;
+    if (name.package != NULL) {
+        str.setTo(name.package, name.packageLen);
+    }
+    if (name.type8 != NULL || name.type != NULL) {
+        if (str.size() > 0) {
+            char16_t div = ':';
+            str.append(&div, 1);
+        }
+        if (name.type8 != NULL) {
+            str.append(String16(name.type8, name.typeLen));
+        } else {
+            str.append(name.type, name.typeLen);
+        }
+    }
+    if (name.name8 != NULL || name.name != NULL) {
+        if (str.size() > 0) {
+            char16_t div = '/';
+            str.append(&div, 1);
+        }
+        if (name.name8 != NULL) {
+            str.append(String16(name.name8, name.nameLen));
+        } else {
+            str.append(name.name, name.nameLen);
+        }
+    }
+
+    return env->NewString((const jchar*)str.string(), str.size());
+}
+
+static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
+                                                                   jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.package != NULL) {
+        return env->NewString((const jchar*)name.package, name.packageLen);
+    }
+
+    return NULL;
+}
+
+static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
+                                                                jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.type8 != NULL) {
+        return env->NewStringUTF(name.type8);
+    }
+
+    if (name.type != NULL) {
+        return env->NewString((const jchar*)name.type, name.typeLen);
+    }
+
+    return NULL;
+}
+
+static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
+                                                                 jint resid)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+
+    ResTable::resource_name name;
+    if (!am->getResources().getResourceName(resid, true, &name)) {
+        return NULL;
+    }
+
+    if (name.name8 != NULL) {
+        return env->NewStringUTF(name.name8);
+    }
+
+    if (name.name != NULL) {
+        return env->NewString((const jchar*)name.name, name.nameLen);
+    }
+
+    return NULL;
+}
+
+static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
+                                                           jint ident,
+                                                           jshort density,
+                                                           jobject outValue,
+                                                           jboolean resolve)
+{
+    if (outValue == NULL) {
+         jniThrowNullPointerException(env, "outValue");
+         return 0;
+    }
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    Res_value value;
+    ResTable_config config;
+    uint32_t typeSpecFlags;
+    ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
+    if (kThrowOnBadId) {
+        if (block == BAD_INDEX) {
+            jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+            return 0;
+        }
+    }
+    uint32_t ref = ident;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags, &config);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    if (block >= 0) {
+        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config);
+    }
+
+    return static_cast<jint>(block);
+}
+
+static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
+                                                           jint ident, jint bagEntryId,
+                                                           jobject outValue, jboolean resolve)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    // Now lock down the resource object and start pulling stuff from it.
+    res.lock();
+
+    ssize_t block = -1;
+    Res_value value;
+
+    const ResTable::bag_entry* entry = NULL;
+    uint32_t typeSpecFlags;
+    ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
+
+    for (ssize_t i=0; i<entryCount; i++) {
+        if (((uint32_t)bagEntryId) == entry->map.name.ident) {
+            block = entry->stringBlock;
+            value = entry->map.value;
+        }
+        entry++;
+    }
+
+    res.unlock();
+
+    if (block < 0) {
+        return static_cast<jint>(block);
+    }
+
+    uint32_t ref = ident;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    if (block >= 0) {
+        return copyValue(env, outValue, &res, value, ref, block, typeSpecFlags);
+    }
+
+    return static_cast<jint>(block);
+}
+
+static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return am->getResources().getTableCount();
+}
+
+static jlong android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
+                                                           jint block)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return reinterpret_cast<jlong>(am->getResources().getTableStringBlock(block));
+}
+
+static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
+                                                       jint cookie)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    String8 name(am->getAssetPath(static_cast<int32_t>(cookie)));
+    if (name.length() == 0) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
+        return NULL;
+    }
+    jstring str = env->NewStringUTF(name.string());
+    return str;
+}
+
+static jobject android_content_AssetManager_getAssignedPackageIdentifiers(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+
+    const ResTable& res = am->getResources();
+
+    jobject sparseArray = env->NewObject(gSparseArrayOffsets.classObject,
+            gSparseArrayOffsets.constructor);
+    const size_t N = res.getBasePackageCount();
+    for (size_t i = 0; i < N; i++) {
+        const String16 name = res.getBasePackageName(i);
+        env->CallVoidMethod(
+            sparseArray, gSparseArrayOffsets.put,
+            static_cast<jint>(res.getBasePackageId(i)),
+            env->NewString(reinterpret_cast<const jchar*>(name.string()),
+                           name.size()));
+    }
+    return sparseArray;
+}
+
+static jlong android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    return reinterpret_cast<jlong>(new ResTable::Theme(am->getResources()));
+}
+
+static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
+                                                     jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    delete theme;
+}
+
+static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
+                                                         jlong themeHandle,
+                                                         jint styleRes,
+                                                         jboolean force)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    theme->applyStyle(styleRes, force ? true : false);
+}
+
+static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
+                                                   jlong destHandle, jlong srcHandle)
+{
+    ResTable::Theme* dest = reinterpret_cast<ResTable::Theme*>(destHandle);
+    ResTable::Theme* src = reinterpret_cast<ResTable::Theme*>(srcHandle);
+    dest->setTo(*src);
+}
+
+static void android_content_AssetManager_clearTheme(JNIEnv* env, jobject clazz, jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    theme->clear();
+}
+
+static jint android_content_AssetManager_loadThemeAttributeValue(
+    JNIEnv* env, jobject clazz, jlong themeHandle, jint ident, jobject outValue, jboolean resolve)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    const ResTable& res(theme->getResTable());
+
+    Res_value value;
+    // XXX value could be different in different configs!
+    uint32_t typeSpecFlags = 0;
+    ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
+    uint32_t ref = 0;
+    if (resolve) {
+        block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return 0;
+            }
+        }
+    }
+    return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
+}
+
+static jint android_content_AssetManager_getThemeChangingConfigurations(JNIEnv* env, jobject clazz,
+                                                                        jlong themeHandle)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    return theme->getChangingConfigurations();
+}
+
+static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
+                                                   jlong themeHandle, jint pri,
+                                                   jstring tag, jstring prefix)
+{
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeHandle);
+    const ResTable& res(theme->getResTable());
+    (void)res;
+
+    // XXX Need to use params.
+    theme->dumpToLog();
+}
+
+static jboolean android_content_AssetManager_resolveAttrs(JNIEnv* env, jobject clazz,
+                                                          jlong themeToken,
+                                                          jint defStyleAttr,
+                                                          jint defStyleRes,
+                                                          jintArray inValues,
+                                                          jintArray attrs,
+                                                          jintArray outValues,
+                                                          jintArray outIndices)
+{
+    if (themeToken == 0) {
+        jniThrowNullPointerException(env, "theme token");
         return JNI_FALSE;
-      }
     }
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-
-  bool result = ResolveAttrs(
-      theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
-      reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
-      attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
-  if (out_indices != nullptr) {
-    env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
-  }
-
-  env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
-  if (values != nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
-  }
-  env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-  return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
-                                         jlong xml_parser_ptr, jintArray java_attrs,
-                                         jintArray out_java_values, jintArray out_java_indices) {
-  const jsize attrs_len = env->GetArrayLength(java_attrs);
-  const jsize out_values_len = env->GetArrayLength(out_java_values);
-  if (out_values_len < (attrs_len * STYLE_NUM_ENTRIES)) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "outValues too small");
-    return JNI_FALSE;
-  }
-
-  jint* attrs = reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(java_attrs, nullptr));
-  if (attrs == nullptr) {
-    return JNI_FALSE;
-  }
-
-  jint* out_values =
-      reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_values, nullptr));
-  if (out_values == nullptr) {
-    env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-    return JNI_FALSE;
-  }
-
-  jint* out_indices = nullptr;
-  if (out_java_indices != nullptr) {
-    jsize out_indices_len = env->GetArrayLength(out_java_indices);
-    if (out_indices_len > attrs_len) {
-      out_indices =
-          reinterpret_cast<jint*>(env->GetPrimitiveArrayCritical(out_java_indices, nullptr));
-      if (out_indices == nullptr) {
-        env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-        env->ReleasePrimitiveArrayCritical(out_java_values, out_values, JNI_ABORT);
+    if (attrs == NULL) {
+        jniThrowNullPointerException(env, "attrs");
         return JNI_FALSE;
-      }
     }
-  }
-
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
-
-  bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
-                                   reinterpret_cast<uint32_t*>(attrs), attrs_len,
-                                   reinterpret_cast<uint32_t*>(out_values),
-                                   reinterpret_cast<uint32_t*>(out_indices));
-
-  if (out_indices != nullptr) {
-    env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
-  }
-  env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
-  env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
-  return result ? JNI_TRUE : JNI_FALSE;
-}
-
-static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  return reinterpret_cast<jlong>(assetmanager->NewTheme().release());
-}
-
-static void NativeThemeDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
-  delete reinterpret_cast<Theme*>(theme_ptr);
-}
-
-static void NativeThemeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                  jint resid, jboolean force) {
-  // AssetManager is accessed via the theme, so grab an explicit lock here.
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-  theme->ApplyStyle(static_cast<uint32_t>(resid), force);
-
-  // TODO(adamlesinski): Consider surfacing exception when result is failure.
-  // CTS currently expects no exceptions from this method.
-  // std::string error_msg = StringPrintf("Failed to apply style 0x%08x to theme", resid);
-  // jniThrowException(env, "java/lang/IllegalArgumentException", error_msg.c_str());
-}
-
-static void NativeThemeCopy(JNIEnv* env, jclass /*clazz*/, jlong dst_theme_ptr,
-                            jlong src_theme_ptr) {
-  Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
-  Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
-  if (!dst_theme->SetTo(*src_theme)) {
-    jniThrowException(env, "java/lang/IllegalArgumentException",
-                      "Themes are from different AssetManagers");
-  }
-}
-
-static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
-  reinterpret_cast<Theme*>(theme_ptr)->Clear();
-}
-
-static jint NativeThemeGetAttributeValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                                         jint resid, jobject typed_value,
-                                         jboolean resolve_references) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-
-  Res_value value;
-  uint32_t flags;
-  ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
-  if (cookie == kInvalidCookie) {
-    return ApkAssetsCookieToJavaCookie(kInvalidCookie);
-  }
-
-  uint32_t ref = 0u;
-  if (resolve_references) {
-    ResTable_config selected_config;
-    cookie =
-        theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
-    if (cookie == kInvalidCookie) {
-      return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+    if (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
     }
-  }
-  return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
+
+    const jsize NI = env->GetArrayLength(attrs);
+    const jsize NV = env->GetArrayLength(outValues);
+    if (NV < (NI*STYLE_NUM_ENTRIES)) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
+        return JNI_FALSE;
+    }
+
+    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+    if (src == NULL) {
+        return JNI_FALSE;
+    }
+
+    jint* srcValues = (jint*)env->GetPrimitiveArrayCritical(inValues, 0);
+    const jsize NSV = srcValues == NULL ? 0 : env->GetArrayLength(inValues);
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    if (baseDest == NULL) {
+        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+        return JNI_FALSE;
+    }
+
+    jint* indices = NULL;
+    if (outIndices != NULL) {
+        if (env->GetArrayLength(outIndices) > NI) {
+            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+        }
+    }
+
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+    bool result = ResolveAttrs(theme, defStyleAttr, defStyleRes,
+                               (uint32_t*) srcValues, NSV,
+                               (uint32_t*) src, NI,
+                               (uint32_t*) baseDest,
+                               (uint32_t*) indices);
+
+    if (indices != NULL) {
+        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+    }
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+    env->ReleasePrimitiveArrayCritical(inValues, srcValues, 0);
+    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
-                            jint priority, jstring tag, jstring prefix) {
-  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  CHECK(theme->GetAssetManager() == &(*assetmanager));
-  (void) assetmanager;
-  (void) theme;
-  (void) priority;
-  (void) tag;
-  (void) prefix;
+static void android_content_AssetManager_applyStyle(JNIEnv* env, jobject, jlong themeToken,
+        jint defStyleAttr, jint defStyleRes, jlong xmlParserToken, jintArray attrsObj, jint length,
+        jlong outValuesAddress, jlong outIndicesAddress) {
+    jint* attrs = env->GetIntArrayElements(attrsObj, 0);
+    ResTable::Theme* theme = reinterpret_cast<ResTable::Theme*>(themeToken);
+    ResXMLParser* xmlParser = reinterpret_cast<ResXMLParser*>(xmlParserToken);
+    uint32_t* outValues = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outValuesAddress));
+    uint32_t* outIndices = reinterpret_cast<uint32_t*>(static_cast<uintptr_t>(outIndicesAddress));
+    ApplyStyle(theme, xmlParser, defStyleAttr, defStyleRes,
+            reinterpret_cast<const uint32_t*>(attrs), length, outValues, outIndices);
+    env->ReleaseIntArrayElements(attrsObj, attrs, JNI_ABORT);
 }
 
-static jint NativeThemeGetChangingConfigurations(JNIEnv* /*env*/, jclass /*clazz*/,
-                                                 jlong theme_ptr) {
-  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
-  return static_cast<jint>(theme->GetChangingConfigurations());
+static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
+                                                        jlong xmlParserToken,
+                                                        jintArray attrs,
+                                                        jintArray outValues,
+                                                        jintArray outIndices)
+{
+    if (xmlParserToken == 0) {
+        jniThrowNullPointerException(env, "xmlParserToken");
+        return JNI_FALSE;
+    }
+    if (attrs == NULL) {
+        jniThrowNullPointerException(env, "attrs");
+        return JNI_FALSE;
+    }
+    if (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_FALSE;
+    }
+    const ResTable& res(am->getResources());
+    ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
+
+    const jsize NI = env->GetArrayLength(attrs);
+    const jsize NV = env->GetArrayLength(outValues);
+    if (NV < (NI*STYLE_NUM_ENTRIES)) {
+        jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
+        return JNI_FALSE;
+    }
+
+    jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
+    if (src == NULL) {
+        return JNI_FALSE;
+    }
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    if (baseDest == NULL) {
+        env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+        return JNI_FALSE;
+    }
+
+    jint* indices = NULL;
+    if (outIndices != NULL) {
+        if (env->GetArrayLength(outIndices) > NI) {
+            indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
+        }
+    }
+
+    bool result = RetrieveAttributes(&res, xmlParser,
+                                     (uint32_t*) src, NI,
+                                     (uint32_t*) baseDest,
+                                     (uint32_t*) indices);
+
+    if (indices != NULL) {
+        env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
+    }
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+    env->ReleasePrimitiveArrayCritical(attrs, src, 0);
+    return result ? JNI_TRUE : JNI_FALSE;
 }
 
-static void NativeAssetDestroy(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  delete reinterpret_cast<Asset*>(asset_ptr);
+static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
+                                                       jint id)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
+    const ResTable& res(am->getResources());
+
+    res.lock();
+    const ResTable::bag_entry* defStyleEnt = NULL;
+    ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
+    res.unlock();
+
+    return static_cast<jint>(bagOff);
 }
 
-static jint NativeAssetReadChar(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  uint8_t b;
-  ssize_t res = asset->read(&b, sizeof(b));
-  return res == sizeof(b) ? static_cast<jint>(b) : -1;
+static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
+                                                        jint id,
+                                                        jintArray outValues)
+{
+    if (outValues == NULL) {
+        jniThrowNullPointerException(env, "out values");
+        return JNI_FALSE;
+    }
+
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return JNI_FALSE;
+    }
+    const ResTable& res(am->getResources());
+    ResTable_config config;
+    Res_value value;
+    ssize_t block;
+
+    const jsize NV = env->GetArrayLength(outValues);
+
+    jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
+    jint* dest = baseDest;
+    if (dest == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", "");
+        return JNI_FALSE;
+    }
+
+    // Now lock down the resource object and start pulling stuff from it.
+    res.lock();
+
+    const ResTable::bag_entry* arrayEnt = NULL;
+    uint32_t arrayTypeSetFlags = 0;
+    ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
+    const ResTable::bag_entry* endArrayEnt = arrayEnt +
+        (bagOff >= 0 ? bagOff : 0);
+
+    int i = 0;
+    uint32_t typeSetFlags;
+    while (i < NV && arrayEnt < endArrayEnt) {
+        block = arrayEnt->stringBlock;
+        typeSetFlags = arrayTypeSetFlags;
+        config.density = 0;
+        value = arrayEnt->map.value;
+
+        uint32_t resid = 0;
+        if (value.dataType != Res_value::TYPE_NULL) {
+            // Take care of resolving the found resource to its final value.
+            //printf("Resolving attribute reference\n");
+            ssize_t newBlock = res.resolveReference(&value, block, &resid,
+                    &typeSetFlags, &config);
+            if (kThrowOnBadId) {
+                if (newBlock == BAD_INDEX) {
+                    jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                    return JNI_FALSE;
+                }
+            }
+            if (newBlock >= 0) block = newBlock;
+        }
+
+        // Deal with the special @null value -- it turns back to TYPE_NULL.
+        if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
+            value.dataType = Res_value::TYPE_NULL;
+            value.data = Res_value::DATA_NULL_UNDEFINED;
+        }
+
+        //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
+
+        // Write the final value back to Java.
+        dest[STYLE_TYPE] = value.dataType;
+        dest[STYLE_DATA] = value.data;
+        dest[STYLE_ASSET_COOKIE] = reinterpret_cast<jint>(res.getTableCookie(block));
+        dest[STYLE_RESOURCE_ID] = resid;
+        dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+        dest[STYLE_DENSITY] = config.density;
+        dest += STYLE_NUM_ENTRIES;
+        i+= STYLE_NUM_ENTRIES;
+        arrayEnt++;
+    }
+
+    i /= STYLE_NUM_ENTRIES;
+
+    res.unlock();
+
+    env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
+
+    return i;
 }
 
-static jint NativeAssetRead(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jbyteArray java_buffer,
-                            jint offset, jint len) {
-  if (len == 0) {
-    return 0;
-  }
+static jlong android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
+                                                         jint cookie,
+                                                         jstring fileName)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return 0;
+    }
 
-  jsize buffer_len = env->GetArrayLength(java_buffer);
-  if (offset < 0 || offset >= buffer_len || len < 0 || len > buffer_len ||
-      offset > buffer_len - len) {
-    jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
-    return -1;
-  }
+    ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
 
-  ScopedByteArrayRW byte_array(env, java_buffer);
-  if (byte_array.get() == nullptr) {
-    return -1;
-  }
+    ScopedUtfChars fileName8(env, fileName);
+    if (fileName8.c_str() == NULL) {
+        return 0;
+    }
 
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  ssize_t res = asset->read(byte_array.get() + offset, len);
-  if (res < 0) {
-    jniThrowException(env, "java/io/IOException", "");
-    return -1;
-  }
-  return res > 0 ? static_cast<jint>(res) : -1;
+    int32_t assetCookie = static_cast<int32_t>(cookie);
+    Asset* a = assetCookie
+        ? am->openNonAsset(assetCookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
+        : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER, &assetCookie);
+
+    if (a == NULL) {
+        jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
+        return 0;
+    }
+
+    const DynamicRefTable* dynamicRefTable =
+            am->getResources().getDynamicRefTableForCookie(assetCookie);
+    ResXMLTree* block = new ResXMLTree(dynamicRefTable);
+    status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
+    a->close();
+    delete a;
+
+    if (err != NO_ERROR) {
+        jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
+        return 0;
+    }
+
+    return reinterpret_cast<jlong>(block);
 }
 
-static jlong NativeAssetSeek(JNIEnv* env, jclass /*clazz*/, jlong asset_ptr, jlong offset,
-                             jint whence) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->seek(
-      static_cast<off64_t>(offset), (whence > 0 ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR))));
+static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
+                                                                 jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N * 2);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
+        jint stringIndex = -1;
+        jint stringBlock = 0;
+        value = bag->map.value;
+
+        // Take care of resolving the found resource to its final value.
+        stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (value.dataType == Res_value::TYPE_STRING) {
+            stringIndex = value.data;
+        }
+
+        if (kThrowOnBadId) {
+            if (stringBlock == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+
+        //todo: It might be faster to allocate a C array to contain
+        //      the blocknums and indices, put them in there and then
+        //      do just one SetIntArrayRegion()
+        env->SetIntArrayRegion(array, j, 1, &stringBlock);
+        env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
+        j = j + 2;
+    }
+    res.unlockBag(startOfBag);
+    return array;
 }
 
-static jlong NativeAssetGetLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->getLength());
+static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
+                                                                        jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jobjectArray array = env->NewObjectArray(N, g_stringClass, NULL);
+    if (env->ExceptionCheck()) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    size_t strLen = 0;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        value = bag->map.value;
+        jstring str = NULL;
+
+        // Take care of resolving the found resource to its final value.
+        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+        if (value.dataType == Res_value::TYPE_STRING) {
+            const ResStringPool* pool = res.getTableStringBlock(block);
+            const char* str8 = pool->string8At(value.data, &strLen);
+            if (str8 != NULL) {
+                str = env->NewStringUTF(str8);
+            } else {
+                const char16_t* str16 = pool->stringAt(value.data, &strLen);
+                str = env->NewString(reinterpret_cast<const jchar*>(str16),
+                                     strLen);
+            }
+
+            // If one of our NewString{UTF} calls failed due to memory, an
+            // exception will be pending.
+            if (env->ExceptionCheck()) {
+                res.unlockBag(startOfBag);
+                return NULL;
+            }
+
+            env->SetObjectArrayElement(array, i, str);
+
+            // str is not NULL at that point, otherwise ExceptionCheck would have been true.
+            // If we have a large amount of strings in our array, we might
+            // overflow the local reference table of the VM.
+            env->DeleteLocalRef(str);
+        }
+    }
+    res.unlockBag(startOfBag);
+    return array;
 }
 
-static jlong NativeAssetGetRemainingLength(JNIEnv* /*env*/, jclass /*clazz*/, jlong asset_ptr) {
-  Asset* asset = reinterpret_cast<Asset*>(asset_ptr);
-  return static_cast<jlong>(asset->getRemainingLength());
+static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
+                                                                        jint arrayResId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(arrayResId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    Res_value value;
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        value = bag->map.value;
+
+        // Take care of resolving the found resource to its final value.
+        ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
+        if (kThrowOnBadId) {
+            if (block == BAD_INDEX) {
+                jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
+                return array;
+            }
+        }
+        if (value.dataType >= Res_value::TYPE_FIRST_INT
+                && value.dataType <= Res_value::TYPE_LAST_INT) {
+            int intVal = value.data;
+            env->SetIntArrayRegion(array, i, 1, &intVal);
+        }
+    }
+    res.unlockBag(startOfBag);
+    return array;
+}
+
+static jintArray android_content_AssetManager_getStyleAttributes(JNIEnv* env, jobject clazz,
+                                                                 jint styleId)
+{
+    AssetManager* am = assetManagerForJavaObject(env, clazz);
+    if (am == NULL) {
+        return NULL;
+    }
+    const ResTable& res(am->getResources());
+
+    const ResTable::bag_entry* startOfBag;
+    const ssize_t N = res.lockBag(styleId, &startOfBag);
+    if (N < 0) {
+        return NULL;
+    }
+
+    jintArray array = env->NewIntArray(N);
+    if (array == NULL) {
+        res.unlockBag(startOfBag);
+        return NULL;
+    }
+
+    const ResTable::bag_entry* bag = startOfBag;
+    for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
+        int resourceId = bag->map.name.ident;
+        env->SetIntArrayRegion(array, i, 1, &resourceId);
+    }
+    res.unlockBag(startOfBag);
+    return array;
+}
+
+static void android_content_AssetManager_init(JNIEnv* env, jobject clazz, jboolean isSystem)
+{
+    if (isSystem) {
+        verifySystemIdmaps();
+    }
+    AssetManager* am = new AssetManager();
+    if (am == NULL) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", "");
+        return;
+    }
+
+    am->addDefaultAssets();
+
+    ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
+    env->SetLongField(clazz, gAssetManagerOffsets.mObject, reinterpret_cast<jlong>(am));
+}
+
+static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
+{
+    AssetManager* am = (AssetManager*)
+        (env->GetLongField(clazz, gAssetManagerOffsets.mObject));
+    ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
+    if (am != NULL) {
+        delete am;
+        env->SetLongField(clazz, gAssetManagerOffsets.mObject, 0);
+    }
+}
+
+static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
+{
+    return Asset::getGlobalCount();
+}
+
+static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
+{
+    String8 alloc = Asset::getAssetAllocations();
+    if (alloc.length() <= 0) {
+        return NULL;
+    }
+
+    jstring str = env->NewStringUTF(alloc.string());
+    return str;
+}
+
+static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
+{
+    return AssetManager::getGlobalCount();
 }
 
 // ----------------------------------------------------------------------------
 
-// JNI registration.
+/*
+ * JNI registration.
+ */
 static const JNINativeMethod gAssetManagerMethods[] = {
-    // AssetManager setup methods.
-    {"nativeCreate", "()J", (void*)NativeCreate},
-    {"nativeDestroy", "(J)V", (void*)NativeDestroy},
-    {"nativeSetApkAssets", "(J[Landroid/content/res/ApkAssets;Z)V", (void*)NativeSetApkAssets},
-    {"nativeSetConfiguration", "(JIILjava/lang/String;IIIIIIIIIIIIIII)V",
-     (void*)NativeSetConfiguration},
-    {"nativeGetAssignedPackageIdentifiers", "(J)Landroid/util/SparseArray;",
-     (void*)NativeGetAssignedPackageIdentifiers},
+    /* name, signature, funcPtr */
 
-    // AssetManager file methods.
-    {"nativeList", "(JLjava/lang/String;)[Ljava/lang/String;", (void*)NativeList},
-    {"nativeOpenAsset", "(JLjava/lang/String;I)J", (void*)NativeOpenAsset},
-    {"nativeOpenAssetFd", "(JLjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
-     (void*)NativeOpenAssetFd},
-    {"nativeOpenNonAsset", "(JILjava/lang/String;I)J", (void*)NativeOpenNonAsset},
-    {"nativeOpenNonAssetFd", "(JILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
-     (void*)NativeOpenNonAssetFd},
-    {"nativeOpenXmlAsset", "(JILjava/lang/String;)J", (void*)NativeOpenXmlAsset},
+    // Basic asset stuff.
+    { "openAsset",      "(Ljava/lang/String;I)J",
+        (void*) android_content_AssetManager_openAsset },
+    { "openAssetFd",      "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+        (void*) android_content_AssetManager_openAssetFd },
+    { "openNonAssetNative", "(ILjava/lang/String;I)J",
+        (void*) android_content_AssetManager_openNonAssetNative },
+    { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
+        (void*) android_content_AssetManager_openNonAssetFdNative },
+    { "list",           "(Ljava/lang/String;)[Ljava/lang/String;",
+        (void*) android_content_AssetManager_list },
+    { "destroyAsset",   "(J)V",
+        (void*) android_content_AssetManager_destroyAsset },
+    { "readAssetChar",  "(J)I",
+        (void*) android_content_AssetManager_readAssetChar },
+    { "readAsset",      "(J[BII)I",
+        (void*) android_content_AssetManager_readAsset },
+    { "seekAsset",      "(JJI)J",
+        (void*) android_content_AssetManager_seekAsset },
+    { "getAssetLength", "(J)J",
+        (void*) android_content_AssetManager_getAssetLength },
+    { "getAssetRemainingLength", "(J)J",
+        (void*) android_content_AssetManager_getAssetRemainingLength },
+    { "addAssetPathNative", "(Ljava/lang/String;Z)I",
+        (void*) android_content_AssetManager_addAssetPath },
+    { "addAssetFdNative", "(Ljava/io/FileDescriptor;Ljava/lang/String;Z)I",
+        (void*) android_content_AssetManager_addAssetFd },
+    { "addOverlayPathNative",   "(Ljava/lang/String;)I",
+        (void*) android_content_AssetManager_addOverlayPath },
+    { "isUpToDate",     "()Z",
+        (void*) android_content_AssetManager_isUpToDate },
 
-    // AssetManager resource methods.
-    {"nativeGetResourceValue", "(JISLandroid/util/TypedValue;Z)I", (void*)NativeGetResourceValue},
-    {"nativeGetResourceBagValue", "(JIILandroid/util/TypedValue;)I",
-     (void*)NativeGetResourceBagValue},
-    {"nativeGetStyleAttributes", "(JI)[I", (void*)NativeGetStyleAttributes},
-    {"nativeGetResourceStringArray", "(JI)[Ljava/lang/String;",
-     (void*)NativeGetResourceStringArray},
-    {"nativeGetResourceStringArrayInfo", "(JI)[I", (void*)NativeGetResourceStringArrayInfo},
-    {"nativeGetResourceIntArray", "(JI)[I", (void*)NativeGetResourceIntArray},
-    {"nativeGetResourceArraySize", "(JI)I", (void*)NativeGetResourceArraySize},
-    {"nativeGetResourceArray", "(JI[I)I", (void*)NativeGetResourceArray},
+    // Resources.
+    { "getLocales",      "()[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getLocales },
+    { "getNonSystemLocales", "()[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getNonSystemLocales },
+    { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
+        (void*) android_content_AssetManager_getSizeConfigurations },
+    { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIIII)V",
+        (void*) android_content_AssetManager_setConfiguration },
+    { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
+        (void*) android_content_AssetManager_getResourceIdentifier },
+    { "getResourceName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceName },
+    { "getResourcePackageName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourcePackageName },
+    { "getResourceTypeName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceTypeName },
+    { "getResourceEntryName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getResourceEntryName },
+    { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadResourceValue },
+    { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadResourceBagValue },
+    { "getStringBlockCount","()I",
+        (void*) android_content_AssetManager_getStringBlockCount },
+    { "getNativeStringBlock","(I)J",
+        (void*) android_content_AssetManager_getNativeStringBlock },
+    { "getCookieName","(I)Ljava/lang/String;",
+        (void*) android_content_AssetManager_getCookieName },
+    { "getAssignedPackageIdentifiers","()Landroid/util/SparseArray;",
+        (void*) android_content_AssetManager_getAssignedPackageIdentifiers },
 
-    // AssetManager resource name/ID methods.
-    {"nativeGetResourceIdentifier", "(JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
-     (void*)NativeGetResourceIdentifier},
-    {"nativeGetResourceName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceName},
-    {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName},
-    {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName},
-    {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName},
-    {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales},
-    {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;",
-     (void*)NativeGetSizeConfigurations},
+    // Themes.
+    { "newTheme", "()J",
+        (void*) android_content_AssetManager_newTheme },
+    { "deleteTheme", "(J)V",
+        (void*) android_content_AssetManager_deleteTheme },
+    { "applyThemeStyle", "(JIZ)V",
+        (void*) android_content_AssetManager_applyThemeStyle },
+    { "copyTheme", "(JJ)V",
+        (void*) android_content_AssetManager_copyTheme },
+    { "clearTheme", "(J)V",
+        (void*) android_content_AssetManager_clearTheme },
+    { "loadThemeAttributeValue", "(JILandroid/util/TypedValue;Z)I",
+        (void*) android_content_AssetManager_loadThemeAttributeValue },
+    { "getThemeChangingConfigurations", "(J)I",
+        (void*) android_content_AssetManager_getThemeChangingConfigurations },
+    { "dumpTheme", "(JILjava/lang/String;Ljava/lang/String;)V",
+        (void*) android_content_AssetManager_dumpTheme },
+    { "applyStyle","(JIIJ[IIJJ)V",
+        (void*) android_content_AssetManager_applyStyle },
+    { "resolveAttrs","(JII[I[I[I[I)Z",
+        (void*) android_content_AssetManager_resolveAttrs },
+    { "retrieveAttributes","(J[I[I[I)Z",
+        (void*) android_content_AssetManager_retrieveAttributes },
+    { "getArraySize","(I)I",
+        (void*) android_content_AssetManager_getArraySize },
+    { "retrieveArray","(I[I)I",
+        (void*) android_content_AssetManager_retrieveArray },
 
-    // Style attribute related methods.
-    {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
-    {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
-    {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
+    // XML files.
+    { "openXmlAssetNative", "(ILjava/lang/String;)J",
+        (void*) android_content_AssetManager_openXmlAssetNative },
 
-    // Theme related methods.
-    {"nativeThemeCreate", "(J)J", (void*)NativeThemeCreate},
-    {"nativeThemeDestroy", "(J)V", (void*)NativeThemeDestroy},
-    {"nativeThemeApplyStyle", "(JJIZ)V", (void*)NativeThemeApplyStyle},
-    {"nativeThemeCopy", "(JJ)V", (void*)NativeThemeCopy},
-    {"nativeThemeClear", "(J)V", (void*)NativeThemeClear},
-    {"nativeThemeGetAttributeValue", "(JJILandroid/util/TypedValue;Z)I",
-     (void*)NativeThemeGetAttributeValue},
-    {"nativeThemeDump", "(JJILjava/lang/String;Ljava/lang/String;)V", (void*)NativeThemeDump},
-    {"nativeThemeGetChangingConfigurations", "(J)I", (void*)NativeThemeGetChangingConfigurations},
+    // Arrays.
+    { "getArrayStringResource","(I)[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getArrayStringResource },
+    { "getArrayStringInfo","(I)[I",
+        (void*) android_content_AssetManager_getArrayStringInfo },
+    { "getArrayIntResource","(I)[I",
+        (void*) android_content_AssetManager_getArrayIntResource },
+    { "getStyleAttributes","(I)[I",
+        (void*) android_content_AssetManager_getStyleAttributes },
 
-    // AssetInputStream methods.
-    {"nativeAssetDestroy", "(J)V", (void*)NativeAssetDestroy},
-    {"nativeAssetReadChar", "(J)I", (void*)NativeAssetReadChar},
-    {"nativeAssetRead", "(J[BII)I", (void*)NativeAssetRead},
-    {"nativeAssetSeek", "(JJI)J", (void*)NativeAssetSeek},
-    {"nativeAssetGetLength", "(J)J", (void*)NativeAssetGetLength},
-    {"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
-
-    // System/idmap related methods.
-    {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
-
-    // Global management/debug methods.
-    {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
-    {"getAssetAllocations", "()Ljava/lang/String;", (void*)NativeGetAssetAllocations},
-    {"getGlobalAssetManagerCount", "()I", (void*)NativeGetGlobalAssetManagerCount},
+    // Bookkeeping.
+    { "init",           "(Z)V",
+        (void*) android_content_AssetManager_init },
+    { "destroy",        "()V",
+        (void*) android_content_AssetManager_destroy },
+    { "getGlobalAssetCount", "()I",
+        (void*) android_content_AssetManager_getGlobalAssetCount },
+    { "getAssetAllocations", "()Ljava/lang/String;",
+        (void*) android_content_AssetManager_getAssetAllocations },
+    { "getGlobalAssetManagerCount", "()I",
+        (void*) android_content_AssetManager_getGlobalAssetManagerCount },
 };
 
-int register_android_content_AssetManager(JNIEnv* env) {
-  jclass apk_assets_class = FindClassOrDie(env, "android/content/res/ApkAssets");
-  gApkAssetsFields.native_ptr = GetFieldIDOrDie(env, apk_assets_class, "mNativePtr", "J");
+int register_android_content_AssetManager(JNIEnv* env)
+{
+    jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
+    gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
+    gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
+    gTypedValueOffsets.mString = GetFieldIDOrDie(env, typedValue, "string",
+                                                 "Ljava/lang/CharSequence;");
+    gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
+    gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
+    gTypedValueOffsets.mChangingConfigurations = GetFieldIDOrDie(env, typedValue,
+                                                                 "changingConfigurations", "I");
+    gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
 
-  jclass typedValue = FindClassOrDie(env, "android/util/TypedValue");
-  gTypedValueOffsets.mType = GetFieldIDOrDie(env, typedValue, "type", "I");
-  gTypedValueOffsets.mData = GetFieldIDOrDie(env, typedValue, "data", "I");
-  gTypedValueOffsets.mString =
-      GetFieldIDOrDie(env, typedValue, "string", "Ljava/lang/CharSequence;");
-  gTypedValueOffsets.mAssetCookie = GetFieldIDOrDie(env, typedValue, "assetCookie", "I");
-  gTypedValueOffsets.mResourceId = GetFieldIDOrDie(env, typedValue, "resourceId", "I");
-  gTypedValueOffsets.mChangingConfigurations =
-      GetFieldIDOrDie(env, typedValue, "changingConfigurations", "I");
-  gTypedValueOffsets.mDensity = GetFieldIDOrDie(env, typedValue, "density", "I");
+    jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
+    gAssetFileDescriptorOffsets.mFd = GetFieldIDOrDie(env, assetFd, "mFd",
+                                                      "Landroid/os/ParcelFileDescriptor;");
+    gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
+    gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
 
-  jclass assetFd = FindClassOrDie(env, "android/content/res/AssetFileDescriptor");
-  gAssetFileDescriptorOffsets.mFd =
-      GetFieldIDOrDie(env, assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
-  gAssetFileDescriptorOffsets.mStartOffset = GetFieldIDOrDie(env, assetFd, "mStartOffset", "J");
-  gAssetFileDescriptorOffsets.mLength = GetFieldIDOrDie(env, assetFd, "mLength", "J");
+    jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
+    gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
 
-  jclass assetManager = FindClassOrDie(env, "android/content/res/AssetManager");
-  gAssetManagerOffsets.mObject = GetFieldIDOrDie(env, assetManager, "mObject", "J");
+    jclass stringClass = FindClassOrDie(env, "java/lang/String");
+    g_stringClass = MakeGlobalRefOrDie(env, stringClass);
 
-  jclass stringClass = FindClassOrDie(env, "java/lang/String");
-  g_stringClass = MakeGlobalRefOrDie(env, stringClass);
+    jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
+    gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
+    gSparseArrayOffsets.constructor = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject,
+                                                       "<init>", "()V");
+    gSparseArrayOffsets.put = GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put",
+                                               "(ILjava/lang/Object;)V");
 
-  jclass sparseArrayClass = FindClassOrDie(env, "android/util/SparseArray");
-  gSparseArrayOffsets.classObject = MakeGlobalRefOrDie(env, sparseArrayClass);
-  gSparseArrayOffsets.constructor =
-      GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "<init>", "()V");
-  gSparseArrayOffsets.put =
-      GetMethodIDOrDie(env, gSparseArrayOffsets.classObject, "put", "(ILjava/lang/Object;)V");
+    jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
+    gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
+    gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass,
+            "<init>", "()V");
+    gConfigurationOffsets.mSmallestScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "smallestScreenWidthDp", "I");
+    gConfigurationOffsets.mScreenWidthDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "screenWidthDp", "I");
+    gConfigurationOffsets.mScreenHeightDpOffset = GetFieldIDOrDie(env, configurationClass,
+            "screenHeightDp", "I");
 
-  jclass configurationClass = FindClassOrDie(env, "android/content/res/Configuration");
-  gConfigurationOffsets.classObject = MakeGlobalRefOrDie(env, configurationClass);
-  gConfigurationOffsets.constructor = GetMethodIDOrDie(env, configurationClass, "<init>", "()V");
-  gConfigurationOffsets.mSmallestScreenWidthDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "smallestScreenWidthDp", "I");
-  gConfigurationOffsets.mScreenWidthDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "screenWidthDp", "I");
-  gConfigurationOffsets.mScreenHeightDpOffset =
-      GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
-
-  return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
-                              NELEM(gAssetManagerMethods));
+    return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
+                                NELEM(gAssetManagerMethods));
 }
 
 }; // namespace android
diff --git a/core/jni/include/android_runtime/android_util_AssetManager.h b/core/jni/include/android_runtime/android_util_AssetManager.h
index 2c1e357..8dd9337 100644
--- a/core/jni/include/android_runtime/android_util_AssetManager.h
+++ b/core/jni/include/android_runtime/android_util_AssetManager.h
@@ -14,20 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_RUNTIME_ASSETMANAGER_H
-#define ANDROID_RUNTIME_ASSETMANAGER_H
+#ifndef android_util_AssetManager_H
+#define android_util_AssetManager_H
 
-#include "androidfw/AssetManager2.h"
-#include "androidfw/MutexGuard.h"
+#include <androidfw/AssetManager.h>
 
 #include "jni.h"
 
 namespace android {
 
-extern AAssetManager* NdkAssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
-extern Guarded<AssetManager2>* AssetManagerForJavaObject(JNIEnv* env, jobject jassetmanager);
-extern Guarded<AssetManager2>* AssetManagerForNdkAssetManager(AAssetManager* assetmanager);
+extern AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject assetMgr);
 
-}  // namespace android
+}
 
-#endif  // ANDROID_RUNTIME_ASSETMANAGER_H
+#endif
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index ff0f4fd..f2b7ab2 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -422,7 +422,7 @@
     optional SettingProto notification_snooze_options = 341 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto enable_gnss_raw_meas_full_tracking = 346 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto zram_enabled = 347 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    optional SettingProto enable_smart_replies_in_notifications = 348 [ (android.privacy).dest = DEST_AUTOMATIC ];
+    optional SettingProto smart_replies_in_notifications_flags = 348 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto show_first_crash_dialog = 349 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto show_restart_in_crash_dialog = 351 [ (android.privacy).dest = DEST_AUTOMATIC ];
     optional SettingProto show_mute_in_crash_dialog = 352 [ (android.privacy).dest = DEST_AUTOMATIC ];
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f6f1d81..5b87c33 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -573,6 +573,10 @@
     <protected-broadcast android:name="android.media.tv.action.CHANNEL_BROWSABLE_REQUESTED" />
     <protected-broadcast android:name="com.android.server.InputMethodManagerService.SHOW_INPUT_METHOD_PICKER" />
 
+    <!-- Time zone rules update intents fired by the system server -->
+    <protected-broadcast android:name="com.android.intent.action.timezone.RULES_UPDATE_OPERATION" />
+    <protected-broadcast android:name="com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK" />
+
     <!-- Made protected in P (was introduced in JB-MR2) -->
     <protected-broadcast android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
     <protected-broadcast android:name="android.telephony.euicc.action.OTA_STATUS_CHANGED" />
@@ -1412,6 +1416,12 @@
     <permission android:name="android.permission.MANAGE_LOWPAN_INTERFACES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows internal management of Wi-Fi connectivity state when on
+         permission review mode.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_WIFI_WHEN_PERMISSION_REVIEW_REQUIRED"
+        android:protectionLevel="signature" />
+
     <!-- ======================================= -->
     <!-- Permissions for short range, peripheral networks -->
     <!-- ======================================= -->
@@ -1495,6 +1505,11 @@
     <permission android:name="android.permission.NFC_HANDOVER_STATUS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows internal management of Bluetooth state when on permission review mode.
+         <p>Not for use by third-party applications. -->
+    <permission android:name="android.permission.MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions for accessing accounts -->
     <!-- ================================== -->
@@ -2955,11 +2970,16 @@
     <permission android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi Allows an application to delete cache files.
-    <p>Not for use by third-party applications. -->
+    <!-- @SystemApi Old permission for deleting an app's cache files, no longer used,
+         but signals for us to quietly ignore calls instead of throwing an exception. -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to delete cache files.
+         @hide -->
+    <permission android:name="android.permission.INTERNAL_DELETE_CACHE_FILES"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi Allows an application to delete packages.
          <p>Not for use by third-party applications.
          <p>Starting in {@link android.os.Build.VERSION_CODES#N}, user confirmation is requested
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 853a36d..5bb9abe 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -220,7 +220,7 @@
                     Settings.Global.ENABLE_DELETION_HELPER_NO_THRESHOLD_TOGGLE,
                     Settings.Global.ENABLE_DISKSTATS_LOGGING,
                     Settings.Global.ENABLE_EPHEMERAL_FEATURE,
-                    Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS,
+                    Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
                     Settings.Global.ENHANCED_4G_MODE_ENABLED,
                     Settings.Global.EPHEMERAL_COOKIE_MAX_SIZE_BYTES,
                     Settings.Global.ERROR_LOGCAT_PREFIX,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index cf41eb8..ada19fc 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.content.Intent;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
@@ -47,7 +48,7 @@
             colors[i] = colorValue;
         }
         final Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
-        final BitmapDrawable drawable = new BitmapDrawable(null, bitmap);
+        final BitmapDrawable drawable = new BitmapDrawable(Resources.getSystem(), bitmap);
         drawable.setTargetDensity(bitmap.getDensity());
         return drawable;
     }
diff --git a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
index ce3ffb9..d425dcc 100644
--- a/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BstatsCpuTimesValidationTest.java
@@ -59,6 +59,7 @@
 import android.util.DebugUtils;
 import android.util.Log;
 
+import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Rule;
 import org.junit.Test;
@@ -118,6 +119,11 @@
         checkCpuTimesAvailability();
     }
 
+    @AfterClass
+    public static void tearDownOnce() throws Exception {
+        batteryReset();
+    }
+
     // Checks cpu freq times of system uid as an indication of whether /proc/uid_time_in_state
     // and /proc/uid/<uid>/time_in_state kernel nodes are available.
     private static void checkCpuTimesAvailability() throws Exception {
@@ -127,7 +133,7 @@
         final long[] totalCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID);
         sCpuFreqTimesAvailable = totalCpuTimes != null;
         final long[] fgSvcCpuTimes = getAllCpuFreqTimes(Process.SYSTEM_UID,
-                PROCESS_STATE_FOREGROUND_SERVICE);
+                PROCESS_STATE_FOREGROUND);
         sPerProcStateTimesAvailable = fgSvcCpuTimes != null;
     }
 
@@ -868,12 +874,16 @@
 
     private static void batteryOn() throws Exception {
         executeCmd("dumpsys battery unplug");
-        assertBatteryState(false);
+        assertBatteryState(false /* pluggedIn */);
     }
 
     private static void batteryOff() throws Exception {
+        executeCmd("dumpsys battery set ac " + BatteryManager.BATTERY_PLUGGED_AC);
+        assertBatteryState(true /* pluggedIn */);
+    }
+
+    private static void batteryReset() throws Exception {
         executeCmd("dumpsys battery reset");
-        assertBatteryState(true);
     }
 
     private void screenOn() throws Exception {
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 69a5874..eacb727 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -22,7 +22,6 @@
 import android.annotation.Size;
 import android.graphics.Canvas.VertexMode;
 import android.text.GraphicsOperations;
-import android.text.MeasuredParagraph;
 import android.text.MeasuredText;
 import android.text.SpannableString;
 import android.text.SpannedString;
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index fe2b523..e7cfcfd 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -19,9 +19,9 @@
 import android.annotation.Nullable;
 import android.content.res.AssetManager;
 import android.graphics.fonts.FontVariationAxis;
-import android.text.FontConfig;
 import android.text.TextUtils;
 import android.util.Log;
+
 import dalvik.annotation.optimization.CriticalNative;
 
 import java.io.FileInputStream;
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 9f672e3..431d0e0 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -16,16 +16,13 @@
 
 package android.graphics;
 
-import android.text.FontConfig;
 import android.graphics.fonts.FontVariationAxis;
+import android.text.FontConfig;
 import android.util.Xml;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.annotation.Nullable;
-import com.android.internal.annotations.VisibleForTesting;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 5a80ee2..ed147e9 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -19,10 +19,8 @@
 import android.annotation.ColorInt;
 import android.annotation.NonNull;
 import android.annotation.Size;
-import android.graphics.FontListParser;
 import android.graphics.fonts.FontVariationAxis;
 import android.os.LocaleList;
-import android.text.FontConfig;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
 import android.text.SpannedString;
@@ -33,14 +31,13 @@
 import dalvik.annotation.optimization.CriticalNative;
 import dalvik.annotation.optimization.FastNative;
 
+import libcore.util.NativeAllocationRegistry;
+
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
 
-import libcore.util.NativeAllocationRegistry;
-
 /**
  * The Paint class holds the style and color information about how to draw
  * geometries, text and bitmaps.
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index f41267e..8595165 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -16,25 +16,17 @@
 
 package android.graphics;
 
-import static android.content.res.FontResourcesParser.ProviderResourceEntry;
-import static android.content.res.FontResourcesParser.FontFileResourceEntry;
-import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry;
 import static android.content.res.FontResourcesParser.FamilyResourceEntry;
+import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry;
+import static android.content.res.FontResourcesParser.FontFileResourceEntry;
+import static android.content.res.FontResourcesParser.ProviderResourceEntry;
 
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.AssetManager;
-import android.graphics.FontListParser;
 import android.graphics.fonts.FontVariationAxis;
 import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ParcelFileDescriptor;
-import android.os.ResultReceiver;
 import android.provider.FontRequest;
 import android.provider.FontsContract;
 import android.text.FontConfig;
@@ -49,8 +41,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
-import libcore.io.IoUtils;
-
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
@@ -58,19 +48,15 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import java.io.InputStream;
 import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
-import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * The Typeface class specifies the typeface and intrinsic style of a font.
@@ -395,7 +381,7 @@
          * weight and italic information, so {@link #setWeight} and {@link #setItalic} are used
          * for style matching during font selection.
          *
-         * @param results The array of {@link FontsContract.FontInfo}
+         * @param fonts The array of {@link FontsContract.FontInfo}
          * @param buffers The mapping from URI to buffers to be used during building.
          * @hide
          */
@@ -879,14 +865,12 @@
      * also the font families in the fallback list.
      * @param fallbackName the family name. If given families don't support characters, the
      *               characters will be rendered with this family.
-     * @param weight the weight for this family. {@link RESOLVE_BY_FONT_TABLE} can be used. In that
-     *               case, the table information in the first family's font is used. If the first
-     *               family has multiple fonts, the closest to the regular weight and upright font
-     *               is used.
-     * @param italic the italic information for this family. {@link RESOLVE_BY_FONT_TABLE} can be
-     *               used. In that case, the table information in the first family's font is used.
-     *               If the first family has multiple fonts, the closest to the regular weight and
-     *               upright font is used.
+     * @param weight the weight for this family. In that case, the table information in the first
+     *               family's font is used. If the first family has multiple fonts, the closest to
+     *               the regular weight and upright font is used.
+     * @param italic the italic information for this family. In that case, the table information in
+     *               the first family's font is used. If the first family has multiple fonts, the
+     *               closest to the regular weight and upright font is used.
      * @param families array of font families
      */
     private static Typeface createFromFamiliesWithDefault(FontFamily[] families,
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 70d5216..251b2e7 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -145,7 +145,6 @@
         "tests/TypeWrappers_test.cpp",
         "tests/ZipUtils_test.cpp",
     ],
-    static_libs: ["libgmock"],
     target: {
         android: {
             srcs: [
@@ -172,7 +171,6 @@
 
         // Actual benchmarks.
         "tests/AssetManager2_bench.cpp",
-        "tests/AttributeResolution_bench.cpp",
         "tests/SparseEntry_bench.cpp",
         "tests/Theme_bench.cpp",
     ],
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index 60f8a18..da0205d 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -231,16 +231,12 @@
   while ((result = ::Next(cookie, &entry, &name)) == 0) {
     StringPiece full_file_path(reinterpret_cast<const char*>(name.name), name.name_length);
     StringPiece leaf_file_path = full_file_path.substr(root_path_full.size());
-
-    if (!leaf_file_path.empty()) {
-      auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
-      if (iter != leaf_file_path.end()) {
-        std::string dir =
-            leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string();
-        dirs.insert(std::move(dir));
-      } else {
-        f(leaf_file_path, kFileTypeRegular);
-      }
+    auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
+    if (iter != leaf_file_path.end()) {
+      dirs.insert(
+          leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string());
+    } else if (!leaf_file_path.empty()) {
+      f(leaf_file_path, kFileTypeRegular);
     }
   }
   ::EndIteration(cookie);
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index a8c916b..415d3e3 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -36,31 +36,6 @@
 
 namespace android {
 
-struct FindEntryResult {
-  // A pointer to the resource table entry for this resource.
-  // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
-  // a ResTable_map_entry and processed as a bag/map.
-  const ResTable_entry* entry;
-
-  // The configuration for which the resulting entry was defined. This is already swapped to host
-  // endianness.
-  ResTable_config config;
-
-  // The bitmask of configuration axis with which the resource value varies.
-  uint32_t type_flags;
-
-  // The dynamic package ID map for the package from which this resource came from.
-  const DynamicRefTable* dynamic_ref_table;
-
-  // The string pool reference to the type's name. This uses a different string pool than
-  // the global string pool, but this is hidden from the caller.
-  StringPoolRef type_string_ref;
-
-  // The string pool reference to the entry's name. This uses a different string pool than
-  // the global string pool, but this is hidden from the caller.
-  StringPoolRef entry_string_ref;
-};
-
 AssetManager2::AssetManager2() {
   memset(&configuration_, 0, sizeof(configuration_));
 }
@@ -69,7 +44,6 @@
                                  bool invalidate_caches) {
   apk_assets_ = apk_assets;
   BuildDynamicRefTable();
-  RebuildFilterList();
   if (invalidate_caches) {
     InvalidateCaches(static_cast<uint32_t>(-1));
   }
@@ -100,14 +74,12 @@
       if (idx == 0xff) {
         package_ids_[package_id] = idx = static_cast<uint8_t>(package_groups_.size());
         package_groups_.push_back({});
-        DynamicRefTable& ref_table = package_groups_.back().dynamic_ref_table;
-        ref_table.mAssignedPackageId = package_id;
-        ref_table.mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
+        package_groups_.back().dynamic_ref_table.mAssignedPackageId = package_id;
       }
       PackageGroup* package_group = &package_groups_[idx];
 
       // Add the package and to the set of packages with the same ID.
-      package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
+      package_group->packages_.push_back(package.get());
       package_group->cookies_.push_back(static_cast<ApkAssetsCookie>(i));
 
       // Add the package name -> build time ID mappings.
@@ -122,7 +94,7 @@
   // Now assign the runtime IDs so that we have a build-time to runtime ID map.
   const auto package_groups_end = package_groups_.end();
   for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
-    const std::string& package_name = iter->packages_[0].loaded_package_->GetPackageName();
+    const std::string& package_name = iter->packages_[0]->GetPackageName();
     for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
       iter2->dynamic_ref_table.addMapping(String16(package_name.c_str(), package_name.size()),
                                           iter->dynamic_ref_table.mAssignedPackageId);
@@ -133,33 +105,20 @@
 void AssetManager2::DumpToLog() const {
   base::ScopedLogSeverity _log(base::INFO);
 
-  LOG(INFO) << base::StringPrintf("AssetManager2(this=%p)", this);
-
   std::string list;
-  for (const auto& apk_assets : apk_assets_) {
-    base::StringAppendF(&list, "%s,", apk_assets->GetPath().c_str());
-  }
-  LOG(INFO) << "ApkAssets: " << list;
-
-  list = "";
   for (size_t i = 0; i < package_ids_.size(); i++) {
     if (package_ids_[i] != 0xff) {
-      base::StringAppendF(&list, "%02x -> %d, ", (int)i, package_ids_[i]);
+      base::StringAppendF(&list, "%02x -> %d, ", (int) i, package_ids_[i]);
     }
   }
   LOG(INFO) << "Package ID map: " << list;
 
   for (const auto& package_group: package_groups_) {
-    list = "";
-    for (const auto& package : package_group.packages_) {
-      const LoadedPackage* loaded_package = package.loaded_package_;
-      base::StringAppendF(&list, "%s(%02x%s), ", loaded_package->GetPackageName().c_str(),
-                          loaded_package->GetPackageId(),
-                          (loaded_package->IsDynamic() ? " dynamic" : ""));
-    }
-    LOG(INFO) << base::StringPrintf("PG (%02x): ",
-                                    package_group.dynamic_ref_table.mAssignedPackageId)
-              << list;
+      list = "";
+      for (const auto& package : package_group.packages_) {
+        base::StringAppendF(&list, "%s(%02x), ", package->GetPackageName().c_str(), package->GetPackageId());
+      }
+      LOG(INFO) << base::StringPrintf("PG (%02x): ", package_group.dynamic_ref_table.mAssignedPackageId) << list;
   }
 }
 
@@ -198,54 +157,52 @@
   configuration_ = configuration;
 
   if (diff) {
-    RebuildFilterList();
     InvalidateCaches(static_cast<uint32_t>(diff));
   }
 }
 
 std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
-                                                                   bool exclude_mipmap) const {
+                                                                   bool exclude_mipmap) {
   ATRACE_CALL();
   std::set<ResTable_config> configurations;
   for (const PackageGroup& package_group : package_groups_) {
-    for (const ConfiguredPackage& package : package_group.packages_) {
-      if (exclude_system && package.loaded_package_->IsSystem()) {
+    for (const LoadedPackage* package : package_group.packages_) {
+      if (exclude_system && package->IsSystem()) {
         continue;
       }
-      package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
+      package->CollectConfigurations(exclude_mipmap, &configurations);
     }
   }
   return configurations;
 }
 
 std::set<std::string> AssetManager2::GetResourceLocales(bool exclude_system,
-                                                        bool merge_equivalent_languages) const {
+                                                        bool merge_equivalent_languages) {
   ATRACE_CALL();
   std::set<std::string> locales;
   for (const PackageGroup& package_group : package_groups_) {
-    for (const ConfiguredPackage& package : package_group.packages_) {
-      if (exclude_system && package.loaded_package_->IsSystem()) {
+    for (const LoadedPackage* package : package_group.packages_) {
+      if (exclude_system && package->IsSystem()) {
         continue;
       }
-      package.loaded_package_->CollectLocales(merge_equivalent_languages, &locales);
+      package->CollectLocales(merge_equivalent_languages, &locales);
     }
   }
   return locales;
 }
 
-std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename,
-                                           Asset::AccessMode mode) const {
+std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
   const std::string new_path = "assets/" + filename;
   return OpenNonAsset(new_path, mode);
 }
 
 std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie,
-                                           Asset::AccessMode mode) const {
+                                           Asset::AccessMode mode) {
   const std::string new_path = "assets/" + filename;
   return OpenNonAsset(new_path, cookie, mode);
 }
 
-std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) const {
+std::unique_ptr<AssetDir> AssetManager2::OpenDir(const std::string& dirname) {
   ATRACE_CALL();
 
   std::string full_path = "assets/" + dirname;
@@ -279,7 +236,7 @@
 // is inconsistent for split APKs.
 std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
                                                    Asset::AccessMode mode,
-                                                   ApkAssetsCookie* out_cookie) const {
+                                                   ApkAssetsCookie* out_cookie) {
   ATRACE_CALL();
   for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
     std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
@@ -298,8 +255,7 @@
 }
 
 std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
-                                                   ApkAssetsCookie cookie,
-                                                   Asset::AccessMode mode) const {
+                                                   ApkAssetsCookie cookie, Asset::AccessMode mode) {
   ATRACE_CALL();
   if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
     return {};
@@ -308,13 +264,14 @@
 }
 
 ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
-                                         bool /*stop_at_first_match*/,
-                                         FindEntryResult* out_entry) const {
+                                         bool stop_at_first_match, FindEntryResult* out_entry) {
+  ATRACE_CALL();
+
   // Might use this if density_override != 0.
   ResTable_config density_override_config;
 
   // Select our configuration or generate a density override configuration.
-  const ResTable_config* desired_config = &configuration_;
+  ResTable_config* desired_config = &configuration_;
   if (density_override != 0 && density_override != configuration_.density) {
     density_override_config = configuration_;
     density_override_config.density = density_override;
@@ -328,135 +285,53 @@
 
   const uint32_t package_id = get_package_id(resid);
   const uint8_t type_idx = get_type_id(resid) - 1;
-  const uint16_t entry_idx = get_entry_id(resid);
+  const uint16_t entry_id = get_entry_id(resid);
 
-  const uint8_t package_idx = package_ids_[package_id];
-  if (package_idx == 0xff) {
+  const uint8_t idx = package_ids_[package_id];
+  if (idx == 0xff) {
     LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.", package_id, resid);
     return kInvalidCookie;
   }
 
-  const PackageGroup& package_group = package_groups_[package_idx];
-  const size_t package_count = package_group.packages_.size();
-
+  FindEntryResult best_entry;
   ApkAssetsCookie best_cookie = kInvalidCookie;
-  const LoadedPackage* best_package = nullptr;
-  const ResTable_type* best_type = nullptr;
-  const ResTable_config* best_config = nullptr;
-  ResTable_config best_config_copy;
-  uint32_t best_offset = 0u;
-  uint32_t type_flags = 0u;
+  uint32_t cumulated_flags = 0u;
 
-  // If desired_config is the same as the set configuration, then we can use our filtered list
-  // and we don't need to match the configurations, since they already matched.
-  const bool use_fast_path = desired_config == &configuration_;
-
-  for (size_t pi = 0; pi < package_count; pi++) {
-    const ConfiguredPackage& loaded_package_impl = package_group.packages_[pi];
-    const LoadedPackage* loaded_package = loaded_package_impl.loaded_package_;
-    ApkAssetsCookie cookie = package_group.cookies_[pi];
-
-    // If the type IDs are offset in this package, we need to take that into account when searching
-    // for a type.
-    const TypeSpec* type_spec = loaded_package->GetTypeSpecByTypeIndex(type_idx);
-    if (UNLIKELY(type_spec == nullptr)) {
+  const PackageGroup& package_group = package_groups_[idx];
+  const size_t package_count = package_group.packages_.size();
+  FindEntryResult current_entry;
+  for (size_t i = 0; i < package_count; i++) {
+    const LoadedPackage* loaded_package = package_group.packages_[i];
+    if (!loaded_package->FindEntry(type_idx, entry_id, *desired_config, &current_entry)) {
       continue;
     }
 
-    uint16_t local_entry_idx = entry_idx;
+    cumulated_flags |= current_entry.type_flags;
 
-    // If there is an IDMAP supplied with this package, translate the entry ID.
-    if (type_spec->idmap_entries != nullptr) {
-      if (!LoadedIdmap::Lookup(type_spec->idmap_entries, local_entry_idx, &local_entry_idx)) {
-        // There is no mapping, so the resource is not meant to be in this overlay package.
-        continue;
-      }
-    }
-
-    type_flags |= type_spec->GetFlagsForEntryIndex(local_entry_idx);
-
-    // If the package is an overlay, then even configurations that are the same MUST be chosen.
-    const bool package_is_overlay = loaded_package->IsOverlay();
-
-    const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
-    if (use_fast_path) {
-      const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
-      const size_t type_count = candidate_configs.size();
-      for (uint32_t i = 0; i < type_count; i++) {
-        const ResTable_config& this_config = candidate_configs[i];
-
-        // We can skip calling ResTable_config::match() because we know that all candidate
-        // configurations that do NOT match have been filtered-out.
-        if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
-            (package_is_overlay && this_config.compare(*best_config) == 0)) {
-          // The configuration matches and is better than the previous selection.
-          // Find the entry value if it exists for this configuration.
-          const ResTable_type* type_chunk = filtered_group.types[i];
-          const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx);
-          if (offset == ResTable_type::NO_ENTRY) {
-            continue;
-          }
-
-          best_cookie = cookie;
-          best_package = loaded_package;
-          best_type = type_chunk;
-          best_config = &this_config;
-          best_offset = offset;
-        }
-      }
-    } else {
-      // This is the slower path, which doesn't use the filtered list of configurations.
-      // Here we must read the ResTable_config from the mmapped APK, convert it to host endianness
-      // and fill in any new fields that did not exist when the APK was compiled.
-      // Furthermore when selecting configurations we can't just record the pointer to the
-      // ResTable_config, we must copy it.
-      const auto iter_end = type_spec->types + type_spec->type_count;
-      for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-        ResTable_config this_config;
-        this_config.copyFromDtoH((*iter)->config);
-
-        if (this_config.match(*desired_config)) {
-          if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) ||
-              (package_is_overlay && this_config.compare(*best_config) == 0)) {
-            // The configuration matches and is better than the previous selection.
-            // Find the entry value if it exists for this configuration.
-            const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx);
-            if (offset == ResTable_type::NO_ENTRY) {
-              continue;
-            }
-
-            best_cookie = cookie;
-            best_package = loaded_package;
-            best_type = *iter;
-            best_config_copy = this_config;
-            best_config = &best_config_copy;
-            best_offset = offset;
-          }
-        }
+    const ResTable_config* current_config = current_entry.config;
+    const ResTable_config* best_config = best_entry.config;
+    if (best_cookie == kInvalidCookie ||
+        current_config->isBetterThan(*best_config, desired_config) ||
+        (loaded_package->IsOverlay() && current_config->compare(*best_config) == 0)) {
+      best_entry = current_entry;
+      best_cookie = package_group.cookies_[i];
+      if (stop_at_first_match) {
+        break;
       }
     }
   }
 
-  if (UNLIKELY(best_cookie == kInvalidCookie)) {
+  if (best_cookie == kInvalidCookie) {
     return kInvalidCookie;
   }
 
-  const ResTable_entry* best_entry = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
-  if (UNLIKELY(best_entry == nullptr)) {
-    return kInvalidCookie;
-  }
-
-  out_entry->entry = best_entry;
-  out_entry->config = *best_config;
-  out_entry->type_flags = type_flags;
-  out_entry->type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
-  out_entry->entry_string_ref =
-      StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
+  *out_entry = best_entry;
   out_entry->dynamic_ref_table = &package_group.dynamic_ref_table;
+  out_entry->type_flags = cumulated_flags;
   return best_cookie;
 }
 
-bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
+bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
   ATRACE_CALL();
 
   FindEntryResult entry;
@@ -466,8 +341,7 @@
     return false;
   }
 
-  const LoadedPackage* package =
-      apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
+  const LoadedPackage* package = apk_assets_[cookie]->GetLoadedArsc()->GetPackageForId(resid);
   if (package == nullptr) {
     return false;
   }
@@ -495,7 +369,7 @@
   return true;
 }
 
-bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
+bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
   FindEntryResult entry;
   ApkAssetsCookie cookie =
       FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */, &entry);
@@ -509,7 +383,7 @@
 ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
                                            uint16_t density_override, Res_value* out_value,
                                            ResTable_config* out_selected_config,
-                                           uint32_t* out_flags) const {
+                                           uint32_t* out_flags) {
   ATRACE_CALL();
 
   FindEntryResult entry;
@@ -528,7 +402,7 @@
     // Create a reference since we can't represent this complex type as a Res_value.
     out_value->dataType = Res_value::TYPE_REFERENCE;
     out_value->data = resid;
-    *out_selected_config = entry.config;
+    *out_selected_config = *entry.config;
     *out_flags = entry.type_flags;
     return cookie;
   }
@@ -540,7 +414,7 @@
   // Convert the package ID to the runtime assigned package ID.
   entry.dynamic_ref_table->lookupResourceValue(out_value);
 
-  *out_selected_config = entry.config;
+  *out_selected_config = *entry.config;
   *out_flags = entry.type_flags;
   return cookie;
 }
@@ -548,14 +422,16 @@
 ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                                 ResTable_config* in_out_selected_config,
                                                 uint32_t* in_out_flags,
-                                                uint32_t* out_last_reference) const {
+                                                uint32_t* out_last_reference) {
   ATRACE_CALL();
   constexpr const int kMaxIterations = 20;
 
   for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
                               in_out_value->data != 0u && iteration < kMaxIterations;
        iteration++) {
-    *out_last_reference = in_out_value->data;
+    if (out_last_reference != nullptr) {
+      *out_last_reference = in_out_value->data;
+    }
     uint32_t new_flags = 0u;
     cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/,
                          in_out_value, in_out_selected_config, &new_flags);
@@ -616,8 +492,7 @@
         // Attributes, arrays, etc don't have a resource id as the name. They specify
         // other data, which would be wrong to change via a lookup.
         if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
-          LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
-                                           resid);
+          LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
           return nullptr;
         }
       }
@@ -649,8 +524,7 @@
   const ResolvedBag* parent_bag = GetBag(parent_resid);
   if (parent_bag == nullptr) {
     // Failed to get the parent that should exist.
-    LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid,
-                                     resid);
+    LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid, resid);
     return nullptr;
   }
 
@@ -669,8 +543,7 @@
     uint32_t child_key = dtohl(map_entry->name.ident);
     if (!is_internal_resid(child_key)) {
       if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
-        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key,
-                                         resid);
+        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key, resid);
         return nullptr;
       }
     }
@@ -709,8 +582,7 @@
     uint32_t new_key = dtohl(map_entry->name.ident);
     if (!is_internal_resid(new_key)) {
       if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
-        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
-                                         resid);
+        LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key, resid);
         return nullptr;
       }
     }
@@ -766,7 +638,7 @@
 
 uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
                                       const std::string& fallback_type,
-                                      const std::string& fallback_package) const {
+                                      const std::string& fallback_package) {
   StringPiece package_name, type, entry;
   if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
     return 0u;
@@ -798,8 +670,7 @@
   const static std::u16string kAttrPrivate16 = u"^attr-private";
 
   for (const PackageGroup& package_group : package_groups_) {
-    for (const ConfiguredPackage& package_impl : package_group.packages_) {
-      const LoadedPackage* package = package_impl.loaded_package_;
+    for (const LoadedPackage* package : package_group.packages_) {
       if (package_name != package->GetPackageName()) {
         // All packages in the same group are expected to have the same package name.
         break;
@@ -821,32 +692,6 @@
   return 0u;
 }
 
-void AssetManager2::RebuildFilterList() {
-  for (PackageGroup& group : package_groups_) {
-    for (ConfiguredPackage& impl : group.packages_) {
-      // Destroy it.
-      impl.filtered_configs_.~ByteBucketArray();
-
-      // Re-create it.
-      new (&impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();
-
-      // Create the filters here.
-      impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec* spec, uint8_t type_index) {
-        FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_index);
-        const auto iter_end = spec->types + spec->type_count;
-        for (auto iter = spec->types; iter != iter_end; ++iter) {
-          ResTable_config this_config;
-          this_config.copyFromDtoH((*iter)->config);
-          if (this_config.match(configuration_)) {
-            group.configurations.push_back(this_config);
-            group.types.push_back(*iter);
-          }
-        }
-      });
-    }
-  }
-}
-
 void AssetManager2::InvalidateCaches(uint32_t diff) {
   if (diff == 0xffffffffu) {
     // Everything must go.
@@ -1027,7 +872,7 @@
 ApkAssetsCookie Theme::ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                                  ResTable_config* in_out_selected_config,
                                                  uint32_t* in_out_type_spec_flags,
-                                                 uint32_t* out_last_ref) const {
+                                                 uint32_t* out_last_ref) {
   if (in_out_value->dataType == Res_value::TYPE_ATTRIBUTE) {
     uint32_t new_flags;
     cookie = GetAttribute(in_out_value->data, in_out_value, &new_flags);
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index f912af4..60e3845 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -20,18 +20,13 @@
 
 #include <log/log.h>
 
-#include "androidfw/AssetManager2.h"
 #include "androidfw/AttributeFinder.h"
+#include "androidfw/ResourceTypes.h"
 
 constexpr bool kDebugStyles = false;
 
 namespace android {
 
-// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
-static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
-  return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
-}
-
 class XmlAttributeFinder
     : public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
  public:
@@ -49,53 +44,58 @@
 };
 
 class BagAttributeFinder
-    : public BackTrackingAttributeFinder<BagAttributeFinder, const ResolvedBag::Entry*> {
+    : public BackTrackingAttributeFinder<BagAttributeFinder, const ResTable::bag_entry*> {
  public:
-  BagAttributeFinder(const ResolvedBag* bag)
-      : BackTrackingAttributeFinder(bag != nullptr ? bag->entries : nullptr,
-                                    bag != nullptr ? bag->entries + bag->entry_count : nullptr) {
-  }
+  BagAttributeFinder(const ResTable::bag_entry* start,
+                     const ResTable::bag_entry* end)
+      : BackTrackingAttributeFinder(start, end) {}
 
-  inline uint32_t GetAttribute(const ResolvedBag::Entry* entry) const {
-    return entry->key;
+  inline uint32_t GetAttribute(const ResTable::bag_entry* entry) const {
+    return entry->map.name.ident;
   }
 };
 
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
-                  uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
-                  size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
+bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr,
+                  uint32_t def_style_res, uint32_t* src_values,
+                  size_t src_values_length, uint32_t* attrs,
+                  size_t attrs_length, uint32_t* out_values,
+                  uint32_t* out_indices) {
   if (kDebugStyles) {
     ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
           def_style_attr, def_style_res);
   }
 
-  AssetManager2* assetmanager = theme->GetAssetManager();
+  const ResTable& res = theme->getResTable();
   ResTable_config config;
   Res_value value;
 
   int indices_idx = 0;
 
   // Load default style from attribute, if specified...
-  uint32_t def_style_flags = 0u;
+  uint32_t def_style_bag_type_set_flags = 0;
   if (def_style_attr != 0) {
     Res_value value;
-    if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
+    if (theme->getAttribute(def_style_attr, &value, &def_style_bag_type_set_flags) >= 0) {
       if (value.dataType == Res_value::TYPE_REFERENCE) {
         def_style_res = value.data;
       }
     }
   }
 
-  // Retrieve the default style bag, if requested.
-  const ResolvedBag* default_style_bag = nullptr;
-  if (def_style_res != 0) {
-    default_style_bag = assetmanager->GetBag(def_style_res);
-    if (default_style_bag != nullptr) {
-      def_style_flags |= default_style_bag->type_spec_flags;
-    }
-  }
+  // Now lock down the resource object and start pulling stuff from it.
+  res.lock();
 
-  BagAttributeFinder def_style_attr_finder(default_style_bag);
+  // Retrieve the default style bag, if requested.
+  const ResTable::bag_entry* def_style_start = nullptr;
+  uint32_t def_style_type_set_flags = 0;
+  ssize_t bag_off = def_style_res != 0
+                        ? res.getBagLocked(def_style_res, &def_style_start,
+                                           &def_style_type_set_flags)
+                        : -1;
+  def_style_type_set_flags |= def_style_bag_type_set_flags;
+  const ResTable::bag_entry* const def_style_end =
+      def_style_start + (bag_off >= 0 ? bag_off : 0);
+  BagAttributeFinder def_style_attr_finder(def_style_start, def_style_end);
 
   // Now iterate through all of the attributes that the client has requested,
   // filling in each with whatever data we can find.
@@ -106,7 +106,7 @@
       ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
     }
 
-    ApkAssetsCookie cookie = kInvalidCookie;
+    ssize_t block = -1;
     uint32_t type_set_flags = 0;
 
     value.dataType = Res_value::TYPE_NULL;
@@ -122,14 +122,15 @@
       value.dataType = Res_value::TYPE_ATTRIBUTE;
       value.data = src_values[ii];
       if (kDebugStyles) {
-        ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
+        ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType,
+              value.data);
       }
     } else {
-      const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
-      if (entry != def_style_attr_finder.end()) {
-        cookie = entry->cookie;
-        type_set_flags = def_style_flags;
-        value = entry->value;
+      const ResTable::bag_entry* const def_style_entry = def_style_attr_finder.Find(cur_ident);
+      if (def_style_entry != def_style_end) {
+        block = def_style_entry->stringBlock;
+        type_set_flags = def_style_type_set_flags;
+        value = def_style_entry->map.value;
         if (kDebugStyles) {
           ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
@@ -139,26 +140,22 @@
     uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ApkAssetsCookie new_cookie =
-          theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
-      if (new_cookie != kInvalidCookie) {
-        cookie = new_cookie;
-      }
+      ssize_t new_block =
+          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
+      if (new_block >= 0) block = new_block;
       if (kDebugStyles) {
         ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
       }
     } else if (value.data != Res_value::DATA_NULL_EMPTY) {
-      // If we still don't have a value for this attribute, try to find it in the theme!
-      ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
-      if (new_cookie != kInvalidCookie) {
+      // If we still don't have a value for this attribute, try to find
+      // it in the theme!
+      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
+      if (new_block >= 0) {
         if (kDebugStyles) {
           ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
-        new_cookie =
-            assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
-        if (new_cookie != kInvalidCookie) {
-          cookie = new_cookie;
-        }
+        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
+        if (new_block >= 0) block = new_block;
         if (kDebugStyles) {
           ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
@@ -172,7 +169,7 @@
       }
       value.dataType = Res_value::TYPE_NULL;
       value.data = Res_value::DATA_NULL_UNDEFINED;
-      cookie = kInvalidCookie;
+      block = -1;
     }
 
     if (kDebugStyles) {
@@ -182,7 +179,9 @@
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
-    out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+    out_values[STYLE_ASSET_COOKIE] =
+        block != -1 ? static_cast<uint32_t>(res.getTableCookie(block))
+                    : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
@@ -196,80 +195,90 @@
     out_values += STYLE_NUM_ENTRIES;
   }
 
+  res.unlock();
+
   if (out_indices != nullptr) {
     out_indices[0] = indices_idx;
   }
   return true;
 }
 
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
-                uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
+void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+                uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
                 uint32_t* out_values, uint32_t* out_indices) {
   if (kDebugStyles) {
-    ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
-          def_style_attr, def_style_resid, xml_parser);
+    ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p",
+          theme, def_style_attr, def_style_res, xml_parser);
   }
 
-  AssetManager2* assetmanager = theme->GetAssetManager();
+  const ResTable& res = theme->getResTable();
   ResTable_config config;
   Res_value value;
 
   int indices_idx = 0;
 
   // Load default style from attribute, if specified...
-  uint32_t def_style_flags = 0u;
+  uint32_t def_style_bag_type_set_flags = 0;
   if (def_style_attr != 0) {
     Res_value value;
-    if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
+    if (theme->getAttribute(def_style_attr, &value,
+                            &def_style_bag_type_set_flags) >= 0) {
       if (value.dataType == Res_value::TYPE_REFERENCE) {
-        def_style_resid = value.data;
+        def_style_res = value.data;
       }
     }
   }
 
-  // Retrieve the style resource ID associated with the current XML tag's style attribute.
-  uint32_t style_resid = 0u;
-  uint32_t style_flags = 0u;
+  // Retrieve the style class associated with the current XML tag.
+  int style = 0;
+  uint32_t style_bag_type_set_flags = 0;
   if (xml_parser != nullptr) {
     ssize_t idx = xml_parser->indexOfStyle();
     if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
       if (value.dataType == value.TYPE_ATTRIBUTE) {
-        // Resolve the attribute with out theme.
-        if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) {
+        if (theme->getAttribute(value.data, &value, &style_bag_type_set_flags) < 0) {
           value.dataType = Res_value::TYPE_NULL;
         }
       }
-
       if (value.dataType == value.TYPE_REFERENCE) {
-        style_resid = value.data;
+        style = value.data;
       }
     }
   }
 
-  // Retrieve the default style bag, if requested.
-  const ResolvedBag* default_style_bag = nullptr;
-  if (def_style_resid != 0) {
-    default_style_bag = assetmanager->GetBag(def_style_resid);
-    if (default_style_bag != nullptr) {
-      def_style_flags |= default_style_bag->type_spec_flags;
-    }
-  }
+  // Now lock down the resource object and start pulling stuff from it.
+  res.lock();
 
-  BagAttributeFinder def_style_attr_finder(default_style_bag);
+  // Retrieve the default style bag, if requested.
+  const ResTable::bag_entry* def_style_attr_start = nullptr;
+  uint32_t def_style_type_set_flags = 0;
+  ssize_t bag_off = def_style_res != 0
+                        ? res.getBagLocked(def_style_res, &def_style_attr_start,
+                                           &def_style_type_set_flags)
+                        : -1;
+  def_style_type_set_flags |= def_style_bag_type_set_flags;
+  const ResTable::bag_entry* const def_style_attr_end =
+      def_style_attr_start + (bag_off >= 0 ? bag_off : 0);
+  BagAttributeFinder def_style_attr_finder(def_style_attr_start,
+                                           def_style_attr_end);
 
   // Retrieve the style class bag, if requested.
-  const ResolvedBag* xml_style_bag = nullptr;
-  if (style_resid != 0) {
-    xml_style_bag = assetmanager->GetBag(style_resid);
-    if (xml_style_bag != nullptr) {
-      style_flags |= xml_style_bag->type_spec_flags;
-    }
-  }
-
-  BagAttributeFinder xml_style_attr_finder(xml_style_bag);
+  const ResTable::bag_entry* style_attr_start = nullptr;
+  uint32_t style_type_set_flags = 0;
+  bag_off =
+      style != 0
+          ? res.getBagLocked(style, &style_attr_start, &style_type_set_flags)
+          : -1;
+  style_type_set_flags |= style_bag_type_set_flags;
+  const ResTable::bag_entry* const style_attr_end =
+      style_attr_start + (bag_off >= 0 ? bag_off : 0);
+  BagAttributeFinder style_attr_finder(style_attr_start, style_attr_end);
 
   // Retrieve the XML attributes, if requested.
+  static const ssize_t kXmlBlock = 0x10000000;
   XmlAttributeFinder xml_attr_finder(xml_parser);
+  const size_t xml_attr_end =
+      xml_parser != nullptr ? xml_parser->getAttributeCount() : 0;
 
   // Now iterate through all of the attributes that the client has requested,
   // filling in each with whatever data we can find.
@@ -280,8 +289,8 @@
       ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
     }
 
-    ApkAssetsCookie cookie = kInvalidCookie;
-    uint32_t type_set_flags = 0u;
+    ssize_t block = kXmlBlock;
+    uint32_t type_set_flags = 0;
 
     value.dataType = Res_value::TYPE_NULL;
     value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -293,7 +302,7 @@
 
     // Walk through the xml attributes looking for the requested attribute.
     const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
-    if (xml_attr_idx != xml_attr_finder.end()) {
+    if (xml_attr_idx != xml_attr_end) {
       // We found the attribute we were looking for.
       xml_parser->getAttributeValue(xml_attr_idx, &value);
       if (kDebugStyles) {
@@ -303,12 +312,12 @@
 
     if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
       // Walk through the style class values looking for the requested attribute.
-      const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
-      if (entry != xml_style_attr_finder.end()) {
+      const ResTable::bag_entry* const style_attr_entry = style_attr_finder.Find(cur_ident);
+      if (style_attr_entry != style_attr_end) {
         // We found the attribute we were looking for.
-        cookie = entry->cookie;
-        type_set_flags = style_flags;
-        value = entry->value;
+        block = style_attr_entry->stringBlock;
+        type_set_flags = style_type_set_flags;
+        value = style_attr_entry->map.value;
         if (kDebugStyles) {
           ALOGI("-> From style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
@@ -317,25 +326,25 @@
 
     if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
       // Walk through the default style values looking for the requested attribute.
-      const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
-      if (entry != def_style_attr_finder.end()) {
+      const ResTable::bag_entry* const def_style_attr_entry = def_style_attr_finder.Find(cur_ident);
+      if (def_style_attr_entry != def_style_attr_end) {
         // We found the attribute we were looking for.
-        cookie = entry->cookie;
-        type_set_flags = def_style_flags;
-        value = entry->value;
+        block = def_style_attr_entry->stringBlock;
+        type_set_flags = style_type_set_flags;
+        value = def_style_attr_entry->map.value;
         if (kDebugStyles) {
           ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
       }
     }
 
-    uint32_t resid = 0u;
+    uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ApkAssetsCookie new_cookie =
-          theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
-      if (new_cookie != kInvalidCookie) {
-        cookie = new_cookie;
+      ssize_t new_block =
+          theme->resolveAttributeReference(&value, block, &resid, &type_set_flags, &config);
+      if (new_block >= 0) {
+        block = new_block;
       }
 
       if (kDebugStyles) {
@@ -343,15 +352,14 @@
       }
     } else if (value.data != Res_value::DATA_NULL_EMPTY) {
       // If we still don't have a value for this attribute, try to find it in the theme!
-      ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
-      if (new_cookie != kInvalidCookie) {
+      ssize_t new_block = theme->getAttribute(cur_ident, &value, &type_set_flags);
+      if (new_block >= 0) {
         if (kDebugStyles) {
           ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
         }
-        new_cookie =
-            assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
-        if (new_cookie != kInvalidCookie) {
-          cookie = new_cookie;
+        new_block = res.resolveReference(&value, new_block, &resid, &type_set_flags, &config);
+        if (new_block >= 0) {
+          block = new_block;
         }
 
         if (kDebugStyles) {
@@ -367,7 +375,7 @@
       }
       value.dataType = Res_value::TYPE_NULL;
       value.data = Res_value::DATA_NULL_UNDEFINED;
-      cookie = kInvalidCookie;
+      block = kXmlBlock;
     }
 
     if (kDebugStyles) {
@@ -377,7 +385,9 @@
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
-    out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+    out_values[STYLE_ASSET_COOKIE] =
+        block != kXmlBlock ? static_cast<uint32_t>(res.getTableCookie(block))
+                           : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
@@ -392,28 +402,36 @@
     out_values += STYLE_NUM_ENTRIES;
   }
 
+  res.unlock();
+
   // out_indices must NOT be nullptr.
   out_indices[0] = indices_idx;
 }
 
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
-                        size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
+bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser,
+                        uint32_t* attrs, size_t attrs_length,
+                        uint32_t* out_values, uint32_t* out_indices) {
   ResTable_config config;
   Res_value value;
 
   int indices_idx = 0;
 
+  // Now lock down the resource object and start pulling stuff from it.
+  res->lock();
+
   // Retrieve the XML attributes, if requested.
   const size_t xml_attr_count = xml_parser->getAttributeCount();
   size_t ix = 0;
   uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
 
+  static const ssize_t kXmlBlock = 0x10000000;
+
   // Now iterate through all of the attributes that the client has requested,
   // filling in each with whatever data we can find.
   for (size_t ii = 0; ii < attrs_length; ii++) {
     const uint32_t cur_ident = attrs[ii];
-    ApkAssetsCookie cookie = kInvalidCookie;
-    uint32_t type_set_flags = 0u;
+    ssize_t block = kXmlBlock;
+    uint32_t type_set_flags = 0;
 
     value.dataType = Res_value::TYPE_NULL;
     value.data = Res_value::DATA_NULL_UNDEFINED;
@@ -432,27 +450,28 @@
       cur_xml_attr = xml_parser->getAttributeNameResID(ix);
     }
 
-    uint32_t resid = 0u;
+    uint32_t resid = 0;
     if (value.dataType != Res_value::TYPE_NULL) {
       // Take care of resolving the found resource to its final value.
-      ApkAssetsCookie new_cookie =
-          assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid);
-      if (new_cookie != kInvalidCookie) {
-        cookie = new_cookie;
-      }
+      // printf("Resolving attribute reference\n");
+      ssize_t new_block = res->resolveReference(&value, block, &resid,
+                                                &type_set_flags, &config);
+      if (new_block >= 0) block = new_block;
     }
 
     // Deal with the special @null value -- it turns back to TYPE_NULL.
     if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
       value.dataType = Res_value::TYPE_NULL;
       value.data = Res_value::DATA_NULL_UNDEFINED;
-      cookie = kInvalidCookie;
+      block = kXmlBlock;
     }
 
     // Write the final value back to Java.
     out_values[STYLE_TYPE] = value.dataType;
     out_values[STYLE_DATA] = value.data;
-    out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
+    out_values[STYLE_ASSET_COOKIE] =
+        block != kXmlBlock ? static_cast<uint32_t>(res->getTableCookie(block))
+                           : static_cast<uint32_t>(-1);
     out_values[STYLE_RESOURCE_ID] = resid;
     out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
     out_values[STYLE_DENSITY] = config.density;
@@ -466,6 +485,8 @@
     out_values += STYLE_NUM_ENTRIES;
   }
 
+  res->unlock();
+
   if (out_indices != nullptr) {
     out_indices[0] = indices_idx;
   }
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index a65d49b..28548e2 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -44,6 +44,44 @@
 
 constexpr const static int kAppPackageId = 0x7f;
 
+// Element of a TypeSpec array. See TypeSpec.
+struct Type {
+  // The configuration for which this type defines entries.
+  // This is already converted to host endianness.
+  ResTable_config configuration;
+
+  // Pointer to the mmapped data where entry definitions are kept.
+  const ResTable_type* type;
+};
+
+// TypeSpec is going to be immediately proceeded by
+// an array of Type structs, all in the same block of memory.
+struct TypeSpec {
+  // Pointer to the mmapped data where flags are kept.
+  // Flags denote whether the resource entry is public
+  // and under which configurations it varies.
+  const ResTable_typeSpec* type_spec;
+
+  // Pointer to the mmapped data where the IDMAP mappings for this type
+  // exist. May be nullptr if no IDMAP exists.
+  const IdmapEntry_header* idmap_entries;
+
+  // The number of types that follow this struct.
+  // There is a type for each configuration
+  // that entries are defined for.
+  size_t type_count;
+
+  // Trick to easily access a variable number of Type structs
+  // proceeding this struct, and to ensure their alignment.
+  const Type types[0];
+};
+
+// TypeSpecPtr points to the block of memory that holds
+// a TypeSpec struct, followed by an array of Type structs.
+// TypeSpecPtr is a managed pointer that knows how to delete
+// itself.
+using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+
 namespace {
 
 // Builder that helps accumulate Type structs and then create a single
@@ -57,22 +95,21 @@
   }
 
   void AddType(const ResTable_type* type) {
-    types_.push_back(type);
+    ResTable_config config;
+    config.copyFromDtoH(type->config);
+    types_.push_back(Type{config, type});
   }
 
   TypeSpecPtr Build() {
     // Check for overflow.
-    using ElementType = const ResTable_type*;
-    if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(ElementType) <
-        types_.size()) {
+    if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(Type) < types_.size()) {
       return {};
     }
-    TypeSpec* type_spec =
-        (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(ElementType)));
+    TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type)));
     type_spec->type_spec = header_;
     type_spec->idmap_entries = idmap_header_;
     type_spec->type_count = types_.size();
-    memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(ElementType));
+    memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type));
     return TypeSpecPtr(type_spec);
   }
 
@@ -81,7 +118,7 @@
 
   const ResTable_typeSpec* header_;
   const IdmapEntry_header* idmap_header_;
-  std::vector<const ResTable_type*> types_;
+  std::vector<Type> types_;
 };
 
 }  // namespace
@@ -125,17 +162,18 @@
   return true;
 }
 
-static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset) {
+static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset,
+                                size_t entry_idx) {
   // Check that the offset is aligned.
   if (entry_offset & 0x03) {
-    LOG(ERROR) << "Entry at offset " << entry_offset << " is not 4-byte aligned.";
+    LOG(ERROR) << "Entry offset at index " << entry_idx << " is not 4-byte aligned.";
     return false;
   }
 
   // Check that the offset doesn't overflow.
   if (entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart)) {
     // Overflow in offset.
-    LOG(ERROR) << "Entry at offset " << entry_offset << " is too large.";
+    LOG(ERROR) << "Entry offset at index " << entry_idx << " is too large.";
     return false;
   }
 
@@ -143,7 +181,7 @@
 
   entry_offset += dtohl(type->entriesStart);
   if (entry_offset > chunk_size - sizeof(ResTable_entry)) {
-    LOG(ERROR) << "Entry at offset " << entry_offset
+    LOG(ERROR) << "Entry offset at index " << entry_idx
                << " is too large. No room for ResTable_entry.";
     return false;
   }
@@ -153,13 +191,13 @@
 
   const size_t entry_size = dtohs(entry->size);
   if (entry_size < sizeof(*entry)) {
-    LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
+    LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
                << " is too small.";
     return false;
   }
 
   if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) {
-    LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
+    LOG(ERROR) << "ResTable_entry size " << entry_size << " at index " << entry_idx
                << " is too large.";
     return false;
   }
@@ -167,7 +205,7 @@
   if (entry_size < sizeof(ResTable_map_entry)) {
     // There needs to be room for one Res_value struct.
     if (entry_offset + entry_size > chunk_size - sizeof(Res_value)) {
-      LOG(ERROR) << "No room for Res_value after ResTable_entry at offset " << entry_offset
+      LOG(ERROR) << "No room for Res_value after ResTable_entry at index " << entry_idx
                  << " for type " << (int)type->id << ".";
       return false;
     }
@@ -176,12 +214,12 @@
         reinterpret_cast<const Res_value*>(reinterpret_cast<const uint8_t*>(entry) + entry_size);
     const size_t value_size = dtohs(value->size);
     if (value_size < sizeof(Res_value)) {
-      LOG(ERROR) << "Res_value at offset " << entry_offset << " is too small.";
+      LOG(ERROR) << "Res_value at index " << entry_idx << " is too small.";
       return false;
     }
 
     if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) {
-      LOG(ERROR) << "Res_value size " << value_size << " at offset " << entry_offset
+      LOG(ERROR) << "Res_value size " << value_size << " at index " << entry_idx
                  << " is too large.";
       return false;
     }
@@ -190,76 +228,119 @@
     const size_t map_entry_count = dtohl(map->count);
     size_t map_entries_start = entry_offset + entry_size;
     if (map_entries_start & 0x03) {
-      LOG(ERROR) << "Map entries at offset " << entry_offset << " start at unaligned offset.";
+      LOG(ERROR) << "Map entries at index " << entry_idx << " start at unaligned offset.";
       return false;
     }
 
     // Each entry is sizeof(ResTable_map) big.
     if (map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map))) {
-      LOG(ERROR) << "Too many map entries in ResTable_map_entry at offset " << entry_offset << ".";
+      LOG(ERROR) << "Too many map entries in ResTable_map_entry at index " << entry_idx << ".";
       return false;
     }
   }
   return true;
 }
 
-const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
-                                              uint16_t entry_index) {
-  uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
-  if (entry_offset == ResTable_type::NO_ENTRY) {
-    return nullptr;
-  }
-  return GetEntryFromOffset(type_chunk, entry_offset);
-}
+bool LoadedPackage::FindEntry(const TypeSpecPtr& type_spec_ptr, uint16_t entry_idx,
+                              const ResTable_config& config, FindEntryResult* out_entry) const {
+  const ResTable_config* best_config = nullptr;
+  const ResTable_type* best_type = nullptr;
+  uint32_t best_offset = 0;
 
-uint32_t LoadedPackage::GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index) {
-  // The configuration matches and is better than the previous selection.
-  // Find the entry value if it exists for this configuration.
-  const size_t entry_count = dtohl(type_chunk->entryCount);
-  const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
+  for (uint32_t i = 0; i < type_spec_ptr->type_count; i++) {
+    const Type* type = &type_spec_ptr->types[i];
+    const ResTable_type* type_chunk = type->type;
 
-  // Check if there is the desired entry in this type.
+    if (type->configuration.match(config) &&
+        (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
+      // The configuration matches and is better than the previous selection.
+      // Find the entry value if it exists for this configuration.
+      const size_t entry_count = dtohl(type_chunk->entryCount);
+      const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
 
-  if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
-    // This is encoded as a sparse map, so perform a binary search.
-    const ResTable_sparseTypeEntry* sparse_indices =
-        reinterpret_cast<const ResTable_sparseTypeEntry*>(
+      // Check if there is the desired entry in this type.
+
+      if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
+        // This is encoded as a sparse map, so perform a binary search.
+        const ResTable_sparseTypeEntry* sparse_indices =
+            reinterpret_cast<const ResTable_sparseTypeEntry*>(
+                reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
+        const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
+        const ResTable_sparseTypeEntry* result =
+            std::lower_bound(sparse_indices, sparse_indices_end, entry_idx,
+                             [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
+                               return dtohs(entry.idx) < entry_idx;
+                             });
+
+        if (result == sparse_indices_end || dtohs(result->idx) != entry_idx) {
+          // No entry found.
+          continue;
+        }
+
+        // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
+        // the real offset divided by 4.
+        best_offset = uint32_t{dtohs(result->offset)} * 4u;
+      } else {
+        if (entry_idx >= entry_count) {
+          // This entry cannot be here.
+          continue;
+        }
+
+        const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
             reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
-    const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
-    const ResTable_sparseTypeEntry* result =
-        std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
-                         [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
-                           return dtohs(entry.idx) < entry_idx;
-                         });
+        const uint32_t offset = dtohl(entry_offsets[entry_idx]);
+        if (offset == ResTable_type::NO_ENTRY) {
+          continue;
+        }
 
-    if (result == sparse_indices_end || dtohs(result->idx) != entry_index) {
-      // No entry found.
-      return ResTable_type::NO_ENTRY;
+        // There is an entry for this resource, record it.
+        best_offset = offset;
+      }
+
+      best_config = &type->configuration;
+      best_type = type_chunk;
     }
-
-    // Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
-    // the real offset divided by 4.
-    return uint32_t{dtohs(result->offset)} * 4u;
   }
 
-  // This type is encoded as a dense array.
-  if (entry_index >= entry_count) {
-    // This entry cannot be here.
-    return ResTable_type::NO_ENTRY;
+  if (best_type == nullptr) {
+    return false;
   }
 
-  const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
-      reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
-  return dtohl(entry_offsets[entry_index]);
+  if (UNLIKELY(!VerifyResTableEntry(best_type, best_offset, entry_idx))) {
+    return false;
+  }
+
+  const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
+      reinterpret_cast<const uint8_t*>(best_type) + best_offset + dtohl(best_type->entriesStart));
+
+  const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec_ptr->type_spec + 1);
+  out_entry->type_flags = dtohl(flags[entry_idx]);
+  out_entry->entry = best_entry;
+  out_entry->config = best_config;
+  out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1);
+  out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index));
+  return true;
 }
 
-const ResTable_entry* LoadedPackage::GetEntryFromOffset(const ResTable_type* type_chunk,
-                                                        uint32_t offset) {
-  if (UNLIKELY(!VerifyResTableEntry(type_chunk, offset))) {
-    return nullptr;
+bool LoadedPackage::FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+                              FindEntryResult* out_entry) const {
+  ATRACE_CALL();
+
+  // If the type IDs are offset in this package, we need to take that into account when searching
+  // for a type.
+  const TypeSpecPtr& ptr = type_specs_[type_idx - type_id_offset_];
+  if (UNLIKELY(ptr == nullptr)) {
+    return false;
   }
-  return reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type_chunk) +
-                                                 offset + dtohl(type_chunk->entriesStart));
+
+  // If there is an IDMAP supplied with this package, translate the entry ID.
+  if (ptr->idmap_entries != nullptr) {
+    if (!LoadedIdmap::Lookup(ptr->idmap_entries, entry_idx, &entry_idx)) {
+      // There is no mapping, so the resource is not meant to be in this overlay package.
+      return false;
+    }
+  }
+  return FindEntry(ptr, entry_idx, config, out_entry);
 }
 
 void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
@@ -267,7 +348,7 @@
   const static std::u16string kMipMap = u"mipmap";
   const size_t type_count = type_specs_.size();
   for (size_t i = 0; i < type_count; i++) {
-    const TypeSpecPtr& type_spec = type_specs_[i];
+    const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
     if (type_spec != nullptr) {
       if (exclude_mipmap) {
         const int type_idx = type_spec->type_spec->id - 1;
@@ -288,11 +369,8 @@
         }
       }
 
-      const auto iter_end = type_spec->types + type_spec->type_count;
-      for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-        ResTable_config config;
-        config.copyFromDtoH((*iter)->config);
-        out_configs->insert(config);
+      for (size_t j = 0; j < type_spec->type_count; j++) {
+        out_configs->insert(type_spec->types[j].configuration);
       }
     }
   }
@@ -302,12 +380,10 @@
   char temp_locale[RESTABLE_MAX_LOCALE_LEN];
   const size_t type_count = type_specs_.size();
   for (size_t i = 0; i < type_count; i++) {
-    const TypeSpecPtr& type_spec = type_specs_[i];
+    const util::unique_cptr<TypeSpec>& type_spec = type_specs_[i];
     if (type_spec != nullptr) {
-      const auto iter_end = type_spec->types + type_spec->type_count;
-      for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-        ResTable_config configuration;
-        configuration.copyFromDtoH((*iter)->config);
+      for (size_t j = 0; j < type_spec->type_count; j++) {
+        const ResTable_config& configuration = type_spec->types[j].configuration;
         if (configuration.locale != 0) {
           configuration.getBcp47Locale(temp_locale, canonicalize);
           std::string locale(temp_locale);
@@ -335,17 +411,17 @@
     return 0u;
   }
 
-  const auto iter_end = type_spec->types + type_spec->type_count;
-  for (auto iter = type_spec->types; iter != iter_end; ++iter) {
-    const ResTable_type* type = *iter;
-    size_t entry_count = dtohl(type->entryCount);
+  for (size_t ti = 0; ti < type_spec->type_count; ti++) {
+    const Type* type = &type_spec->types[ti];
+    size_t entry_count = dtohl(type->type->entryCount);
     for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
       const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
-          reinterpret_cast<const uint8_t*>(type) + dtohs(type->header.headerSize));
+          reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
       const uint32_t offset = dtohl(entry_offsets[entry_idx]);
       if (offset != ResTable_type::NO_ENTRY) {
-        const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
-            reinterpret_cast<const uint8_t*>(type) + dtohl(type->entriesStart) + offset);
+        const ResTable_entry* entry =
+            reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type->type) +
+                                                    dtohl(type->type->entriesStart) + offset);
         if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) {
           // The package ID will be overridden by the caller (due to runtime assignment of package
           // IDs for shared libraries).
@@ -357,7 +433,8 @@
   return 0u;
 }
 
-const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const {
+const LoadedPackage* LoadedArsc::GetPackageForId(uint32_t resid) const {
+  const uint8_t package_id = get_package_id(resid);
   for (const auto& loaded_package : packages_) {
     if (loaded_package->GetPackageId() == package_id) {
       return loaded_package.get();
@@ -409,10 +486,14 @@
   util::ReadUtf16StringFromDevice(header->name, arraysize(header->name),
                                   &loaded_package->package_name_);
 
-  // A map of TypeSpec builders, each associated with an type index.
-  // We use these to accumulate the set of Types available for a TypeSpec, and later build a single,
-  // contiguous block of memory that holds all the Types together with the TypeSpec.
-  std::unordered_map<int, std::unique_ptr<TypeSpecPtrBuilder>> type_builder_map;
+  // A TypeSpec builder. We use this to accumulate the set of Types
+  // available for a TypeSpec, and later build a single, contiguous block
+  // of memory that holds all the Types together with the TypeSpec.
+  std::unique_ptr<TypeSpecPtrBuilder> types_builder;
+
+  // Keep track of the last seen type index. Since type IDs are 1-based,
+  // this records their index, which is 0-based (type ID - 1).
+  uint8_t last_type_idx = 0;
 
   ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
   while (iter.HasNext()) {
@@ -446,6 +527,28 @@
       case RES_TABLE_TYPE_SPEC_TYPE: {
         ATRACE_NAME("LoadTableTypeSpec");
 
+        // Starting a new TypeSpec, so finish the old one if there was one.
+        if (types_builder) {
+          TypeSpecPtr type_spec_ptr = types_builder->Build();
+          if (type_spec_ptr == nullptr) {
+            LOG(ERROR) << "Too many type configurations, overflow detected.";
+            return {};
+          }
+
+          // We only add the type to the package if there is no IDMAP, or if the type is
+          // overlaying something.
+          if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
+            // If this is an overlay, insert it at the target type ID.
+            if (type_spec_ptr->idmap_entries != nullptr) {
+              last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
+            }
+            loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+          }
+
+          types_builder = {};
+          last_type_idx = 0;
+        }
+
         const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
         if (type_spec == nullptr) {
           LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE too small.";
@@ -480,6 +583,8 @@
           return {};
         }
 
+        last_type_idx = type_spec->id - 1;
+
         // If this is an overlay, associate the mapping of this type to the target type
         // from the IDMAP.
         const IdmapEntry_header* idmap_entry_header = nullptr;
@@ -487,13 +592,7 @@
           idmap_entry_header = loaded_idmap->GetEntryMapForType(type_spec->id);
         }
 
-        std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
-        if (builder_ptr == nullptr) {
-          builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
-        } else {
-          LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
-                                       type_spec->id);
-        }
+        types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec, idmap_entry_header);
       } break;
 
       case RES_TABLE_TYPE_TYPE: {
@@ -508,15 +607,12 @@
         }
 
         // Type chunks must be preceded by their TypeSpec chunks.
-        std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type->id - 1];
-        if (builder_ptr != nullptr) {
-          builder_ptr->AddType(type);
-        } else {
-          LOG(ERROR) << StringPrintf(
-              "RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.",
-              type->id);
+        if (!types_builder || type->id - 1 != last_type_idx) {
+          LOG(ERROR) << "RES_TABLE_TYPE_TYPE found without preceding RES_TABLE_TYPE_SPEC_TYPE.";
           return {};
         }
+
+        types_builder->AddType(type);
       } break;
 
       case RES_TABLE_LIBRARY_TYPE: {
@@ -542,7 +638,7 @@
                                           arraysize(entry_iter->packageName), &package_name);
 
           if (dtohl(entry_iter->packageId) >= std::numeric_limits<uint8_t>::max()) {
-            LOG(ERROR) << StringPrintf(
+            LOG(ERROR) << base::StringPrintf(
                 "Package ID %02x in RES_TABLE_LIBRARY_TYPE too large for package '%s'.",
                 dtohl(entry_iter->packageId), package_name.c_str());
             return {};
@@ -555,20 +651,14 @@
       } break;
 
       default:
-        LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
         break;
     }
   }
 
-  if (iter.HadError()) {
-    LOG(ERROR) << iter.GetLastError();
-    return {};
-  }
-
-  // Flatten and construct the TypeSpecs.
-  for (auto& entry : type_builder_map) {
-    uint8_t type_idx = static_cast<uint8_t>(entry.first);
-    TypeSpecPtr type_spec_ptr = entry.second->Build();
+  // Finish the last TypeSpec.
+  if (types_builder) {
+    TypeSpecPtr type_spec_ptr = types_builder->Build();
     if (type_spec_ptr == nullptr) {
       LOG(ERROR) << "Too many type configurations, overflow detected.";
       return {};
@@ -579,15 +669,40 @@
     if (loaded_idmap == nullptr || type_spec_ptr->idmap_entries != nullptr) {
       // If this is an overlay, insert it at the target type ID.
       if (type_spec_ptr->idmap_entries != nullptr) {
-        type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
+        last_type_idx = dtohs(type_spec_ptr->idmap_entries->target_type_id) - 1;
       }
-      loaded_package->type_specs_.editItemAt(type_idx) = std::move(type_spec_ptr);
+      loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
     }
   }
 
+  if (iter.HadError()) {
+    LOG(ERROR) << iter.GetLastError();
+    return {};
+  }
   return std::move(loaded_package);
 }
 
+bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config,
+                           FindEntryResult* out_entry) const {
+  ATRACE_CALL();
+
+  const uint8_t package_id = get_package_id(resid);
+  const uint8_t type_id = get_type_id(resid);
+  const uint16_t entry_id = get_entry_id(resid);
+
+  if (UNLIKELY(type_id == 0)) {
+    LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
+    return false;
+  }
+
+  for (const auto& loaded_package : packages_) {
+    if (loaded_package->GetPackageId() == package_id) {
+      return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry);
+    }
+  }
+  return false;
+}
+
 bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
                            bool load_as_shared_library) {
   ATRACE_CALL();
@@ -637,7 +752,7 @@
       } break;
 
       default:
-        LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
         break;
     }
   }
@@ -669,7 +784,7 @@
         break;
 
       default:
-        LOG(WARNING) << StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
         break;
     }
   }
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index ef08897..b033137 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -69,8 +69,6 @@
   Entry entries[0];
 };
 
-struct FindEntryResult;
-
 // AssetManager2 is the main entry point for accessing assets and resources.
 // AssetManager2 provides caching of resources retrieved via the underlying ApkAssets.
 class AssetManager2 {
@@ -129,7 +127,7 @@
   // If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap'
   // will be excluded from the list.
   std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false,
-                                                      bool exclude_mipmap = false) const;
+                                                      bool exclude_mipmap = false);
 
   // Returns all the locales for which there are resources defined. This includes resource
   // locales in all the ApkAssets set for this AssetManager.
@@ -138,24 +136,24 @@
   // If `merge_equivalent_languages` is set to true, resource locales will be canonicalized
   // and de-duped in the resulting list.
   std::set<std::string> GetResourceLocales(bool exclude_system = false,
-                                           bool merge_equivalent_languages = false) const;
+                                           bool merge_equivalent_languages = false);
 
   // Searches the set of APKs loaded by this AssetManager and opens the first one found located
   // in the assets/ directory.
   // `mode` controls how the file is opened.
   //
   // NOTE: The loaded APKs are searched in reverse order.
-  std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode) const;
+  std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode);
 
   // Opens a file within the assets/ directory of the APK specified by `cookie`.
   // `mode` controls how the file is opened.
   std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie,
-                              Asset::AccessMode mode) const;
+                              Asset::AccessMode mode);
 
   // Opens the directory specified by `dirname`. The result is an AssetDir that is the combination
   // of all directories matching `dirname` under the assets/ directory of every ApkAssets loaded.
   // The entries are sorted by their ASCII name.
-  std::unique_ptr<AssetDir> OpenDir(const std::string& dirname) const;
+  std::unique_ptr<AssetDir> OpenDir(const std::string& dirname);
 
   // Searches the set of APKs loaded by this AssetManager and opens the first one found.
   // `mode` controls how the file is opened.
@@ -163,24 +161,24 @@
   //
   // NOTE: The loaded APKs are searched in reverse order.
   std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode,
-                                      ApkAssetsCookie* out_cookie = nullptr) const;
+                                      ApkAssetsCookie* out_cookie = nullptr);
 
   // Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened.
   // This is typically used to open a specific AndroidManifest.xml, or a binary XML file
   // referenced by a resource lookup with GetResource().
   std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
-                                      Asset::AccessMode mode) const;
+                                      Asset::AccessMode mode);
 
   // Populates the `out_name` parameter with resource name information.
   // Utf8 strings are preferred, and only if they are unavailable are
   // the Utf16 variants populated.
   // Returns false if the resource was not found or the name was missing/corrupt.
-  bool GetResourceName(uint32_t resid, ResourceName* out_name) const;
+  bool GetResourceName(uint32_t resid, ResourceName* out_name);
 
   // Populates `out_flags` with the bitmask of configuration axis that this resource varies with.
   // See ResTable_config for the list of configuration axis.
   // Returns false if the resource was not found.
-  bool GetResourceFlags(uint32_t resid, uint32_t* out_flags) const;
+  bool GetResourceFlags(uint32_t resid, uint32_t* out_flags);
 
   // Finds the resource ID assigned to `resource_name`.
   // `resource_name` must be of the form '[package:][type/]entry'.
@@ -188,7 +186,7 @@
   // If no type is specified in `resource_name`, then `fallback_type` is used as the type.
   // Returns 0x0 if no resource by that name was found.
   uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {},
-                         const std::string& fallback_package = {}) const;
+                         const std::string& fallback_package = {});
 
   // Retrieves the best matching resource with ID `resid`. The resource value is filled into
   // `out_value` and the configuration for the selected value is populated in `out_selected_config`.
@@ -201,7 +199,7 @@
   // this function logs if the resource was a map/bag type before returning kInvalidCookie.
   ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override,
                               Res_value* out_value, ResTable_config* out_selected_config,
-                              uint32_t* out_flags) const;
+                              uint32_t* out_flags);
 
   // Resolves the resource reference in `in_out_value` if the data type is
   // Res_value::TYPE_REFERENCE.
@@ -217,7 +215,7 @@
   // it was not found.
   ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                    ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
-                                   uint32_t* out_last_reference) const;
+                                   uint32_t* out_last_reference);
 
   // Retrieves the best matching bag/map resource with ID `resid`.
   // This method will resolve all parent references for this bag and merge keys with the child.
@@ -235,9 +233,9 @@
   std::unique_ptr<Theme> NewTheme();
 
   template <typename Func>
-  void ForEachPackage(Func func) const {
+  void ForEachPackage(Func func) {
     for (const PackageGroup& package_group : package_groups_) {
-      func(package_group.packages_.front().loaded_package_->GetPackageName(),
+      func(package_group.packages_.front()->GetPackageName(),
            package_group.dynamic_ref_table.mAssignedPackageId);
     }
   }
@@ -262,7 +260,7 @@
   // NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
   // bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
   ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
-                            FindEntryResult* out_entry) const;
+                            FindEntryResult* out_entry);
 
   // Assigns package IDs to all shared library ApkAssets.
   // Should be called whenever the ApkAssets are changed.
@@ -272,43 +270,13 @@
   // bitmask `diff`.
   void InvalidateCaches(uint32_t diff);
 
-  // Triggers the re-construction of lists of types that match the set configuration.
-  // This should always be called when mutating the AssetManager's configuration or ApkAssets set.
-  void RebuildFilterList();
-
   // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
   // have a longer lifetime.
   std::vector<const ApkAssets*> apk_assets_;
 
-  // A collection of configurations and their associated ResTable_type that match the current
-  // AssetManager configuration.
-  struct FilteredConfigGroup {
-    std::vector<ResTable_config> configurations;
-    std::vector<const ResTable_type*> types;
-  };
-
-  // Represents an single package.
-  struct ConfiguredPackage {
-    // A pointer to the immutable, loaded package info.
-    const LoadedPackage* loaded_package_;
-
-    // A mutable AssetManager-specific list of configurations that match the AssetManager's
-    // current configuration. This is used as an optimization to avoid checking every single
-    // candidate configuration when looking up resources.
-    ByteBucketArray<FilteredConfigGroup> filtered_configs_;
-  };
-
-  // Represents a logical package, which can be made up of many individual packages. Each package
-  // in a PackageGroup shares the same package name and package ID.
   struct PackageGroup {
-    // The set of packages that make-up this group.
-    std::vector<ConfiguredPackage> packages_;
-
-    // The cookies associated with each package in the group. They share the same order as
-    // packages_.
+    std::vector<const LoadedPackage*> packages_;
     std::vector<ApkAssetsCookie> cookies_;
-
-    // A library reference table that contains build-package ID to runtime-package ID mappings.
     DynamicRefTable dynamic_ref_table;
   };
 
@@ -382,7 +350,7 @@
   ApkAssetsCookie ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
                                             ResTable_config* in_out_selected_config = nullptr,
                                             uint32_t* in_out_type_spec_flags = nullptr,
-                                            uint32_t* out_last_ref = nullptr) const;
+                                            uint32_t* out_last_ref = nullptr);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(Theme);
diff --git a/libs/androidfw/include/androidfw/AttributeFinder.h b/libs/androidfw/include/androidfw/AttributeFinder.h
index 03fad49..f281921 100644
--- a/libs/androidfw/include/androidfw/AttributeFinder.h
+++ b/libs/androidfw/include/androidfw/AttributeFinder.h
@@ -58,7 +58,6 @@
   BackTrackingAttributeFinder(const Iterator& begin, const Iterator& end);
 
   Iterator Find(uint32_t attr);
-  inline Iterator end();
 
  private:
   void JumpToClosestAttribute(uint32_t package_id);
@@ -202,11 +201,6 @@
   return end_;
 }
 
-template <typename Derived, typename Iterator>
-Iterator BackTrackingAttributeFinder<Derived, Iterator>::end() {
-  return end_;
-}
-
 }  // namespace android
 
 #endif  // ANDROIDFW_ATTRIBUTE_FINDER_H
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index 35ef98d..69b76041 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -17,8 +17,7 @@
 #ifndef ANDROIDFW_ATTRIBUTERESOLUTION_H
 #define ANDROIDFW_ATTRIBUTERESOLUTION_H
 
-#include "androidfw/AssetManager2.h"
-#include "androidfw/ResourceTypes.h"
+#include <androidfw/ResourceTypes.h>
 
 namespace android {
 
@@ -43,19 +42,19 @@
 
 // `out_values` must NOT be nullptr.
 // `out_indices` may be nullptr.
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid,
+bool ResolveAttrs(ResTable::Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
                   uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
                   size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
 
 // `out_values` must NOT be nullptr.
 // `out_indices` is NOT optional and must NOT be nullptr.
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
-                uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
+void ApplyStyle(ResTable::Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
+                uint32_t def_style_res, const uint32_t* attrs, size_t attrs_length,
                 uint32_t* out_values, uint32_t* out_indices);
 
 // `out_values` must NOT be nullptr.
 // `out_indices` may be nullptr.
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
+bool RetrieveAttributes(const ResTable* res, ResXMLParser* xml_parser, uint32_t* attrs,
                         size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
 
 }  // namespace android
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 35ae5fc..965e2db 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -41,40 +41,32 @@
   int package_id = 0;
 };
 
-// TypeSpec is going to be immediately proceeded by
-// an array of Type structs, all in the same block of memory.
-struct TypeSpec {
-  // Pointer to the mmapped data where flags are kept.
-  // Flags denote whether the resource entry is public
-  // and under which configurations it varies.
-  const ResTable_typeSpec* type_spec;
+struct FindEntryResult {
+  // A pointer to the resource table entry for this resource.
+  // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
+  // a ResTable_map_entry and processed as a bag/map.
+  const ResTable_entry* entry = nullptr;
 
-  // Pointer to the mmapped data where the IDMAP mappings for this type
-  // exist. May be nullptr if no IDMAP exists.
-  const IdmapEntry_header* idmap_entries;
+  // The configuration for which the resulting entry was defined.
+  const ResTable_config* config = nullptr;
 
-  // The number of types that follow this struct.
-  // There is a type for each configuration that entries are defined for.
-  size_t type_count;
+  // Stores the resulting bitmask of configuration axis with which the resource value varies.
+  uint32_t type_flags = 0u;
 
-  // Trick to easily access a variable number of Type structs
-  // proceeding this struct, and to ensure their alignment.
-  const ResTable_type* types[0];
+  // The dynamic package ID map for the package from which this resource came from.
+  const DynamicRefTable* dynamic_ref_table = nullptr;
 
-  inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const {
-    if (entry_index >= dtohl(type_spec->entryCount)) {
-      return 0u;
-    }
+  // The string pool reference to the type's name. This uses a different string pool than
+  // the global string pool, but this is hidden from the caller.
+  StringPoolRef type_string_ref;
 
-    const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1);
-    return flags[entry_index];
-  }
+  // The string pool reference to the entry's name. This uses a different string pool than
+  // the global string pool, but this is hidden from the caller.
+  StringPoolRef entry_string_ref;
 };
 
-// TypeSpecPtr points to a block of memory that holds a TypeSpec struct, followed by an array of
-// ResTable_type pointers.
-// TypeSpecPtr is a managed pointer that knows how to delete itself.
-using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+struct TypeSpec;
+class LoadedArsc;
 
 class LoadedPackage {
  public:
@@ -84,6 +76,9 @@
 
   ~LoadedPackage();
 
+  bool FindEntry(uint8_t type_idx, uint16_t entry_idx, const ResTable_config& config,
+                 FindEntryResult* out_entry) const;
+
   // Finds the entry with the specified type name and entry name. The names are in UTF-16 because
   // the underlying ResStringPool API expects this. For now this is acceptable, but since
   // the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
@@ -91,12 +86,6 @@
   // for patching the correct package ID to the resource ID.
   uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
 
-  static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index);
-
-  static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index);
-
-  static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset);
-
   // Returns the string pool where type names are stored.
   inline const ResStringPool* GetTypeStringPool() const {
     return &type_string_pool_;
@@ -146,32 +135,14 @@
   // before being inserted into the set. This may cause some equivalent locales to de-dupe.
   void CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const;
 
-  // type_idx is TT - 1 from 0xPPTTEEEE.
-  inline const TypeSpec* GetTypeSpecByTypeIndex(uint8_t type_index) const {
-    // If the type IDs are offset in this package, we need to take that into account when searching
-    // for a type.
-    return type_specs_[type_index - type_id_offset_].get();
-  }
-
-  template <typename Func>
-  void ForEachTypeSpec(Func f) const {
-    for (size_t i = 0; i < type_specs_.size(); i++) {
-      const TypeSpecPtr& ptr = type_specs_[i];
-      if (ptr != nullptr) {
-        uint8_t type_id = ptr->type_spec->id;
-        if (ptr->idmap_entries != nullptr) {
-          type_id = ptr->idmap_entries->target_type_id;
-        }
-        f(ptr.get(), type_id - 1);
-      }
-    }
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
 
   LoadedPackage();
 
+  bool FindEntry(const util::unique_cptr<TypeSpec>& type_spec_ptr, uint16_t entry_idx,
+                 const ResTable_config& config, FindEntryResult* out_entry) const;
+
   ResStringPool type_string_pool_;
   ResStringPool key_string_pool_;
   std::string package_name_;
@@ -181,7 +152,7 @@
   bool system_ = false;
   bool overlay_ = false;
 
-  ByteBucketArray<TypeSpecPtr> type_specs_;
+  ByteBucketArray<util::unique_cptr<TypeSpec>> type_specs_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
 };
 
@@ -209,20 +180,25 @@
     return &global_string_pool_;
   }
 
-  // Gets a pointer to the package with the specified package ID, or nullptr if no such package
-  // exists.
-  const LoadedPackage* GetPackageById(uint8_t package_id) const;
+  // Finds the resource with ID `resid` with the best value for configuration `config`.
+  // The parameter `out_entry` will be filled with the resulting resource entry.
+  // The resource entry can be a simple entry (ResTable_entry) or a complex bag
+  // (ResTable_entry_map).
+  bool FindEntry(uint32_t resid, const ResTable_config& config, FindEntryResult* out_entry) const;
 
-  // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
-  inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
-    return packages_;
-  }
+  // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
+  const LoadedPackage* GetPackageForId(uint32_t resid) const;
 
   // Returns true if this is a system provided resource.
   inline bool IsSystem() const {
     return system_;
   }
 
+  // Returns a vector of LoadedPackage pointers, representing the packages in this LoadedArsc.
+  inline const std::vector<std::unique_ptr<const LoadedPackage>>& GetPackages() const {
+    return packages_;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
 
diff --git a/libs/androidfw/include/androidfw/MutexGuard.h b/libs/androidfw/include/androidfw/MutexGuard.h
deleted file mode 100644
index 64924f4..0000000
--- a/libs/androidfw/include/androidfw/MutexGuard.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROIDFW_MUTEXGUARD_H
-#define ANDROIDFW_MUTEXGUARD_H
-
-#include <mutex>
-#include <type_traits>
-
-#include "android-base/macros.h"
-
-namespace android {
-
-template <typename T>
-class ScopedLock;
-
-// Owns the guarded object and protects access to it via a mutex.
-// The guarded object is inaccessible via this class.
-// The mutex is locked and the object accessed via the ScopedLock<T> class.
-//
-// NOTE: The template parameter T should not be a raw pointer, since ownership
-// is ambiguous and error-prone. Instead use an std::unique_ptr<>.
-//
-// Example use:
-//
-//   Guarded<std::string> shared_string("hello");
-//   {
-//     ScopedLock<std::string> locked_string(shared_string);
-//     *locked_string += " world";
-//   }
-//
-template <typename T>
-class Guarded {
-  static_assert(!std::is_pointer<T>::value, "T must not be a raw pointer");
-
- public:
-  explicit Guarded() : guarded_() {
-  }
-
-  template <typename U = T>
-  explicit Guarded(const T& guarded,
-                   typename std::enable_if<std::is_copy_constructible<U>::value>::type = void())
-      : guarded_(guarded) {
-  }
-
-  template <typename U = T>
-  explicit Guarded(T&& guarded,
-                   typename std::enable_if<std::is_move_constructible<U>::value>::type = void())
-      : guarded_(std::move(guarded)) {
-  }
-
- private:
-  friend class ScopedLock<T>;
-
-  DISALLOW_COPY_AND_ASSIGN(Guarded);
-
-  std::mutex lock_;
-  T guarded_;
-};
-
-template <typename T>
-class ScopedLock {
- public:
-  explicit ScopedLock(Guarded<T>& guarded) : lock_(guarded.lock_), guarded_(guarded.guarded_) {
-  }
-
-  T& operator*() {
-    return guarded_;
-  }
-
-  T* operator->() {
-    return &guarded_;
-  }
-
-  T* get() {
-    return &guarded_;
-  }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(ScopedLock);
-
-  std::lock_guard<std::mutex> lock_;
-  T& guarded_;
-};
-
-}  // namespace android
-
-#endif  // ANDROIDFW_MUTEXGUARD_H
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index d94779b..c2eae85 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -28,7 +28,7 @@
                          StringPiece* out_entry);
 
 inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
-  return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24);
+  return resid | (static_cast<uint32_t>(package_id) << 24);
 }
 
 inline uint8_t get_package_id(uint32_t resid) {
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
index e2b9f00..6c43a67 100644
--- a/libs/androidfw/tests/ApkAssets_test.cpp
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -26,56 +26,58 @@
 
 using ::android::base::unique_fd;
 using ::com::android::basic::R;
-using ::testing::Eq;
-using ::testing::Ge;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-using ::testing::StrEq;
 
 namespace android {
 
 TEST(ApkAssetsTest, LoadApk) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
   const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
-  ASSERT_THAT(loaded_arsc, NotNull());
-  ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull());
-  ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+  ASSERT_NE(nullptr, loaded_package);
+
+  std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+  ASSERT_NE(nullptr, asset);
 }
 
 TEST(ApkAssetsTest, LoadApkFromFd) {
   const std::string path = GetTestDataPath() + "/basic/basic.apk";
   unique_fd fd(::open(path.c_str(), O_RDONLY | O_BINARY));
-  ASSERT_THAT(fd.get(), Ge(0));
+  ASSERT_GE(fd.get(), 0);
 
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::LoadFromFd(std::move(fd), path, false /*system*/, false /*force_shared_lib*/);
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
   const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
-  ASSERT_THAT(loaded_arsc, NotNull());
-  ASSERT_THAT(loaded_arsc->GetPackageById(0x7fu), NotNull());
-  ASSERT_THAT(loaded_apk->Open("res/layout/main.xml"), NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const LoadedPackage* loaded_package = loaded_arsc->GetPackageForId(0x7f010000);
+  ASSERT_NE(nullptr, loaded_package);
+
+  std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+  ASSERT_NE(nullptr, asset);
 }
 
 TEST(ApkAssetsTest, LoadApkAsSharedLibrary) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
-
+  ASSERT_NE(nullptr, loaded_apk);
   const LoadedArsc* loaded_arsc = loaded_apk->GetLoadedArsc();
-  ASSERT_THAT(loaded_arsc, NotNull());
-  ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
+  ASSERT_NE(nullptr, loaded_arsc);
+  ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
   EXPECT_FALSE(loaded_arsc->GetPackages()[0]->IsDynamic());
 
   loaded_apk = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
   loaded_arsc = loaded_apk->GetLoadedArsc();
-  ASSERT_THAT(loaded_arsc, NotNull());
-  ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
+  ASSERT_NE(nullptr, loaded_arsc);
+  ASSERT_EQ(1u, loaded_arsc->GetPackages().size());
   EXPECT_TRUE(loaded_arsc->GetPackages()[0]->IsDynamic());
 }
 
@@ -84,22 +86,19 @@
   ResTable target_table;
   const std::string target_path = GetTestDataPath() + "/basic/basic.apk";
   ASSERT_TRUE(ReadFileFromZipToString(target_path, "resources.arsc", &contents));
-  ASSERT_THAT(target_table.add(contents.data(), contents.size(), 0, true /*copyData*/),
-              Eq(NO_ERROR));
+  ASSERT_EQ(NO_ERROR, target_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
 
   ResTable overlay_table;
   const std::string overlay_path = GetTestDataPath() + "/overlay/overlay.apk";
   ASSERT_TRUE(ReadFileFromZipToString(overlay_path, "resources.arsc", &contents));
-  ASSERT_THAT(overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/),
-              Eq(NO_ERROR));
+  ASSERT_EQ(NO_ERROR, overlay_table.add(contents.data(), contents.size(), 0, true /*copyData*/));
 
   util::unique_cptr<void> idmap_data;
   void* temp_data;
   size_t idmap_len;
 
-  ASSERT_THAT(target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
-                                       overlay_path.c_str(), &temp_data, &idmap_len),
-              Eq(NO_ERROR));
+  ASSERT_EQ(NO_ERROR, target_table.createIdmap(overlay_table, 0u, 0u, target_path.c_str(),
+                                               overlay_path.c_str(), &temp_data, &idmap_len));
   idmap_data.reset(temp_data);
 
   TemporaryFile tf;
@@ -109,30 +108,37 @@
   // Open something so that the destructor of TemporaryFile closes a valid fd.
   tf.fd = open("/dev/null", O_WRONLY);
 
-  ASSERT_THAT(ApkAssets::LoadOverlay(tf.path), NotNull());
+  std::unique_ptr<const ApkAssets> loaded_overlay_apk = ApkAssets::LoadOverlay(tf.path);
+  ASSERT_NE(nullptr, loaded_overlay_apk);
 }
 
 TEST(ApkAssetsTest, CreateAndDestroyAssetKeepsApkAssetsOpen) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
-  { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); }
+  {
+    std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER);
+    ASSERT_NE(nullptr, assets);
+  }
 
-  { ASSERT_THAT(loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER), NotNull()); }
+  {
+    std::unique_ptr<Asset> assets = loaded_apk->Open("res/layout/main.xml", Asset::ACCESS_BUFFER);
+    ASSERT_NE(nullptr, assets);
+  }
 }
 
 TEST(ApkAssetsTest, OpenUncompressedAssetFd) {
   std::unique_ptr<const ApkAssets> loaded_apk =
       ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
-  ASSERT_THAT(loaded_apk, NotNull());
+  ASSERT_NE(nullptr, loaded_apk);
 
   auto asset = loaded_apk->Open("assets/uncompressed.txt", Asset::ACCESS_UNKNOWN);
-  ASSERT_THAT(asset, NotNull());
+  ASSERT_NE(nullptr, asset);
 
   off64_t start, length;
   unique_fd fd(asset->openFileDescriptor(&start, &length));
-  ASSERT_THAT(fd.get(), Ge(0));
+  EXPECT_GE(fd.get(), 0);
 
   lseek64(fd.get(), start, SEEK_SET);
 
@@ -140,7 +146,7 @@
   buffer.resize(length);
   ASSERT_TRUE(base::ReadFully(fd.get(), &*buffer.begin(), length));
 
-  EXPECT_THAT(buffer, StrEq("This should be uncompressed.\n\n"));
+  EXPECT_EQ("This should be uncompressed.\n\n", buffer);
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 437e147..85e8f25 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -81,18 +81,17 @@
 }
 BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
 
-static void BM_AssetManagerGetResource(benchmark::State& state, uint32_t resid) {
-  GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid, state);
+static void BM_AssetManagerGetResource(benchmark::State& state) {
+  GetResourceBenchmark({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
+                       basic::R::integer::number1, state);
 }
-BENCHMARK_CAPTURE(BM_AssetManagerGetResource, number1, basic::R::integer::number1);
-BENCHMARK_CAPTURE(BM_AssetManagerGetResource, deep_ref, basic::R::integer::deep_ref);
+BENCHMARK(BM_AssetManagerGetResource);
 
-static void BM_AssetManagerGetResourceOld(benchmark::State& state, uint32_t resid) {
-  GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/, resid,
-                          state);
+static void BM_AssetManagerGetResourceOld(benchmark::State& state) {
+  GetResourceBenchmarkOld({GetTestDataPath() + "/basic/basic.apk"}, nullptr /*config*/,
+                          basic::R::integer::number1, state);
 }
-BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, number1, basic::R::integer::number1);
-BENCHMARK_CAPTURE(BM_AssetManagerGetResourceOld, deep_ref, basic::R::integer::deep_ref);
+BENCHMARK(BM_AssetManagerGetResourceOld);
 
 static void BM_AssetManagerGetLibraryResource(benchmark::State& state) {
   GetResourceBenchmark(
@@ -197,7 +196,7 @@
 static void BM_AssetManagerGetResourceLocalesOld(benchmark::State& state) {
   AssetManager assets;
   if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
-                           true /*isSystemAssets*/)) {
+                           false /*isSystemAssets*/)) {
     state.SkipWithError("Failed to load assets");
     return;
   }
@@ -212,44 +211,4 @@
 }
 BENCHMARK(BM_AssetManagerGetResourceLocalesOld);
 
-static void BM_AssetManagerSetConfigurationFramework(benchmark::State& state) {
-  std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
-  if (apk == nullptr) {
-    state.SkipWithError("Failed to load assets");
-    return;
-  }
-
-  AssetManager2 assets;
-  assets.SetApkAssets({apk.get()});
-
-  ResTable_config config;
-  memset(&config, 0, sizeof(config));
-
-  while (state.KeepRunning()) {
-    config.sdkVersion = ~config.sdkVersion;
-    assets.SetConfiguration(config);
-  }
-}
-BENCHMARK(BM_AssetManagerSetConfigurationFramework);
-
-static void BM_AssetManagerSetConfigurationFrameworkOld(benchmark::State& state) {
-  AssetManager assets;
-  if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /*cookie*/, false /*appAsLib*/,
-                           true /*isSystemAssets*/)) {
-    state.SkipWithError("Failed to load assets");
-    return;
-  }
-
-  const ResTable& table = assets.getResources(true);
-
-  ResTable_config config;
-  memset(&config, 0, sizeof(config));
-
-  while (state.KeepRunning()) {
-    config.sdkVersion = ~config.sdkVersion;
-    assets.setConfiguration(config);
-  }
-}
-BENCHMARK(BM_AssetManagerSetConfigurationFrameworkOld);
-
 }  // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 7cac2b3..92462a6 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -36,10 +36,6 @@
 namespace lib_two = com::android::lib_two;
 namespace libclient = com::android::libclient;
 
-using ::testing::Eq;
-using ::testing::NotNull;
-using ::testing::StrEq;
-
 namespace android {
 
 class AssetManager2Test : public ::testing::Test {
@@ -63,14 +59,11 @@
     libclient_assets_ = ApkAssets::Load(GetTestDataPath() + "/libclient/libclient.apk");
     ASSERT_NE(nullptr, libclient_assets_);
 
-    appaslib_assets_ = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/appaslib/appaslib.apk");
+    appaslib_assets_ = ApkAssets::Load(GetTestDataPath() + "/appaslib/appaslib.apk");
     ASSERT_NE(nullptr, appaslib_assets_);
 
     system_assets_ = ApkAssets::Load(GetTestDataPath() + "/system/system.apk", true /*system*/);
     ASSERT_NE(nullptr, system_assets_);
-
-    app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk");
-    ASSERT_THAT(app_assets_, NotNull());
   }
 
  protected:
@@ -82,7 +75,6 @@
   std::unique_ptr<const ApkAssets> libclient_assets_;
   std::unique_ptr<const ApkAssets> appaslib_assets_;
   std::unique_ptr<const ApkAssets> system_assets_;
-  std::unique_ptr<const ApkAssets> app_assets_;
 };
 
 TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
@@ -241,25 +233,6 @@
   assetmanager.SetApkAssets(
       {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
 
-  const ResolvedBag* bag = assetmanager.GetBag(fix_package_id(lib_one::R::style::Theme, 0x03));
-  ASSERT_NE(nullptr, bag);
-  ASSERT_GE(bag->entry_count, 2u);
-
-  // First two attributes come from lib_one.
-  EXPECT_EQ(1, bag->entries[0].cookie);
-  EXPECT_EQ(0x03, get_package_id(bag->entries[0].key));
-  EXPECT_EQ(1, bag->entries[1].cookie);
-  EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
-}
-
-TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) {
-  AssetManager2 assetmanager;
-
-  // libclient is built with lib_one and then lib_two in order.
-  // Reverse the order to test that proper package ID re-assignment is happening.
-  assetmanager.SetApkAssets(
-      {lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
-
   const ResolvedBag* bag = assetmanager.GetBag(libclient::R::style::Theme);
   ASSERT_NE(nullptr, bag);
   ASSERT_GE(bag->entry_count, 2u);
@@ -473,68 +446,8 @@
             assetmanager.GetResourceId("main", "layout", "com.android.basic"));
 }
 
-TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {
-  AssetManager2 assetmanager;
-  assetmanager.SetApkAssets({system_assets_.get()});
+TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {}
 
-  std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
-  ASSERT_THAT(asset, NotNull());
-
-  const char* data = reinterpret_cast<const char*>(asset->getBuffer(false /*wordAligned*/));
-  ASSERT_THAT(data, NotNull());
-  EXPECT_THAT(std::string(data, asset->getLength()), StrEq("file\n"));
-}
-
-TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {
-  AssetManager2 assetmanager;
-  assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
-
-  std::unique_ptr<Asset> asset = assetmanager.Open("file.txt", Asset::ACCESS_BUFFER);
-  ASSERT_THAT(asset, NotNull());
-
-  const char* data = reinterpret_cast<const char*>(asset->getBuffer(false /*wordAligned*/));
-  ASSERT_THAT(data, NotNull());
-  EXPECT_THAT(std::string(data, asset->getLength()), StrEq("app override file\n"));
-}
-
-TEST_F(AssetManager2Test, OpenDir) {
-  AssetManager2 assetmanager;
-  assetmanager.SetApkAssets({system_assets_.get()});
-
-  std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
-  ASSERT_THAT(asset_dir, NotNull());
-  ASSERT_THAT(asset_dir->getFileCount(), Eq(2u));
-
-  EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("file.txt")));
-  EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
-
-  EXPECT_THAT(asset_dir->getFileName(1), Eq(String8("subdir")));
-  EXPECT_THAT(asset_dir->getFileType(1), Eq(FileType::kFileTypeDirectory));
-
-  asset_dir = assetmanager.OpenDir("subdir");
-  ASSERT_THAT(asset_dir, NotNull());
-  ASSERT_THAT(asset_dir->getFileCount(), Eq(1u));
-
-  EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("subdir_file.txt")));
-  EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
-}
-
-TEST_F(AssetManager2Test, OpenDirFromManyApks) {
-  AssetManager2 assetmanager;
-  assetmanager.SetApkAssets({system_assets_.get(), app_assets_.get()});
-
-  std::unique_ptr<AssetDir> asset_dir = assetmanager.OpenDir("");
-  ASSERT_THAT(asset_dir, NotNull());
-  ASSERT_THAT(asset_dir->getFileCount(), Eq(3u));
-
-  EXPECT_THAT(asset_dir->getFileName(0), Eq(String8("app_file.txt")));
-  EXPECT_THAT(asset_dir->getFileType(0), Eq(FileType::kFileTypeRegular));
-
-  EXPECT_THAT(asset_dir->getFileName(1), Eq(String8("file.txt")));
-  EXPECT_THAT(asset_dir->getFileType(1), Eq(FileType::kFileTypeRegular));
-
-  EXPECT_THAT(asset_dir->getFileName(2), Eq(String8("subdir")));
-  EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory));
-}
+TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
 
 }  // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp
deleted file mode 100644
index fa300c5..0000000
--- a/libs/androidfw/tests/AttributeResolution_bench.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "benchmark/benchmark.h"
-
-//#include "android-base/stringprintf.h"
-#include "androidfw/ApkAssets.h"
-#include "androidfw/AssetManager.h"
-#include "androidfw/AssetManager2.h"
-#include "androidfw/AttributeResolution.h"
-#include "androidfw/ResourceTypes.h"
-
-#include "BenchmarkHelpers.h"
-#include "data/basic/R.h"
-#include "data/styles/R.h"
-
-namespace app = com::android::app;
-namespace basic = com::android::basic;
-
-namespace android {
-
-constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk";
-constexpr const static uint32_t Theme_Material_Light = 0x01030237u;
-
-static void BM_ApplyStyle(benchmark::State& state) {
-  std::unique_ptr<const ApkAssets> styles_apk =
-      ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
-  if (styles_apk == nullptr) {
-    state.SkipWithError("failed to load assets");
-    return;
-  }
-
-  AssetManager2 assetmanager;
-  assetmanager.SetApkAssets({styles_apk.get()});
-
-  std::unique_ptr<Asset> asset =
-      assetmanager.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
-  if (asset == nullptr) {
-    state.SkipWithError("failed to load layout");
-    return;
-  }
-
-  ResXMLTree xml_tree;
-  if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) {
-    state.SkipWithError("corrupt xml layout");
-    return;
-  }
-
-  // Skip to the first tag.
-  while (xml_tree.next() != ResXMLParser::START_TAG) {
-  }
-
-  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
-  theme->ApplyStyle(app::R::style::StyleTwo);
-
-  std::array<uint32_t, 6> attrs{{app::R::attr::attr_one, app::R::attr::attr_two,
-                                 app::R::attr::attr_three, app::R::attr::attr_four,
-                                 app::R::attr::attr_five, app::R::attr::attr_empty}};
-  std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
-  std::array<uint32_t, attrs.size() + 1> indices;
-
-  while (state.KeepRunning()) {
-    ApplyStyle(theme.get(), &xml_tree, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
-               attrs.size(), values.data(), indices.data());
-  }
-}
-BENCHMARK(BM_ApplyStyle);
-
-static void BM_ApplyStyleFramework(benchmark::State& state) {
-  std::unique_ptr<const ApkAssets> framework_apk = ApkAssets::Load(kFrameworkPath);
-  if (framework_apk == nullptr) {
-    state.SkipWithError("failed to load framework assets");
-    return;
-  }
-
-  std::unique_ptr<const ApkAssets> basic_apk =
-      ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
-  if (basic_apk == nullptr) {
-    state.SkipWithError("failed to load assets");
-    return;
-  }
-
-  AssetManager2 assetmanager;
-  assetmanager.SetApkAssets({framework_apk.get(), basic_apk.get()});
-
-  ResTable_config device_config;
-  memset(&device_config, 0, sizeof(device_config));
-  device_config.language[0] = 'e';
-  device_config.language[1] = 'n';
-  device_config.country[0] = 'U';
-  device_config.country[1] = 'S';
-  device_config.orientation = ResTable_config::ORIENTATION_PORT;
-  device_config.smallestScreenWidthDp = 700;
-  device_config.screenWidthDp = 700;
-  device_config.screenHeightDp = 1024;
-  device_config.sdkVersion = 27;
-
-  Res_value value;
-  ResTable_config config;
-  uint32_t flags = 0u;
-  ApkAssetsCookie cookie =
-      assetmanager.GetResource(basic::R::layout::layoutt, false /*may_be_bag*/,
-                               0u /*density_override*/, &value, &config, &flags);
-  if (cookie == kInvalidCookie) {
-    state.SkipWithError("failed to find R.layout.layout");
-    return;
-  }
-
-  size_t len = 0u;
-  const char* layout_path =
-      assetmanager.GetStringPoolForCookie(cookie)->string8At(value.data, &len);
-  if (layout_path == nullptr || len == 0u) {
-    state.SkipWithError("failed to lookup layout path");
-    return;
-  }
-
-  std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(
-      StringPiece(layout_path, len).to_string(), cookie, Asset::ACCESS_BUFFER);
-  if (asset == nullptr) {
-    state.SkipWithError("failed to load layout");
-    return;
-  }
-
-  ResXMLTree xml_tree;
-  if (xml_tree.setTo(asset->getBuffer(true), asset->getLength(), false /*copyData*/) != NO_ERROR) {
-    state.SkipWithError("corrupt xml layout");
-    return;
-  }
-
-  // Skip to the first tag.
-  while (xml_tree.next() != ResXMLParser::START_TAG) {
-  }
-
-  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
-  theme->ApplyStyle(Theme_Material_Light);
-
-  std::array<uint32_t, 92> attrs{
-      {0x0101000e, 0x01010034, 0x01010095, 0x01010096, 0x01010097, 0x01010098, 0x01010099,
-       0x0101009a, 0x0101009b, 0x010100ab, 0x010100af, 0x010100b0, 0x010100b1, 0x0101011f,
-       0x01010120, 0x0101013f, 0x01010140, 0x0101014e, 0x0101014f, 0x01010150, 0x01010151,
-       0x01010152, 0x01010153, 0x01010154, 0x01010155, 0x01010156, 0x01010157, 0x01010158,
-       0x01010159, 0x0101015a, 0x0101015b, 0x0101015c, 0x0101015d, 0x0101015e, 0x0101015f,
-       0x01010160, 0x01010161, 0x01010162, 0x01010163, 0x01010164, 0x01010165, 0x01010166,
-       0x01010167, 0x01010168, 0x01010169, 0x0101016a, 0x0101016b, 0x0101016c, 0x0101016d,
-       0x0101016e, 0x0101016f, 0x01010170, 0x01010171, 0x01010217, 0x01010218, 0x0101021d,
-       0x01010220, 0x01010223, 0x01010224, 0x01010264, 0x01010265, 0x01010266, 0x010102c5,
-       0x010102c6, 0x010102c7, 0x01010314, 0x01010315, 0x01010316, 0x0101035e, 0x0101035f,
-       0x01010362, 0x01010374, 0x0101038c, 0x01010392, 0x01010393, 0x010103ac, 0x0101045d,
-       0x010104b6, 0x010104b7, 0x010104d6, 0x010104d7, 0x010104dd, 0x010104de, 0x010104df,
-       0x01010535, 0x01010536, 0x01010537, 0x01010538, 0x01010546, 0x01010567, 0x011100c9,
-       0x011100ca}};
-
-  std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
-  std::array<uint32_t, attrs.size() + 1> indices;
-  while (state.KeepRunning()) {
-    ApplyStyle(theme.get(), &xml_tree, 0x01010084u /*def_style_attr*/, 0u /*def_style_res*/,
-               attrs.data(), attrs.size(), values.data(), indices.data());
-  }
-}
-BENCHMARK(BM_ApplyStyleFramework);
-
-}  // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index c8dbe20..2d73ce8 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -21,8 +21,6 @@
 #include "android-base/file.h"
 #include "android-base/logging.h"
 #include "android-base/macros.h"
-#include "androidfw/AssetManager2.h"
-#include "androidfw/ResourceUtils.h"
 
 #include "TestHelpers.h"
 #include "data/styles/R.h"
@@ -34,14 +32,15 @@
 class AttributeResolutionTest : public ::testing::Test {
  public:
   virtual void SetUp() override {
-    styles_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
-    ASSERT_NE(nullptr, styles_assets_);
-    assetmanager_.SetApkAssets({styles_assets_.get()});
+    std::string contents;
+    ASSERT_TRUE(ReadFileFromZipToString(
+        GetTestDataPath() + "/styles/styles.apk", "resources.arsc", &contents));
+    ASSERT_EQ(NO_ERROR, table_.add(contents.data(), contents.size(),
+                                   1 /*cookie*/, true /*copyData*/));
   }
 
  protected:
-  std::unique_ptr<const ApkAssets> styles_assets_;
-  AssetManager2 assetmanager_;
+  ResTable table_;
 };
 
 class AttributeResolutionXmlTest : public AttributeResolutionTest {
@@ -49,12 +48,13 @@
   virtual void SetUp() override {
     AttributeResolutionTest::SetUp();
 
-    std::unique_ptr<Asset> asset =
-        assetmanager_.OpenNonAsset("res/layout/layout.xml", Asset::ACCESS_BUFFER);
-    ASSERT_NE(nullptr, asset);
+    std::string contents;
+    ASSERT_TRUE(
+        ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk",
+                                "res/layout/layout.xml", &contents));
 
-    ASSERT_EQ(NO_ERROR,
-              xml_parser_.setTo(asset->getBuffer(true), asset->getLength(), true /*copyData*/));
+    ASSERT_EQ(NO_ERROR, xml_parser_.setTo(contents.data(), contents.size(),
+                                          true /*copyData*/));
 
     // Skip to the first tag.
     while (xml_parser_.next() != ResXMLParser::START_TAG) {
@@ -65,50 +65,15 @@
   ResXMLTree xml_parser_;
 };
 
-TEST(AttributeResolutionLibraryTest, ApplyStyleWithDefaultStyleResId) {
-  AssetManager2 assetmanager;
-  auto apk_assets = ApkAssets::LoadAsSharedLibrary(GetTestDataPath() + "/styles/styles.apk");
-  ASSERT_NE(nullptr, apk_assets);
-  assetmanager.SetApkAssets({apk_assets.get()});
-
-  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
-
-  std::array<uint32_t, 2> attrs{
-      {fix_package_id(R::attr::attr_one, 0x02), fix_package_id(R::attr::attr_two, 0x02)}};
-  std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
-  std::array<uint32_t, attrs.size() + 1> indices;
-  ApplyStyle(theme.get(), nullptr /*xml_parser*/, 0u /*def_style_attr*/,
-             fix_package_id(R::style::StyleOne, 0x02), attrs.data(), attrs.size(), values.data(),
-             indices.data());
-
-  const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
-
-  const uint32_t* values_cursor = values.data();
-  EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
-  EXPECT_EQ(1u, values_cursor[STYLE_DATA]);
-  EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
-  EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
-  EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
-  EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
-
-  values_cursor += STYLE_NUM_ENTRIES;
-  EXPECT_EQ(Res_value::TYPE_INT_DEC, values_cursor[STYLE_TYPE]);
-  EXPECT_EQ(2u, values_cursor[STYLE_DATA]);
-  EXPECT_EQ(0u, values_cursor[STYLE_RESOURCE_ID]);
-  EXPECT_EQ(1u, values_cursor[STYLE_ASSET_COOKIE]);
-  EXPECT_EQ(0u, values_cursor[STYLE_DENSITY]);
-  EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
-}
-
 TEST_F(AttributeResolutionTest, Theme) {
-  std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
-  ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+  ResTable::Theme theme(table_);
+  ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
   std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
                                  R::attr::attr_four, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
 
-  ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/,
+  ASSERT_TRUE(ResolveAttrs(&theme, 0 /*def_style_attr*/, 0 /*def_style_res*/,
                            nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
                            attrs.size(), values.data(), nullptr /*out_indices*/));
 
@@ -161,8 +126,8 @@
                                  R::attr::attr_four, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
 
-  ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(),
-                                 values.data(), nullptr /*out_indices*/));
+  ASSERT_TRUE(RetrieveAttributes(&table_, &xml_parser_, attrs.data(), attrs.size(), values.data(),
+                                 nullptr /*out_indices*/));
 
   uint32_t* values_cursor = values.data();
   EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -206,15 +171,15 @@
 }
 
 TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
-  std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
-  ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+  ResTable::Theme theme(table_);
+  ASSERT_EQ(NO_ERROR, theme.applyStyle(R::style::StyleTwo));
 
   std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
                                  R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
   std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
   std::array<uint32_t, attrs.size() + 1> indices;
 
-  ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
+  ApplyStyle(&theme, &xml_parser_, 0 /*def_style_attr*/, 0 /*def_style_res*/, attrs.data(),
              attrs.size(), values.data(), indices.data());
 
   const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index faddfe5..7149bee 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -33,21 +33,19 @@
     }
   }
 
-  // Make sure to force creation of the ResTable first, or else the configuration doesn't get set.
-  const ResTable& table = assetmanager.getResources(true);
   if (config != nullptr) {
     assetmanager.setConfiguration(*config);
   }
 
+  const ResTable& table = assetmanager.getResources(true);
+
   Res_value value;
   ResTable_config selected_config;
   uint32_t flags;
-  uint32_t last_ref = 0u;
 
   while (state.KeepRunning()) {
-    ssize_t block = table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
-                                      &selected_config);
-    table.resolveReference(&value, block, &last_ref, &flags, &selected_config);
+    table.getResource(resid, &value, false /*may_be_bag*/, 0u /*density*/, &flags,
+                      &selected_config);
   }
 }
 
@@ -74,12 +72,10 @@
   Res_value value;
   ResTable_config selected_config;
   uint32_t flags;
-  uint32_t last_id = 0u;
 
   while (state.KeepRunning()) {
-    ApkAssetsCookie cookie = assetmanager.GetResource(
-        resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags);
-    assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_id);
+    assetmanager.GetResource(resid, false /* may_be_bag */, 0u /* density_override */, &value,
+                             &selected_config, &flags);
   }
 }
 
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index cae632d..37ddafb 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -16,9 +16,6 @@
 
 #include "androidfw/LoadedArsc.h"
 
-#include "android-base/file.h"
-#include "androidfw/ResourceUtils.h"
-
 #include "TestHelpers.h"
 #include "data/basic/R.h"
 #include "data/libclient/R.h"
@@ -30,14 +27,6 @@
 namespace libclient = com::android::libclient;
 namespace sparse = com::android::sparse;
 
-using ::android::base::ReadFileToString;
-using ::testing::Eq;
-using ::testing::Ge;
-using ::testing::IsNull;
-using ::testing::NotNull;
-using ::testing::SizeIs;
-using ::testing::StrEq;
-
 namespace android {
 
 TEST(LoadedArscTest, LoadSinglePackageArsc) {
@@ -46,24 +35,39 @@
                                       &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
-  const LoadedPackage* package =
-      loaded_arsc->GetPackageById(get_package_id(app::R::string::string_one));
-  ASSERT_THAT(package, NotNull());
-  EXPECT_THAT(package->GetPackageName(), StrEq("com.android.app"));
-  EXPECT_THAT(package->GetPackageId(), Eq(0x7f));
+  const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+  ASSERT_EQ(1u, packages.size());
+  EXPECT_EQ(std::string("com.android.app"), packages[0]->GetPackageName());
+  EXPECT_EQ(0x7f, packages[0]->GetPackageId());
 
-  const uint8_t type_index = get_type_id(app::R::string::string_one) - 1;
-  const uint16_t entry_index = get_entry_id(app::R::string::string_one);
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  config.sdkVersion = 24;
 
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
+  FindEntryResult entry;
 
-  const ResTable_type* type = type_spec->types[0];
-  ASSERT_THAT(type, NotNull());
-  ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+  ASSERT_TRUE(loaded_arsc->FindEntry(app::R::string::string_one, config, &entry));
+  ASSERT_NE(nullptr, entry.entry);
+}
+
+TEST(LoadedArscTest, FindDefaultEntry) {
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry));
+  ASSERT_NE(nullptr, entry.entry);
 }
 
 TEST(LoadedArscTest, LoadSparseEntryApp) {
@@ -72,22 +76,15 @@
                                       &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
-  const LoadedPackage* package =
-      loaded_arsc->GetPackageById(get_package_id(sparse::R::integer::foo_9));
-  ASSERT_THAT(package, NotNull());
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  config.sdkVersion = 26;
 
-  const uint8_t type_index = get_type_id(sparse::R::integer::foo_9) - 1;
-  const uint16_t entry_index = get_entry_id(sparse::R::integer::foo_9);
-
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
-
-  const ResTable_type* type = type_spec->types[0];
-  ASSERT_THAT(type, NotNull());
-  ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(sparse::R::integer::foo_9, config, &entry));
+  ASSERT_NE(nullptr, entry.entry);
 }
 
 TEST(LoadedArscTest, LoadSharedLibrary) {
@@ -96,13 +93,14 @@
                                       &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
-  ASSERT_THAT(packages, SizeIs(1u));
+  ASSERT_EQ(1u, packages.size());
+
   EXPECT_TRUE(packages[0]->IsDynamic());
-  EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.lib_one"));
-  EXPECT_THAT(packages[0]->GetPackageId(), Eq(0));
+  EXPECT_EQ(std::string("com.android.lib_one"), packages[0]->GetPackageName());
+  EXPECT_EQ(0, packages[0]->GetPackageId());
 
   const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
 
@@ -116,23 +114,25 @@
                                       "resources.arsc", &contents));
 
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
-  ASSERT_THAT(packages, SizeIs(1u));
+  ASSERT_EQ(1u, packages.size());
+
   EXPECT_FALSE(packages[0]->IsDynamic());
-  EXPECT_THAT(packages[0]->GetPackageName(), StrEq("com.android.libclient"));
-  EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
+  EXPECT_EQ(std::string("com.android.libclient"), packages[0]->GetPackageName());
+  EXPECT_EQ(0x7f, packages[0]->GetPackageId());
 
   const auto& dynamic_pkg_map = packages[0]->GetDynamicPackageMap();
 
   // The library has two dependencies.
-  ASSERT_THAT(dynamic_pkg_map, SizeIs(2u));
-  EXPECT_THAT(dynamic_pkg_map[0].package_name, StrEq("com.android.lib_one"));
-  EXPECT_THAT(dynamic_pkg_map[0].package_id, Eq(0x02));
+  ASSERT_EQ(2u, dynamic_pkg_map.size());
 
-  EXPECT_THAT(dynamic_pkg_map[1].package_name, StrEq("com.android.lib_two"));
-  EXPECT_THAT(dynamic_pkg_map[1].package_id, Eq(0x03));
+  EXPECT_EQ(std::string("com.android.lib_one"), dynamic_pkg_map[0].package_name);
+  EXPECT_EQ(0x02, dynamic_pkg_map[0].package_id);
+
+  EXPECT_EQ(std::string("com.android.lib_two"), dynamic_pkg_map[1].package_name);
+  EXPECT_EQ(0x03, dynamic_pkg_map[1].package_id);
 }
 
 TEST(LoadedArscTest, LoadAppAsSharedLibrary) {
@@ -143,12 +143,13 @@
   std::unique_ptr<const LoadedArsc> loaded_arsc =
       LoadedArsc::Load(StringPiece(contents), nullptr /*loaded_idmap*/, false /*system*/,
                        true /*load_as_shared_library*/);
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
   const auto& packages = loaded_arsc->GetPackages();
-  ASSERT_THAT(packages, SizeIs(1u));
+  ASSERT_EQ(1u, packages.size());
+
   EXPECT_TRUE(packages[0]->IsDynamic());
-  EXPECT_THAT(packages[0]->GetPackageId(), Eq(0x7f));
+  EXPECT_EQ(0x7f, packages[0]->GetPackageId());
 }
 
 TEST(LoadedArscTest, LoadFeatureSplit) {
@@ -156,67 +157,21 @@
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
                                       &contents));
   std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
+  ASSERT_NE(nullptr, loaded_arsc);
 
-  const LoadedPackage* package =
-      loaded_arsc->GetPackageById(get_package_id(basic::R::string::test3));
-  ASSERT_THAT(package, NotNull());
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
 
-  uint8_t type_index = get_type_id(basic::R::string::test3) - 1;
-  uint8_t entry_index = get_entry_id(basic::R::string::test3);
-
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
-  ASSERT_THAT(type_spec->types[0], NotNull());
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test3, desired_config, &entry));
 
   size_t len;
-  const char16_t* type_name16 =
-      package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len);
-  ASSERT_THAT(type_name16, NotNull());
-  EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string"));
+  const char16_t* type_name16 = entry.type_string_ref.string16(&len);
+  ASSERT_NE(nullptr, type_name16);
+  ASSERT_NE(0u, len);
 
-  ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
-}
-
-// AAPT(2) generates resource tables with chunks in a certain order. The rule is that
-// a RES_TABLE_TYPE_TYPE with id `i` must always be preceded by a RES_TABLE_TYPE_SPEC_TYPE with
-// id `i`. The RES_TABLE_TYPE_SPEC_TYPE does not need to be directly preceding, however.
-//
-// AAPT(2) generates something like:
-//   RES_TABLE_TYPE_SPEC_TYPE id=1
-//   RES_TABLE_TYPE_TYPE id=1
-//   RES_TABLE_TYPE_SPEC_TYPE id=2
-//   RES_TABLE_TYPE_TYPE id=2
-//
-// But the following is valid too:
-//   RES_TABLE_TYPE_SPEC_TYPE id=1
-//   RES_TABLE_TYPE_SPEC_TYPE id=2
-//   RES_TABLE_TYPE_TYPE id=1
-//   RES_TABLE_TYPE_TYPE id=2
-//
-TEST(LoadedArscTest, LoadOutOfOrderTypeSpecs) {
-  std::string contents;
-  ASSERT_TRUE(
-      ReadFileFromZipToString(GetTestDataPath() + "/out_of_order_types/out_of_order_types.apk",
-                              "resources.arsc", &contents));
-
-  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
-  ASSERT_THAT(loaded_arsc, NotNull());
-
-  ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
-  const auto& package = loaded_arsc->GetPackages()[0];
-  ASSERT_THAT(package, NotNull());
-
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
-  ASSERT_THAT(type_spec->types[0], NotNull());
-
-  type_spec = package->GetTypeSpecByTypeIndex(1);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
-  ASSERT_THAT(type_spec->types[0], NotNull());
+  std::string type_name = util::Utf16ToUtf8(StringPiece16(type_name16, len));
+  EXPECT_EQ(std::string("string"), type_name);
 }
 
 class MockLoadedIdmap : public LoadedIdmap {
@@ -244,33 +199,23 @@
 };
 
 TEST(LoadedArscTest, LoadOverlay) {
-  std::string contents;
+  std::string contents, overlay_contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
   ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlay/overlay.apk", "resources.arsc",
-                                      &contents));
+                                      &overlay_contents));
 
   MockLoadedIdmap loaded_idmap;
 
   std::unique_ptr<const LoadedArsc> loaded_arsc =
-      LoadedArsc::Load(StringPiece(contents), &loaded_idmap);
-  ASSERT_THAT(loaded_arsc, NotNull());
+      LoadedArsc::Load(StringPiece(overlay_contents), &loaded_idmap);
+  ASSERT_NE(nullptr, loaded_arsc);
 
-  const LoadedPackage* package = loaded_arsc->GetPackageById(0x08u);
-  ASSERT_THAT(package, NotNull());
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
 
-  const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0x03u - 1);
-  ASSERT_THAT(type_spec, NotNull());
-  ASSERT_THAT(type_spec->type_count, Ge(1u));
-  ASSERT_THAT(type_spec->types[0], NotNull());
-
-  // The entry being overlaid doesn't exist at the original entry index.
-  ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0001u), IsNull());
-
-  // Since this is an overlay, the actual entry ID must be mapped.
-  ASSERT_THAT(type_spec->idmap_entries, NotNull());
-  uint16_t target_entry_id = 0u;
-  ASSERT_TRUE(LoadedIdmap::Lookup(type_spec->idmap_entries, 0x0001u, &target_entry_id));
-  ASSERT_THAT(target_entry_id, Eq(0x0u));
-  ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], 0x0000), NotNull());
+  FindEntryResult entry;
+  ASSERT_TRUE(loaded_arsc->FindEntry(0x08030001u, desired_config, &entry));
 }
 
 // structs with size fields (like Res_value, ResTable_entry) should be
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index df0c642..43a9955 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -20,7 +20,6 @@
 #include <string>
 
 #include "androidfw/ResourceTypes.h"
-#include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
 #include "CommonHelpers.h"
diff --git a/libs/androidfw/tests/data/app/app.apk b/libs/androidfw/tests/data/app/app.apk
index c8ad86d..ccb0824 100644
--- a/libs/androidfw/tests/data/app/app.apk
+++ b/libs/androidfw/tests/data/app/app.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/app/assets/app_file.txt b/libs/androidfw/tests/data/app/assets/app_file.txt
deleted file mode 100644
index b214e06..0000000
--- a/libs/androidfw/tests/data/app/assets/app_file.txt
+++ /dev/null
@@ -1 +0,0 @@
-app file
diff --git a/libs/androidfw/tests/data/app/assets/file.txt b/libs/androidfw/tests/data/app/assets/file.txt
deleted file mode 100644
index 0811542..0000000
--- a/libs/androidfw/tests/data/app/assets/file.txt
+++ /dev/null
@@ -1 +0,0 @@
-app override file
diff --git a/libs/androidfw/tests/data/app/build b/libs/androidfw/tests/data/app/build
index 09af842..d418158 100755
--- a/libs/androidfw/tests/data/app/build
+++ b/libs/androidfw/tests/data/app/build
@@ -17,11 +17,4 @@
 
 set -e
 
-aapt2 compile --dir res -o compiled.flata
-aapt2 link \
-    --manifest AndroidManifest.xml \
-    -I ../system/system.apk \
-    -A assets \
-    -o app.apk \
-    compiled.flata
-rm compiled.flata
+aapt package -I ../system/system.apk -M AndroidManifest.xml -S res -F app.apk -f
diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h
index b7e814f..94a2a14 100644
--- a/libs/androidfw/tests/data/basic/R.h
+++ b/libs/androidfw/tests/data/basic/R.h
@@ -34,7 +34,6 @@
   struct layout {
     enum : uint32_t {
       main = 0x7f020000,
-      layoutt = 0x7f020001,
     };
   };
 
@@ -56,7 +55,6 @@
       number2 = 0x7f040001,
       ref1 = 0x7f040002,
       ref2 = 0x7f040003,
-      deep_ref = 0x7f040004,
 
       // From feature
       number3 = 0x80030000,
diff --git a/libs/androidfw/tests/data/basic/basic.apk b/libs/androidfw/tests/data/basic/basic.apk
index 1733b6a..18ef75e 100644
--- a/libs/androidfw/tests/data/basic/basic.apk
+++ b/libs/androidfw/tests/data/basic/basic.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/basic/res/layout/layout.xml b/libs/androidfw/tests/data/basic/res/layout/layout.xml
deleted file mode 100644
index 045ede4..0000000
--- a/libs/androidfw/tests/data/basic/res/layout/layout.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<Button xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/ok"
-    android:layout_width="0sp"
-    android:layout_height="fill_parent"
-    android:layout_weight="1"
-    android:layout_marginStart="2dip"
-    android:layout_marginEnd="2dip"
-    android:textAppearance="?android:attr/textAppearanceMedium"
-    android:textStyle="bold"
-    android:text="@android:string/ok" />
\ No newline at end of file
diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml
index b343562..6c47459 100644
--- a/libs/androidfw/tests/data/basic/res/values/values.xml
+++ b/libs/androidfw/tests/data/basic/res/values/values.xml
@@ -22,7 +22,6 @@
     <attr name="attr2" format="reference|integer" />
 
     <public type="layout" name="main" id="0x7f020000" />
-    <public type="layout" name="layout" id="0x7f020001" />
 
     <public type="string" name="test1" id="0x7f030000" />
     <string name="test1">test1</string>
@@ -44,18 +43,6 @@
     <public type="integer" name="ref2" id="0x7f040003" />
     <integer name="ref2">12000</integer>
 
-    <public type="integer" name="deep_ref" id="0x7f040004" />
-    <integer name="deep_ref">@integer/deep_ref_1</integer>
-    <integer name="deep_ref_1">@integer/deep_ref_2</integer>
-    <integer name="deep_ref_2">@integer/deep_ref_3</integer>
-    <integer name="deep_ref_3">@integer/deep_ref_4</integer>
-    <integer name="deep_ref_4">@integer/deep_ref_5</integer>
-    <integer name="deep_ref_5">@integer/deep_ref_6</integer>
-    <integer name="deep_ref_6">@integer/deep_ref_7</integer>
-    <integer name="deep_ref_7">@integer/deep_ref_8</integer>
-    <integer name="deep_ref_8">@integer/deep_ref_9</integer>
-    <integer name="deep_ref_9">100</integer>
-
     <public type="style" name="Theme1" id="0x7f050000" />
     <style name="Theme1">
         <item name="com.android.basic:attr1">100</item>
diff --git a/libs/androidfw/tests/data/out_of_order_types/build b/libs/androidfw/tests/data/out_of_order_types/build
deleted file mode 100755
index 8496f81..0000000
--- a/libs/androidfw/tests/data/out_of_order_types/build
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-set -e
-
-aapt2 compile --dir res -o compiled.flata
-aapt2 link --manifest AndroidManifest.xml -o out_of_order_types.apk compiled.flata
-rm compiled.flata
diff --git a/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt b/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt
deleted file mode 100644
index eca8f47..0000000
--- a/libs/androidfw/tests/data/out_of_order_types/edited_resources.arsc.txt
+++ /dev/null
@@ -1,43 +0,0 @@
-00000000: 0200 0c00 ac02 0000 0100 0000 0100 1c00  ................
-00000010: 1c00 0000 0000 0000 0000 0000 0001 0000  ................
-00000020: 1c00 0000 0000 0000 0002 2001 8402 0000  .......... .....
-00000030: 7f00 0000 6300 6f00 6d00 2e00 6100 6e00  ....c.o.m...a.n.
-00000040: 6400 7200 6f00 6900 6400 2e00 6100 7000  d.r.o.i.d...a.p.
-00000050: 7000 0000 0000 0000 0000 0000 0000 0000  p...............
-00000060: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000080: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000090: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-000000a0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-000000b0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-000000c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-000000d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-000000e0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-000000f0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000100: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000110: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000120: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000130: 0000 0000 2001 0000 0000 0000 6401 0000  .... .......d...
-00000140: 0000 0000 0000 0000 0100 1c00 4400 0000  ............D...
-00000150: 0200 0000 0000 0000 0000 0000 2400 0000  ............$...
-00000160: 0000 0000 0000 0000 0c00 0000 0400 6200  ..............b.
-00000170: 6f00 6f00 6c00 0000 0700 6900 6e00 7400  o.o.l.....i.n.t.
-00000180: 6500 6700 6500 7200 0000 0000 0100 1c00  e.g.e.r.........
-00000190: 2800 0000 0100 0000 0000 0000 0001 0000  (...............
-000001a0: 2000 0000 0000 0000 0000 0000 0404 7465   .............te
-000001b0: 7374 0000 0202 1000 1400 0000 0100 0000  st..............
-000001c0: 0100 0000 0000 0000 0202 1000 1400 0000
-000001d0: 0200 0000 0100 0000 0000 0000 0102 5400
-000001e0: 6800 0000 0100 0000 0100 0000 5800 0000
-000001f0: 4000 0000 0000 0000 0000 0000 0000 0000
-00000200: 0000 0000 0000 0000 0000 0000 0000 0000
-00000210: 0000 0000 0000 0000 0000 0000 0000 0000
-00000220: 0000 0000 0000 0000 0000 0000 0000 0000
-00000230: 0000 0000 0800 0000 0000 0000 0800 0012
-00000240: ffff ffff 0102 5400 6800 0000 0200 0000  ......T.h.......
-00000250: 0100 0000 5800 0000 4000 0000 0000 0000  ....X...@.......
-00000260: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000270: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000280: 0000 0000 0000 0000 0000 0000 0000 0000  ................
-00000290: 0000 0000 0000 0000 0000 0000 0800 0000  ................
-000002a0: 0000 0000 0800 0010 0100 0000            ............
diff --git a/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk b/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk
deleted file mode 100644
index 75146e0..0000000
--- a/libs/androidfw/tests/data/out_of_order_types/out_of_order_types.apk
+++ /dev/null
Binary files differ
diff --git a/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml b/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml
deleted file mode 100644
index 7c54fba..0000000
--- a/libs/androidfw/tests/data/out_of_order_types/res/values/values.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <bool name="test">true</bool>
-    <integer name="test">1</integer>
-</resources>
diff --git a/libs/androidfw/tests/data/system/assets/file.txt b/libs/androidfw/tests/data/system/assets/file.txt
deleted file mode 100644
index f73f309..0000000
--- a/libs/androidfw/tests/data/system/assets/file.txt
+++ /dev/null
@@ -1 +0,0 @@
-file
diff --git a/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt b/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt
deleted file mode 100644
index 3f74eb6..0000000
--- a/libs/androidfw/tests/data/system/assets/subdir/subdir_file.txt
+++ /dev/null
@@ -1 +0,0 @@
-subdir file
diff --git a/libs/androidfw/tests/data/system/build b/libs/androidfw/tests/data/system/build
index b65145a..bfbdf4c 100755
--- a/libs/androidfw/tests/data/system/build
+++ b/libs/androidfw/tests/data/system/build
@@ -17,6 +17,4 @@
 
 set -e
 
-aapt2 compile --dir res -o compiled.flata
-aapt2 link --manifest AndroidManifest.xml -A assets -o system.apk compiled.flata
-rm compiled.flata
+aapt package -x -M AndroidManifest.xml -S res -F system.apk -f
diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
index 5f60d21..b97bdb6 100644
--- a/libs/androidfw/tests/data/system/res/values-sv/values.xml
+++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml
@@ -15,5 +15,6 @@
 -->
 
 <resources>
+    <public type="integer" name="number" id="0x01030000" />
     <integer name="number">1</integer>
 </resources>
diff --git a/libs/androidfw/tests/data/system/res/values/themes.xml b/libs/androidfw/tests/data/system/res/values/themes.xml
index 7893c94..35d43c7 100644
--- a/libs/androidfw/tests/data/system/res/values/themes.xml
+++ b/libs/androidfw/tests/data/system/res/values/themes.xml
@@ -18,7 +18,6 @@
     <public name="background" type="attr" id="0x01010000"/>
     <public name="foreground" type="attr" id="0x01010001"/>
     <public name="Theme.One" type="style" id="0x01020000"/>
-    <public type="integer" name="number" id="0x01030000" />
 
     <attr name="background" format="color|reference"/>
     <attr name="foreground" format="color|reference"/>
diff --git a/libs/androidfw/tests/data/system/system.apk b/libs/androidfw/tests/data/system/system.apk
index 9045d6c..1299016 100644
--- a/libs/androidfw/tests/data/system/system.apk
+++ b/libs/androidfw/tests/data/system/system.apk
Binary files differ
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index f662406..18358e2 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -518,10 +518,7 @@
             Bitmap& bitmap = getBitmapUpdateIfDirty();
             SkBitmap skiaBitmap;
             bitmap.getSkBitmap(&skiaBitmap);
-            if (!surface->getCanvas()->writePixels(skiaBitmap, dst.fLeft, dst.fTop)) {
-                ALOGD("VectorDrawable caching failed to efficiently upload");
-                surface->getCanvas()->drawBitmap(skiaBitmap, dst.fLeft, dst.fTop);
-            }
+            surface->writePixels(skiaBitmap, dst.fLeft, dst.fTop);
         }
         mCache.dirty = false;
     }
diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h
index e568e4c..0a8a5aa 100644
--- a/libs/protoutil/include/android/util/EncodedBuffer.h
+++ b/libs/protoutil/include/android/util/EncodedBuffer.h
@@ -64,6 +64,11 @@
         size_t mOffset;
     };
 
+    /**
+     * Clears the buffer by rewinding its write pointer to avoid de/allocate buffers in heap.
+     */
+    void clear();
+
     /******************************** Write APIs ************************************************/
 
     /**
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index faea9b2..52830d3 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -123,6 +123,11 @@
     EncodedBuffer::iterator data(); // Get the reader apis of the data.
     bool flush(int fd); // Flush data directly to a file descriptor.
 
+    /**
+     * Clears the ProtoOutputStream so the buffer can be reused instead of deallocation/allocation again.
+     */
+    void clear();
+
     // Please don't use the following functions to dump protos unless you are familiar with protobuf encoding.
     void writeRawVarint(uint64_t varint);
     void writeLengthDelimitedHeader(uint32_t id, size_t size);
diff --git a/libs/protoutil/src/EncodedBuffer.cpp b/libs/protoutil/src/EncodedBuffer.cpp
index 435ae88..3a5e2e9 100644
--- a/libs/protoutil/src/EncodedBuffer.cpp
+++ b/libs/protoutil/src/EncodedBuffer.cpp
@@ -106,6 +106,13 @@
     return mBuffers[p.index()] + p.offset();
 }
 
+void
+EncodedBuffer::clear()
+{
+    mWp.rewind();
+    mEp.rewind();
+}
+
 /******************************** Write APIs ************************************************/
 size_t
 EncodedBuffer::size() const
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index f24abae..9d9ffec 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -36,6 +36,18 @@
 {
 }
 
+
+void
+ProtoOutputStream::clear()
+{
+    mBuffer.clear();
+    mCopyBegin = 0;
+    mCompact = false;
+    mDepth = 0;
+    mObjectId = 0;
+    mExpectedObjectToken = 0LL;
+}
+
 bool
 ProtoOutputStream::write(uint64_t fieldId, double val)
 {
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index cd4143c..4c37014 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -16,9 +16,7 @@
 
 package android.media;
 
-import android.app.PendingIntent;
 import android.bluetooth.BluetoothDevice;
-import android.content.ComponentName;
 import android.media.AudioAttributes;
 import android.media.AudioFocusInfo;
 import android.media.AudioPlaybackConfiguration;
@@ -31,25 +29,33 @@
 import android.media.IRingtonePlayer;
 import android.media.IVolumeController;
 import android.media.PlayerBase;
-import android.media.Rating;
 import android.media.VolumePolicy;
 import android.media.audiopolicy.AudioPolicyConfig;
 import android.media.audiopolicy.IAudioPolicyCallback;
-import android.net.Uri;
-import android.view.KeyEvent;
 
 /**
  * {@hide}
  */
 interface IAudioService {
+    // C++ and Java methods below.
 
-    // WARNING: When methods are inserted or deleted, the transaction IDs in
+    // WARNING: When methods are inserted or deleted in this section, the transaction IDs in
     // frameworks/native/include/audiomanager/IAudioManager.h must be updated to match the order
     // in this file.
     //
     // When a method's argument list is changed, BpAudioManager's corresponding serialization code
     // (if any) in frameworks/native/services/audiomanager/IAudioManager.cpp must be updated.
 
+    int trackPlayer(in PlayerBase.PlayerIdCard pic);
+
+    oneway void playerAttributes(in int piid, in AudioAttributes attr);
+
+    oneway void playerEvent(in int piid, in int event);
+
+    oneway void releasePlayer(in int piid);
+
+    // Java-only methods below.
+
     oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
             String callingPackage, String caller);
 
@@ -187,14 +193,6 @@
 
     List<AudioPlaybackConfiguration> getActivePlaybackConfigurations();
 
-    int trackPlayer(in PlayerBase.PlayerIdCard pic);
-
-    oneway void playerAttributes(in int piid, in AudioAttributes attr);
-
-    oneway void playerEvent(in int piid, in int event);
-
-    oneway void releasePlayer(in int piid);
-
     void disableRingtoneSync(in int userId);
 
     int getFocusRampTimeMs(in int focusGain, in AudioAttributes attr);
@@ -210,5 +208,6 @@
     oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
             in IAudioPolicyCallback pcb);
 
-    // WARNING: read warning at top of file, it is recommended to add new methods at the end
+    // WARNING: read warning at top of file, new methods that need to be used by native
+    // code via IAudioManager.h need to be added to the top section.
 }
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 90fcaab..279e05f 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -634,8 +634,39 @@
      * @throws ResourceBusyException if required resources are in use
      */
     @NonNull
-    public native byte[] openSession() throws NotProvisionedException,
-            ResourceBusyException;
+    public byte[] openSession() throws NotProvisionedException,
+            ResourceBusyException {
+        return openSession(getMaxSecurityLevel());
+    }
+
+    /**
+     * Open a new session at a requested security level. The security level
+     * represents the robustness of the device's DRM implementation. By default,
+     * sessions are opened at the native security level of the device.
+     * Overriding the security level is necessary when the decrypted frames need
+     * to be manipulated, such as for image compositing. The security level
+     * parameter must be lower than the native level. Reducing the security
+     * level will typically limit the content to lower resolutions, as
+     * determined by the license policy. If the requested level is not
+     * supported, the next lower supported security level will be set. The level
+     * can be queried using {@link #getSecurityLevel}. A session
+     * ID is returned.
+     *
+     * @param level the new security level, one of
+     * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE},
+     * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or
+     * {@link #HW_SECURE_ALL}.
+     *
+     * @throws NotProvisionedException if provisioning is needed
+     * @throws ResourceBusyException if required resources are in use
+     * @throws IllegalArgumentException if the requested security level is
+     * higher than the native level or lower than the lowest supported level or
+     * if the device does not support specifying the security level when opening
+     * a session
+     */
+    @NonNull
+    public native byte[] openSession(@SecurityLevel int level) throws
+            NotProvisionedException, ResourceBusyException;
 
     /**
      * Close a session on the MediaDrm object that was previously opened
@@ -1109,7 +1140,7 @@
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SECURITY_LEVEL_UNKNOWN, SW_SECURE_CRYPTO, SW_SECURE_DECODE,
-                        HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL})
+            HW_SECURE_CRYPTO, HW_SECURE_DECODE, HW_SECURE_ALL})
     public @interface SecurityLevel {}
 
     /**
@@ -1119,39 +1150,55 @@
     public static final int SECURITY_LEVEL_UNKNOWN = 0;
 
     /**
-     *  Software-based whitebox crypto
+     * DRM key management uses software-based whitebox crypto.
      */
     public static final int SW_SECURE_CRYPTO = 1;
 
     /**
-     * Software-based whitebox crypto and an obfuscated decoder
+     * DRM key management and decoding use software-based whitebox crypto.
      */
-     public static final int SW_SECURE_DECODE = 2;
+    public static final int SW_SECURE_DECODE = 2;
 
     /**
-     * DRM key management and crypto operations are performed within a
-     * hardware backed trusted execution environment
+     * DRM key management and crypto operations are performed within a hardware
+     * backed trusted execution environment.
      */
     public static final int HW_SECURE_CRYPTO = 3;
 
     /**
-     * DRM key management, crypto operations and decoding of content
-     * are performed within a hardware backed trusted execution environment
+     * DRM key management, crypto operations and decoding of content are
+     * performed within a hardware backed trusted execution environment.
      */
-     public static final int HW_SECURE_DECODE = 4;
+    public static final int HW_SECURE_DECODE = 4;
 
     /**
      * DRM key management, crypto operations, decoding of content and all
-     * handling of the media (compressed and uncompressed) is handled within
-     * a hardware backed trusted execution environment.
+     * handling of the media (compressed and uncompressed) is handled within a
+     * hardware backed trusted execution environment.
      */
     public static final int HW_SECURE_ALL = 5;
 
     /**
-     * Return the current security level of a session. A session
-     * has an initial security level determined by the robustness of
-     * the DRM system's implementation on the device. The security
-     * level may be adjusted using {@link #setSecurityLevel}.
+     * The maximum security level supported by the device. This is the default
+     * security level when a session is opened.
+     * @hide
+     */
+    public static final int SECURITY_LEVEL_MAX = 6;
+
+    /**
+     * The maximum security level supported by the device. This is the default
+     * security level when a session is opened.
+     */
+    @SecurityLevel
+    public static final int getMaxSecurityLevel() {
+        return SECURITY_LEVEL_MAX;
+    }
+
+    /**
+     * Return the current security level of a session. A session has an initial
+     * security level determined by the robustness of the DRM system's
+     * implementation on the device. The security level may be changed at the
+     * time a session is opened using {@link #openSession}.
      * @param sessionId the session to query.
      * <p>
      * @return one of {@link #SECURITY_LEVEL_UNKNOWN},
@@ -1163,21 +1210,6 @@
     public native int getSecurityLevel(@NonNull byte[] sessionId);
 
     /**
-     * Set the security level of a session. This can be useful if specific
-     * attributes of a lower security level are needed by an application,
-     * such as image manipulation or compositing. Reducing the security
-     * level will typically limit decryption to lower content resolutions,
-     * depending on the license policy.
-     * @param sessionId the session to set the security level on.
-     * @param level the new security level, one of
-     * {@link #SW_SECURE_CRYPTO}, {@link #SW_SECURE_DECODE},
-     * {@link #HW_SECURE_CRYPTO}, {@link #HW_SECURE_DECODE} or
-     * {@link #HW_SECURE_ALL}.
-     */
-    public native void setSecurityLevel(@NonNull byte[] sessionId,
-            @SecurityLevel int level);
-
-    /**
      * String property name: identifies the maker of the DRM plugin
      */
     public static final String PROPERTY_VENDOR = "vendor";
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index d4e9aac..49bbc2b 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -1212,6 +1212,7 @@
         } else if (scheme != null) {
             // handle non-file sources
             nativeSetDataSource(
+                srcId,
                 Media2HTTPService.createHTTPService(path, cookies),
                 path,
                 keys,
@@ -1231,7 +1232,7 @@
     }
 
     private native void nativeSetDataSource(
-        Media2HTTPService httpService, String path, String[] keys, String[] values)
+        long srcId, Media2HTTPService httpService, String path, String[] keys, String[] values)
         throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
 
     /**
@@ -1245,10 +1246,10 @@
      */
     private void setDataSourcePriv(long srcId, FileDescriptor fd, long offset, long length)
             throws IOException {
-        _setDataSource(fd, offset, length);
+        _setDataSource(srcId, fd, offset, length);
     }
 
-    private native void _setDataSource(FileDescriptor fd, long offset, long length)
+    private native void _setDataSource(long srcId, FileDescriptor fd, long offset, long length)
             throws IOException;
 
     /**
@@ -1256,10 +1257,10 @@
      * @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
      */
     private void setDataSourcePriv(long srcId, Media2DataSource dataSource) {
-        _setDataSource(dataSource);
+        _setDataSource(srcId, dataSource);
     }
 
-    private native void _setDataSource(Media2DataSource dataSource);
+    private native void _setDataSource(long srcId, Media2DataSource dataSource);
 
     /**
      * Prepares the player for playback, synchronously.
@@ -3073,6 +3074,10 @@
 
         @Override
         public void handleMessage(Message msg) {
+            handleMessage(msg, 0);
+        }
+
+        public void handleMessage(Message msg, long srcId) {
             if (mMediaPlayer.mNativeContext == 0) {
                 Log.w(TAG, "mediaplayer2 went away with unhandled events");
                 return;
@@ -3095,7 +3100,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, MEDIA_INFO_PREPARED, 0));
+                                mMediaPlayer, srcId, MEDIA_INFO_PREPARED, 0));
                     }
                 }
                 return;
@@ -3133,7 +3138,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
+                                mMediaPlayer, srcId, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
                     }
                 }
                 stayAwake(false);
@@ -3163,7 +3168,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onBufferingUpdate(
-                                mMediaPlayer, 0, percent));
+                                mMediaPlayer, srcId, percent));
                     }
                 }
                 return;
@@ -3172,7 +3177,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, MEDIA_INFO_COMPLETE_CALL_SEEK, 0));
+                                mMediaPlayer, srcId, MEDIA_INFO_COMPLETE_CALL_SEEK, 0));
                     }
                 }
                 // fall through
@@ -3192,7 +3197,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onVideoSizeChanged(
-                                mMediaPlayer, 0, width, height));
+                                mMediaPlayer, srcId, width, height));
                     }
                 }
                 return;
@@ -3202,9 +3207,9 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onError(
-                                mMediaPlayer, 0, what, extra));
+                                mMediaPlayer, srcId, what, extra));
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
+                                mMediaPlayer, srcId, MEDIA_INFO_PLAYBACK_COMPLETE, 0));
                     }
                 }
                 stayAwake(false);
@@ -3247,7 +3252,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
-                                mMediaPlayer, 0, what, extra));
+                                mMediaPlayer, srcId, what, extra));
                     }
                 }
                 // No real default action so far.
@@ -3272,7 +3277,7 @@
 
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
-                        cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, 0, text));
+                        cb.first.execute(() -> cb.second.onTimedText(mMediaPlayer, srcId, text));
                     }
                 }
                 return;
@@ -3303,7 +3308,7 @@
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onTimedMetaDataAvailable(
-                                mMediaPlayer, 0, data));
+                                mMediaPlayer, srcId, data));
                     }
                 }
                 return;
@@ -3335,7 +3340,7 @@
      * code is safe from the object disappearing from underneath it.  (This is
      * the cookie passed to native_setup().)
      */
-    private static void postEventFromNative(Object mediaplayer2_ref,
+    private static void postEventFromNative(Object mediaplayer2_ref, long srcId,
                                             int what, int arg1, int arg2, Object obj)
     {
         final MediaPlayer2Impl mp = (MediaPlayer2Impl)((WeakReference)mediaplayer2_ref).get();
@@ -3388,7 +3393,13 @@
 
         if (mp.mEventHandler != null) {
             Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
-            mp.mEventHandler.sendMessage(m);
+
+            mp.mEventHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mp.mEventHandler.handleMessage(m, srcId);
+                }
+            });
         }
     }
 
@@ -4490,7 +4501,7 @@
         // no need for log(N) search performance
         private MediaTimeProvider.OnMediaTimeListener mListeners[];
         private long mTimes[];
-        private Handler mEventHandler;
+        private EventHandler mEventHandler;
         private boolean mRefresh = false;
         private boolean mPausing = false;
         private boolean mSeeking = false;
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 4f06caa..d7f51d4 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -145,6 +145,7 @@
 
 struct SecurityLevels {
     jint kSecurityLevelUnknown;
+    jint kSecurityLevelMax;
     jint kSecurityLevelSwSecureCrypto;
     jint kSecurityLevelSwSecureDecode;
     jint kSecurityLevelHwSecureCrypto;
@@ -683,6 +684,10 @@
     GET_STATIC_FIELD_ID(field, clazz, "HW_SECURE_ALL", "I");
     gSecurityLevels.kSecurityLevelHwSecureAll = env->GetStaticIntField(clazz, field);
 
+    jmethodID getMaxSecurityLevel;
+    GET_STATIC_METHOD_ID(getMaxSecurityLevel, clazz, "getMaxSecurityLevel", "()I");
+    gSecurityLevels.kSecurityLevelMax = env->CallStaticIntMethod(clazz, getMaxSecurityLevel);
+
     FIND_CLASS(clazz, "android/media/MediaDrm$KeyRequest");
     GET_FIELD_ID(gFields.keyRequest.data, clazz, "mData", "[B");
     GET_FIELD_ID(gFields.keyRequest.defaultUrl, clazz, "mDefaultUrl", "Ljava/lang/String;");
@@ -813,7 +818,7 @@
 }
 
 static jbyteArray android_media_MediaDrm_openSession(
-    JNIEnv *env, jobject thiz) {
+        JNIEnv *env, jobject thiz, jint jlevel) {
     sp<IDrm> drm = GetDrm(env, thiz);
 
     if (drm == NULL) {
@@ -823,7 +828,26 @@
     }
 
     Vector<uint8_t> sessionId;
-    status_t err = drm->openSession(sessionId);
+    DrmPlugin::SecurityLevel level;
+
+    if (jlevel == gSecurityLevels.kSecurityLevelMax) {
+        level = DrmPlugin::kSecurityLevelMax;
+    }  else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
+        level = DrmPlugin::kSecurityLevelSwSecureCrypto;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
+        level = DrmPlugin::kSecurityLevelSwSecureDecode;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
+        level = DrmPlugin::kSecurityLevelHwSecureCrypto;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
+        level = DrmPlugin::kSecurityLevelHwSecureDecode;
+    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
+        level = DrmPlugin::kSecurityLevelHwSecureAll;
+    } else {
+        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
+        return NULL;
+    }
+
+    status_t err = drm->openSession(level, sessionId);
 
     if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
         return NULL;
@@ -1345,40 +1369,6 @@
 }
 
 
-static void android_media_MediaDrm_setSecurityLevel(JNIEnv *env,
-        jobject thiz, jbyteArray jsessionId, jint jlevel) {
-    sp<IDrm> drm = GetDrm(env, thiz);
-
-    if (!CheckSession(env, drm, jsessionId)) {
-        return;
-    }
-
-    Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
-    DrmPlugin::SecurityLevel level;
-
-    if (jlevel == gSecurityLevels.kSecurityLevelSwSecureCrypto) {
-        level = DrmPlugin::kSecurityLevelSwSecureCrypto;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelSwSecureDecode) {
-        level = DrmPlugin::kSecurityLevelSwSecureDecode;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureCrypto) {
-        level = DrmPlugin::kSecurityLevelHwSecureCrypto;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureDecode) {
-        level = DrmPlugin::kSecurityLevelHwSecureDecode;
-    } else if (jlevel == gSecurityLevels.kSecurityLevelHwSecureAll) {
-        level = DrmPlugin::kSecurityLevelHwSecureAll;
-    } else {
-        jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid security level");
-        return;
-    }
-
-    status_t err = drm->setSecurityLevel(sessionId, level);
-
-    if (throwExceptionAsNecessary(env, err, "Failed to set security level")) {
-        return;
-    }
-}
-
-
 static jstring android_media_MediaDrm_getPropertyString(
     JNIEnv *env, jobject thiz, jstring jname) {
     sp<IDrm> drm = GetDrm(env, thiz);
@@ -1724,7 +1714,7 @@
     { "isCryptoSchemeSupportedNative", "([BLjava/lang/String;)Z",
       (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
 
-    { "openSession", "()[B",
+    { "openSession", "(I)[B",
       (void *)android_media_MediaDrm_openSession },
 
     { "closeSession", "([B)V",
@@ -1785,9 +1775,6 @@
     { "getSecurityLevel", "([B)I",
       (void *)android_media_MediaDrm_getSecurityLevel },
 
-    { "setSecurityLevel", "([BI)V",
-      (void *)android_media_MediaDrm_setSecurityLevel },
-
     { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
       (void *)android_media_MediaDrm_getPropertyString },
 
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 0eb98f3..e73b2f8 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -154,7 +154,8 @@
 public:
     JNIMediaPlayer2Listener(JNIEnv* env, jobject thiz, jobject weak_thiz);
     ~JNIMediaPlayer2Listener();
-    virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
+    virtual void notify(int64_t srcId, int msg, int ext1, int ext2,
+                        const Parcel *obj = NULL) override;
 private:
     JNIMediaPlayer2Listener();
     jclass      mClass;     // Reference to MediaPlayer2 class
@@ -187,7 +188,7 @@
     env->DeleteGlobalRef(mClass);
 }
 
-void JNIMediaPlayer2Listener::notify(int msg, int ext1, int ext2, const Parcel *obj)
+void JNIMediaPlayer2Listener::notify(int64_t srcId, int msg, int ext1, int ext2, const Parcel *obj)
 {
     JNIEnv *env = AndroidRuntime::getJNIEnv();
     if (obj && obj->dataSize() > 0) {
@@ -196,12 +197,12 @@
             Parcel* nativeParcel = parcelForJavaObject(env, jParcel);
             nativeParcel->setData(obj->data(), obj->dataSize());
             env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
-                    msg, ext1, ext2, jParcel);
+                    srcId, msg, ext1, ext2, jParcel);
             env->DeleteLocalRef(jParcel);
         }
     } else {
         env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
-                msg, ext1, ext2, NULL);
+                srcId, msg, ext1, ext2, NULL);
     }
     if (env->ExceptionCheck()) {
         ALOGW("An exception occurred while notifying an event.");
@@ -243,7 +244,11 @@
     if (exception == NULL) {  // Don't throw exception. Instead, send an event.
         if (opStatus != (status_t) OK) {
             sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-            if (mp != 0) mp->notify(MEDIA2_ERROR, opStatus, 0);
+            if (mp != 0) {
+                int64_t srcId = 0;
+                mp->getSrcId(&srcId);
+                mp->notify(srcId, MEDIA2_ERROR, opStatus, 0);
+            }
         }
     } else {  // Throw exception!
         if ( opStatus == (status_t) INVALID_OPERATION ) {
@@ -268,7 +273,7 @@
 
 static void
 android_media_MediaPlayer2_setDataSourceAndHeaders(
-        JNIEnv *env, jobject thiz, jobject httpServiceObj, jstring path,
+        JNIEnv *env, jobject thiz, jlong srcId, jobject httpServiceObj, jstring path,
         jobjectArray keys, jobjectArray values) {
 
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
@@ -286,7 +291,7 @@
     if (tmp == NULL) {  // Out of memory
         return;
     }
-    ALOGV("setDataSourceAndHeaders: path %s", tmp);
+    ALOGV("setDataSourceAndHeaders: path %s, srcId %lld", tmp, (long long)srcId);
 
     if (strncmp(tmp, "content://", 10) == 0) {
         ALOGE("setDataSourceAndHeaders: content scheme is not supported in native code");
@@ -296,6 +301,7 @@
     }
 
     sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mId = srcId;
     dsd->mType = DataSourceDesc::TYPE_URL;
     dsd->mUrl = tmp;
 
@@ -321,7 +327,7 @@
 
 static void
 android_media_MediaPlayer2_setDataSourceFD(
-    JNIEnv *env, jobject thiz, jobject fileDescriptor, jlong offset, jlong length)
+    JNIEnv *env, jobject thiz, jlong srcId, jobject fileDescriptor, jlong offset, jlong length)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -334,8 +340,8 @@
         return;
     }
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    ALOGV("setDataSourceFD: fd=%d (%s), offset=%lld, length=%lld",
-          fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
+    ALOGV("setDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
+          (long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
 
     struct stat sb;
     int ret = fstat(fd, &sb);
@@ -363,6 +369,7 @@
     }
 
     sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mId = srcId;
     dsd->mType = DataSourceDesc::TYPE_FD;
     dsd->mFD = fd;
     dsd->mFDOffset = offset;
@@ -373,7 +380,7 @@
 
 static void
 android_media_MediaPlayer2_setDataSourceCallback(
-    JNIEnv *env, jobject thiz, jobject dataSource)
+    JNIEnv *env, jobject thiz, jlong srcId, jobject dataSource)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -387,6 +394,7 @@
     }
     sp<DataSource> callbackDataSource = new JMedia2DataSource(env, dataSource);
     sp<DataSourceDesc> dsd = new DataSourceDesc();
+    dsd->mId = srcId;
     dsd->mType = DataSourceDesc::TYPE_CALLBACK;
     dsd->mCallbackSource = callbackDataSource;
     process_media_player_call(env, thiz, mp->setDataSource(dsd),
@@ -1012,7 +1020,7 @@
     }
 
     fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
-                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+                                               "(Ljava/lang/Object;JIIILjava/lang/Object;)V");
     if (fields.post_event == NULL) {
         return;
     }
@@ -1382,13 +1390,13 @@
 static const JNINativeMethod gMethods[] = {
     {
         "nativeSetDataSource",
-        "(Landroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
+        "(JLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
         "[Ljava/lang/String;)V",
         (void *)android_media_MediaPlayer2_setDataSourceAndHeaders
     },
 
-    {"_setDataSource",      "(Ljava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer2_setDataSourceFD},
-    {"_setDataSource",      "(Landroid/media/Media2DataSource;)V",(void *)android_media_MediaPlayer2_setDataSourceCallback },
+    {"_setDataSource",      "(JLjava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer2_setDataSourceFD},
+    {"_setDataSource",      "(JLandroid/media/Media2DataSource;)V",(void *)android_media_MediaPlayer2_setDataSourceCallback },
     {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer2_setVideoSurface},
     {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
     {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
index 5566b4e..ddb05f0 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/Camera2RecordingTest.java
@@ -659,6 +659,10 @@
                 updatePreviewSurfaceWithVideo(videoSz, profile.videoFrameRate);
 
                 prepareVideoSnapshot(videoSnapshotRequestBuilder, imageListener);
+                Range<Integer> fpsRange = Range.create(profile.videoFrameRate,
+                        profile.videoFrameRate);
+                videoSnapshotRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
+                        fpsRange);
                 CaptureRequest request = videoSnapshotRequestBuilder.build();
 
                 // Start recording
diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp
index e70d5ea..98e9a42 100644
--- a/native/android/asset_manager.cpp
+++ b/native/android/asset_manager.cpp
@@ -18,11 +18,9 @@
 #include <utils/Log.h>
 
 #include <android/asset_manager_jni.h>
-#include <android_runtime/android_util_AssetManager.h>
 #include <androidfw/Asset.h>
 #include <androidfw/AssetDir.h>
 #include <androidfw/AssetManager.h>
-#include <androidfw/AssetManager2.h>
 #include <utils/threads.h>
 
 #include "jni.h"
@@ -37,20 +35,21 @@
 
 // -----
 struct AAssetDir {
-    std::unique_ptr<AssetDir> mAssetDir;
+    AssetDir* mAssetDir;
     size_t mCurFileIndex;
     String8 mCachedFileName;
 
-    explicit AAssetDir(std::unique_ptr<AssetDir> dir) :
-        mAssetDir(std::move(dir)), mCurFileIndex(0) { }
+    explicit AAssetDir(AssetDir* dir) : mAssetDir(dir), mCurFileIndex(0) { }
+    ~AAssetDir() { delete mAssetDir; }
 };
 
 
 // -----
 struct AAsset {
-    std::unique_ptr<Asset> mAsset;
+    Asset* mAsset;
 
-    explicit AAsset(std::unique_ptr<Asset> asset) : mAsset(std::move(asset)) { }
+    explicit AAsset(Asset* asset) : mAsset(asset) { }
+    ~AAsset() { delete mAsset; }
 };
 
 // -------------------- Public native C API --------------------
@@ -105,18 +104,19 @@
         return NULL;
     }
 
-    ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
-    std::unique_ptr<Asset> asset = locked_mgr->Open(filename, amMode);
-    if (asset == nullptr) {
-        return nullptr;
+    AssetManager* mgr = static_cast<AssetManager*>(amgr);
+    Asset* asset = mgr->open(filename, amMode);
+    if (asset == NULL) {
+        return NULL;
     }
-    return new AAsset(std::move(asset));
+
+    return new AAsset(asset);
 }
 
 AAssetDir* AAssetManager_openDir(AAssetManager* amgr, const char* dirName)
 {
-    ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(amgr));
-    return new AAssetDir(locked_mgr->OpenDir(dirName));
+    AssetManager* mgr = static_cast<AssetManager*>(amgr);
+    return new AAssetDir(mgr->openDir(dirName));
 }
 
 /**
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index 87fe9ed..77237ae 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -17,10 +17,9 @@
 #define LOG_TAG "Configuration"
 #include <utils/Log.h>
 
-#include <androidfw/AssetManager2.h>
+#include <androidfw/AssetManager.h>
 
 #include <android_runtime/android_content_res_Configuration.h>
-#include <android_runtime/android_util_AssetManager.h>
 
 using namespace android;
 
@@ -35,11 +34,7 @@
 }
 
 void AConfiguration_fromAssetManager(AConfiguration* out, AAssetManager* am) {
-    ScopedLock<AssetManager2> locked_mgr(*AssetManagerForNdkAssetManager(am));
-    ResTable_config config = locked_mgr->GetConfiguration();
-
-    // AConfiguration is not a virtual subclass, so we can memcpy.
-    memcpy(out, &config, sizeof(config));
+    ((AssetManager*)am)->getConfiguration(out);
 }
 
 void AConfiguration_copy(AConfiguration* dest, AConfiguration* src) {
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
index 88b85e0..12972f1 100644
--- a/packages/CtsShim/Android.mk
+++ b/packages/CtsShim/Android.mk
@@ -32,9 +32,10 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
 
-my_archs := arm x86
-my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))
-LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShimPriv.apk
+LOCAL_SRC_FILES_arm := apk/arm/CtsShimPriv.apk
+LOCAL_SRC_FILES_arm64 := apk/arm/CtsShimPriv.apk
+LOCAL_SRC_FILES_x86 := apk/x86/CtsShimPriv.apk
+LOCAL_SRC_FILES_x86_64 := apk/x86/CtsShimPriv.apk
 
 include $(BUILD_PREBUILT)
 
@@ -53,9 +54,10 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_MODULE_TARGET_ARCH := arm arm64 x86 x86_64
 
-my_archs := arm x86
-my_src_arch := $(call get-prebuilt-src-arch, $(my_archs))
-LOCAL_SRC_FILES := apk/$(my_src_arch)/CtsShim.apk
+LOCAL_SRC_FILES_arm := apk/arm/CtsShim.apk
+LOCAL_SRC_FILES_arm64 := apk/arm/CtsShim.apk
+LOCAL_SRC_FILES_x86 := apk/x86/CtsShim.apk
+LOCAL_SRC_FILES_x86_64 := apk/x86/CtsShim.apk
 
 include $(BUILD_PREBUILT)
 
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e557c65..e6f4ec6e 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -805,13 +805,17 @@
         <item>Colors optimized for digital content</item>
     </string-array>
 
-    <!-- Settings item title for inactive apps [CHAR LIMIT=35] -->
-    <string name="inactive_apps_title">Inactive apps</string>
+    <!-- Settings item title for apps in standby (limiting background activity) [CHAR LIMIT=35] -->
+    <string name="inactive_apps_title">Standby apps</string>
     <!-- Settings item summary for inactive app [CHAR LIMIT=100] -->
     <string name="inactive_app_inactive_summary">Inactive. Tap to toggle.</string>
     <!-- Settings item summary for active app [CHAR LIMIT=100] -->
     <string name="inactive_app_active_summary">Active. Tap to toggle.</string>
 
+    <!-- Settings item summary for standby bucket value of an app. [CHAR LIMIT=100] -->
+    <string name="standby_bucket_summary">App standby
+        state:<xliff:g id="bucket"> %s</xliff:g></string>
+
     <!-- Services settings screen, setting option name for the user to go to the screen to view running services -->
     <string name="runningservices_settings_title">Running services</string>
     <!-- Services settings screen, setting option summary for the user to go to the screen to view running services  -->
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 39f2b52..1551b8e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1112,8 +1112,8 @@
                 Settings.Global.ZRAM_ENABLED,
                 GlobalSettingsProto.ZRAM_ENABLED);
         dumpSetting(s, p,
-                Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS,
-                GlobalSettingsProto.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS);
+                Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS,
+                GlobalSettingsProto.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS);
         dumpSetting(s, p,
                 Settings.Global.SHOW_FIRST_CRASH_DIALOG,
                 GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 79299aa..4d49899b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -139,6 +139,11 @@
     <uses-permission android:name="android.permission.MANAGE_SENSORS" />
     <uses-permission android:name="android.permission.MANAGE_AUDIO_POLICY" />
     <uses-permission android:name="android.permission.MANAGE_CAMERA" />
+    <!-- Permission needed to enable/disable Bluetooth/Wifi when on permission review mode -->
+    <uses-permission
+        android:name="android.permission.MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED" />
+    <uses-permission
+        android:name="android.permission.MANAGE_WIFI_WHEN_PERMISSION_REVIEW_REQUIRED" />
 
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 28a0935..4934e14 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -44,13 +44,13 @@
     <!-- Default clock parameters -->
     <dimen name="bottom_text_spacing_digital">-24dp</dimen>
     <!-- Slice header -->
-    <dimen name="widget_title_font_size">28sp</dimen>
+    <dimen name="widget_title_font_size">24sp</dimen>
     <!-- Slice subtitle  -->
     <dimen name="widget_label_font_size">16sp</dimen>
     <!-- Clock without header -->
     <dimen name="widget_big_font_size">64dp</dimen>
     <!-- Clock with header -->
-    <dimen name="widget_small_font_size">22dp</dimen>
+    <dimen name="widget_small_font_size">24dp</dimen>
     <!-- Dash between clock and header -->
     <dimen name="widget_separator_width">16dp</dimen>
     <dimen name="widget_separator_thickness">1dp</dimen>
diff --git a/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml b/packages/SystemUI/res/color/accent_tint_color_selector.xml
similarity index 73%
rename from libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml
rename to packages/SystemUI/res/color/accent_tint_color_selector.xml
index 34016db..85af186 100644
--- a/libs/androidfw/tests/data/out_of_order_types/AndroidManifest.xml
+++ b/packages/SystemUI/res/color/accent_tint_color_selector.xml
@@ -13,6 +13,9 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+          android:color="?android:attr/colorButtonNormal"/>
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.app" />
+    <item android:color="?android:attr/colorAccent"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 36298ca..803659f 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -15,8 +15,8 @@
 -->
 <com.android.systemui.volume.VolumeUiLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:background="@android:color/transparent"
     android:theme="@style/qs_theme"
     android:clipChildren="false" >
@@ -29,7 +29,6 @@
         android:minWidth="@dimen/volume_dialog_panel_width"
         android:background="@android:color/transparent"
         android:layout_margin="@dimen/volume_dialog_base_margin"
-        android:translationZ="8dp"
         android:orientation="vertical"
         android:clipChildren="false" >
 
@@ -39,59 +38,64 @@
             android:layout_height="wrap_content"
             android:clipChildren="false"
             android:clipToPadding="false"
-            android:paddingTop="10dp"
-            android:paddingBottom="10dp"
             android:background="@drawable/rounded_bg_full"
-            android:translationZ="8dp"
+            android:translationZ="@dimen/volume_panel_elevation"
             android:orientation="horizontal" >
                 <!-- volume rows added and removed here! :-) -->
         </LinearLayout>
 
-        <LinearLayout
+        <FrameLayout
             android:id="@+id/footer"
             android:layout_width="@dimen/volume_dialog_panel_width"
             android:layout_height="@dimen/volume_dialog_panel_width"
-            android:clipChildren="false"
-            android:clipToPadding="false"
             android:layout_marginTop="6dp"
             android:layout_marginBottom="6dp"
             android:layout_below="@id/volume_dialog_rows"
-            android:background="@drawable/rounded_bg_full"
-            android:gravity="center"
-            android:layout_gravity="end"
-            android:translationZ="8dp"
-            android:clickable="true"
-            android:orientation="vertical" >
+            android:background="@drawable/rounded_bg_full">
 
-            <TextView
-                android:id="@+id/ringer_title"
-                android:text="@string/ring_toggle_title"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:maxLines="1"
-                android:layout_centerVertical="true"
-                android:textColor="?android:attr/colorControlNormal"
-                android:textAppearance="@style/TextAppearance.Volume.Header" />
+            <LinearLayout
+                android:id="@+id/footer_linear_layout"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:clipChildren="false"
+                android:clipToPadding="false"
+                android:gravity="center"
+                android:layout_gravity="end"
+                android:translationZ="@dimen/volume_panel_elevation"
+                android:clickable="true"
+                android:orientation="vertical" >
 
-            <com.android.keyguard.AlphaOptimizedImageButton
-                android:id="@+id/ringer_icon"
-                style="@style/VolumeButtons"
-                android:background="?android:selectableItemBackgroundBorderless"
-                android:layout_width="@dimen/volume_dialog_panel_width"
-                android:layout_height="@dimen/volume_button_size"
-                android:tint="?android:attr/colorAccent"
-                android:soundEffectsEnabled="false" />
+                <TextView
+                    android:id="@+id/ringer_title"
+                    android:text="@string/ring_toggle_title"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:maxLines="1"
+                    android:layout_centerVertical="true"
+                    android:textColor="?android:attr/colorControlNormal"
+                    android:textAppearance="@style/TextAppearance.Volume.Header" />
 
-            <TextView
-                android:id="@+id/ringer_status"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:ellipsize="end"
-                android:maxLines="1"
-                android:textColor="?android:attr/colorControlNormal"
-                android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/ringer_icon"
+                    style="@style/VolumeButtons"
+                    android:background="?android:selectableItemBackgroundBorderless"
+                    android:layout_width="@dimen/volume_dialog_panel_width"
+                    android:layout_height="@dimen/volume_button_size"
+                    android:tint="@color/accent_tint_color_selector"
+                    android:soundEffectsEnabled="false" />
 
-        </LinearLayout>
+                <TextView
+                    android:id="@+id/ringer_status"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:ellipsize="end"
+                    android:maxLines="1"
+                    android:textColor="?android:attr/colorControlNormal"
+                    android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
+            </LinearLayout>
+
+            <include layout="@layout/volume_dnd_icon"/>
+        </FrameLayout>
     </LinearLayout>
 </com.android.systemui.volume.VolumeUiLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index 70654a8..fb9355a 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -13,89 +13,98 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<LinearLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:tag="row"
     android:layout_height="wrap_content"
     android:layout_width="@dimen/volume_dialog_panel_width"
     android:clipChildren="true"
     android:clipToPadding="true"
-    android:theme="@style/qs_theme"
-    android:gravity="center"
-    android:orientation="vertical" >
+    android:theme="@style/qs_theme">
 
     <LinearLayout
-        android:orientation="vertical"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_marginTop="10dp"
+        android:layout_marginBottom="10dp"
         android:gravity="center"
-        android:padding="5dp">
-        <TextView
-            android:id="@+id/volume_row_header"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:ellipsize="end"
-            android:maxLength="10"
-            android:maxLines="1"
-            android:textColor="?android:attr/colorControlNormal"
-            android:textAppearance="@style/TextAppearance.Volume.Header" />
+        android:orientation="vertical" >
+
         <LinearLayout
-            android:id="@+id/output_chooser"
             android:orientation="vertical"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:minWidth="48dp"
-            android:minHeight="48dp"
-            android:paddingTop="10dp"
-            android:background="?android:selectableItemBackgroundBorderless"
-            android:gravity="center">
+            android:gravity="center"
+            android:padding="5dp">
             <TextView
-                android:id="@+id/volume_row_connected_device"
-                android:visibility="gone"
+                android:id="@+id/volume_row_header"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:maxLength="10"
                 android:ellipsize="end"
+                android:maxLength="10"
                 android:maxLines="1"
-                android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
-            <com.android.keyguard.AlphaOptimizedImageButton
-                android:id="@+id/output_chooser_button"
-                android:layout_width="24dp"
-                android:layout_height="24dp"
+                android:textColor="?android:attr/colorControlNormal"
+                android:textAppearance="@style/TextAppearance.Volume.Header" />
+            <LinearLayout
+                android:id="@+id/output_chooser"
+                android:orientation="vertical"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:minWidth="48dp"
+                android:minHeight="48dp"
+                android:paddingTop="10dp"
                 android:background="?android:selectableItemBackgroundBorderless"
-                android:contentDescription="@string/accessibility_output_chooser"
-                style="@style/VolumeButtons"
-                android:clickable="false"
-                android:layout_centerVertical="true"
-                android:src="@drawable/ic_swap"
-                android:soundEffectsEnabled="false" />
+                android:gravity="center">
+                <TextView
+                    android:id="@+id/volume_row_connected_device"
+                    android:visibility="gone"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:maxLength="10"
+                    android:ellipsize="end"
+                    android:maxLines="1"
+                    android:textAppearance="@style/TextAppearance.Volume.Header.Secondary" />
+                <com.android.keyguard.AlphaOptimizedImageButton
+                    android:id="@+id/output_chooser_button"
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"
+                    android:background="?android:selectableItemBackgroundBorderless"
+                    android:contentDescription="@string/accessibility_output_chooser"
+                    style="@style/VolumeButtons"
+                    android:clickable="false"
+                    android:layout_centerVertical="true"
+                    android:src="@drawable/ic_swap"
+                    android:soundEffectsEnabled="false"/>
+            </LinearLayout>
         </LinearLayout>
-    </LinearLayout>
-    <FrameLayout
-        android:id="@+id/volume_row_slider_frame"
-        android:padding="0dp"
-        android:layout_width="@dimen/volume_dialog_panel_width"
-        android:layoutDirection="rtl"
-        android:layout_height="@dimen/volume_dialog_panel_width">
-        <SeekBar
-            android:id="@+id/volume_row_slider"
-            android:clickable="true"
+        <FrameLayout
+            android:id="@+id/volume_row_slider_frame"
             android:padding="0dp"
-            android:layout_margin="0dp"
             android:layout_width="@dimen/volume_dialog_panel_width"
-            android:layout_height="@dimen/volume_dialog_panel_width"
             android:layoutDirection="rtl"
-            android:layout_gravity="center"
-            android:rotation="90" />
-    </FrameLayout>
+            android:layout_height="@dimen/volume_dialog_panel_width">
+            <SeekBar
+                android:id="@+id/volume_row_slider"
+                android:clickable="true"
+                android:padding="0dp"
+                android:layout_margin="0dp"
+                android:layout_width="@dimen/volume_dialog_panel_width"
+                android:layout_height="@dimen/volume_dialog_panel_width"
+                android:layoutDirection="rtl"
+                android:layout_gravity="center"
+                android:rotation="90" />
+        </FrameLayout>
 
-    <com.android.keyguard.AlphaOptimizedImageButton
-        android:id="@+id/volume_row_icon"
-        style="@style/VolumeButtons"
-        android:padding="10dp"
-        android:layout_width="@dimen/volume_button_size"
-        android:layout_height="@dimen/volume_button_size"
-        android:background="?android:selectableItemBackgroundBorderless"
-        android:soundEffectsEnabled="false" />
+        <com.android.keyguard.AlphaOptimizedImageButton
+            android:id="@+id/volume_row_icon"
+            style="@style/VolumeButtons"
+            android:padding="10dp"
+            android:layout_width="@dimen/volume_button_size"
+            android:layout_height="@dimen/volume_button_size"
+            android:background="?android:selectableItemBackgroundBorderless"
+            android:soundEffectsEnabled="false" />
+    </LinearLayout>
 
-</LinearLayout>
\ No newline at end of file
+    <include layout="@layout/volume_dnd_icon"/>
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/volume_dnd_icon.xml b/packages/SystemUI/res/layout/volume_dnd_icon.xml
new file mode 100644
index 0000000..215b230
--- /dev/null
+++ b/packages/SystemUI/res/layout/volume_dnd_icon.xml
@@ -0,0 +1,30 @@
+<!--
+     Copyright (C) 2018 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="14dp"
+    android:layout_height="14dp"
+    android:layout_marginTop="6dp"
+    android:layout_marginRight="6dp"
+    android:layout_gravity="right|top">
+
+    <ImageView
+        android:id="@+id/dnd_icon"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:src="@drawable/ic_dnd"
+        android:tint="?android:attr/textColorTertiary"/>
+</FrameLayout>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f2e5d3b..cf0659a 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -475,4 +475,11 @@
         <item>60</item>
         <item>120</item>
     </integer-array>
+
+    <!-- Smart replies in notifications: Whether smart replies in notifications are enabled. -->
+    <bool name="config_smart_replies_in_notifications_enabled">true</bool>
+
+    <!-- Smart replies in notifications: Maximum number of times SmartReplyView will try to find a
+         better (narrower) line-break for a double-line smart reply button. -->
+    <integer name="config_smart_replies_in_notifications_max_squeeze_remeasure_attempts">3</integer>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a9021ae..c351b94 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -704,6 +704,8 @@
     <dimen name="volume_expander_margin_end">2dp</dimen>
     <dimen name="volume_expander_margin_top">6dp</dimen>
 
+    <dimen name="volume_panel_elevation">8dp</dimen>
+
     <!-- Padding between icon and text for managed profile toast -->
     <dimen name="managed_profile_toast_padding">4dp</dimen>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index cd9e126..7f382ac 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -36,25 +36,25 @@
 
     /**
      * Sent when a user has quickly flinged on the nav bar to switch tasks. Once this event is sent
-     * the caller will stop sending any motion events.
+     * the caller will stop sending any motion events and will no longer preemptively cancel any
+     * recents animations started as a part of the motion event handling.
      */
     void onQuickSwitch();
 
     /**
      * Sent when the user starts to actively scrub the nav bar to switch tasks. Once this event is
-     * sent the caller will stop sending any motion events.
+     * sent the caller will stop sending any motion events and will no longer preemptively cancel
+     * any recents animations started as a part of the motion event handling.
      */
     void onQuickScrubStart();
 
     /**
-     * Sent when the user stops actively scrubbing the nav bar to switch tasks. Once this event is
-     * sent the caller will stop sending any motion events.
+     * Sent when the user stops actively scrubbing the nav bar to switch tasks.
      */
     void onQuickScrubEnd();
 
     /**
-     * Sent for each movement over the nav bar while the user is scrubbing it to switch tasks. Once
-     * this event is sent the caller will stop sending any motion events.
+     * Sent for each movement over the nav bar while the user is scrubbing it to switch tasks.
      */
     void onQuickScrubProgress(float progress);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index b30b0c5..d0128ef 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -99,9 +99,7 @@
         public void onRecentsAnimationStarted() {
             long token = Binder.clearCallingIdentity();
             try {
-                mHandler.post(() -> {
-                    notifyRecentsAnimationStarted();
-                });
+                mHandler.post(OverviewProxyService.this::notifyRecentsAnimationStarted);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 0f3daf5..d1834e9 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
 
 import java.util.function.Consumer;
 
@@ -130,6 +131,8 @@
         providers.put(NotificationGutsManager.class, () -> new NotificationGutsManager(context));
         providers.put(NotificationRemoteInputManager.class,
                 () -> new NotificationRemoteInputManager(context));
+        providers.put(SmartReplyConstants.class,
+                () -> new SmartReplyConstants(Dependency.get(Dependency.MAIN_HANDLER), context));
         providers.put(NotificationListener.class, () -> new NotificationListener(context));
         providers.put(NotificationLogger.class, NotificationLogger::new);
         providers.put(NotificationViewHierarchyManager.class,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index e811ed3..c4d0b79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -22,7 +22,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Build;
-import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -36,6 +35,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.HybridGroupManager;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
@@ -44,6 +44,7 @@
 import com.android.systemui.statusbar.notification.NotificationViewWrapper;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.RemoteInputView;
+import com.android.systemui.statusbar.policy.SmartReplyConstants;
 import com.android.systemui.statusbar.policy.SmartReplyView;
 
 /**
@@ -75,6 +76,8 @@
 
     private RemoteInputView mExpandedRemoteInput;
     private RemoteInputView mHeadsUpRemoteInput;
+
+    private SmartReplyConstants mSmartReplyConstants;
     private SmartReplyView mExpandedSmartReplyView;
 
     private NotificationViewWrapper mContractedWrapper;
@@ -145,6 +148,7 @@
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mHybridGroupManager = new HybridGroupManager(getContext(), this);
+        mSmartReplyConstants = Dependency.get(SmartReplyConstants.class);
         initView();
     }
 
@@ -1166,8 +1170,7 @@
             return;
         }
 
-        boolean enableSmartReplies = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS, 0) != 0;
+        boolean enableSmartReplies = mSmartReplyConstants.isEnabled();
 
         boolean hasRemoteInput = false;
         RemoteInput remoteInputWithChoices = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index f25379a..3c480d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -299,6 +299,11 @@
                         }
                     }, REMOTE_INPUT_KEPT_ENTRY_AUTO_CANCEL_DELAY);
                 }
+                try {
+                    mBarService.onNotificationDirectReplied(entry.notification.getKey());
+                } catch (RemoteException e) {
+                    // Nothing to do, system going down
+                }
             }
         });
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 8d14db78..d15c771 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -28,7 +28,6 @@
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.MotionEvent;
@@ -159,25 +158,19 @@
                 mRecentsAnimationStarted = false;
                 break;
             }
-            case MotionEvent.ACTION_UP: {
-                // If the overview proxy service has not started the recents animation then clean up
-                // after it to ensure that the nav bar buttons still work
-                if (mOverviewProxyService.getProxy() != null && !mRecentsAnimationStarted) {
-                    try {
-                        ActivityManager.getService().cancelRecentsAnimation();
-                    } catch (RemoteException e) {
-                        Log.e(TAG, "Could not cancel recents animation", e);
-                    }
-                }
-                break;
-            }
         }
-        if (mStatusBar.isPresenterFullyCollapsed()
-                && !mQuickScrubController.onInterceptTouchEvent(event)) {
+        boolean handledByQuickscrub = mQuickScrubController.onInterceptTouchEvent(event);
+        if (mStatusBar.isPresenterFullyCollapsed() && !handledByQuickscrub) {
+            // Proxy motion events until we start intercepting for quickscrub
             proxyMotionEvents(event);
-            return false;
         }
-        return (mDockWindowEnabled && interceptDockWindowEvent(event)) || mRecentsAnimationStarted;
+
+        boolean result = handledByQuickscrub;
+        result |= mRecentsAnimationStarted;
+        if (mDockWindowEnabled) {
+            result |= interceptDockWindowEvent(event);
+        }
+        return result;
     }
 
     public boolean onTouchEvent(MotionEvent event) {
@@ -188,10 +181,11 @@
                 && (mQuickScrubController.onTouchEvent(event)
                 || ignoreProxyDownEvent
                 || proxyMotionEvents(event));
+        result |= mRecentsAnimationStarted;
         if (mDockWindowEnabled) {
             result |= handleDockWindowEvent(event);
         }
-        return result || mRecentsAnimationStarted;
+        return result;
     }
 
     public void onDraw(Canvas canvas) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index ea449c2..9d1c1e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -27,10 +27,12 @@
 import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
@@ -55,6 +57,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
 public class KeyButtonView extends ImageView implements ButtonInterface {
+    private static final String TAG = KeyButtonView.class.getSimpleName();
 
     private final boolean mPlaySounds;
     private int mContentDescriptionRes;
@@ -264,6 +267,13 @@
                 }
                 if (mCode != 0) {
                     if (doIt) {
+                        // If there was a pending remote recents animation, then we need to
+                        // cancel the animation now before we handle the button itself
+                        try {
+                            ActivityManager.getService().cancelRecentsAnimation();
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Could not cancel recents animation", e);
+                        }
                         sendEvent(KeyEvent.ACTION_UP, 0);
                         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
                     } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
new file mode 100644
index 0000000..c5067a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyConstants.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.provider.Settings;
+import android.util.KeyValueListParser;
+import android.util.Log;
+
+import com.android.systemui.R;
+
+public final class SmartReplyConstants extends ContentObserver {
+
+    private static final String TAG = "SmartReplyConstants";
+
+    private static final String KEY_ENABLED = "enabled";
+    private static final String KEY_MAX_SQUEEZE_REMEASURE_ATTEMPTS =
+            "max_squeeze_remeasure_attempts";
+
+    private final boolean mDefaultEnabled;
+    private final int mDefaultMaxSqueezeRemeasureAttempts;
+
+    private boolean mEnabled;
+    private int mMaxSqueezeRemeasureAttempts;
+
+    private final Context mContext;
+    private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+    public SmartReplyConstants(Handler handler, Context context) {
+        super(handler);
+
+        mContext = context;
+        final Resources resources = mContext.getResources();
+        mDefaultEnabled = resources.getBoolean(
+                R.bool.config_smart_replies_in_notifications_enabled);
+        mDefaultMaxSqueezeRemeasureAttempts = resources.getInteger(
+                R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Global.getUriFor(Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS),
+                false, this);
+        updateConstants();
+    }
+
+    @Override
+    public void onChange(boolean selfChange, Uri uri) {
+        updateConstants();
+    }
+
+    private void updateConstants() {
+        synchronized (SmartReplyConstants.this) {
+            try {
+                mParser.setString(Settings.Global.getString(mContext.getContentResolver(),
+                        Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS));
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Bad smart reply constants", e);
+            }
+            mEnabled = mParser.getBoolean(KEY_ENABLED, mDefaultEnabled);
+            mMaxSqueezeRemeasureAttempts = mParser.getInt(
+                    KEY_MAX_SQUEEZE_REMEASURE_ATTEMPTS, mDefaultMaxSqueezeRemeasureAttempts);
+        }
+    }
+
+    /** Returns whether smart replies in notifications are enabled. */
+    public boolean isEnabled() {
+        return mEnabled;
+    }
+
+    /**
+     * Returns the maximum number of times {@link SmartReplyView#onMeasure(int, int)} will try to
+     * find a better (narrower) line-break for a double-line smart reply button.
+     */
+    public int getMaxSqueezeRemeasureAttempts() {
+        return mMaxSqueezeRemeasureAttempts;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 2d829af..57fc03c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -12,6 +12,7 @@
 import android.widget.Button;
 import android.widget.LinearLayout;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 
 /** View which displays smart reply buttons in notifications. */
@@ -19,8 +20,11 @@
 
     private static final String TAG = "SmartReplyView";
 
+    private final SmartReplyConstants mConstants;
+
     public SmartReplyView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mConstants = Dependency.get(SmartReplyConstants.class);
     }
 
     public void setRepliesFromRemoteInput(RemoteInput remoteInput, PendingIntent pendingIntent) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index c622677..8881ee9 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -37,6 +37,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.PixelFormat;
 import android.graphics.drawable.ColorDrawable;
 import android.media.AudioManager;
 import android.media.AudioSystem;
@@ -54,6 +55,7 @@
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.view.ContextThemeWrapper;
+import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
@@ -66,6 +68,7 @@
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.ImageButton;
+import android.widget.ImageView;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
 import android.widget.TextView;
@@ -107,7 +110,9 @@
     private ViewGroup mDialogRowsView;
     private ViewGroup mFooter;
     private ImageButton mRingerIcon;
+    private ImageView mZenIcon;
     private TextView mRingerStatus;
+    private TextView mRingerTitle;
     private final List<VolumeRow> mRows = new ArrayList<>();
     private ConfigurableTexts mConfigurableTexts;
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
@@ -176,7 +181,15 @@
         mWindow.setTitle(VolumeDialogImpl.class.getSimpleName());
         mWindow.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
         mWindow.setWindowAnimations(com.android.internal.R.style.Animation_Toast);
+        final WindowManager.LayoutParams lp = mWindow.getAttributes();
+        lp.format = PixelFormat.TRANSLUCENT;
+        lp.setTitle(VolumeDialogImpl.class.getSimpleName());
+        lp.gravity = Gravity.RIGHT | Gravity.CENTER_VERTICAL;
+        lp.windowAnimations = -1;
+        mWindow.setAttributes(lp);
+        mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
 
+        mDialog.setCanceledOnTouchOutside(true);
         mDialog.setContentView(R.layout.volume_dialog);
         mDialog.setOnShowListener(dialog -> {
             mDialogView.setTranslationX(mDialogView.getWidth() / 2);
@@ -199,13 +212,15 @@
             rescheduleTimeoutH();
             return true;
         });
-        VolumeUiLayout hardwareLayout = VolumeUiLayout.get(mDialogView);
-        hardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
+        VolumeUiLayout uiLayout = VolumeUiLayout.get(mDialogView);
+        uiLayout.updateRotation();
 
         mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
         mFooter = mDialog.findViewById(R.id.footer);
         mRingerIcon = mFooter.findViewById(R.id.ringer_icon);
         mRingerStatus = mFooter.findViewById(R.id.ringer_status);
+        mRingerTitle = mFooter.findViewById(R.id.ringer_title);
+        mZenIcon = mFooter.findViewById(R.id.dnd_icon);
 
         if (mRows.isEmpty()) {
             addRow(AudioManager.STREAM_MUSIC,
@@ -339,6 +354,7 @@
         if (stream == STREAM_ACCESSIBILITY) {
             row.header.setFilters(new InputFilter[] {new InputFilter.LengthFilter(13)});
         }
+        row.dndIcon = row.view.findViewById(R.id.dnd_icon);
         row.slider =  row.view.findViewById(R.id.volume_row_slider);
         row.slider.setOnSeekBarChangeListener(new VolumeSeekBarChangeListener(row));
         row.anim = null;
@@ -549,6 +565,8 @@
             if (ss == null) {
                 return;
             }
+
+            enableRingerViewsH(mState.zenMode == Global.ZEN_MODE_OFF || !mState.disallowRinger);
             switch (mState.ringerModeInternal) {
                 case AudioManager.RINGER_MODE_VIBRATE:
                     mRingerStatus.setText(R.string.volume_ringer_status_vibrate);
@@ -593,6 +611,28 @@
         }
     }
 
+    /**
+     * Toggles enable state of views in a VolumeRow (not including seekbar, outputChooser or icon)
+     * Hides/shows zen icon
+     * @param enable whether to enable volume row views and hide dnd icon
+     */
+    private void enableVolumeRowViewsH(VolumeRow row, boolean enable) {
+        row.header.setEnabled(enable);
+        row.dndIcon.setVisibility(enable ? View.GONE : View.VISIBLE);
+    }
+
+    /**
+     * Toggles enable state of footer/ringer views
+     * Hides/shows zen icon
+     * @param enable whether to enable ringer views and hide dnd icon
+     */
+    private void enableRingerViewsH(boolean enable) {
+        mRingerTitle.setEnabled(enable);
+        mRingerStatus.setEnabled(enable);
+        mRingerIcon.setEnabled(enable);
+        mZenIcon.setVisibility(enable ? View.GONE : View.VISIBLE);
+    }
+
     private void trimObsoleteH() {
         if (D.BUG) Log.d(TAG, "trimObsoleteH");
         for (int i = mRows.size() - 1; i >= 0; i--) {
@@ -738,6 +778,7 @@
         if (zenMuted) {
             row.tracking = false;
         }
+        enableVolumeRowViewsH(row, !zenMuted);
 
         // update slider
         final boolean enableSlider = !zenMuted;
@@ -1015,15 +1056,21 @@
         }
 
         @Override
+        public boolean onTouchEvent(MotionEvent event) {
+            if (isShowing()) {
+                if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
+                    dismissH(Events.DISMISS_REASON_TOUCH_OUTSIDE);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        @Override
         public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
             event.setClassName(getClass().getSuperclass().getName());
             event.setPackageName(mContext.getPackageName());
 
-            ViewGroup.LayoutParams params = getWindow().getAttributes();
-            boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
-                    (params.height == ViewGroup.LayoutParams.MATCH_PARENT);
-            event.setFullScreen(isFullScreen);
-
             if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
                 if (mShowing) {
                     event.getText().add(mContext.getString(
@@ -1162,5 +1209,6 @@
         private int lastAudibleLevel = 1;
         private View outputChooser;
         private TextView connectedDevice;
+        private ImageView dndIcon;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
index 3d44381..0a3a2ab 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUiLayout.java
@@ -37,10 +37,6 @@
 public class VolumeUiLayout extends FrameLayout  {
 
     private View mChild;
-    private int mOldHeight;
-    private boolean mAnimating;
-    private AnimatorSet mAnimation;
-    private boolean mHasOutsideTouch;
     private int mRotation = ROTATION_NONE;
     @Nullable
     private DisplayCutout mDisplayCutout;
@@ -52,13 +48,11 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsListener);
         mDisplayCutout = null;
     }
 
@@ -68,16 +62,11 @@
         if (mChild == null) {
             if (getChildCount() != 0) {
                 mChild = getChildAt(0);
-                mOldHeight = mChild.getMeasuredHeight();
                 updateRotation();
             } else {
                 return;
             }
         }
-        int newHeight = mChild.getMeasuredHeight();
-        if (newHeight != mOldHeight) {
-            animateChild(mOldHeight, newHeight);
-        }
     }
 
     @Override
@@ -95,8 +84,13 @@
         }
     }
 
-    private void updateRotation() {
+    public void updateRotation() {
         setDisplayCutout();
+        if (mChild == null) {
+            if (getChildCount() != 0) {
+                mChild = getChildAt(0);
+            }
+        }
         int rotation = RotationUtils.getRotation(getContext());
         if (rotation != mRotation) {
             updateSafeInsets(rotation);
@@ -144,43 +138,11 @@
         return r.bottom - r.top;
     }
 
-
-    private void animateChild(int oldHeight, int newHeight) {
-        if (true) return;
-        if (mAnimating) {
-            mAnimation.cancel();
-        }
-        mAnimating = true;
-        mAnimation = new AnimatorSet();
-        mAnimation.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                mAnimating = false;
-            }
-        });
-        int fromTop = mChild.getTop();
-        int fromBottom = mChild.getBottom();
-        int toTop = fromTop - ((newHeight - oldHeight) / 2);
-        int toBottom = fromBottom + ((newHeight - oldHeight) / 2);
-        ObjectAnimator top = ObjectAnimator.ofInt(mChild, "top", fromTop, toTop);
-        mAnimation.playTogether(top,
-                ObjectAnimator.ofInt(mChild, "bottom", fromBottom, toBottom));
-    }
-
-
     @Override
     public ViewOutlineProvider getOutlineProvider() {
         return super.getOutlineProvider();
     }
 
-    public void setOutsideTouchListener(OnClickListener onClickListener) {
-        mHasOutsideTouch = true;
-        requestLayout();
-        setOnClickListener(onClickListener);
-        setClickable(true);
-        setFocusable(true);
-    }
-
     public static VolumeUiLayout get(View v) {
         if (v instanceof VolumeUiLayout) return (VolumeUiLayout) v;
         if (v.getParent() instanceof View) {
@@ -188,16 +150,4 @@
         }
         return null;
     }
-
-    private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsListener = inoutInfo -> {
-        if (mHasOutsideTouch || (mChild == null)) {
-            inoutInfo.setTouchableInsets(
-                    ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);
-            return;
-        }
-        inoutInfo.setTouchableInsets(
-                ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT);
-        inoutInfo.contentInsets.set(mChild.getLeft(), mChild.getTop(),
-                0, getBottom() - mChild.getBottom());
-    };
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
new file mode 100644
index 0000000..32a7cb9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SmartReplyConstantsTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableResources;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
[email protected]
+@SmallTest
+public class SmartReplyConstantsTest extends SysuiTestCase {
+
+    private static final int CONTENT_OBSERVER_TIMEOUT_SECONDS = 10;
+
+    private SmartReplyConstants mConstants;
+
+    @Before
+    public void setUp() {
+        overrideSetting(null); // No config.
+        TestableResources resources = mContext.getOrCreateTestableResources();
+        resources.addOverride(R.bool.config_smart_replies_in_notifications_enabled, true);
+        resources.addOverride(
+                R.integer.config_smart_replies_in_notifications_max_squeeze_remeasure_attempts, 7);
+        mConstants = new SmartReplyConstants(new Handler(Looper.getMainLooper()), mContext);
+    }
+
+    @Test
+    public void testIsEnabledWithNoConfig() {
+        assertTrue(mConstants.isEnabled());
+    }
+
+    @Test
+    public void testIsEnabledWithInvalidConfig() {
+        overrideSetting("invalid config");
+        triggerConstantsOnChange();
+        assertTrue(mConstants.isEnabled());
+    }
+
+    @Test
+    public void testIsEnabledWithValidConfig() {
+        overrideSetting("enabled=false,max_squeeze_remeasure_attempts=5");
+        triggerConstantsOnChange();
+        assertFalse(mConstants.isEnabled());
+    }
+
+    @Test
+    public void testGetMaxSqueezeRemeasureAttemptsWithNoConfig() {
+        assertTrue(mConstants.isEnabled());
+        assertEquals(7, mConstants.getMaxSqueezeRemeasureAttempts());
+    }
+
+    @Test
+    public void testGetMaxSqueezeRemeasureAttemptsWithInvalidConfig() {
+        overrideSetting("invalid config");
+        triggerConstantsOnChange();
+        assertEquals(7, mConstants.getMaxSqueezeRemeasureAttempts());
+    }
+
+    @Test
+    public void testGetMaxSqueezeRemeasureAttemptsWithValidConfig() {
+        overrideSetting("enabled=false,max_squeeze_remeasure_attempts=5");
+        triggerConstantsOnChange();
+        assertEquals(5, mConstants.getMaxSqueezeRemeasureAttempts());
+    }
+
+    private void overrideSetting(String flags) {
+        Settings.Global.putString(mContext.getContentResolver(),
+                Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS, flags);
+    }
+
+    private void triggerConstantsOnChange() {
+        // Since Settings.Global is mocked in TestableContext, we need to manually trigger the
+        // content observer.
+        mConstants.onChange(false,
+                Settings.Global.getUriFor(Settings.Global.SMART_REPLIES_IN_NOTIFICATIONS_FLAGS));
+    }
+}
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index 0254673..7efe8ab 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -5,8 +5,6 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := telephony-common
-
 LOCAL_PACKAGE_NAME := WallpaperCropper
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 52d0e08e..b32be73 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -24,9 +24,8 @@
 #include <utils/misc.h>
 #include <inttypes.h>
 
-#include <android-base/macros.h>
 #include <androidfw/Asset.h>
-#include <androidfw/AssetManager2.h>
+#include <androidfw/AssetManager.h>
 #include <androidfw/ResourceTypes.h>
 #include <android-base/macros.h>
 
@@ -1665,22 +1664,18 @@
 static jlong
 nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path)
 {
-    Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
+    AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
     if (mgr == nullptr) {
         return 0;
     }
 
     AutoJavaStringToUTF8 str(_env, _path);
-    std::unique_ptr<Asset> asset;
-    {
-        ScopedLock<AssetManager2> locked_mgr(*mgr);
-        asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
-        if (asset == nullptr) {
-            return 0;
-        }
+    Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    if (asset == nullptr) {
+        return 0;
     }
 
-    jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset.release());
+    jlong id = (jlong)(uintptr_t)rsaFileA3DCreateFromAsset((RsContext)con, asset);
     return id;
 }
 
@@ -1757,25 +1752,22 @@
 nFontCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path,
                      jfloat fontSize, jint dpi)
 {
-    Guarded<AssetManager2>* mgr = AssetManagerForJavaObject(_env, _assetMgr);
+    AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
     if (mgr == nullptr) {
         return 0;
     }
 
     AutoJavaStringToUTF8 str(_env, _path);
-    std::unique_ptr<Asset> asset;
-    {
-        ScopedLock<AssetManager2> locked_mgr(*mgr);
-        asset = locked_mgr->Open(str.c_str(), Asset::ACCESS_BUFFER);
-        if (asset == nullptr) {
-            return 0;
-        }
+    Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
+    if (asset == nullptr) {
+        return 0;
     }
 
     jlong id = (jlong)(uintptr_t)rsFontCreateFromMemory((RsContext)con,
                                            str.c_str(), str.length(),
                                            fontSize, dpi,
                                            asset->getBuffer(false), asset->getLength());
+    delete asset;
     return id;
 }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index fc6058c..eba9830 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1020,7 +1020,7 @@
 
             // Disconnect from services for the old user.
             UserState oldUserState = getCurrentUserStateLocked();
-            oldUserState.onSwitchToAnotherUser();
+            oldUserState.onSwitchToAnotherUserLocked();
 
             // Disable the local managers for the old user.
             if (oldUserState.mUserClients.getRegisteredCallbackCount() > 0) {
@@ -1349,21 +1349,29 @@
     private void updateRelevantEventsLocked(UserState userState) {
         mMainHandler.post(() -> {
             broadcastToClients(userState, ignoreRemoteException(client -> {
-                int relevantEventTypes = computeRelevantEventTypes(userState, client);
+                int relevantEventTypes;
+                boolean changed = false;
+                synchronized (mLock) {
+                    relevantEventTypes = computeRelevantEventTypesLocked(userState, client);
 
-                if (client.mLastSentRelevantEventTypes != relevantEventTypes) {
-                    client.mLastSentRelevantEventTypes = relevantEventTypes;
+                    if (client.mLastSentRelevantEventTypes != relevantEventTypes) {
+                        client.mLastSentRelevantEventTypes = relevantEventTypes;
+                        changed = true;
+                    }
+                }
+                if (changed) {
                     client.mCallback.setRelevantEventTypes(relevantEventTypes);
                 }
             }));
         });
     }
 
-    private int computeRelevantEventTypes(UserState userState, Client client) {
+    private int computeRelevantEventTypesLocked(UserState userState, Client client) {
         int relevantEventTypes = 0;
 
-        // Use iterator for thread-safety
-        for (AccessibilityServiceConnection service : userState.mBoundServices) {
+        int serviceCount = userState.mBoundServices.size();
+        for (int i = 0; i < serviceCount; i++) {
+            AccessibilityServiceConnection service = userState.mBoundServices.get(i);
             relevantEventTypes |= isClientInPackageWhitelist(service.getServiceInfo(), client)
                     ? service.getRelevantEventTypes()
                     : 0;
@@ -3616,7 +3624,9 @@
         private Client(IAccessibilityManagerClient callback, int clientUid, UserState userState) {
             mCallback = callback;
             mPackageNames = mPackageManager.getPackagesForUid(clientUid);
-            mLastSentRelevantEventTypes = computeRelevantEventTypes(userState, this);
+            synchronized (mLock) {
+                mLastSentRelevantEventTypes = computeRelevantEventTypesLocked(userState, this);
+            }
         }
     }
 
@@ -3635,8 +3645,7 @@
 
         // Transient state.
 
-        public final CopyOnWriteArrayList<AccessibilityServiceConnection> mBoundServices =
-                new CopyOnWriteArrayList<>();
+        public final ArrayList<AccessibilityServiceConnection> mBoundServices = new ArrayList<>();
 
         public final Map<ComponentName, AccessibilityServiceConnection> mComponentNameToServiceMap =
                 new HashMap<>();
@@ -3698,7 +3707,7 @@
             return !mBoundServices.isEmpty() || !mBindingServices.isEmpty();
         }
 
-        public void onSwitchToAnotherUser() {
+        public void onSwitchToAnotherUserLocked() {
             // Unbind all services.
             unbindAllServicesLocked(this);
 
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 7ab5812..10fad62 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -55,6 +55,7 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.system.Os;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.util.ArrayMap;
@@ -99,7 +100,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.LocalLog;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.internal.util.Preconditions;
+import com.android.server.AppStateTracker.Listener;
 
 /**
  * Alarm manager implementaion.
@@ -158,6 +160,7 @@
     private long mNextNonWakeup;
     private long mLastWakeupSet;
     private long mLastWakeup;
+    private long mLastTrigger;
     private long mLastTickSet;
     private long mLastTickIssued; // elapsed
     private long mLastTickReceived;
@@ -250,7 +253,7 @@
     private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray =
             new SparseArray<>();
 
-    private final ForceAppStandbyTracker mForceAppStandbyTracker;
+    private AppStateTracker mAppStateTracker;
     private boolean mAppStandbyParole;
     private ArrayMap<Pair<String, Integer>, Long> mLastAlarmDeliveredForPackage = new ArrayMap<>();
 
@@ -708,9 +711,6 @@
         super(context);
         mConstants = new Constants(mHandler);
 
-        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
-        mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
-
         publishLocalService(AlarmManagerInternal.class, new LocalService());
     }
 
@@ -1330,13 +1330,15 @@
     @Override
     public void onBootPhase(int phase) {
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
-            mForceAppStandbyTracker.start();
             mConstants.start(getContext().getContentResolver());
             mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
             mLocalDeviceIdleController
                     = LocalServices.getService(DeviceIdleController.LocalService.class);
             mUsageStatsManagerInternal = LocalServices.getService(UsageStatsManagerInternal.class);
             mUsageStatsManagerInternal.addAppIdleStateChangeListener(new AppStandbyTracker());
+
+            mAppStateTracker = LocalServices.getService(AppStateTracker.class);
+            mAppStateTracker.addListener(mForceAppStandbyListener);
         }
     }
 
@@ -1725,7 +1727,8 @@
             // timing restrictions.
             } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
                     || UserHandle.isSameApp(callingUid, mSystemUiUid)
-                    || mForceAppStandbyTracker.isUidPowerSaveWhitelisted(callingUid))) {
+                    || ((mAppStateTracker != null)
+                        && mAppStateTracker.isUidPowerSaveWhitelisted(callingUid)))) {
                 flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
                 flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
             }
@@ -1808,8 +1811,10 @@
             mConstants.dump(pw);
             pw.println();
 
-            mForceAppStandbyTracker.dump(pw, "  ");
-            pw.println();
+            if (mAppStateTracker != null) {
+                mAppStateTracker.dump(pw, "  ");
+                pw.println();
+            }
 
             pw.println("  App Standby Parole: " + mAppStandbyParole);
             pw.println();
@@ -1836,27 +1841,32 @@
                 pw.print("  Time since non-interactive: ");
                 TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw);
                 pw.println();
-                pw.print("  Max wakeup delay: ");
-                TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
-                pw.println();
-                pw.print("  Time since last dispatch: ");
-                TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
-                pw.println();
-                pw.print("  Next non-wakeup delivery time: ");
-                TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
-                pw.println();
             }
+            pw.print("  Max wakeup delay: ");
+            TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw);
+            pw.println();
+            pw.print("  Time since last dispatch: ");
+            TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw);
+            pw.println();
+            pw.print("  Next non-wakeup delivery time: ");
+            TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw);
+            pw.println();
 
             long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED);
             long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED);
             pw.print("  Next non-wakeup alarm: ");
                     TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw);
+                    pw.print(" = "); pw.print(mNextNonWakeup);
                     pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC)));
-            pw.print("  Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
+            pw.print("  Next wakeup alarm: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw);
+                    pw.print(" = "); pw.print(mNextWakeup);
                     pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC)));
+            pw.print("    set at "); TimeUtils.formatDuration(mLastWakeupSet, nowELAPSED, pw);
+                    pw.println();
             pw.print("  Last wakeup: "); TimeUtils.formatDuration(mLastWakeup, nowELAPSED, pw);
-            pw.print(" set at "); TimeUtils.formatDuration(mLastWakeupSet, nowELAPSED, pw);
-            pw.println();
+                    pw.print(" = "); pw.println(mLastWakeup);
+            pw.print("  Last trigger: "); TimeUtils.formatDuration(mLastTrigger, nowELAPSED, pw);
+                    pw.print(" = "); pw.println(mLastTrigger);
             pw.print("  Num time change events: "); pw.println(mNumTimeChanged);
 
             pw.println();
@@ -2157,8 +2167,10 @@
 
             mConstants.dumpProto(proto, AlarmManagerServiceProto.SETTINGS);
 
-            mForceAppStandbyTracker.dumpProto(proto,
-                    AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
+            if (mAppStateTracker != null) {
+                mAppStateTracker.dumpProto(proto,
+                        AlarmManagerServiceProto.FORCE_APP_STANDBY_TRACKER);
+            }
 
             proto.write(AlarmManagerServiceProto.IS_INTERACTIVE, mInteractive);
             if (!mInteractive) {
@@ -2884,7 +2896,14 @@
                 alarmNanoseconds = (when % 1000) * 1000 * 1000;
             }
 
-            set(mNativeData, type, alarmSeconds, alarmNanoseconds);
+            final int result = set(mNativeData, type, alarmSeconds, alarmNanoseconds);
+            if (result != 0) {
+                final long nowElapsed = SystemClock.elapsedRealtime();
+                Slog.wtf(TAG, "Unable to set kernel alarm, now=" + nowElapsed
+                        + " type=" + type + " when=" + when
+                        + " @ (" + alarmSeconds + "," + alarmNanoseconds
+                        + "), ret = " + result + " = " + Os.strerror(result));
+            }
         } else {
             Message msg = Message.obtain();
             msg.what = ALARM_EVENT;
@@ -2938,20 +2957,21 @@
         }
         final String sourcePackage = alarm.sourcePackage;
         final int sourceUid = alarm.creatorUid;
-        return mForceAppStandbyTracker.areAlarmsRestricted(sourceUid, sourcePackage,
-                allowWhileIdle);
+        return (mAppStateTracker != null) &&
+                mAppStateTracker.areAlarmsRestricted(sourceUid, sourcePackage, allowWhileIdle);
     }
 
     private native long init();
     private native void close(long nativeData);
-    private native void set(long nativeData, int type, long seconds, long nanoseconds);
+    private native int set(long nativeData, int type, long seconds, long nanoseconds);
     private native int waitForAlarm(long nativeData);
     private native int setKernelTime(long nativeData, long millis);
     private native int setKernelTimezone(long nativeData, int minuteswest);
 
     private long getWhileIdleMinIntervalLocked(int uid) {
         final boolean dozing = mPendingIdleUntil != null;
-        final boolean ebs = mForceAppStandbyTracker.isForceAllAppsStandbyEnabled();
+        final boolean ebs = (mAppStateTracker != null)
+                && mAppStateTracker.isForceAllAppsStandbyEnabled();
         if (!dozing && !ebs) {
             return mConstants.ALLOW_WHILE_IDLE_SHORT_TIME;
         }
@@ -3363,12 +3383,14 @@
             while (true)
             {
                 int result = waitForAlarm(mNativeData);
-                mLastWakeup = SystemClock.elapsedRealtime();
-
-                triggerList.clear();
 
                 final long nowRTC = System.currentTimeMillis();
                 final long nowELAPSED = SystemClock.elapsedRealtime();
+                synchronized (mLock) {
+                    mLastWakeup = nowELAPSED;
+                }
+
+                triggerList.clear();
 
                 if ((result & TIME_CHANGED_MASK) != 0) {
                     // The kernel can give us spurious time change notifications due to
@@ -3434,6 +3456,7 @@
                             }
                         }
 
+                        mLastTrigger = nowELAPSED;
                         boolean hasWakeup = triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
                         if (!hasWakeup && checkAllowNonWakeupDelayLocked(nowELAPSED)) {
                             // if there are no wakeup alarms and the screen is off, we can
@@ -4139,7 +4162,8 @@
             if (allowWhileIdle) {
                 // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
                 mLastAllowWhileIdleDispatch.put(alarm.creatorUid, nowELAPSED);
-                if (mForceAppStandbyTracker.isUidInForeground(alarm.creatorUid)) {
+                if ((mAppStateTracker == null)
+                        || mAppStateTracker.isUidInForeground(alarm.creatorUid)) {
                     mUseAllowWhileIdleShortTime.put(alarm.creatorUid, true);
                 } else {
                     mUseAllowWhileIdleShortTime.put(alarm.creatorUid, false);
diff --git a/services/core/java/com/android/server/ForceAppStandbyTracker.java b/services/core/java/com/android/server/AppStateTracker.java
similarity index 95%
rename from services/core/java/com/android/server/ForceAppStandbyTracker.java
rename to services/core/java/com/android/server/AppStateTracker.java
index b65d126..9b29b32 100644
--- a/services/core/java/com/android/server/ForceAppStandbyTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -54,7 +54,6 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
-import com.android.server.DeviceIdleController.LocalService;
 import com.android.server.ForceAppStandbyTrackerProto.ExemptedPackage;
 import com.android.server.ForceAppStandbyTrackerProto.RunAnyInBackgroundRestrictedPackages;
 
@@ -73,14 +72,14 @@
  * TODO: Make it a LocalService.
  *
  * Test:
-  atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+  atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
  */
-public class ForceAppStandbyTracker {
+public class AppStateTracker {
     private static final String TAG = "ForceAppStandbyTracker";
     private static final boolean DEBUG = true;
 
-    @GuardedBy("ForceAppStandbyTracker.class")
-    private static ForceAppStandbyTracker sInstance;
+    @GuardedBy("AppStateTracker.class")
+    private static AppStateTracker sInstance;
 
     private final Object mLock = new Object();
     private final Context mContext;
@@ -89,6 +88,7 @@
     static final int TARGET_OP = AppOpsManager.OP_RUN_ANY_IN_BACKGROUND;
 
     IActivityManager mIActivityManager;
+    ActivityManagerInternal mActivityManagerInternal;
     AppOpsManager mAppOpsManager;
     IAppOpsService mAppOpsService;
     PowerManagerInternal mPowerManagerInternal;
@@ -172,6 +172,9 @@
         int EXEMPT_CHANGED = 6;
         int FORCE_ALL_CHANGED = 7;
         int FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED = 8;
+
+        int IS_UID_ACTIVE_CACHED = 9;
+        int IS_UID_ACTIVE_RAW = 10;
     }
 
     private final StatLogger mStatLogger = new StatLogger(new String[] {
@@ -184,6 +187,9 @@
             "EXEMPT_CHANGED",
             "FORCE_ALL_CHANGED",
             "FORCE_APP_STANDBY_FEATURE_FLAG_CHANGED",
+
+            "IS_UID_ACTIVE_CACHED",
+            "IS_UID_ACTIVE_RAW",
     });
 
     @VisibleForTesting
@@ -249,7 +255,7 @@
         /**
          * This is called when the OP_RUN_ANY_IN_BACKGROUND appops changed for a package.
          */
-        private void onRunAnyAppOpsChanged(ForceAppStandbyTracker sender,
+        private void onRunAnyAppOpsChanged(AppStateTracker sender,
                 int uid, @NonNull String packageName) {
             updateJobsForUidPackage(uid, packageName);
 
@@ -264,14 +270,14 @@
         /**
          * This is called when the foreground state changed for a UID.
          */
-        private void onUidForegroundStateChanged(ForceAppStandbyTracker sender, int uid) {
+        private void onUidForegroundStateChanged(AppStateTracker sender, int uid) {
             onUidForeground(uid, sender.isUidInForeground(uid));
         }
 
         /**
          * This is called when the active/idle state changed for a UID.
          */
-        private void onUidActiveStateChanged(ForceAppStandbyTracker sender, int uid) {
+        private void onUidActiveStateChanged(AppStateTracker sender, int uid) {
             updateJobsForUid(uid);
 
             if (sender.isUidActive(uid)) {
@@ -282,7 +288,7 @@
         /**
          * This is called when an app-id(s) is removed from the power save whitelist.
          */
-        private void onPowerSaveUnwhitelisted(ForceAppStandbyTracker sender) {
+        private void onPowerSaveUnwhitelisted(AppStateTracker sender) {
             updateAllJobs();
             unblockAllUnrestrictedAlarms();
         }
@@ -291,14 +297,14 @@
          * This is called when the power save whitelist changes, excluding the
          * {@link #onPowerSaveUnwhitelisted} case.
          */
-        private void onPowerSaveWhitelistedChanged(ForceAppStandbyTracker sender) {
+        private void onPowerSaveWhitelistedChanged(AppStateTracker sender) {
             updateAllJobs();
         }
 
         /**
          * This is called when the temp whitelist changes.
          */
-        private void onTempPowerSaveWhitelistChanged(ForceAppStandbyTracker sender) {
+        private void onTempPowerSaveWhitelistChanged(AppStateTracker sender) {
 
             // TODO This case happens rather frequently; consider optimizing and update jobs
             // only for affected app-ids.
@@ -311,7 +317,7 @@
         /**
          * This is called when the EXEMPT bucket is updated.
          */
-        private void onExemptChanged(ForceAppStandbyTracker sender) {
+        private void onExemptChanged(AppStateTracker sender) {
             // This doesn't happen very often, so just re-evaluate all jobs / alarms.
             updateAllJobs();
             unblockAllUnrestrictedAlarms();
@@ -320,7 +326,7 @@
         /**
          * This is called when the global "force all apps standby" flag changes.
          */
-        private void onForceAllAppsStandbyChanged(ForceAppStandbyTracker sender) {
+        private void onForceAllAppsStandbyChanged(AppStateTracker sender) {
             updateAllJobs();
 
             if (!sender.isForceAllAppsStandbyEnabled()) {
@@ -377,30 +383,15 @@
         }
     }
 
-    @VisibleForTesting
-    ForceAppStandbyTracker(Context context, Looper looper) {
+    public AppStateTracker(Context context, Looper looper) {
         mContext = context;
         mHandler = new MyHandler(looper);
     }
 
-    private ForceAppStandbyTracker(Context context) {
-        this(context, FgThread.get().getLooper());
-    }
-
-    /**
-     * Get the singleton instance.
-     */
-    public static synchronized ForceAppStandbyTracker getInstance(Context context) {
-        if (sInstance == null) {
-            sInstance = new ForceAppStandbyTracker(context);
-        }
-        return sInstance;
-    }
-
     /**
      * Call it when the system is ready.
      */
-    public void start() {
+    public void onSystemServicesReady() {
         synchronized (mLock) {
             if (mStarted) {
                 return;
@@ -408,6 +399,7 @@
             mStarted = true;
 
             mIActivityManager = Preconditions.checkNotNull(injectIActivityManager());
+            mActivityManagerInternal = Preconditions.checkNotNull(injectActivityManagerInternal());
             mAppOpsManager = Preconditions.checkNotNull(injectAppOpsManager());
             mAppOpsService = Preconditions.checkNotNull(injectIAppOpsService());
             mPowerManagerInternal = Preconditions.checkNotNull(injectPowerManagerInternal());
@@ -475,6 +467,11 @@
     }
 
     @VisibleForTesting
+    ActivityManagerInternal injectActivityManagerInternal() {
+        return LocalServices.getService(ActivityManagerInternal.class);
+    }
+
+    @VisibleForTesting
     PowerManagerInternal injectPowerManagerInternal() {
         return LocalServices.getService(PowerManagerInternal.class);
     }
@@ -804,7 +801,7 @@
                     return;
                 }
             }
-            final ForceAppStandbyTracker sender = ForceAppStandbyTracker.this;
+            final AppStateTracker sender = AppStateTracker.this;
 
             long start = mStatLogger.getTime();
             switch (msg.what) {
@@ -1094,11 +1091,11 @@
     }
 
     /**
-     * @return whether a UID is in active or not.
+     * @return whether a UID is in active or not *based on cached information.*
      *
      * Note this information is based on the UID proc state callback, meaning it's updated
      * asynchronously and may subtly be stale. If the fresh data is needed, use
-     * {@link ActivityManagerInternal#getUidProcessState} instead.
+     * {@link #isUidActiveSynced} instead.
      */
     public boolean isUidActive(int uid) {
         if (UserHandle.isCore(uid)) {
@@ -1110,6 +1107,23 @@
     }
 
     /**
+     * @return whether a UID is in active or not *right now.*
+     *
+     * This gives the fresh information, but may access the activity manager so is slower.
+     */
+    public boolean isUidActiveSynced(int uid) {
+        if (isUidActive(uid)) { // Use the cached one first.
+            return true;
+        }
+        final long start = mStatLogger.getTime();
+
+        final boolean ret = mActivityManagerInternal.isUidActive(uid);
+        mStatLogger.logDurationStat(Stats.IS_UID_ACTIVE_RAW, start);
+
+        return ret;
+    }
+
+    /**
      * @return whether a UID is in the foreground or not.
      *
      * Note this information is based on the UID proc state callback, meaning it's updated
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 2077790..55ad8cc 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -948,8 +948,11 @@
         return true;
     }
 
-    private boolean startConsentUiIfNeeded(String packageName, int callingUid, String intentAction)
-            throws RemoteException {
+    private boolean startConsentUiIfNeeded(String packageName,
+            int callingUid, String intentAction) throws RemoteException {
+        if (checkBluetoothPermissionWhenPermissionReviewRequired()) {
+            return false;
+        }
         try {
             // Validate the package only if we are going to use it
             ApplicationInfo applicationInfo = mContext.getPackageManager()
@@ -957,7 +960,8 @@
                             PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                             UserHandle.getUserId(callingUid));
             if (applicationInfo.uid != callingUid) {
-                throw new SecurityException("Package " + callingUid + " not in uid " + callingUid);
+                throw new SecurityException("Package " + packageName
+                        + " not in uid " + callingUid);
             }
 
             Intent intent = new Intent(intentAction);
@@ -977,6 +981,26 @@
         }
     }
 
+    /**
+     * Check if the caller must still pass permission check or if the caller is exempted
+     * from the consent UI via the MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED check.
+     *
+     * Commands from some callers may be exempted from triggering the consent UI when
+     * enabling bluetooth. This exemption is checked via the
+     * MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED and allows calls to skip
+     * the consent UI where it may otherwise be required.
+     *
+     * @hide
+     */
+    private boolean checkBluetoothPermissionWhenPermissionReviewRequired() {
+        if (!mPermissionReviewRequired) {
+            return false;
+        }
+        int result = mContext.checkCallingPermission(
+                android.Manifest.permission.MANAGE_BLUETOOTH_WHEN_PERMISSION_REVIEW_REQUIRED);
+        return result == PackageManager.PERMISSION_GRANTED;
+    }
+
     public void unbindAndFinish() {
         if (DBG) {
             Slog.d(TAG, "unbindAndFinish(): " + mBluetooth + " mBinding = " + mBinding
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 3bfa31a..efad7d5 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1402,7 +1402,8 @@
     public boolean isActiveNetworkMetered() {
         enforceAccessPermission();
 
-        final NetworkCapabilities caps = getNetworkCapabilities(getActiveNetwork());
+        final int uid = Binder.getCallingUid();
+        final NetworkCapabilities caps = getUnfilteredActiveNetworkState(uid).networkCapabilities;
         if (caps != null) {
             return !caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
         } else {
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 44974ff..2b3c585 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -82,6 +82,7 @@
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.net.NetworkPolicyManagerInternal;
@@ -128,6 +129,7 @@
     private Intent mIdleIntent;
     private Intent mLightIdleIntent;
     private AnyMotionDetector mAnyMotionDetector;
+    private final AppStateTracker mAppStateTracker;
     private boolean mLightEnabled;
     private boolean mDeepEnabled;
     private boolean mForceIdle;
@@ -1371,6 +1373,8 @@
         super(context);
         mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
         mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
+        mAppStateTracker = new AppStateTracker(context, FgThread.get().getLooper());
+        LocalServices.addService(AppStateTracker.class, mAppStateTracker);
     }
 
     boolean isAppOnWhitelistInternal(int appid) {
@@ -1501,6 +1505,8 @@
                         (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
                         mHandler, mSensorManager, this, angleThreshold);
 
+                mAppStateTracker.onSystemServicesReady();
+
                 mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
                 mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_FOREGROUND);
@@ -2615,7 +2621,7 @@
     }
 
     private void passWhiteListToForceAppStandbyTrackerLocked() {
-        ForceAppStandbyTracker.getInstance(getContext()).setPowerSaveWhitelistAppIds(
+        mAppStateTracker.setPowerSaveWhitelistAppIds(
                 mPowerSaveWhitelistExceptIdleAppIdArray,
                 mTempWhitelistAppIdArray);
     }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index a07a982..45a4dfb9 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1438,7 +1438,9 @@
 
         switch (config.getMode()) {
             case IpSecTransform.MODE_TRANSPORT:
+                break;
             case IpSecTransform.MODE_TUNNEL:
+                enforceNetworkStackPermission();
                 break;
             default:
                 throw new IllegalArgumentException(
@@ -1446,6 +1448,11 @@
         }
     }
 
+    private void enforceNetworkStackPermission() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
+                "IpSecService");
+    }
+
     private void createOrUpdateTransform(
             IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord)
             throws RemoteException {
@@ -1615,6 +1622,7 @@
     @Override
     public synchronized void applyTunnelModeTransform(
             int tunnelResourceId, int direction, int transformResourceId) throws RemoteException {
+        enforceNetworkStackPermission();
         checkDirection(direction);
 
         UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/StatLogger.java b/services/core/java/com/android/server/StatLogger.java
index f211731..0e6f5e2 100644
--- a/services/core/java/com/android/server/StatLogger.java
+++ b/services/core/java/com/android/server/StatLogger.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.os.SystemClock;
+import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
@@ -33,6 +34,8 @@
  * @hide
  */
 public class StatLogger {
+    private static final String TAG = "StatLogger";
+
     private final Object mLock = new Object();
 
     private final int SIZE;
@@ -66,8 +69,12 @@
      */
     public void logDurationStat(int eventId, long start) {
         synchronized (mLock) {
-            mCountStats[eventId]++;
-            mDurationStats[eventId] += (getTime() - start);
+            if (eventId >= 0 && eventId < SIZE) {
+                mCountStats[eventId]++;
+                mDurationStats[eventId] += (getTime() - start);
+            } else {
+                Slog.wtf(TAG, "Invalid event ID: " + eventId);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 0baa3d0..7fe5d7c 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -912,6 +912,7 @@
         Vibration fallbackVib =
                 new Vibration(vib.token, effect, vib.usageHint, vib.uid, vib.opPkg);
         final int intensity = getCurrentIntensityLocked(fallbackVib);
+        linkVibration(fallbackVib);
         applyVibrationIntensityScalingLocked(fallbackVib, intensity);
         startVibrationInnerLocked(fallbackVib);
         return 0;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 5215b6f..c8e0a5e 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -558,14 +558,7 @@
                 Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");
             } else {
                 Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject);
-                for (int i=0; i<blockedCheckers.size(); i++) {
-                    Slog.w(TAG, blockedCheckers.get(i).getName() + " stack trace:");
-                    StackTraceElement[] stackTrace
-                            = blockedCheckers.get(i).getThread().getStackTrace();
-                    for (StackTraceElement element: stackTrace) {
-                        Slog.w(TAG, "    at " + element);
-                    }
-                }
+                WatchdogDiagnostics.diagnoseCheckers(blockedCheckers);
                 Slog.w(TAG, "*** GOODBYE!");
                 Process.killProcess(Process.myPid());
                 System.exit(10);
diff --git a/services/core/java/com/android/server/WatchdogDiagnostics.java b/services/core/java/com/android/server/WatchdogDiagnostics.java
new file mode 100644
index 0000000..01db2d3
--- /dev/null
+++ b/services/core/java/com/android/server/WatchdogDiagnostics.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.util.Log;
+import android.util.LogWriter;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.Watchdog.HandlerChecker;
+
+import dalvik.system.AnnotatedStackTraceElement;
+import dalvik.system.VMStack;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Class to give diagnostic messages for Watchdogs.
+ */
+class WatchdogDiagnostics {
+    private static String getBlockedOnString(Object blockedOn) {
+        return String.format("- waiting to lock <0x%08x> (a %s)",
+                System.identityHashCode(blockedOn), blockedOn.getClass().getName());
+    }
+
+    private static String getLockedString(Object heldLock) {
+        return String.format("- locked <0x%08x> (a %s)", System.identityHashCode(heldLock),
+                heldLock.getClass().getName());
+    }
+
+    /**
+     * Print the annotated stack for the given thread. If the annotated stack cannot be retrieved,
+     * returns false.
+     */
+    @VisibleForTesting
+    public static boolean printAnnotatedStack(Thread thread, PrintWriter out) {
+        AnnotatedStackTraceElement stack[] = VMStack.getAnnotatedThreadStackTrace(thread);
+        if (stack == null) {
+            return false;
+        }
+        out.println(thread.getName() + " annotated stack trace:");
+        for (AnnotatedStackTraceElement element : stack) {
+            out.println("    at " + element.getStackTraceElement());
+            if (element.getBlockedOn() != null) {
+                out.println("    " + getBlockedOnString(element.getBlockedOn()));
+            }
+            if (element.getHeldLocks() != null) {
+                for (Object held : element.getHeldLocks()) {
+                    out.println("    " + getLockedString(held));
+                }
+            }
+        }
+        return true;
+    }
+
+    public static void diagnoseCheckers(final List<HandlerChecker> blockedCheckers) {
+        PrintWriter out = new PrintWriter(new LogWriter(Log.WARN, Watchdog.TAG, Log.LOG_ID_SYSTEM),
+                true);
+        for (int i=0; i<blockedCheckers.size(); i++) {
+            Thread blockedThread = blockedCheckers.get(i).getThread();
+            if (printAnnotatedStack(blockedThread, out)) {
+                continue;
+            }
+
+            // Fall back to "regular" stack trace, if necessary.
+            Slog.w(Watchdog.TAG, blockedThread.getName() + " stack trace:");
+            StackTraceElement[] stackTrace = blockedThread.getStackTrace();
+            for (StackTraceElement element : stackTrace) {
+                Slog.w(Watchdog.TAG, "    at " + element);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index 220014f..608352b 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -657,6 +657,26 @@
         return false;
     }
 
+    void remove() {
+        final boolean destroyContentOnRemoval = shouldDestroyContentOnRemove();
+        while (getChildCount() > 0) {
+            final ActivityStack stack = getChildAt(0);
+            if (destroyContentOnRemoval) {
+                mSupervisor.moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY,
+                        false /* onTop */);
+                stack.finishAllActivitiesLocked(true /* immediately */);
+            } else {
+                // Moving all tasks to fullscreen stack, because it's guaranteed to be
+                // a valid launch stack for all activities. This way the task history from
+                // external display will be preserved on primary after move.
+                mSupervisor.moveTasksToFullscreenStackLocked(stack, true /* onTop */);
+            }
+        }
+
+        mWindowContainerController.removeContainer();
+        mWindowContainerController = null;
+    }
+
     /** Update and get all UIDs that are present on the display and have access to it. */
     IntArray getPresentUIDs() {
         mDisplayAccessUIDs.clear();
@@ -666,7 +686,7 @@
         return mDisplayAccessUIDs;
     }
 
-    boolean shouldDestroyContentOnRemove() {
+    private boolean shouldDestroyContentOnRemove() {
         return mDisplay.getRemoveMode() == REMOVE_MODE_DESTROY_CONTENT;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e44223b..cd8b6d7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -25966,6 +25966,14 @@
         public boolean isCallerRecents(int callingUid) {
             return getRecentTasks().isCallerRecents(callingUid);
         }
+
+        @Override
+        public boolean isUidActive(int uid) {
+            synchronized (ActivityManagerService.this) {
+                final UidRecord uidRec = mActiveUids.get(uid);
+                return (uidRec != null) && !uidRec.idle;
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 66f0592..e2ceb31ce 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -32,6 +32,8 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.MemoryStatUtil.MemoryStat;
+import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg;
 
 import android.content.Context;
 import android.metrics.LogMaker;
@@ -67,6 +69,7 @@
     private static final long INVALID_START_TIME = -1;
 
     private static final int MSG_CHECK_VISIBILITY = 0;
+    private static final int MSG_LOG_APP_START_MEMORY_STATE_CAPTURE = 1;
 
     // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
     // time we log.
@@ -102,6 +105,9 @@
                     final SomeArgs args = (SomeArgs) msg.obj;
                     checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
                     break;
+                case MSG_LOG_APP_START_MEMORY_STATE_CAPTURE:
+                    logAppStartMemoryStateCapture((StackTransitionInfo) msg.obj);
+                    break;
             }
         }
     };
@@ -187,10 +193,7 @@
      * @param launchedActivity the activity that is being launched
      */
     void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity) {
-        final ProcessRecord processRecord = launchedActivity != null
-                ? mSupervisor.mService.mProcessNames.get(launchedActivity.processName,
-                        launchedActivity.appInfo.uid)
-                : null;
+        final ProcessRecord processRecord = findProcessForActivity(launchedActivity);
         final boolean processRunning = processRecord != null;
 
         // We consider this a "process switch" if the process of the activity that gets launched
@@ -492,6 +495,7 @@
                     info.bindApplicationDelayMs,
                     info.windowsDrawnDelayMs,
                     launchToken);
+            mHandler.obtainMessage(MSG_LOG_APP_START_MEMORY_STATE_CAPTURE, info).sendToTarget();
         }
     }
 
@@ -548,4 +552,38 @@
         }
         return -1;
     }
+
+    private void logAppStartMemoryStateCapture(StackTransitionInfo info) {
+        final ProcessRecord processRecord = findProcessForActivity(info.launchedActivity);
+        if (processRecord == null) {
+            if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null");
+            return;
+        }
+
+        final int pid = processRecord.pid;
+        final int uid = info.launchedActivity.appInfo.uid;
+        final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid);
+        if (memoryStat == null) {
+            if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null");
+            return;
+        }
+
+        StatsLog.write(
+                StatsLog.APP_START_MEMORY_STATE_CAPTURED,
+                uid,
+                info.launchedActivity.processName,
+                info.launchedActivity.info.name,
+                memoryStat.pgfault,
+                memoryStat.pgmajfault,
+                memoryStat.rssInBytes,
+                memoryStat.cacheInBytes,
+                memoryStat.swapInBytes);
+    }
+
+    private ProcessRecord findProcessForActivity(ActivityRecord launchedActivity) {
+        return launchedActivity != null
+                ? mSupervisor.mService.mProcessNames.get(launchedActivity.processName,
+                        launchedActivity.appInfo.uid)
+                : null;
+    }
 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 831f89a..4928e90 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4092,25 +4092,12 @@
             if (activityDisplay == null) {
                 return;
             }
-            final boolean destroyContentOnRemoval
-                    = activityDisplay.shouldDestroyContentOnRemove();
-            while (activityDisplay.getChildCount() > 0) {
-                final ActivityStack stack = activityDisplay.getChildAt(0);
-                if (destroyContentOnRemoval) {
-                    moveStackToDisplayLocked(stack.mStackId, DEFAULT_DISPLAY, false /* onTop */);
-                    stack.finishAllActivitiesLocked(true /* immediately */);
-                } else {
-                    // Moving all tasks to fullscreen stack, because it's guaranteed to be
-                    // a valid launch stack for all activities. This way the task history from
-                    // external display will be preserved on primary after move.
-                    moveTasksToFullscreenStackLocked(stack, true /* onTop */);
-                }
-            }
+
+            activityDisplay.remove();
 
             releaseSleepTokens(activityDisplay);
 
             mActivityDisplays.remove(displayId);
-            mWindowManager.onDisplayRemoved(displayId);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/MemoryStatUtil.java b/services/core/java/com/android/server/am/MemoryStatUtil.java
new file mode 100644
index 0000000..d97c2a2
--- /dev/null
+++ b/services/core/java/com/android/server/am/MemoryStatUtil.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.Nullable;
+import android.os.FileUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Static utility methods related to {@link MemoryStat}.
+ */
+final class MemoryStatUtil {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "MemoryStatUtil" : TAG_AM;
+
+    /** Path to memory stat file for logging app start memory state */
+    private static final String MEMORY_STAT_FILE_FMT = "/dev/memcg/apps/uid_%d/pid_%d/memory.stat";
+
+    private static final Pattern PGFAULT = Pattern.compile("total_pgfault (\\d+)");
+    private static final Pattern PGMAJFAULT = Pattern.compile("total_pgmajfault (\\d+)");
+    private static final Pattern RSS_IN_BYTES = Pattern.compile("total_rss (\\d+)");
+    private static final Pattern CACHE_IN_BYTES = Pattern.compile("total_cache (\\d+)");
+    private static final Pattern SWAP_IN_BYTES = Pattern.compile("total_swap (\\d+)");
+
+    private MemoryStatUtil() {}
+
+    /**
+     * Reads memory.stat of a process from memcg.
+     */
+    static @Nullable MemoryStat readMemoryStatFromMemcg(int uid, int pid) {
+        final String memoryStatPath = String.format(MEMORY_STAT_FILE_FMT, uid, pid);
+        final File memoryStatFile = new File(memoryStatPath);
+        if (!memoryStatFile.exists()) {
+            if (DEBUG_METRICS) Slog.i(TAG, memoryStatPath + " not found");
+            return null;
+        }
+
+        try {
+            final String memoryStatContents = FileUtils.readTextFile(
+                    memoryStatFile, 0 /* max */, null /* ellipsis */);
+            return parseMemoryStat(memoryStatContents);
+        } catch (IOException e) {
+            Slog.e(TAG, "Failed to read file:", e);
+            return null;
+        }
+    }
+
+    /**
+     * Parses relevant statistics out from the contents of a memory.stat file in memcg.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    static @Nullable MemoryStat parseMemoryStat(String memoryStatContents) {
+        MemoryStat memoryStat = new MemoryStat();
+        if (memoryStatContents == null) {
+            return memoryStat;
+        }
+
+        Matcher m;
+        m = PGFAULT.matcher(memoryStatContents);
+        memoryStat.pgfault = m.find() ? Long.valueOf(m.group(1)) : 0;
+        m = PGMAJFAULT.matcher(memoryStatContents);
+        memoryStat.pgmajfault = m.find() ? Long.valueOf(m.group(1)) : 0;
+        m = RSS_IN_BYTES.matcher(memoryStatContents);
+        memoryStat.rssInBytes = m.find() ? Long.valueOf(m.group(1)) : 0;
+        m = CACHE_IN_BYTES.matcher(memoryStatContents);
+        memoryStat.cacheInBytes = m.find() ? Long.valueOf(m.group(1)) : 0;
+        m = SWAP_IN_BYTES.matcher(memoryStatContents);
+        memoryStat.swapInBytes = m.find() ? Long.valueOf(m.group(1)) : 0;
+        return memoryStat;
+    }
+
+    static final class MemoryStat {
+        /** Number of page faults */
+        long pgfault;
+        /** Number of major page faults */
+        long pgmajfault;
+        /** Number of bytes of anonymous and swap cache memory */
+        long rssInBytes;
+        /** Number of bytes of page cache memory */
+        long cacheInBytes;
+        /** Number of bytes of swap usage */
+        long swapInBytes;
+    }
+}
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
index e77cb7a..2a9d3860 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/Tuner.java
@@ -98,10 +98,6 @@
     private native boolean nativeIsAnalogForced(long nativeContext);
     private native void nativeSetAnalogForced(long nativeContext, boolean isForced);
 
-    private native Map<String, String> nativeSetParameters(long nativeContext,
-            Map<String, String> parameters);
-    private native Map<String, String> nativeGetParameters(long nativeContext, List<String> keys);
-
     @Override
     public void close() {
         synchronized (mLock) {
@@ -291,26 +287,11 @@
 
     @Override
     public Map setParameters(Map parameters) {
-        Map<String, String> results;
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            results = nativeSetParameters(mNativeContext, Objects.requireNonNull(parameters));
-        }
-        if (results == null) return Collections.emptyMap();
-        return results;
+        throw new UnsupportedOperationException("Not supported by HAL 1.x");
     }
 
     @Override
     public Map getParameters(List<String> keys) {
-        if (keys == null) {
-            throw new IllegalArgumentException("The argument must not be a null pointer");
-        }
-        Map<String, String> results;
-        synchronized (mLock) {
-            checkNotClosedLocked();
-            results = nativeGetParameters(mNativeContext, keys);
-        }
-        if (results == null) return Collections.emptyMap();
-        return results;
+        throw new UnsupportedOperationException("Not supported by HAL 1.x");
     }
 }
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
index 04c0e57..7ad73c3 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/TunerCallback.java
@@ -169,7 +169,7 @@
 
     @Override
     public void onParametersUpdated(Map parameters) {
-        dispatch(() -> mClientCallback.onParametersUpdated(parameters));
+        Slog.e(TAG, "Not applicable for HAL 1.x");
     }
 
     @Override
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 401c05e..47a4fb2 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -40,7 +40,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.Intent.UriFlags;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
@@ -79,7 +78,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.server.DeviceIdleController;
 import com.android.server.FgThread;
-import com.android.server.ForceAppStandbyTracker;
+import com.android.server.AppStateTracker;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerServiceDumpProto.ActiveJob;
 import com.android.server.job.JobSchedulerServiceDumpProto.PendingJob;
@@ -184,7 +183,7 @@
     ActivityManagerInternal mActivityManagerInternal;
     IBatteryStats mBatteryStats;
     DeviceIdleController.LocalService mLocalDeviceIdleController;
-    final ForceAppStandbyTracker mForceAppStandbyTracker;
+    AppStateTracker mAppStateTracker;
 
     /**
      * Set to true once we are allowed to run third party apps.
@@ -787,20 +786,13 @@
     }
 
     /**
-     * Return whether an UID is in the foreground or not.
+     * Return whether an UID is active or idle.
      */
-    private boolean isUidInForeground(int uid) {
-        synchronized (mLock) {
-            if (mUidPriorityOverride.get(uid, 0) > 0) {
-                return true;
-            }
-        }
-        // Note UID observer may not be called in time, so we always check with the AM.
-        return mActivityManagerInternal.getUidProcessState(uid)
-                <= ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+    private boolean isUidActive(int uid) {
+        return mAppStateTracker.isUidActiveSynced(uid);
     }
 
-    private final Predicate<Integer> mIsUidInForegroundPredicate = this::isUidInForeground;
+    private final Predicate<Integer> mIsUidActivePredicate = this::isUidActive;
 
     public int scheduleAsPackage(JobInfo job, JobWorkItem work, int uId, String packageName,
             int userId, String tag) {
@@ -826,7 +818,7 @@
 
                     // If any of work item is enqueued when the source is in the foreground,
                     // exempt the entire job.
-                    toCancel.maybeAddForegroundExemption(mIsUidInForegroundPredicate);
+                    toCancel.maybeAddForegroundExemption(mIsUidActivePredicate);
 
                     return JobScheduler.RESULT_SUCCESS;
                 }
@@ -838,7 +830,7 @@
             // Note if it's a sync job, this method is called on the handler so it's not exactly
             // the state when requestSync() was called, but that should be fine because of the
             // 1 minute foreground grace period.
-            jobStatus.maybeAddForegroundExemption(mIsUidInForegroundPredicate);
+            jobStatus.maybeAddForegroundExemption(mIsUidActivePredicate);
 
             if (DEBUG) Slog.d(TAG, "SCHEDULE: " + jobStatus.toShortString());
             // Jobs on behalf of others don't apply to the per-app job cap
@@ -1123,8 +1115,6 @@
         mDeviceIdleJobsController = DeviceIdleJobsController.get(this);
         mControllers.add(mDeviceIdleJobsController);
 
-        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
-
         // If the job store determined that it can't yet reschedule persisted jobs,
         // we need to start watching the clock.
         if (!mJobs.jobTimesInflatedValid()) {
@@ -1185,7 +1175,8 @@
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
             mConstants.start(getContext().getContentResolver());
 
-            mForceAppStandbyTracker.start();
+            mAppStateTracker = Preconditions.checkNotNull(
+                    LocalServices.getService(AppStateTracker.class));
 
             // Register br for package removals and user removals.
             final IntentFilter filter = new IntentFilter();
diff --git a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
index 5eb7700..e8057fb 100644
--- a/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/BackgroundJobsController.java
@@ -22,8 +22,10 @@
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
 
-import com.android.server.ForceAppStandbyTracker;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.internal.util.Preconditions;
+import com.android.server.AppStateTracker;
+import com.android.server.AppStateTracker.Listener;
+import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
 import com.android.server.job.JobStore;
 import com.android.server.job.StateControllerProto;
@@ -42,8 +44,7 @@
 
     private final JobSchedulerService mJobSchedulerService;
 
-    private final ForceAppStandbyTracker mForceAppStandbyTracker;
-
+    private final AppStateTracker mAppStateTracker;
 
     public static BackgroundJobsController get(JobSchedulerService service) {
         synchronized (sCreationLock) {
@@ -59,10 +60,9 @@
         super(service, context, lock);
         mJobSchedulerService = service;
 
-        mForceAppStandbyTracker = ForceAppStandbyTracker.getInstance(context);
-
-        mForceAppStandbyTracker.addListener(mForceAppStandbyListener);
-        mForceAppStandbyTracker.start();
+        mAppStateTracker = Preconditions.checkNotNull(
+                LocalServices.getService(AppStateTracker.class));
+        mAppStateTracker.addListener(mForceAppStandbyListener);
     }
 
     @Override
@@ -79,7 +79,7 @@
     public void dumpControllerStateLocked(final PrintWriter pw, final int filterUid) {
         pw.println("BackgroundJobsController");
 
-        mForceAppStandbyTracker.dump(pw, "");
+        mAppStateTracker.dump(pw, "");
 
         pw.println("Job state:");
         mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
@@ -92,16 +92,16 @@
             jobStatus.printUniqueId(pw);
             pw.print(" from ");
             UserHandle.formatUid(pw, uid);
-            pw.print(mForceAppStandbyTracker.isUidActive(uid) ? " active" : " idle");
-            if (mForceAppStandbyTracker.isUidPowerSaveWhitelisted(uid) ||
-                    mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(uid)) {
+            pw.print(mAppStateTracker.isUidActive(uid) ? " active" : " idle");
+            if (mAppStateTracker.isUidPowerSaveWhitelisted(uid) ||
+                    mAppStateTracker.isUidTempPowerSaveWhitelisted(uid)) {
                 pw.print(", whitelisted");
             }
             pw.print(": ");
             pw.print(sourcePkg);
 
             pw.print(" [RUN_ANY_IN_BACKGROUND ");
-            pw.print(mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg)
+            pw.print(mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(uid, sourcePkg)
                     ? "allowed]" : "disallowed]");
 
             if ((jobStatus.satisfiedConstraints
@@ -118,7 +118,7 @@
         final long token = proto.start(fieldId);
         final long mToken = proto.start(StateControllerProto.BACKGROUND);
 
-        mForceAppStandbyTracker.dumpProto(proto,
+        mAppStateTracker.dumpProto(proto,
                 StateControllerProto.BackgroundJobsController.FORCE_APP_STANDBY_TRACKER);
 
         mJobSchedulerService.getJobStore().forEachJob((jobStatus) -> {
@@ -136,14 +136,14 @@
             proto.write(TrackedJob.SOURCE_PACKAGE_NAME, sourcePkg);
 
             proto.write(TrackedJob.IS_IN_FOREGROUND,
-                    mForceAppStandbyTracker.isUidActive(sourceUid));
+                    mAppStateTracker.isUidActive(sourceUid));
             proto.write(TrackedJob.IS_WHITELISTED,
-                    mForceAppStandbyTracker.isUidPowerSaveWhitelisted(sourceUid) ||
-                    mForceAppStandbyTracker.isUidTempPowerSaveWhitelisted(sourceUid));
+                    mAppStateTracker.isUidPowerSaveWhitelisted(sourceUid) ||
+                    mAppStateTracker.isUidTempPowerSaveWhitelisted(sourceUid));
 
             proto.write(
                     TrackedJob.CAN_RUN_ANY_IN_BACKGROUND,
-                    mForceAppStandbyTracker.isRunAnyInBackgroundAppOpsAllowed(
+                    mAppStateTracker.isRunAnyInBackgroundAppOpsAllowed(
                             sourceUid, sourcePkg));
 
             proto.write(
@@ -197,7 +197,7 @@
         final int uid = jobStatus.getSourceUid();
         final String packageName = jobStatus.getSourcePackageName();
 
-        final boolean canRun = !mForceAppStandbyTracker.areJobsRestricted(uid, packageName,
+        final boolean canRun = !mAppStateTracker.areJobsRestricted(uid, packageName,
                 (jobStatus.getInternalFlags() & JobStatus.INTERNAL_FLAG_HAS_FOREGROUND_EXEMPTION)
                         != 0);
 
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 55c0f5a..3e43d8e 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -206,7 +206,7 @@
     private static final int UPDATE_NETWORK_STATE = 4;
     private static final int INJECT_NTP_TIME = 5;
     private static final int DOWNLOAD_XTRA_DATA = 6;
-    private static final int UPDATE_LOCATION = 7;
+    private static final int UPDATE_LOCATION = 7;  // Handle external location from network listener
     private static final int ADD_LISTENER = 8;
     private static final int REMOVE_LISTENER = 9;
     private static final int INJECT_NTP_TIME_FINISHED = 10;
@@ -259,6 +259,42 @@
         }
     }
 
+    // Simple class to hold stats reported in the Extras Bundle
+    private static class LocationExtras {
+        private int mSvCount;
+        private int mMeanCn0;
+        private int mMaxCn0;
+        private final Bundle mBundle;
+
+        public LocationExtras() {
+            mBundle = new Bundle();
+        }
+
+        public void set(int svCount, int meanCn0, int maxCn0) {
+            mSvCount = svCount;
+            mMeanCn0 = meanCn0;
+            mMaxCn0 = maxCn0;
+            setBundle(mBundle);
+        }
+
+        public void reset() {
+            set(0,0,0);
+        }
+
+        // Also used by outside methods to add to other bundles
+        public void setBundle(Bundle extras) {
+            if (extras != null) {
+                extras.putInt("satellites", mSvCount);
+                extras.putInt("meanCn0", mMeanCn0);
+                extras.putInt("maxCn0", mMaxCn0);
+            }
+        }
+
+        public Bundle getBundle() {
+            return mBundle;
+        }
+    }
+
     private Object mLock = new Object();
 
     // current status
@@ -369,7 +405,7 @@
     private final NtpTrustedTime mNtpTime;
     private final ILocationManager mILocationManager;
     private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
-    private Bundle mLocationExtras = new Bundle();
+    private final LocationExtras mLocationExtras = new LocationExtras();
     private final GnssStatusListenerHelper mListenerHelper;
     private final GnssMeasurementsProvider mGnssMeasurementsProvider;
     private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
@@ -713,7 +749,7 @@
         mNtpTime = NtpTrustedTime.getInstance(context);
         mILocationManager = ilocationManager;
 
-        mLocation.setExtras(mLocationExtras);
+        mLocation.setExtras(mLocationExtras.getBundle());
 
         // Create a wake lock
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -1245,29 +1281,17 @@
 
     @Override
     public int getStatus(Bundle extras) {
-        setLocationExtras(extras);
+        mLocationExtras.setBundle(extras);
         return mStatus;
     }
 
-    private void updateStatus(int status, int svCount, int meanCn0, int maxCn0) {
-        if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0) {
+    private void updateStatus(int status) {
+        if (status != mStatus) {
             mStatus = status;
-            mSvCount = svCount;
-            mMeanCn0 = meanCn0;
-            mMaxCn0 = maxCn0;
-            setLocationExtras(mLocationExtras);
             mStatusUpdateTime = SystemClock.elapsedRealtime();
         }
     }
 
-    private void setLocationExtras(Bundle extras) {
-        if (extras != null) {
-            extras.putInt("satellites", mSvCount);
-            extras.putInt("meanCn0", mMeanCn0);
-            extras.putInt("maxCn0", mMaxCn0);
-        }
-    }
-
     @Override
     public long getStatusUpdateTime() {
         return mStatusUpdateTime;
@@ -1563,7 +1587,8 @@
             }
 
             // reset SV count to zero
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
+            mLocationExtras.reset();
             mFixRequestTime = SystemClock.elapsedRealtime();
             if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
                 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
@@ -1586,7 +1611,8 @@
             mLastFixTime = 0;
 
             // reset SV count to zero
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
+            mLocationExtras.reset();
         }
     }
 
@@ -1626,7 +1652,7 @@
             // It would be nice to push the elapsed real-time timestamp
             // further down the stack, but this is still useful
             mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
-            mLocation.setExtras(mLocationExtras);
+            mLocation.setExtras(mLocationExtras.getBundle());
 
             try {
                 mILocationManager.reportLocation(mLocation, false);
@@ -1662,8 +1688,9 @@
         }
 
         if (mStarted && mStatus != LocationProvider.AVAILABLE) {
-            // we want to time out if we do not receive a fix
-            // within the time out and we are requesting infrequent fixes
+            // For devices that use framework scheduling, a timer may be set to ensure we don't
+            // spend too much power searching for a location, when the requested update rate is slow.
+            // As we just recievied a location, we'll cancel that timer.
             if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
                 mAlarmManager.cancel(mTimeoutIntent);
             }
@@ -1672,7 +1699,7 @@
             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            updateStatus(LocationProvider.AVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
+            updateStatus(LocationProvider.AVAILABLE);
         }
 
         if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
@@ -1771,7 +1798,7 @@
             meanCn0 /= usedInFixCount;
         }
         // return number of sats used in fix instead of total reported
-        updateStatus(mStatus, usedInFixCount, meanCn0, maxCn0);
+        mLocationExtras.set(usedInFixCount, meanCn0, maxCn0);
 
         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
                 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
@@ -1779,7 +1806,7 @@
             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE);
         }
     }
 
@@ -2726,9 +2753,6 @@
     private float mSvElevations[] = new float[MAX_SVS];
     private float mSvAzimuths[] = new float[MAX_SVS];
     private float mSvCarrierFreqs[] = new float[MAX_SVS];
-    private int mSvCount;
-    private int mMeanCn0;
-    private int mMaxCn0;
     // preallocated to avoid memory allocation in reportNmea()
     private byte[] mNmeaBuffer = new byte[120];
 
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 961a451..3cc4d83 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -187,6 +187,7 @@
      */
     @VisibleForTesting
     public static long multiplySafe(long value, long num, long den) {
+        if (den == 0) den = 1;
         long x = value;
         long y = num;
 
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 30088dd..fb81ebf 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -274,7 +274,7 @@
             }
 
             // Propagate permissions before removing any state
-            propagateInstantAppPermissionsIfNeeded(pkg.packageName, userId);
+            propagateInstantAppPermissionsIfNeeded(pkg, userId);
 
             // Track instant apps
             if (ps.getInstantApp(userId)) {
@@ -869,10 +869,10 @@
         return uninstalledApps;
     }
 
-    private void propagateInstantAppPermissionsIfNeeded(@NonNull String packageName,
+    private void propagateInstantAppPermissionsIfNeeded(@NonNull PackageParser.Package pkg,
             @UserIdInt int userId) {
         InstantAppInfo appInfo = peekOrParseUninstalledInstantAppInfo(
-                packageName, userId);
+                pkg.packageName, userId);
         if (appInfo == null) {
             return;
         }
@@ -884,8 +884,8 @@
             for (String grantedPermission : appInfo.getGrantedPermissions()) {
                 final boolean propagatePermission =
                         mService.mSettings.canPropagatePermissionToInstantApp(grantedPermission);
-                if (propagatePermission) {
-                    mService.grantRuntimePermission(packageName, grantedPermission, userId);
+                if (propagatePermission && pkg.requestedPermissions.contains(grantedPermission)) {
+                    mService.grantRuntimePermission(pkg.packageName, grantedPermission, userId);
                 }
             }
         } finally {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 384b074..3cd24f9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -965,7 +965,7 @@
     volatile boolean mSystemReady;
     volatile boolean mSafeMode;
     volatile boolean mHasSystemUidErrors;
-    private volatile boolean mEphemeralAppsDisabled;
+    private volatile boolean mWebInstantAppsDisabled;
 
     ApplicationInfo mAndroidApplication;
     final ActivityInfo mResolveActivity = new ActivityInfo();
@@ -5217,7 +5217,13 @@
 
     @Override
     public int checkUidPermission(String permName, int uid) {
-        return mPermissionManager.checkUidPermission(permName, uid, getCallingUid());
+        synchronized (mPackages) {
+            final String[] packageNames = getPackagesForUid(uid);
+            final PackageParser.Package pkg = (packageNames != null && packageNames.length > 0)
+                    ? mPackages.get(packageNames[0])
+                    : null;
+            return mPermissionManager.checkUidPermission(permName, pkg, uid, getCallingUid());
+        }
     }
 
     @Override
@@ -5951,11 +5957,11 @@
     /**
      * Returns whether or not instant apps have been disabled remotely.
      */
-    private boolean isEphemeralDisabled() {
-        return mEphemeralAppsDisabled;
+    private boolean areWebInstantAppsDisabled() {
+        return mWebInstantAppsDisabled;
     }
 
-    private boolean isInstantAppAllowed(
+    private boolean isInstantAppResolutionAllowed(
             Intent intent, List<ResolveInfo> resolvedActivities, int userId,
             boolean skipPackageCheck) {
         if (mInstantAppResolverConnection == null) {
@@ -5980,8 +5986,12 @@
                     || (intent.getFlags() & Intent.FLAG_ACTIVITY_MATCH_EXTERNAL) == 0) {
                 return false;
             }
-        } else if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
-            return false;
+        } else {
+            if (intent.getData() == null || TextUtils.isEmpty(intent.getData().getHost())) {
+                return false;
+            } else if (areWebInstantAppsDisabled()) {
+                return false;
+            }
         }
         // Deny ephemeral apps if the user chose _ALWAYS or _ALWAYS_ASK for intent resolution.
         // Or if there's already an ephemeral app installed that handles the action
@@ -6512,14 +6522,13 @@
                 }
             }
             return applyPostResolutionFilter(
-                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId);
+                    list, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId, intent);
         }
 
         // reader
         boolean sortResult = false;
-        boolean addEphemeral = false;
+        boolean addInstant = false;
         List<ResolveInfo> result;
-        final boolean ephemeralDisabled = isEphemeralDisabled();
         synchronized (mPackages) {
             if (pkgName == null) {
                 List<CrossProfileIntentFilter> matchingFilters =
@@ -6532,14 +6541,14 @@
                     xpResult.add(xpResolveInfo);
                     return applyPostResolutionFilter(
                             filterIfNotSystemUser(xpResult, userId), instantAppPkgName,
-                            allowDynamicSplits, filterCallingUid, userId);
+                            allowDynamicSplits, filterCallingUid, userId, intent);
                 }
 
                 // Check for results in the current profile.
                 result = filterIfNotSystemUser(mActivities.queryIntent(
                         intent, resolvedType, flags, userId), userId);
-                addEphemeral = !ephemeralDisabled
-                        && isInstantAppAllowed(intent, result, userId, false /*skipPackageCheck*/);
+                addInstant = isInstantAppResolutionAllowed(intent, result, userId,
+                        false /*skipPackageCheck*/);
                 // Check for cross profile results.
                 boolean hasNonNegativePriorityResult = hasNonNegativePriority(result);
                 xpResolveInfo = queryCrossProfileIntents(
@@ -6566,20 +6575,20 @@
                             // in the result.
                             result.remove(xpResolveInfo);
                         }
-                        if (result.size() == 0 && !addEphemeral) {
+                        if (result.size() == 0 && !addInstant) {
                             // No result in current profile, but found candidate in parent user.
                             // And we are not going to add emphemeral app, so we can return the
                             // result straight away.
                             result.add(xpDomainInfo.resolveInfo);
                             return applyPostResolutionFilter(result, instantAppPkgName,
-                                    allowDynamicSplits, filterCallingUid, userId);
+                                    allowDynamicSplits, filterCallingUid, userId, intent);
                         }
-                    } else if (result.size() <= 1 && !addEphemeral) {
+                    } else if (result.size() <= 1 && !addInstant) {
                         // No result in parent user and <= 1 result in current profile, and we
                         // are not going to add emphemeral app, so we can return the result without
                         // further processing.
                         return applyPostResolutionFilter(result, instantAppPkgName,
-                                allowDynamicSplits, filterCallingUid, userId);
+                                allowDynamicSplits, filterCallingUid, userId, intent);
                     }
                     // We have more than one candidate (combining results from current and parent
                     // profile), so we need filtering and sorting.
@@ -6599,8 +6608,7 @@
                 if (result == null || result.size() == 0) {
                     // the caller wants to resolve for a particular package; however, there
                     // were no installed results, so, try to find an ephemeral result
-                    addEphemeral = !ephemeralDisabled
-                            && isInstantAppAllowed(
+                    addInstant = isInstantAppResolutionAllowed(
                                     intent, null /*result*/, userId, true /*skipPackageCheck*/);
                     if (result == null) {
                         result = new ArrayList<>();
@@ -6608,7 +6616,7 @@
                 }
             }
         }
-        if (addEphemeral) {
+        if (addInstant) {
             result = maybeAddInstantAppInstaller(
                     result, intent, resolvedType, flags, userId, resolveForStart);
         }
@@ -6616,7 +6624,7 @@
             Collections.sort(result, mResolvePrioritySorter);
         }
         return applyPostResolutionFilter(
-                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId);
+                result, instantAppPkgName, allowDynamicSplits, filterCallingUid, userId, intent);
     }
 
     private List<ResolveInfo> maybeAddInstantAppInstaller(List<ResolveInfo> result, Intent intent,
@@ -6820,12 +6828,20 @@
      * @param resolveInfos The pre-filtered list of resolved activities
      * @param ephemeralPkgName The ephemeral package name. If {@code null}, no filtering
      *          is performed.
+     * @param intent
      * @return A filtered list of resolved activities.
      */
     private List<ResolveInfo> applyPostResolutionFilter(List<ResolveInfo> resolveInfos,
-            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, int userId) {
+            String ephemeralPkgName, boolean allowDynamicSplits, int filterCallingUid, int userId,
+            Intent intent) {
+        final boolean blockInstant = intent.isWebIntent() && areWebInstantAppsDisabled();
         for (int i = resolveInfos.size() - 1; i >= 0; i--) {
             final ResolveInfo info = resolveInfos.get(i);
+            // remove locally resolved instant app web results when disabled
+            if (info.isInstantAppAvailable && blockInstant) {
+                resolveInfos.remove(i);
+                continue;
+            }
             // allow activities that are defined in the provided package
             if (allowDynamicSplits
                     && info.activityInfo != null
@@ -7457,7 +7473,7 @@
                 }
             }
             return applyPostResolutionFilter(
-                    list, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+                    list, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
         }
 
         // reader
@@ -7467,14 +7483,14 @@
                 final List<ResolveInfo> result =
                         mReceivers.queryIntent(intent, resolvedType, flags, userId);
                 return applyPostResolutionFilter(
-                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
                 final List<ResolveInfo> result = mReceivers.queryIntentForPackage(
                         intent, resolvedType, flags, pkg.receivers, userId);
                 return applyPostResolutionFilter(
-                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId);
+                        result, instantAppPkgName, allowDynamicSplits, callingUid, userId, intent);
             }
             return Collections.emptyList();
         }
@@ -7944,7 +7960,7 @@
 
     @Override
     public ParceledListSlice<InstantAppInfo> getInstantApps(int userId) {
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return null;
         }
         if (!canViewInstantApps(Binder.getCallingUid(), userId)) {
@@ -7969,7 +7985,7 @@
         mPermissionManager.enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "isInstantApp");
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return false;
         }
 
@@ -7995,7 +8011,7 @@
 
     @Override
     public byte[] getInstantAppCookie(String packageName, int userId) {
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return null;
         }
 
@@ -8013,7 +8029,7 @@
 
     @Override
     public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) {
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return true;
         }
 
@@ -8031,7 +8047,7 @@
 
     @Override
     public Bitmap getInstantAppIcon(String packageName, int userId) {
-        if (HIDE_EPHEMERAL_APIS || isEphemeralDisabled()) {
+        if (HIDE_EPHEMERAL_APIS) {
             return null;
         }
 
@@ -19102,8 +19118,21 @@
     public void deleteApplicationCacheFilesAsUser(final String packageName, final int userId,
             final IPackageDataObserver observer) {
         final int callingUid = Binder.getCallingUid();
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.DELETE_CACHE_FILES, null);
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES)
+                != PackageManager.PERMISSION_GRANTED) {
+            // If the caller has the old delete cache permission, silently ignore.  Else throw.
+            if (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.DELETE_CACHE_FILES)
+                    == PackageManager.PERMISSION_GRANTED) {
+                Slog.w(TAG, "Calling uid " + callingUid + " does not have " +
+                        android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES +
+                        ", silently ignoring");
+                return;
+            }
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.INTERNAL_DELETE_CACHE_FILES, null);
+        }
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 /* requireFullPermission= */ true, /* checkShell= */ false,
                 "delete application cache files");
@@ -20705,7 +20734,7 @@
         ContentObserver co = new ContentObserver(mHandler) {
             @Override
             public void onChange(boolean selfChange) {
-                mEphemeralAppsDisabled =
+                mWebInstantAppsDisabled =
                         (Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0) ||
                                 (Secure.getInt(resolver, Secure.INSTANT_APPS_ENABLED, 1) == 0);
             }
@@ -20713,7 +20742,7 @@
         mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
                         .getUriFor(Global.ENABLE_EPHEMERAL_FEATURE),
                 false, co, UserHandle.USER_SYSTEM);
-        mContext.getContentResolver().registerContentObserver(android.provider.Settings.Global
+        mContext.getContentResolver().registerContentObserver(android.provider.Settings.Secure
                         .getUriFor(Secure.INSTANT_APPS_ENABLED), false, co, UserHandle.USER_SYSTEM);
         co.onChange(true);
 
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
index 60c118b..859bbe3 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
@@ -146,7 +146,8 @@
 
     public abstract int checkPermission(@NonNull String permName, @NonNull String packageName,
             int callingUid, int userId);
-    public abstract int checkUidPermission(String permName, int uid, int callingUid);
+    public abstract int checkUidPermission(@NonNull String permName,
+            @Nullable PackageParser.Package pkg, int uid, int callingUid);
 
     /**
      * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 3f8a1e8..afaafbc 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -242,7 +242,8 @@
         return PackageManager.PERMISSION_DENIED;
     }
 
-    private int checkUidPermission(String permName, int uid, int callingUid) {
+    private int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
+            int callingUid) {
         final int callingUserId = UserHandle.getUserId(callingUid);
         final boolean isCallerInstantApp =
                 mPackageManagerInt.getInstantAppPackageName(callingUid) != null;
@@ -253,28 +254,13 @@
             return PackageManager.PERMISSION_DENIED;
         }
 
-        final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
-        if (packages != null && packages.length > 0) {
-            PackageParser.Package pkg = null;
-            for (String packageName : packages) {
-                pkg = mPackageManagerInt.getPackage(packageName);
-                if (pkg != null) {
-                    break;
-                }
-            }
-            if (pkg == null) {
-Slog.e(TAG, "TODD: No package not found; UID: " + uid);
-Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages));
-                return PackageManager.PERMISSION_DENIED;
-            }
+        if (pkg != null) {
             if (pkg.mSharedUserId != null) {
                 if (isCallerInstantApp) {
                     return PackageManager.PERMISSION_DENIED;
                 }
-            } else {
-                if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
-                    return PackageManager.PERMISSION_DENIED;
-                }
+            } else if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) {
+                return PackageManager.PERMISSION_DENIED;
             }
             final PermissionsState permissionsState =
                     ((PackageSetting) pkg.mExtras).getPermissionsState();
@@ -2068,8 +2054,9 @@
                     permName, packageName, callingUid, userId);
         }
         @Override
-        public int checkUidPermission(String permName, int uid, int callingUid) {
-            return PermissionManagerService.this.checkUidPermission(permName, uid, callingUid);
+        public int checkUidPermission(String permName, PackageParser.Package pkg, int uid,
+                int callingUid) {
+            return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid);
         }
         @Override
         public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index 0e8d8bc..8f4cada 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -59,7 +59,7 @@
     private static final String TAG = "timezone.PackageTracker";
 
     private final PackageManagerHelper mPackageManagerHelper;
-    private final IntentHelper mIntentHelper;
+    private final PackageTrackerIntentHelper mIntentHelper;
     private final ConfigHelper mConfigHelper;
     private final PackageStatusStorage mPackageStatusStorage;
     private final Clock mElapsedRealtimeClock;
@@ -103,13 +103,13 @@
                 helperImpl /* configHelper */,
                 helperImpl /* packageManagerHelper */,
                 new PackageStatusStorage(storageDir),
-                new IntentHelperImpl(context));
+                new PackageTrackerIntentHelperImpl(context));
     }
 
     // A constructor that can be used by tests to supply mocked / faked dependencies.
     PackageTracker(Clock elapsedRealtimeClock, ConfigHelper configHelper,
             PackageManagerHelper packageManagerHelper, PackageStatusStorage packageStatusStorage,
-            IntentHelper intentHelper) {
+            PackageTrackerIntentHelper intentHelper) {
         mElapsedRealtimeClock = elapsedRealtimeClock;
         mConfigHelper = configHelper;
         mPackageManagerHelper = packageManagerHelper;
diff --git a/services/core/java/com/android/server/timezone/IntentHelper.java b/services/core/java/com/android/server/timezone/PackageTrackerIntentHelper.java
similarity index 97%
rename from services/core/java/com/android/server/timezone/IntentHelper.java
rename to services/core/java/com/android/server/timezone/PackageTrackerIntentHelper.java
index 5de5432..3753ece 100644
--- a/services/core/java/com/android/server/timezone/IntentHelper.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerIntentHelper.java
@@ -21,7 +21,7 @@
  * it is not possible to test various cases with the real one because of the need to simulate
  * receiving and broadcasting intents.
  */
-interface IntentHelper {
+interface PackageTrackerIntentHelper {
 
     void initialize(String updateAppPackageName, String dataAppPackageName,
             PackageTracker packageTracker);
diff --git a/services/core/java/com/android/server/timezone/IntentHelperImpl.java b/services/core/java/com/android/server/timezone/PackageTrackerIntentHelperImpl.java
similarity index 93%
rename from services/core/java/com/android/server/timezone/IntentHelperImpl.java
rename to services/core/java/com/android/server/timezone/PackageTrackerIntentHelperImpl.java
index 6e6259d..4110d88 100644
--- a/services/core/java/com/android/server/timezone/IntentHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerIntentHelperImpl.java
@@ -28,16 +28,16 @@
 import android.util.Slog;
 
 /**
- * The bona fide implementation of {@link IntentHelper}.
+ * The bona fide implementation of {@link PackageTrackerIntentHelper}.
  */
-final class IntentHelperImpl implements IntentHelper {
+final class PackageTrackerIntentHelperImpl implements PackageTrackerIntentHelper {
 
-    private final static String TAG = "timezone.IntentHelperImpl";
+    private final static String TAG = "timezone.PackageTrackerIntentHelperImpl";
 
     private final Context mContext;
     private String mUpdaterAppPackageName;
 
-    IntentHelperImpl(Context context) {
+    PackageTrackerIntentHelperImpl(Context context) {
         mContext = context;
     }
 
diff --git a/services/core/java/com/android/server/timezone/RulesManagerIntentHelper.java b/services/core/java/com/android/server/timezone/RulesManagerIntentHelper.java
new file mode 100644
index 0000000..bb317cf
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/RulesManagerIntentHelper.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.timezone;
+
+/**
+ * An easy-to-mock interface around intent sending / receiving for use by
+ * {@link RulesManagerService}; it is not possible to test various cases with the real one because
+ * of the need to simulate broadcasting intents.
+ */
+interface RulesManagerIntentHelper {
+
+    /**
+     * Send a broadcast informing listeners that a time zone operation is staged.
+     */
+    void sendTimeZoneOperationStaged();
+
+    /**
+     * Send a broadcast informing listeners that a time zone operation is no longer staged.
+     */
+    void sendTimeZoneOperationUnstaged();
+}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index be9b204..872d723 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -99,6 +99,7 @@
     private final PermissionHelper mPermissionHelper;
     private final PackageTracker mPackageTracker;
     private final Executor mExecutor;
+    private final RulesManagerIntentHelper mIntentHelper;
     private final TimeZoneDistroInstaller mInstaller;
 
     private static RulesManagerService create(Context context) {
@@ -106,16 +107,19 @@
         return new RulesManagerService(
                 helper /* permissionHelper */,
                 helper /* executor */,
+                helper /* intentHelper */,
                 PackageTracker.create(context),
                 new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR));
     }
 
     // A constructor that can be used by tests to supply mocked / faked dependencies.
-    RulesManagerService(PermissionHelper permissionHelper,
-            Executor executor, PackageTracker packageTracker,
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    RulesManagerService(PermissionHelper permissionHelper, Executor executor,
+            RulesManagerIntentHelper intentHelper, PackageTracker packageTracker,
             TimeZoneDistroInstaller timeZoneDistroInstaller) {
         mPermissionHelper = permissionHelper;
         mExecutor = executor;
+        mIntentHelper = intentHelper;
         mPackageTracker = packageTracker;
         mInstaller = timeZoneDistroInstaller;
     }
@@ -271,6 +275,10 @@
 
                 TimeZoneDistro distro = new TimeZoneDistro(is);
                 int installerResult = mInstaller.stageInstallWithErrorCode(distro);
+
+                // Notify interested parties that something is staged.
+                sendInstallNotificationIntentIfRequired(installerResult);
+
                 int resultCode = mapInstallerResultToApiCode(installerResult);
                 EventLogTags.writeTimezoneInstallComplete(toStringOrNull(mCheckToken), resultCode);
                 sendFinishedStatus(mCallback, resultCode);
@@ -291,6 +299,12 @@
             }
         }
 
+        private void sendInstallNotificationIntentIfRequired(int installerResult) {
+            if (installerResult == TimeZoneDistroInstaller.INSTALL_SUCCESS) {
+                mIntentHelper.sendTimeZoneOperationStaged();
+            }
+        }
+
         private int mapInstallerResultToApiCode(int installerResult) {
             switch (installerResult) {
                 case TimeZoneDistroInstaller.INSTALL_SUCCESS:
@@ -351,6 +365,10 @@
             boolean packageTrackerStatus = false;
             try {
                 int uninstallResult = mInstaller.stageUninstall();
+
+                // Notify interested parties that something is staged.
+                sendUninstallNotificationIntentIfRequired(uninstallResult);
+
                 packageTrackerStatus = (uninstallResult == TimeZoneDistroInstaller.UNINSTALL_SUCCESS
                         || uninstallResult == TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED);
 
@@ -374,6 +392,20 @@
                 mOperationInProgress.set(false);
             }
         }
+
+        private void sendUninstallNotificationIntentIfRequired(int uninstallResult) {
+            switch (uninstallResult) {
+                case TimeZoneDistroInstaller.UNINSTALL_SUCCESS:
+                    mIntentHelper.sendTimeZoneOperationStaged();
+                    break;
+                case TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED:
+                    mIntentHelper.sendTimeZoneOperationUnstaged();
+                    break;
+                case TimeZoneDistroInstaller.UNINSTALL_FAIL:
+                default:
+                    // No-op - unknown or nothing to notify about.
+            }
+        }
     }
 
     private void sendFinishedStatus(ICallback callback, int resultCode) {
diff --git a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
index e8a401e..8f5c7a7 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
@@ -18,22 +18,20 @@
 
 import com.android.internal.util.DumpUtils;
 
+import android.app.timezone.RulesManager;
 import android.content.Context;
-import android.content.pm.PackageManager;
+import android.content.Intent;
 import android.os.AsyncTask;
-import android.os.Binder;
-import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
 
-import java.io.FileInputStream;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.concurrent.Executor;
-import libcore.io.Streams;
 
 /**
  * A single class that implements multiple helper interfaces for use by {@link RulesManagerService}.
  */
-final class RulesManagerServiceHelperImpl implements PermissionHelper, Executor {
+final class RulesManagerServiceHelperImpl
+        implements PermissionHelper, Executor, RulesManagerIntentHelper {
 
     private final Context mContext;
 
@@ -55,4 +53,22 @@
     public void execute(Runnable runnable) {
         AsyncTask.execute(runnable);
     }
+
+    @Override
+    public void sendTimeZoneOperationStaged() {
+        sendOperationIntent(true /* staged */);
+    }
+
+    @Override
+    public void sendTimeZoneOperationUnstaged() {
+        sendOperationIntent(false /* staged */);
+    }
+
+    private void sendOperationIntent(boolean staged) {
+        Intent intent = new Intent(RulesManager.ACTION_RULES_UPDATE_OPERATION);
+        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        intent.putExtra(RulesManager.EXTRA_OPERATION_STAGED, staged);
+        mContext.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
+    }
+
 }
diff --git a/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java b/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java
index 116fe7f..0450816 100644
--- a/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/CarrierIdInstallReceiver.java
@@ -33,7 +33,7 @@
     @Override
     protected void postInstall(Context context, Intent intent) {
         ContentResolver resolver = context.getContentResolver();
-        resolver.update(Uri.withAppendedPath(Telephony.CarrierIdentification.CONTENT_URI,
+        resolver.update(Uri.withAppendedPath(Telephony.CarrierIdentification.All.CONTENT_URI,
                 "update_db"), new ContentValues(), null, null);
     }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2512dbd..41a6e2b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -725,8 +725,9 @@
      *                            wallpaper windows in the window list.
      */
     DisplayContent(Display display, WindowManagerService service,
-            WallpaperController wallpaperController) {
+            WallpaperController wallpaperController, DisplayWindowController controller) {
         super(service);
+        setController(controller);
         if (service.mRoot.getDisplayContent(display.getDisplayId()) != null) {
             throw new IllegalArgumentException("Display with ID=" + display.getDisplayId()
                     + " already exists=" + service.mRoot.getDisplayContent(display.getDisplayId())
@@ -1941,6 +1942,8 @@
         } finally {
             mRemovingDisplay = false;
         }
+
+        mService.onDisplayRemoved(mDisplayId);
     }
 
     /** Returns true if a removal action is still being deferred. */
@@ -1950,7 +1953,6 @@
 
         if (!stillDeferringRemoval && mDeferredRemoval) {
             removeImmediately();
-            mService.onDisplayRemoved(mDisplayId);
             return false;
         }
         return true;
diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java
index ad4957e..0e12838 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowController.java
@@ -16,11 +16,14 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.content.res.Configuration;
+import android.os.Binder;
 import android.util.Slog;
+import android.view.Display;
 
 /**
  * Controller for the display container. This is created by activity manager to link activity
@@ -36,9 +39,16 @@
         mDisplayId = displayId;
 
         synchronized (mWindowMap) {
-            // TODO: Convert to setContainer() from DisplayContent once everything is hooked up.
-            // Currently we are not setup to register for config changes.
-            mContainer = mRoot.getDisplayContentOrCreate(displayId);
+            final Display display = mService.mDisplayManager.getDisplay(displayId);
+            if (display != null) {
+                final long callingIdentity = Binder.clearCallingIdentity();
+                try {
+                    mRoot.createDisplayContent(display, this /* controller */);
+                } finally {
+                    Binder.restoreCallingIdentity(callingIdentity);
+                }
+            }
+
             if (mContainer == null) {
                 throw new IllegalArgumentException("Trying to add displayId=" + displayId);
             }
@@ -47,14 +57,22 @@
 
     @Override
     public void removeContainer() {
-        // TODO: Pipe through from ActivityDisplay to remove the display
-        throw new UnsupportedOperationException("To be implemented");
+        synchronized (mWindowMap) {
+            if(mContainer == null) {
+                if (DEBUG_DISPLAY) Slog.i(TAG_WM, "removeDisplay: could not find displayId="
+                        + mDisplayId);
+                return;
+            }
+            mContainer.removeIfPossible();
+            super.removeContainer();
+        }
     }
 
     @Override
     public void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
-        // TODO: Pipe through from ActivityDisplay to update the configuration for the display
-        throw new UnsupportedOperationException("To be implemented");
+        // TODO: The container receives override configuration changes through other means. enabling
+        // callbacks through the controller causes layout issues. Investigate consolidating
+        // override configuration propagation to just here.
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index c535fe5..f5760e5 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -193,30 +193,6 @@
         }
     }
 
-    /**
-     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
-     * there is a Display for the displayId.
-     *
-     * @param displayId The display the caller is interested in.
-     * @return The DisplayContent associated with displayId or null if there is no Display for it.
-     */
-    DisplayContent getDisplayContentOrCreate(int displayId) {
-        DisplayContent dc = getDisplayContent(displayId);
-
-        if (dc == null) {
-            final Display display = mService.mDisplayManager.getDisplay(displayId);
-            if (display != null) {
-                final long callingIdentity = Binder.clearCallingIdentity();
-                try {
-                    dc = createDisplayContent(display);
-                } finally {
-                    Binder.restoreCallingIdentity(callingIdentity);
-                }
-            }
-        }
-        return dc;
-    }
-
     DisplayContent getDisplayContent(int displayId) {
         for (int i = mChildren.size() - 1; i >= 0; --i) {
             final DisplayContent current = mChildren.get(i);
@@ -227,9 +203,9 @@
         return null;
     }
 
-    private DisplayContent createDisplayContent(final Display display) {
-        final DisplayContent dc = new DisplayContent(display, mService,
-                mWallpaperController);
+    DisplayContent createDisplayContent(final Display display, DisplayWindowController controller) {
+        final DisplayContent dc =
+                new DisplayContent(display, mService, mWallpaperController, controller);
         final int displayId = display.getDisplayId();
 
         if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Adding display=" + display);
@@ -748,19 +724,6 @@
                     (mSustainedPerformanceModeEnabled ? 1 : 0));
         }
 
-        if (mService.mTurnOnScreen) {
-            if (mService.mAllowTheaterModeWakeFromLayout
-                    || Settings.Global.getInt(mService.mContext.getContentResolver(),
-                    Settings.Global.THEATER_MODE_ON, 0) == 0) {
-                if (DEBUG_VISIBILITY || DEBUG_POWER) {
-                    Slog.v(TAG, "Turning screen on after layout!");
-                }
-                mService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
-                        "android.server.wm:TURN_ON");
-            }
-            mService.mTurnOnScreen = false;
-        }
-
         if (mUpdateRotation) {
             if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
             // TODO(multi-display): Update rotation for different displays separately.
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 1b2f954..98fcb0b 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -169,7 +169,12 @@
         anim.addUpdateListener(animation -> {
             synchronized (mCancelLock) {
                 if (!a.mCancelled) {
-                    applyTransformation(a, mFrameTransaction, anim.getCurrentPlayTime());
+                    final long duration = anim.getDuration();
+                    long currentPlayTime = anim.getCurrentPlayTime();
+                    if (currentPlayTime > duration) {
+                        currentPlayTime = duration;
+                    }
+                    applyTransformation(a, mFrameTransaction, currentPlayTime);
                 }
             }
 
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index cec13ab..49a30d5 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -161,7 +161,7 @@
                 final int numDisplays = mDisplayContentsAnimators.size();
                 for (int i = 0; i < numDisplays; i++) {
                     final int displayId = mDisplayContentsAnimators.keyAt(i);
-                    final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
                     DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
 
                     final ScreenRotationAnimation screenRotationAnimation =
@@ -195,7 +195,7 @@
 
                 for (int i = 0; i < numDisplays; i++) {
                     final int displayId = mDisplayContentsAnimators.keyAt(i);
-                    final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                    final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
 
                     dc.checkAppWindowsReadyToShow();
 
@@ -228,7 +228,7 @@
             final int numDisplays = mDisplayContentsAnimators.size();
             for (int i = 0; i < numDisplays; i++) {
                 final int displayId = mDisplayContentsAnimators.keyAt(i);
-                final DisplayContent dc = mService.mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
                 dc.onPendingTransactionApplied();
             }
 
@@ -305,7 +305,7 @@
                     pw.println(":");
             final DisplayContentsAnimator displayAnimator = mDisplayContentsAnimators.valueAt(i);
             final DisplayContent dc =
-                    mService.mRoot.getDisplayContentOrCreate(mDisplayContentsAnimators.keyAt(i));
+                    mService.mRoot.getDisplayContent(mDisplayContentsAnimators.keyAt(i));
             dc.dumpWindowAnimators(pw, subPrefix);
             if (displayAnimator.mScreenRotationAnimation != null) {
                 pw.print(subPrefix); pw.println("mScreenRotationAnimation:");
@@ -339,7 +339,7 @@
         if (displayId < 0) {
             return 0;
         }
-        final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
+        final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
         return (displayContent != null) ? displayContent.pendingLayoutChanges : 0;
     }
 
@@ -347,7 +347,7 @@
         if (displayId < 0) {
             return;
         }
-        final DisplayContent displayContent = mService.mRoot.getDisplayContentOrCreate(displayId);
+        final DisplayContent displayContent = mService.mRoot.getDisplayContent(displayId);
         if (displayContent != null) {
             displayContent.pendingLayoutChanges |= changes;
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 676fb9f..c2ed2ae 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -737,7 +737,6 @@
     final InputManagerService mInputManager;
     final DisplayManagerInternal mDisplayManagerInternal;
     final DisplayManager mDisplayManager;
-    private final Display[] mDisplays;
 
     // Indicates whether this device supports wide color gamut rendering
     private boolean mHasWideColorGamutSupport;
@@ -746,8 +745,6 @@
     private Session mHoldingScreenOn;
     private PowerManager.WakeLock mHoldingScreenWakeLock;
 
-    boolean mTurnOnScreen;
-
     // Whether or not a layout can cause a wake up when theater mode is enabled.
     boolean mAllowTheaterModeWakeFromLayout;
 
@@ -915,7 +912,6 @@
             @Override
             public void run() {
                 WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
-
                 mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
             }
         }, 0);
@@ -974,10 +970,6 @@
         }
 
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
-        mDisplays = mDisplayManager.getDisplays();
-        for (Display display : mDisplays) {
-            createDisplayContentLocked(display);
-        }
 
         mKeyguardDisableHandler = new KeyguardDisableHandler(mContext, mPolicy);
 
@@ -1066,6 +1058,13 @@
         mDragDropController = new DragDropController(this, mH.getLooper());
 
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
+    }
+
+    /**
+     * Called after all entities (such as the {@link ActivityManagerService}) have been set up and
+     * associated with the {@link WindowManagerService}.
+     */
+    public void onInitReady() {
         initPolicy();
 
         // Add ourself to the Watchdog monitors.
@@ -1081,6 +1080,7 @@
         showEmulatorDisplayOverlayIfNeeded();
     }
 
+
     public InputMonitor getInputMonitor() {
         return mInputMonitor;
     }
@@ -1131,7 +1131,7 @@
                 throw new IllegalStateException("Display has not been initialialized");
             }
 
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 Slog.w(TAG_WM, "Attempted to add window to a display that does not exist: "
                         + displayId + ".  Aborting.");
@@ -2277,7 +2277,7 @@
         }
 
         synchronized(mWindowMap) {
-            final DisplayContent dc = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent dc = mRoot.getDisplayContent(displayId);
             WindowToken token = dc.getWindowToken(binder);
             if (token != null) {
                 Slog.w(TAG_WM, "addWindowToken: Attempted to add binder token: " + binder
@@ -3666,7 +3666,7 @@
             boolean wallpaperOnly) {
         final DisplayContent displayContent;
         synchronized(mWindowMap) {
-            displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 if (DEBUG_SCREENSHOT) Slog.i(TAG_WM, "Screenshot returning null. No Display for "
                         + "displayId=" + displayId);
@@ -3885,7 +3885,7 @@
     public boolean registerWallpaperVisibilityListener(IWallpaperVisibilityListener listener,
             int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent == null) {
                 throw new IllegalArgumentException("Trying to register visibility event "
                         + "for invalid display: " + displayId);
@@ -4442,10 +4442,13 @@
     }
 
     public void displayReady() {
-        for (Display display : mDisplays) {
+        final int displayCount = mRoot.mChildren.size();
+        for (int i = 0; i < displayCount; ++i) {
+            final DisplayContent display = mRoot.mChildren.get(i);
             displayReady(display.getDisplayId());
         }
 
+
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
             if (mMaxUiWidth > 0) {
@@ -4476,7 +4479,7 @@
 
     private void displayReady(int displayId) {
         synchronized(mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null) {
                 mAnimator.addDisplayLocked(displayId);
                 displayContent.initializeDisplayBaseInfo();
@@ -5025,7 +5028,7 @@
     @Override
     public void getInitialDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 size.x = displayContent.mInitialDisplayWidth;
                 size.y = displayContent.mInitialDisplayHeight;
@@ -5036,7 +5039,7 @@
     @Override
     public void getBaseDisplaySize(int displayId, Point size) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 size.x = displayContent.mBaseDisplayWidth;
                 size.y = displayContent.mBaseDisplayHeight;
@@ -5063,7 +5066,7 @@
                 final int MIN_WIDTH = 200;
                 final int MIN_HEIGHT = 200;
                 final int MAX_SCALE = 2;
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     width = Math.min(Math.max(width, MIN_WIDTH),
                             displayContent.mInitialDisplayWidth * MAX_SCALE);
@@ -5093,7 +5096,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     if (mode < 0 || mode > 1) {
                         mode = 0;
@@ -5175,7 +5178,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
                             displayContent.mInitialDisplayHeight);
@@ -5191,7 +5194,7 @@
     @Override
     public int getInitialDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 return displayContent.mInitialDisplayDensity;
             }
@@ -5202,7 +5205,7 @@
     @Override
     public int getBaseDisplayDensity(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null && displayContent.hasAccess(Binder.getCallingUid())) {
                 return displayContent.mBaseDisplayDensity;
             }
@@ -5228,7 +5231,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null && mCurrentUserId == targetUserId) {
                     setForcedDisplayDensityLocked(displayContent, density);
                 }
@@ -5259,7 +5262,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null && mCurrentUserId == callingUserId) {
                     setForcedDisplayDensityLocked(displayContent,
                             displayContent.mInitialDisplayDensity);
@@ -5351,7 +5354,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             synchronized(mWindowMap) {
-                DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+                DisplayContent displayContent = mRoot.getDisplayContent(displayId);
                 if (displayContent != null) {
                     setOverscanLocked(displayContent, left, top, right, bottom);
                 }
@@ -6614,19 +6617,11 @@
         synchronized (mWindowMap) { }
     }
 
-    // TODO: All the display method below should probably be moved into the RootWindowContainer...
-    private void createDisplayContentLocked(final Display display) {
-        if (display == null) {
-            throw new IllegalArgumentException("getDisplayContent: display must not be null");
-        }
-        mRoot.getDisplayContentOrCreate(display.getDisplayId());
-    }
-
     // There is an inherent assumption that this will never return null.
     // TODO(multi-display): Inspect all the call-points of this method to see if they make sense to
     // support non-default display.
     DisplayContent getDefaultDisplayContentLocked() {
-        return mRoot.getDisplayContentOrCreate(DEFAULT_DISPLAY);
+        return mRoot.getDisplayContent(DEFAULT_DISPLAY);
     }
 
     public void onDisplayAdded(int displayId) {
@@ -6641,10 +6636,6 @@
 
     public void onDisplayRemoved(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
-            if (displayContent != null) {
-                displayContent.removeIfPossible();
-            }
             mAnimator.removeDisplayLocked(displayId);
             mWindowPlacerLocked.requestTraversal();
         }
@@ -6660,7 +6651,7 @@
 
     public void onDisplayChanged(int displayId) {
         synchronized (mWindowMap) {
-            final DisplayContent displayContent = mRoot.getDisplayContentOrCreate(displayId);
+            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
             if (displayContent != null) {
                 displayContent.updateDisplayInfo();
             }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b6712c0..21b4361 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.os.PowerManager.DRAW_WAKE_LOCK;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.SurfaceControl.Transaction;
@@ -167,6 +168,7 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.WorkSource;
+import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.MergedConfiguration;
@@ -285,7 +287,6 @@
     int mLayer;
     boolean mHaveFrame;
     boolean mObscured;
-    boolean mTurnOnScreen;
 
     int mLayoutSeq = -1;
 
@@ -635,6 +636,11 @@
     private TapExcludeRegionHolder mTapExcludeRegionHolder;
 
     /**
+     * Used for testing because the real PowerManager is final.
+     */
+    private PowerManagerWrapper mPowerManagerWrapper;
+
+    /**
      * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
      * of z-order and 1 otherwise.
      */
@@ -663,9 +669,34 @@
 
     private static final float DEFAULT_DIM_AMOUNT_DEAD_WINDOW = 0.5f;
 
+    interface PowerManagerWrapper {
+        void wakeUp(long time, String reason);
+
+        boolean isInteractive();
+
+    }
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
-           WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
-           int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
+            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
+            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) {
+        this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId,
+                ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
+                    @Override
+                    public void wakeUp(long time, String reason) {
+                        service.mPowerManager.wakeUp(time, reason);
+                    }
+
+                    @Override
+                    public boolean isInteractive() {
+                        return service.mPowerManager.isInteractive();
+                    }
+                });
+    }
+
+    WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
+            WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a,
+            int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow,
+            PowerManagerWrapper powerManagerWrapper) {
         super(service);
         mSession = s;
         mClient = c;
@@ -682,6 +713,7 @@
         DeathRecipient deathRecipient = new DeathRecipient();
         mSeq = seq;
         mEnforceSizeCompat = (mAttrs.privateFlags & PRIVATE_FLAG_COMPATIBLE_WINDOW) != 0;
+        mPowerManagerWrapper = powerManagerWrapper;
         if (localLOGV) Slog.v(
             TAG, "Window " + this + " client=" + c.asBinder()
             + " token=" + token + " (" + mAttrs.token + ")" + " params=" + a);
@@ -2275,9 +2307,34 @@
 
     void prepareWindowToDisplayDuringRelayout(boolean wasVisible) {
         // We need to turn on screen regardless of visibility.
-        if ((mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0) {
-            if (DEBUG_VISIBILITY) Slog.v(TAG, "Relayout window turning screen on: " + this);
-            mTurnOnScreen = true;
+        boolean hasTurnScreenOnFlag = (mAttrs.flags & FLAG_TURN_SCREEN_ON) != 0;
+        boolean allowTheaterMode =
+                mService.mAllowTheaterModeWakeFromLayout || Settings.Global.getInt(
+                        mService.mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0)
+                        == 0;
+        boolean canTurnScreenOn = mAppToken == null || mAppToken.canTurnScreenOn();
+
+        // The screen will turn on if the following conditions are met
+        // 1. The window has the flag FLAG_TURN_SCREEN_ON
+        // 2. The WMS allows theater mode.
+        // 3. No AWT or the AWT allows the screen to be turned on. This should only be true once
+        // per resume to prevent the screen getting getting turned on for each relayout. Set
+        // canTurnScreenOn will be set to false so the window doesn't turn the screen on again
+        // during this resume.
+        // 4. When the screen is not interactive. This is because when the screen is already
+        // interactive, the value may persist until the next animation, which could potentially
+        // be occurring while turning off the screen. This would lead to the screen incorrectly
+        // turning back on.
+        if (hasTurnScreenOnFlag && allowTheaterMode && canTurnScreenOn
+                && !mPowerManagerWrapper.isInteractive()) {
+            if (DEBUG_VISIBILITY || DEBUG_POWER) {
+                Slog.v(TAG, "Relayout window turning screen on: " + this);
+            }
+            mPowerManagerWrapper.wakeUp(SystemClock.uptimeMillis(),
+                    "android.server.wm:TURN_ON");
+        }
+        if (mAppToken != null) {
+            mAppToken.setCanTurnScreenOn(false);
         }
 
         // If we were already visible, skip rest of preparation.
@@ -2571,8 +2628,7 @@
                 // in wake lock statistics.  So in particular, we don't want to include the
                 // window's hash code as in toString().
                 final CharSequence tag = getWindowTag();
-                mDrawLock = mService.mPowerManager.newWakeLock(
-                        PowerManager.DRAW_WAKE_LOCK, "Window:" + tag);
+                mDrawLock = mService.mPowerManager.newWakeLock(DRAW_WAKE_LOCK, "Window:" + tag);
                 mDrawLock.setReferenceCounted(false);
                 mDrawLock.setWorkSource(new WorkSource(mOwnerUid, mAttrs.packageName));
             }
@@ -3327,15 +3383,13 @@
                     pw.print(" mDestroying="); pw.print(mDestroying);
                     pw.print(" mRemoved="); pw.println(mRemoved);
         }
-        if (getOrientationChanging() || mAppFreezing || mTurnOnScreen
-                || mReportOrientationChanged) {
+        if (getOrientationChanging() || mAppFreezing || mReportOrientationChanged) {
             pw.print(prefix); pw.print("mOrientationChanging=");
                     pw.print(mOrientationChanging);
                     pw.print(" configOrientationChanging=");
                     pw.print(getLastReportedConfiguration().orientation
                             != getConfiguration().orientation);
                     pw.print(" mAppFreezing="); pw.print(mAppFreezing);
-                    pw.print(" mTurnOnScreen="); pw.print(mTurnOnScreen);
                     pw.print(" mReportOrientationChanged="); pw.println(mReportOrientationChanged);
         }
         if (mLastFreezeDuration != 0) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index dd23b6f..9621ee5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1108,31 +1108,6 @@
                         w.setOrientationChanging(false);
                     }
                 }
-                // We process mTurnOnScreen even for windows which have already
-                // been shown, to handle cases where windows are not necessarily
-                // hidden while the screen is turning off.
-                // TODO(b/63773439): These cases should be eliminated, though we probably still
-                // want to process mTurnOnScreen in this way for clarity.
-                if (mWin.mTurnOnScreen &&
-                        (mWin.mAppToken == null || mWin.mAppToken.canTurnScreenOn())) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG, "Show surface turning screen on: " + mWin);
-                    mWin.mTurnOnScreen = false;
-
-                    // The window should only turn the screen on once per resume, but
-                    // prepareSurfaceLocked can be called multiple times. Set canTurnScreenOn to
-                    // false so the window doesn't turn the screen on again during this resume.
-                    if (mWin.mAppToken != null) {
-                        mWin.mAppToken.setCanTurnScreenOn(false);
-                    }
-
-                    // We do not add {@code SET_TURN_ON_SCREEN} when the screen is already
-                    // interactive as the value may persist until the next animation, which could
-                    // potentially occurring while turning off the screen. This would lead to the
-                    // screen incorrectly turning back on.
-                    if (!mService.mPowerManager.isInteractive()) {
-                        mService.mTurnOnScreen = true;
-                    }
-                }
             }
             if (hasSurface()) {
                 w.mToken.hasVisible = true;
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 4045b72..72f95fb 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -110,7 +110,6 @@
         "[email protected]",
         "[email protected]",
         "[email protected]",
-        "[email protected]",
         "[email protected]",
         "[email protected]",
         "[email protected]",
diff --git a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
index 176ae81..14e3578 100644
--- a/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
+++ b/services/core/jni/BroadcastRadio/BroadcastRadioService.cpp
@@ -23,7 +23,7 @@
 #include "convert.h"
 
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <broadcastradio-utils-1x/Utils.h>
 #include <core_jni_helpers.h>
@@ -45,7 +45,6 @@
 
 namespace V1_0 = hardware::broadcastradio::V1_0;
 namespace V1_1 = hardware::broadcastradio::V1_1;
-namespace V1_2 = hardware::broadcastradio::V1_2;
 namespace utils = hardware::broadcastradio::utils;
 
 using V1_0::BandConfig;
@@ -149,11 +148,7 @@
 
         auto halRev = HalRevision::V1_0;
         auto halMinor = 0;
-        if (V1_2::IBroadcastRadioFactory::castFrom(factory).withDefault(nullptr) != nullptr) {
-            halRev = HalRevision::V1_2;
-            halMinor = 2;
-        } else if (V1_1::IBroadcastRadioFactory::castFrom(factory).withDefault(nullptr)
-                != nullptr) {
+        if (V1_1::IBroadcastRadioFactory::castFrom(factory).withDefault(nullptr) != nullptr) {
             halRev = HalRevision::V1_1;
             halMinor = 1;
         }
diff --git a/services/core/jni/BroadcastRadio/Tuner.cpp b/services/core/jni/BroadcastRadio/Tuner.cpp
index 42c1332..36d2994 100644
--- a/services/core/jni/BroadcastRadio/Tuner.cpp
+++ b/services/core/jni/BroadcastRadio/Tuner.cpp
@@ -22,7 +22,7 @@
 #include "convert.h"
 #include "TunerCallback.h"
 
-#include <android/hardware/broadcastradio/1.2/IBroadcastRadioFactory.h>
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
 #include <binder/IPCThreadState.h>
 #include <broadcastradio-utils-1x/Utils.h>
 #include <core_jni_helpers.h>
@@ -44,16 +44,15 @@
 
 namespace V1_0 = hardware::broadcastradio::V1_0;
 namespace V1_1 = hardware::broadcastradio::V1_1;
-namespace V1_2 = hardware::broadcastradio::V1_2;
 namespace utils = hardware::broadcastradio::utils;
 
 using V1_0::Band;
 using V1_0::BandConfig;
 using V1_0::MetaData;
 using V1_0::Result;
+using V1_1::ITunerCallback;
 using V1_1::ProgramListResult;
 using V1_1::VendorKeyValue;
-using V1_2::ITunerCallback;
 using utils::HalRevision;
 
 static mutex gContextMutex;
@@ -94,7 +93,6 @@
     wp<V1_1::IBroadcastRadio> mHalModule11;
     sp<V1_0::ITuner> mHalTuner;
     sp<V1_1::ITuner> mHalTuner11;
-    sp<V1_2::ITuner> mHalTuner12;
     sp<HalDeathRecipient> mHalDeathRecipient;
 
 private:
@@ -181,11 +179,8 @@
 
     ctx.mHalTuner = halTuner;
     ctx.mHalTuner11 = V1_1::ITuner::castFrom(halTuner).withDefault(nullptr);
-    ctx.mHalTuner12 = V1_2::ITuner::castFrom(halTuner).withDefault(nullptr);
     ALOGW_IF(ctx.mHalRev >= HalRevision::V1_1 && ctx.mHalTuner11 == nullptr,
             "Provided tuner does not implement 1.1 HAL");
-    ALOGW_IF(ctx.mHalRev >= HalRevision::V1_2 && ctx.mHalTuner12 == nullptr,
-            "Provided tuner does not implement 1.2 HAL");
 
     ctx.mHalDeathRecipient = new HalDeathRecipient(getNativeCallback(env, jTuner));
     halTuner->linkToDeath(ctx.mHalDeathRecipient, 0);
@@ -209,11 +204,6 @@
     return getNativeContext(nativeContext).mHalTuner11;
 }
 
-static sp<V1_2::ITuner> getHalTuner12(jlong nativeContext) {
-    lock_guard<mutex> lk(gContextMutex);
-    return getNativeContext(nativeContext).mHalTuner12;
-}
-
 sp<ITunerCallback> getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner) {
     return TunerCallback::getNativeCallback(env,
             env->GetObjectField(tuner.get(), gjni.Tuner.tunerCallback));
@@ -243,7 +233,6 @@
     ctx.mHalDeathRecipient = nullptr;
 
     ctx.mHalTuner11 = nullptr;
-    ctx.mHalTuner12 = nullptr;
     ctx.mHalTuner = nullptr;
 }
 
@@ -466,48 +455,6 @@
     convert::ThrowIfFailed(env, halResult);
 }
 
-static jobject nativeSetParameters(JNIEnv *env, jobject obj, jlong nativeContext, jobject jParameters) {
-    ALOGV("%s", __func__);
-
-    auto halTuner = getHalTuner12(nativeContext);
-    if (halTuner == nullptr) {
-        ALOGI("Parameters are not supported with HAL < 1.2");
-        return nullptr;
-    }
-
-    JavaRef<jobject> jResults = nullptr;
-    auto parameters = convert::VendorInfoToHal(env, jParameters);
-    auto hidlResult = halTuner->setParameters(parameters,
-            [&](const hidl_vec<VendorKeyValue> results) {
-        jResults = convert::VendorInfoFromHal(env, results);
-    });
-
-    if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
-
-    return jResults.release();
-}
-
-static jobject nativeGetParameters(JNIEnv *env, jobject obj, jlong nativeContext, jobject jKeys) {
-    ALOGV("%s", __func__);
-
-    auto halTuner = getHalTuner12(nativeContext);
-    if (halTuner == nullptr) {
-        ALOGI("Parameters are not supported with HAL < 1.2");
-        return nullptr;
-    }
-
-    JavaRef<jobject> jResults = nullptr;
-    auto keys = convert::StringListToHal(env, jKeys);
-    auto hidlResult = halTuner->getParameters(keys,
-            [&](const hidl_vec<VendorKeyValue> parameters) {
-        jResults = convert::VendorInfoFromHal(env, parameters);
-    });
-
-    if (convert::ThrowIfFailed(env, hidlResult)) return nullptr;
-
-    return jResults.release();
-}
-
 static const JNINativeMethod gTunerMethods[] = {
     { "nativeInit", "(IZI)J", (void*)nativeInit },
     { "nativeFinalize", "(J)V", (void*)nativeFinalize },
@@ -528,8 +475,6 @@
     { "nativeGetImage", "(JI)[B", (void*)nativeGetImage},
     { "nativeIsAnalogForced", "(J)Z", (void*)nativeIsAnalogForced },
     { "nativeSetAnalogForced", "(JZ)V", (void*)nativeSetAnalogForced },
-    { "nativeSetParameters", "(JLjava/util/Map;)Ljava/util/Map;", (void*)nativeSetParameters },
-    { "nativeGetParameters", "(JLjava/util/List;)Ljava/util/Map;", (void*)nativeGetParameters },
 };
 
 } // namespace Tuner
diff --git a/services/core/jni/BroadcastRadio/Tuner.h b/services/core/jni/BroadcastRadio/Tuner.h
index 48c3bc7..818597b 100644
--- a/services/core/jni/BroadcastRadio/Tuner.h
+++ b/services/core/jni/BroadcastRadio/Tuner.h
@@ -22,8 +22,8 @@
 #include "JavaRef.h"
 
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
-#include <android/hardware/broadcastradio/1.2/ITuner.h>
-#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.1/ITuner.h>
+#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
 #include <jni.h>
 #include <utils/StrongPointer.h>
 
@@ -39,7 +39,7 @@
         sp<hardware::broadcastradio::V1_0::IBroadcastRadio> halModule,
         sp<hardware::broadcastradio::V1_0::ITuner> halTuner);
 
-sp<hardware::broadcastradio::V1_2::ITunerCallback>
+sp<hardware::broadcastradio::V1_1::ITunerCallback>
 getNativeCallback(JNIEnv *env, JavaRef<jobject> const &tuner);
 
 Region getRegion(JNIEnv *env, jobject obj);
diff --git a/services/core/jni/BroadcastRadio/TunerCallback.cpp b/services/core/jni/BroadcastRadio/TunerCallback.cpp
index 39f2c05..085a86a 100644
--- a/services/core/jni/BroadcastRadio/TunerCallback.cpp
+++ b/services/core/jni/BroadcastRadio/TunerCallback.cpp
@@ -40,18 +40,17 @@
 
 namespace V1_0 = hardware::broadcastradio::V1_0;
 namespace V1_1 = hardware::broadcastradio::V1_1;
-namespace V1_2 = hardware::broadcastradio::V1_2;
 namespace utils = hardware::broadcastradio::utils;
 
 using V1_0::Band;
 using V1_0::BandConfig;
 using V1_0::MetaData;
 using V1_0::Result;
+using V1_1::ITunerCallback;
 using V1_1::ProgramInfo;
 using V1_1::ProgramListResult;
 using V1_1::ProgramSelector;
 using V1_1::VendorKeyValue;
-using V1_2::ITunerCallback;
 using utils::HalRevision;
 
 static JavaVM *gvm = nullptr;
@@ -70,7 +69,6 @@
         jmethodID onBackgroundScanAvailabilityChange;
         jmethodID onBackgroundScanComplete;
         jmethodID onProgramListChanged;
-        jmethodID onParametersUpdated;
     } TunerCallback;
 } gjni;
 
@@ -122,7 +120,6 @@
     virtual Return<void> backgroundScanComplete(ProgramListResult result);
     virtual Return<void> programListChanged();
     virtual Return<void> currentProgramInfoChanged(const ProgramInfo& info);
-    virtual Return<void> parametersUpdated(const hidl_vec<VendorKeyValue>& parameters);
 };
 
 struct TunerCallbackContext {
@@ -344,17 +341,6 @@
     return Return<void>();
 }
 
-Return<void> NativeCallback::parametersUpdated(const hidl_vec<VendorKeyValue>& parameters) {
-    ALOGV("%s", __func__);
-
-    mCallbackThread.enqueue([this, parameters](JNIEnv *env) {
-        auto jParameters = convert::VendorInfoFromHal(env, parameters);
-        env->CallVoidMethod(mJCallback, gjni.TunerCallback.onParametersUpdated, jParameters.get());
-    });
-
-    return {};
-}
-
 static TunerCallbackContext& getNativeContext(jlong nativeContextHandle) {
     auto nativeContext = reinterpret_cast<TunerCallbackContext*>(nativeContextHandle);
     LOG_ALWAYS_FATAL_IF(nativeContext == nullptr, "Native context not initialized");
@@ -441,8 +427,6 @@
             "onBackgroundScanComplete", "()V");
     gjni.TunerCallback.onProgramListChanged = GetMethodIDOrDie(env, tunerCbClass,
             "onProgramListChanged", "()V");
-    gjni.TunerCallback.onParametersUpdated = GetMethodIDOrDie(env, tunerCbClass,
-            "onParametersUpdated", "(Ljava/util/Map;)V");
 
     auto res = jniRegisterNativeMethods(env, "com/android/server/broadcastradio/hal1/TunerCallback",
             gTunerCallbackMethods, NELEM(gTunerCallbackMethods));
diff --git a/services/core/jni/BroadcastRadio/TunerCallback.h b/services/core/jni/BroadcastRadio/TunerCallback.h
index 7e776c2..af12d21 100644
--- a/services/core/jni/BroadcastRadio/TunerCallback.h
+++ b/services/core/jni/BroadcastRadio/TunerCallback.h
@@ -21,7 +21,7 @@
 #include "NativeCallbackThread.h"
 #include "types.h"
 
-#include <android/hardware/broadcastradio/1.2/ITunerCallback.h>
+#include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
 #include <jni.h>
 
 namespace android {
@@ -32,7 +32,7 @@
 namespace BroadcastRadio {
 namespace TunerCallback {
 
-sp<hardware::broadcastradio::V1_2::ITunerCallback>
+sp<hardware::broadcastradio::V1_1::ITunerCallback>
 getNativeCallback(JNIEnv *env, jobject jTunerCallback);
 
 } // namespace TunerCallback
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index bcb0b4f..47350c1 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -385,20 +385,21 @@
     delete impl;
 }
 
-static void android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
+static jint android_server_AlarmManagerService_set(JNIEnv*, jobject, jlong nativeData, jint type, jlong seconds, jlong nanoseconds)
 {
     AlarmImpl *impl = reinterpret_cast<AlarmImpl *>(nativeData);
     struct timespec ts;
     ts.tv_sec = seconds;
     ts.tv_nsec = nanoseconds;
 
-    int result = impl->set(type, &ts);
+    const int result = impl->set(type, &ts);
     if (result < 0)
     {
         ALOGE("Unable to set alarm to %lld.%09lld: %s\n",
               static_cast<long long>(seconds),
               static_cast<long long>(nanoseconds), strerror(errno));
     }
+    return result >= 0 ? 0 : errno;
 }
 
 static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv*, jobject, jlong nativeData)
@@ -424,7 +425,7 @@
      /* name, signature, funcPtr */
     {"init", "()J", (void*)android_server_AlarmManagerService_init},
     {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
-    {"set", "(JIJJ)V", (void*)android_server_AlarmManagerService_set},
+    {"set", "(JIJJ)I", (void*)android_server_AlarmManagerService_set},
     {"waitForAlarm", "(J)I", (void*)android_server_AlarmManagerService_waitForAlarm},
     {"setKernelTime", "(JJ)I", (void*)android_server_AlarmManagerService_setKernelTime},
     {"setKernelTimezone", "(JI)I", (void*)android_server_AlarmManagerService_setKernelTimezone},
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 5ea113b..75bb5e4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -842,6 +842,14 @@
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
             traceEnd();
 
+            traceBeginAndSlog("SetWindowManagerService");
+            mActivityManagerService.setWindowManager(wm);
+            traceEnd();
+
+            traceBeginAndSlog("WindowManagerServiceOnInitReady");
+            wm.onInitReady();
+            traceEnd();
+
             // Start receiving calls from HIDL services. Start in in a separate thread
             // because it need to connect to SensorManager. This have to start
             // after START_SENSOR_SERVICE is done.
@@ -859,10 +867,6 @@
                 traceEnd();
             }
 
-            traceBeginAndSlog("SetWindowManagerService");
-            mActivityManagerService.setWindowManager(wm);
-            traceEnd();
-
             traceBeginAndSlog("StartInputManager");
             inputManager.setWindowManagerCallbacks(wm.getInputMonitor());
             inputManager.start();
diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
index cd9311f..a5beed0 100644
--- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
+++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java
@@ -17,19 +17,21 @@
 package com.android.server.backup;
 
 import static com.android.server.backup.testing.TransportData.backupTransport;
-import static com.android.server.backup.testing.TransportTestUtils.setUpTransport;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
@@ -44,6 +46,7 @@
 import android.app.backup.BackupAgent;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
+import android.app.backup.BackupManager;
 import android.app.backup.BackupTransport;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.IBackupManager;
@@ -70,6 +73,7 @@
 import com.android.server.backup.internal.OnTaskFinishedListener;
 import com.android.server.backup.internal.PerformBackupTask;
 import com.android.server.backup.testing.TransportData;
+import com.android.server.backup.testing.TransportTestUtils;
 import com.android.server.backup.testing.TransportTestUtils.TransportMock;
 import com.android.server.backup.transport.TransportClient;
 import com.android.server.testing.FrameworkRobolectricTestRunner;
@@ -132,31 +136,25 @@
     @Mock private IBackupManagerMonitor mMonitor;
     @Mock private OnTaskFinishedListener mListener;
     private TransportData mTransport;
-    private IBackupTransport mTransportBinder;
-    private TransportClient mTransportClient;
     private ShadowLooper mShadowBackupLooper;
     private BackupHandler mBackupHandler;
     private PowerManager.WakeLock mWakeLock;
     private ShadowPackageManager mShadowPackageManager;
     private FakeIBackupManager mBackupManager;
+    private File mBaseStateDir;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         mTransport = backupTransport();
-        TransportMock transportMock = setUpTransport(mTransportManager, mTransport);
-        mTransportBinder = transportMock.transport;
-        mTransportClient = transportMock.transportClient;
 
         Application application = RuntimeEnvironment.application;
         File cacheDir = application.getCacheDir();
-        File baseStateDir = new File(cacheDir, "base_state_dir");
+        mBaseStateDir = new File(cacheDir, "base_state_dir");
         File dataDir = new File(cacheDir, "data_dir");
-        File stateDir = new File(baseStateDir, mTransport.transportDirName);
-        assertThat(baseStateDir.mkdir()).isTrue();
+        assertThat(mBaseStateDir.mkdir()).isTrue();
         assertThat(dataDir.mkdir()).isTrue();
-        assertThat(stateDir.mkdir()).isTrue();
 
         PackageManager packageManager = application.getPackageManager();
         mShadowPackageManager = Shadow.extract(packageManager);
@@ -182,7 +180,7 @@
         when(mBackupManagerService.getWakelock()).thenReturn(mWakeLock);
         when(mBackupManagerService.getCurrentOpLock()).thenReturn(new Object());
         when(mBackupManagerService.getQueueLock()).thenReturn(new Object());
-        when(mBackupManagerService.getBaseStateDir()).thenReturn(baseStateDir);
+        when(mBackupManagerService.getBaseStateDir()).thenReturn(mBaseStateDir);
         when(mBackupManagerService.getDataDir()).thenReturn(dataDir);
         when(mBackupManagerService.getCurrentOperations()).thenReturn(new SparseArray<>());
         when(mBackupManagerService.getBackupHandler()).thenReturn(mBackupHandler);
@@ -192,10 +190,16 @@
 
     @Test
     public void testRunTask_whenTransportProvidesFlags_passesThemToTheAgent() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
         AgentMock agentMock = setUpAgent(PACKAGE_1);
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
-        when(mTransportBinder.getTransportFlags()).thenReturn(flags);
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        when(transportMock.transport.getTransportFlags()).thenReturn(flags);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
 
         runTask(task);
 
@@ -205,8 +209,14 @@
 
     @Test
     public void testRunTask_whenTransportDoesNotProvidesFlags() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
         AgentMock agentMock = setUpAgent(PACKAGE_1);
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
 
         runTask(task);
 
@@ -216,13 +226,19 @@
     @Test
     public void testRunTask_whenTransportProvidesFlagsAndMultipleAgents_passesToAll()
             throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
         List<AgentMock> agentMocks = setUpAgents(PACKAGE_1, PACKAGE_2);
         BackupAgent agent1 = agentMocks.get(0).agent;
         BackupAgent agent2 = agentMocks.get(1).agent;
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
-        when(mTransportBinder.getTransportFlags()).thenReturn(flags);
+        when(transportMock.transport.getTransportFlags()).thenReturn(flags);
         PerformBackupTask task =
-                createPerformBackupTask(emptyList(), false, true, PACKAGE_1, PACKAGE_2);
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1,
+                        PACKAGE_2);
 
         runTask(task);
 
@@ -232,10 +248,16 @@
 
     @Test
     public void testRunTask_whenTransportChangeFlagsAfterTaskCreation() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
         AgentMock agentMock = setUpAgent(PACKAGE_1);
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
         int flags = BackupAgent.FLAG_CLIENT_SIDE_ENCRYPTION_ENABLED;
-        when(mTransportBinder.getTransportFlags()).thenReturn(flags);
+        when(transportMock.transport.getTransportFlags()).thenReturn(flags);
 
         runTask(task);
 
@@ -244,17 +266,26 @@
     }
 
     @Test
-    public void testRunTask_callsListenerOnTaskFinished() throws Exception {
+    public void testRunTask_callsListenerAndObserver() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
         setUpAgent(PACKAGE_1);
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
 
         runTask(task);
 
         verify(mListener).onFinished(any());
+        verify(mObserver).backupFinished(eq(BackupManager.SUCCESS));
     }
 
     @Test
-    public void testRunTask_callsTransportPerformBackup() throws Exception {
+    public void testRunTask_callsTransportPerformBackupWithAgentData() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transportBinder = transportMock.transport;
         AgentMock agentMock = setUpAgent(PACKAGE_1);
         agentOnBackupDo(
                 agentMock.agent,
@@ -262,15 +293,20 @@
                     writeData(dataOutput, "key1", "foo".getBytes());
                     writeData(dataOutput, "key2", "bar".getBytes());
                 });
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
         // We need to verify at call time because the file is deleted right after
-        when(mTransportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                 .then(this::mockAndVerifyTransportPerformBackupData);
 
         runTask(task);
 
         // Already verified data in mockAndVerifyPerformBackupData
-        verify(mTransportBinder).performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
+        verify(transportBinder).performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt());
     }
 
     private int mockAndVerifyTransportPerformBackupData(InvocationOnMock invocation)
@@ -305,18 +341,26 @@
     @Test
     public void testRunTask_whenPerformBackupSucceeds_callsTransportFinishBackup()
             throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transportBinder = transportMock.transport;
         setUpAgent(PACKAGE_1);
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
-        when(mTransportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
                 .thenReturn(BackupTransport.TRANSPORT_OK);
 
         runTask(task);
 
-        verify(mTransportBinder).finishBackup();
+        verify(transportBinder).finishBackup();
     }
 
     @Test
     public void testRunTask_whenProhibitedKey_failsAgent() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
         AgentMock agentMock = setUpAgent(PACKAGE_1);
         agentOnBackupDo(
                 agentMock.agent,
@@ -324,13 +368,149 @@
                     char prohibitedChar = 0xff00;
                     writeData(dataOutput, prohibitedChar + "key", "foo".getBytes());
                 });
-        PerformBackupTask task = createPerformBackupTask(emptyList(), false, true, PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
 
         runTask(task);
 
+        // TODO: Should it not call mListener.onFinished()? PerformBackupTask:891 return?
+        // verify(mListener).onFinished(any());
+        verify(mObserver).onResult(eq(PACKAGE_1), eq(BackupManager.ERROR_AGENT_FAILURE));
         verify(agentMock.agentBinder).fail(any());
     }
 
+    @Test
+    public void testRunTask_whenTransportUnavailable() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport.unavailable());
+        setUpAgent(PACKAGE_1);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(mListener).onFinished(any());
+        // TODO: Should it be 2 times? (PBT.beginBackup() and PBT.finalizeBackup())
+        verify(mObserver, times(2)).backupFinished(eq(BackupManager.ERROR_TRANSPORT_ABORTED));
+    }
+
+    @Test
+    public void testRunTask_whenTransportRejectsPackage() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        setUpAgent(PACKAGE_1);
+        when(transportMock.transport.performBackup(
+                        argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+        verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+    }
+
+    @Test
+    public void testRunTask_whenTransportRejectsFirstPackageButLastSucceeds() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transportBinder = transportMock.transport;
+        setUpAgents(PACKAGE_1, PACKAGE_2);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_OK);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1,
+                        PACKAGE_2);
+
+        runTask(task);
+
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+        verify(mObserver).onResult(PACKAGE_2, BackupManager.SUCCESS);
+        verify(mObserver).backupFinished(BackupManager.SUCCESS);
+    }
+
+    @Test
+    public void testRunTask_whenTransportRejectsLastPackageButFirstSucceeds() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        IBackupTransport transportBinder = transportMock.transport;
+        setUpAgents(PACKAGE_1, PACKAGE_2);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_OK);
+        when(transportBinder.performBackup(argThat(packageInfo(PACKAGE_2)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_PACKAGE_REJECTED);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1,
+                        PACKAGE_2);
+
+        runTask(task);
+
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.SUCCESS);
+        verify(mObserver).onResult(PACKAGE_2, BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED);
+        // TODO: Should we return the status of the last?
+        verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+    }
+
+    @Test
+    public void testRunTask_whenTransportReturnsQuotaExceeded() throws Exception {
+        TransportMock transportMock = setUpTransport(mTransport);
+        AgentMock agentMock = setUpAgent(PACKAGE_1);
+        when(transportMock.transport.performBackup(
+                        argThat(packageInfo(PACKAGE_1)), any(), anyInt()))
+                .thenReturn(BackupTransport.TRANSPORT_QUOTA_EXCEEDED);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED);
+        verify(mObserver).backupFinished(BackupManager.ERROR_TRANSPORT_ABORTED);
+        verify(agentMock.agent).onQuotaExceeded(anyLong(), anyLong());
+    }
+
+    // TODO: Giving NPE at PerformBackupTask:524 because mCurrentPackage is null (PackageManager
+    // rightfully threw NameNotFoundException). Uncomment @Test when fixed.
+    // @Test
+    public void testRunTask_whenAgentUnknown() throws Exception {
+        // Not calling setUpAgent()
+        TransportMock transportMock = setUpTransport(mTransport);
+        PerformBackupTask task =
+                createPerformBackupTask(
+                        transportMock.transportClient,
+                        mTransport.transportDirName,
+                        emptyList(),
+                        PACKAGE_1);
+
+        runTask(task);
+
+        verify(transportMock.transport, never()).performBackup(any(), any(), anyInt());
+        verify(mObserver).onResult(PACKAGE_1, BackupManager.ERROR_PACKAGE_NOT_FOUND);
+        verify(mObserver).backupFinished(BackupManager.SUCCESS);
+    }
+
     private void runTask(PerformBackupTask task) {
         Message message = mBackupHandler.obtainMessage(BackupHandler.MSG_BACKUP_RESTORE_STEP, task);
         mBackupHandler.sendMessage(message);
@@ -339,6 +519,14 @@
         }
     }
 
+    private TransportMock setUpTransport(TransportData transport) throws Exception {
+        TransportMock transportMock =
+                TransportTestUtils.setUpTransport(mTransportManager, transport);
+        File stateDir = new File(mBaseStateDir, transport.transportDirName);
+        assertThat(stateDir.mkdir()).isTrue();
+        return transportMock;
+    }
+
     private List<AgentMock> setUpAgents(String... packageNames) {
         return Stream.of(packageNames).map(this::setUpAgent).collect(toList());
     }
@@ -370,9 +558,9 @@
     }
 
     private PerformBackupTask createPerformBackupTask(
+            TransportClient transportClient,
+            String transportDirName,
             List<String> pendingFullBackups,
-            boolean userInitiated,
-            boolean nonIncremental,
             String... packages) {
         ArrayList<BackupRequest> backupRequests =
                 Stream.of(packages).map(BackupRequest::new).collect(toCollection(ArrayList::new));
@@ -380,22 +568,30 @@
         PerformBackupTask task =
                 new PerformBackupTask(
                         mBackupManagerService,
-                        mTransportClient,
-                        mTransport.transportDirName,
+                        transportClient,
+                        transportDirName,
                         backupRequests,
                         mDataChangedJournal,
                         mObserver,
                         mMonitor,
                         mListener,
                         pendingFullBackups,
-                        userInitiated,
-                        nonIncremental);
+                        /* userInitiated */ false,
+                        /* nonIncremental */ true);
         mBackupManager.setUp(mBackupHandler, task);
         return task;
     }
 
     private static ArgumentMatcher<PackageInfo> packageInfo(String packageName) {
-        return packageInfo -> packageName.equals(packageInfo.packageName);
+        // We have to test for packageInfo nulity because of Mockito's own stubbing with argThat().
+        // E.g. if you do:
+        //
+        //   1. when(object.method(argThat(str -> str.equals("foo")))).thenReturn(0)
+        //   2. when(object.method(argThat(str -> str.equals("bar")))).thenReturn(2)
+        //
+        // The second line will throw NPE because it will call lambda 1 with null, since argThat()
+        // returns null. So we guard against that by checking for null.
+        return packageInfo -> packageInfo != null && packageName.equals(packageInfo.packageName);
     }
 
     private static ArgumentMatcher<BackupDataOutput> dataOutputWithTransportFlags(int flags) {
@@ -435,7 +631,7 @@
         private final IBackupAgent agentBinder;
         private final BackupAgent agent;
 
-        public AgentMock(IBackupAgent agentBinder, BackupAgent agent) {
+        private AgentMock(IBackupAgent agentBinder, BackupAgent agent) {
             this.agentBinder = agentBinder;
             this.agent = agent;
         }
diff --git a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
similarity index 93%
rename from services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
rename to services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
index a499472..90db2a3 100644
--- a/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
@@ -15,7 +15,7 @@
  */
 package com.android.server;
 
-import static com.android.server.ForceAppStandbyTracker.TARGET_OP;
+import static com.android.server.AppStateTracker.TARGET_OP;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -33,6 +33,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.AppOpsManager;
 import android.app.AppOpsManager.OpEntry;
 import android.app.AppOpsManager.PackageOps;
@@ -63,7 +64,7 @@
 
 import com.android.internal.app.IAppOpsCallback;
 import com.android.internal.app.IAppOpsService;
-import com.android.server.ForceAppStandbyTracker.Listener;
+import com.android.server.AppStateTracker.Listener;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -82,17 +83,17 @@
 import java.util.function.Consumer;
 
 /**
- * Tests for {@link ForceAppStandbyTracker}
+ * Tests for {@link AppStateTracker}
  *
  * Run with:
- atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/ForceAppStandbyTrackerTest.java
+ atest $ANDROID_BUILD_TOP/frameworks/base/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class ForceAppStandbyTrackerTest {
+public class AppStateTrackerTest {
 
-    private class ForceAppStandbyTrackerTestable extends ForceAppStandbyTracker {
-        ForceAppStandbyTrackerTestable() {
+    private class AppStateTrackerTestable extends AppStateTracker {
+        AppStateTrackerTestable() {
             super(mMockContext, Looper.getMainLooper());
         }
 
@@ -112,6 +113,11 @@
         }
 
         @Override
+        ActivityManagerInternal injectActivityManagerInternal() {
+            return mMockIActivityManagerInternal;
+        }
+
+        @Override
         PowerManagerInternal injectPowerManagerInternal() {
             return mMockPowerManagerInternal;
         }
@@ -152,6 +158,9 @@
     private IActivityManager mMockIActivityManager;
 
     @Mock
+    private ActivityManagerInternal mMockIActivityManagerInternal;
+
+    @Mock
     private AppOpsManager mMockAppOpsManager;
 
     @Mock
@@ -195,7 +204,7 @@
         return new PowerSaveState.Builder().setBatterySaverEnabled(mPowerSaveMode).build();
     }
 
-    private ForceAppStandbyTrackerTestable newInstance() throws Exception {
+    private AppStateTrackerTestable newInstance() throws Exception {
         MockitoAnnotations.initMocks(this);
 
         when(mMockIAppOpsService.checkOperation(eq(TARGET_OP), anyInt(), anyString()))
@@ -205,12 +214,12 @@
                             AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED;
                 });
 
-        final ForceAppStandbyTrackerTestable instance = new ForceAppStandbyTrackerTestable();
+        final AppStateTrackerTestable instance = new AppStateTrackerTestable();
 
         return instance;
     }
 
-    private void callStart(ForceAppStandbyTrackerTestable instance) throws RemoteException {
+    private void callStart(AppStateTrackerTestable instance) throws RemoteException {
 
         // Set up functions that start() calls.
         when(mMockPowerManagerInternal.getLowPowerState(eq(ServiceType.FORCE_ALL_APPS_STANDBY)))
@@ -223,7 +232,7 @@
         when(mMockContext.getContentResolver()).thenReturn(mMockContentResolver);
 
         // Call start.
-        instance.start();
+        instance.onSystemServicesReady();
 
         // Capture the listeners.
         ArgumentCaptor<IUidObserver> uidObserverArgumentCaptor =
@@ -287,7 +296,7 @@
     private static final int JOBS_ONLY = 1 << 1;
     private static final int JOBS_AND_ALARMS = ALARMS_ONLY | JOBS_ONLY;
 
-    private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
+    private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName,
             int restrictionTypes, boolean exemptFromBatterySaver) {
         assertEquals(((restrictionTypes & JOBS_ONLY) != 0),
                 instance.areJobsRestricted(uid, packageName, exemptFromBatterySaver));
@@ -295,13 +304,13 @@
                 instance.areAlarmsRestricted(uid, packageName, exemptFromBatterySaver));
     }
 
-    private void areRestricted(ForceAppStandbyTrackerTestable instance, int uid, String packageName,
+    private void areRestricted(AppStateTrackerTestable instance, int uid, String packageName,
             int restrictionTypes) {
         areRestricted(instance, uid, packageName, restrictionTypes,
                 /*exemptFromBatterySaver=*/ false);
     }
 
-    private void areRestrictedWithExemption(ForceAppStandbyTrackerTestable instance,
+    private void areRestrictedWithExemption(AppStateTrackerTestable instance,
             int uid, String packageName, int restrictionTypes) {
         areRestricted(instance, uid, packageName, restrictionTypes,
                 /*exemptFromBatterySaver=*/ true);
@@ -309,7 +318,7 @@
 
     @Test
     public void testAll() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
         assertFalse(instance.isForceAllAppsStandbyEnabled());
@@ -466,7 +475,7 @@
 
     @Test
     public void testUidStateForeground() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
         mIUidObserver.onUidActive(UID_1);
@@ -476,6 +485,10 @@
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
 
+        assertTrue(instance.isUidActiveSynced(UID_1));
+        assertFalse(instance.isUidActiveSynced(UID_2));
+        assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
         assertFalse(instance.isUidInForeground(UID_1));
         assertFalse(instance.isUidInForeground(UID_2));
         assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
@@ -489,6 +502,10 @@
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
 
+        assertTrue(instance.isUidActiveSynced(UID_1));
+        assertFalse(instance.isUidActiveSynced(UID_2));
+        assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
         assertFalse(instance.isUidInForeground(UID_1));
         assertTrue(instance.isUidInForeground(UID_2));
         assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
@@ -548,14 +565,34 @@
         assertFalse(instance.isUidActive(UID_2));
         assertTrue(instance.isUidActive(Process.SYSTEM_UID));
 
+        assertFalse(instance.isUidActiveSynced(UID_1));
+        assertFalse(instance.isUidActiveSynced(UID_2));
+        assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
         assertFalse(instance.isUidInForeground(UID_1));
         assertFalse(instance.isUidInForeground(UID_2));
         assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
+        // The result from AMI.isUidActive() only affects isUidActiveSynced().
+        when(mMockIActivityManagerInternal.isUidActive(anyInt())).thenReturn(true);
+
+        assertFalse(instance.isUidActive(UID_1));
+        assertFalse(instance.isUidActive(UID_2));
+        assertTrue(instance.isUidActive(Process.SYSTEM_UID));
+
+        assertTrue(instance.isUidActiveSynced(UID_1));
+        assertTrue(instance.isUidActiveSynced(UID_2));
+        assertTrue(instance.isUidActiveSynced(Process.SYSTEM_UID));
+
+        assertFalse(instance.isUidInForeground(UID_1));
+        assertFalse(instance.isUidInForeground(UID_2));
+        assertTrue(instance.isUidInForeground(Process.SYSTEM_UID));
+
     }
 
     @Test
     public void testExempt() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
         assertFalse(instance.isForceAllAppsStandbyEnabled());
@@ -621,7 +658,7 @@
     }
 
     public void loadPersistedAppOps() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
 
         final List<PackageOps> ops = new ArrayList<>();
 
@@ -631,7 +668,7 @@
                 AppOpsManager.OP_ACCESS_NOTIFICATIONS,
                 AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
         entries.add(new AppOpsManager.OpEntry(
-                ForceAppStandbyTracker.TARGET_OP,
+                AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
 
         ops.add(new PackageOps(PACKAGE_1, UID_1, entries));
@@ -639,7 +676,7 @@
         //--------------------------------------------------
         entries = new ArrayList<>();
         entries.add(new AppOpsManager.OpEntry(
-                ForceAppStandbyTracker.TARGET_OP,
+                AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
 
         ops.add(new PackageOps(PACKAGE_2, UID_2, entries));
@@ -647,7 +684,7 @@
         //--------------------------------------------------
         entries = new ArrayList<>();
         entries.add(new AppOpsManager.OpEntry(
-                ForceAppStandbyTracker.TARGET_OP,
+                AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_ALLOWED, 0, 0, 0, 0, null));
 
         ops.add(new PackageOps(PACKAGE_1, UID_10_1, entries));
@@ -655,7 +692,7 @@
         //--------------------------------------------------
         entries = new ArrayList<>();
         entries.add(new AppOpsManager.OpEntry(
-                ForceAppStandbyTracker.TARGET_OP,
+                AppStateTracker.TARGET_OP,
                 AppOpsManager.MODE_IGNORED, 0, 0, 0, 0, null));
         entries.add(new AppOpsManager.OpEntry(
                 AppOpsManager.OP_ACCESS_NOTIFICATIONS,
@@ -688,10 +725,10 @@
 
     @Test
     public void testPowerSaveListener() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
-        ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class);
+        AppStateTracker.Listener l = mock(AppStateTracker.Listener.class);
         instance.addListener(l);
 
         // Power save on.
@@ -731,10 +768,10 @@
 
     @Test
     public void testAllListeners() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
-        ForceAppStandbyTracker.Listener l = mock(ForceAppStandbyTracker.Listener.class);
+        AppStateTracker.Listener l = mock(AppStateTracker.Listener.class);
         instance.addListener(l);
 
         // -------------------------------------------------------------------------
@@ -1042,7 +1079,7 @@
 
     @Test
     public void testUserRemoved() throws Exception {
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
 
         mIUidObserver.onUidActive(UID_1);
@@ -1077,7 +1114,7 @@
         // This is a small battery device
         mIsSmallBatteryDevice = true;
 
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
         assertFalse(instance.isForceAllAppsStandbyEnabled());
 
@@ -1103,7 +1140,7 @@
         // Not a small battery device, so plugged in status should not affect forced app standby
         mIsSmallBatteryDevice = false;
 
-        final ForceAppStandbyTrackerTestable instance = newInstance();
+        final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
         assertFalse(instance.isForceAllAppsStandbyEnabled());
 
@@ -1152,7 +1189,7 @@
 
     private void checkAnyAppIdUnwhitelisted(int[] prevArray, int[] newArray, boolean expected) {
         assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
-                expected, ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(prevArray, newArray));
+                expected, AppStateTracker.isAnyAppIdUnwhitelisted(prevArray, newArray));
 
         // Also test isAnyAppIdUnwhitelistedSlow.
         assertEquals("Input: " + Arrays.toString(prevArray) + " " + Arrays.toString(newArray),
@@ -1184,7 +1221,7 @@
             final int[] array2 = makeRandomArray();
 
             final boolean expected = isAnyAppIdUnwhitelistedSlow(array1, array2);
-            final boolean actual = ForceAppStandbyTracker.isAnyAppIdUnwhitelisted(array1, array2);
+            final boolean actual = AppStateTracker.isAnyAppIdUnwhitelisted(array1, array2);
 
             assertEquals("Input: " + Arrays.toString(array1) + " " + Arrays.toString(array2),
                     expected, actual);
diff --git a/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
new file mode 100644
index 0000000..6e76b67
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.runner.AndroidJUnit4;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Unit tests for {@link WatchdogDiagnostics}
+ */
+@RunWith(AndroidJUnit4.class)
+public class WatchdogDiagnosticsTest {
+
+    private static class TestThread1 extends Thread {
+        Object lock1;
+        Object lock2;
+        volatile boolean inB = false;
+
+        public TestThread1(Object lock1, Object lock2) {
+            super("TestThread1");
+            this.lock1 = lock1;
+            this.lock2 = lock2;
+        }
+
+        @Override
+        public void run() {
+            a();
+        }
+
+        private void a() {
+            synchronized(lock1) {
+                b();
+            }
+        }
+
+        private void b() {
+            inB = true;
+            synchronized(lock2) {
+                // Nothing.
+            }
+        }
+    }
+
+    private static class TestThread2 extends Thread {
+        Object lock1;
+        Object lock2;
+        volatile boolean inY = false;
+
+        public TestThread2(Object lock1, Object lock2) {
+            super("TestThread2");
+            this.lock1 = lock1;
+            this.lock2 = lock2;
+        }
+
+        @Override
+        public void run() {
+            x();
+        }
+
+        private void x() {
+            synchronized(lock1) {
+                y();
+            }
+        }
+
+        private void y() {
+            synchronized(lock2) {
+                inY = true;
+                try {
+                    lock2.wait();
+                } catch (Exception exc) {
+                    throw new RuntimeException(exc);
+                }
+            }
+        }
+    }
+
+    @Test
+    public void printAnnotatedStack() throws Exception {
+        // Preparation.
+
+        Object heldLock1 = new Object();
+        Object heldLock2 = 0;
+        Object waitLock = "123";
+
+        TestThread1 thread1 = new TestThread1(heldLock1, heldLock2);
+        TestThread2 thread2 = new TestThread2(heldLock2, waitLock);
+
+        // Start the second thread, ensure it grabs heldLock2.
+        thread2.start();
+        while(!thread2.inY) {
+            Thread.yield();
+        }
+
+        // Start the first thread, ensure it made progress.
+        thread1.start();
+        while(!thread1.inB) {
+            Thread.yield();
+        }
+
+        // Now wait till both are no longer in runnable state.
+        while (thread1.getState() == Thread.State.RUNNABLE) {
+            Thread.yield();
+        }
+        while (thread2.getState() == Thread.State.RUNNABLE) {
+            Thread.yield();
+        }
+
+        // Now do the test.
+        StringWriter stringBuffer = new StringWriter();
+        PrintWriter print = new PrintWriter(stringBuffer, true);
+
+        {
+            WatchdogDiagnostics.printAnnotatedStack(thread1, print);
+
+            String output = stringBuffer.toString();
+            String expected =
+                    "TestThread1 annotated stack trace:\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread1.b(" +
+                            "WatchdogDiagnosticsTest.java:59)\n" +
+                    "    - waiting to lock <HASH> (a java.lang.Integer)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread1.a(" +
+                            "WatchdogDiagnosticsTest.java:53)\n" +
+                    "    - locked <HASH> (a java.lang.Object)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread1.run(" +
+                            "WatchdogDiagnosticsTest.java:48)\n";
+            assertEquals(expected, filterHashes(output));
+        }
+
+        stringBuffer.getBuffer().setLength(0);
+
+        {
+            WatchdogDiagnostics.printAnnotatedStack(thread2, print);
+
+            String output = stringBuffer.toString();
+            String expected =
+                    "TestThread2 annotated stack trace:\n" +
+                    "    at java.lang.Object.wait(Native Method)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" +
+                            "WatchdogDiagnosticsTest.java:91)\n" +
+                    "    - locked <HASH> (a java.lang.String)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread2.x(" +
+                            "WatchdogDiagnosticsTest.java:83)\n" +
+                    "    - locked <HASH> (a java.lang.Integer)\n" +
+                    "    at com.android.server.WatchdogDiagnosticsTest$TestThread2.run(" +
+                            "WatchdogDiagnosticsTest.java:78)\n";
+            assertEquals(expected, filterHashes(output));
+        }
+
+        // Let the threads finish.
+        synchronized (waitLock) {
+            waitLock.notifyAll();
+        }
+
+        thread1.join();
+        thread2.join();
+    }
+
+    /**
+     * A filter function that removes hash codes (which will change between tests and cannot be
+     * controlled.)
+     * <p>
+     * Note: leaves "<HASH>" to indicate that something was replaced.
+     */
+    private static String filterHashes(String t) {
+        return t.replaceAll("<0x[0-9a-f]{8}>", "<HASH>");
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
new file mode 100644
index 0000000..a7e3810
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/am/MemoryStatUtilTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import static com.android.server.am.MemoryStatUtil.parseMemoryStat;
+import static com.android.server.am.MemoryStatUtil.MemoryStat;
+
+import static org.junit.Assert.assertEquals;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class MemoryStatUtilTest {
+  private String MEMORY_STAT_CONTENTS = String.join(
+      "\n",
+      "cache 96", // keep different from total_cache to catch reading wrong value
+      "rss 97", // keep different from total_rss to catch reading wrong value
+      "rss_huge 0",
+      "mapped_file 524288",
+      "writeback 0",
+      "swap 95", // keep different from total_rss to catch reading wrong value
+      "pgpgin 16717",
+      "pgpgout 5037",
+      "pgfault 99", // keep different from total_pgfault to catch reading wrong value
+      "pgmajfault 98", // keep different from total_pgmajfault to catch reading wrong value
+      "inactive_anon 503808",
+      "active_anon 46309376",
+      "inactive_file 876544",
+      "active_file 81920",
+      "unevictable 0",
+      "hierarchical_memory_limit 18446744073709551615",
+      "hierarchical_memsw_limit 18446744073709551615",
+      "total_cache 4",
+      "total_rss 3",
+      "total_rss_huge 0",
+      "total_mapped_file 524288",
+      "total_writeback 0",
+      "total_swap 5",
+      "total_pgpgin 16717",
+      "total_pgpgout 5037",
+      "total_pgfault 1",
+      "total_pgmajfault 2",
+      "total_inactive_anon 503808",
+      "total_active_anon 46309376",
+      "total_inactive_file 876544",
+      "total_active_file 81920",
+      "total_unevictable 0");
+
+
+  @Test
+  public void testParseMemoryStat_parsesCorrectValues() throws Exception {
+    MemoryStat stat = parseMemoryStat(MEMORY_STAT_CONTENTS);
+    assertEquals(stat.pgfault, 1);
+    assertEquals(stat.pgmajfault, 2);
+    assertEquals(stat.rssInBytes, 3);
+    assertEquals(stat.cacheInBytes, 4);
+    assertEquals(stat.swapInBytes, 5);
+  }
+
+  @Test
+  public void testParseMemoryStat_emptyMemoryStatContents() throws Exception {
+    MemoryStat stat = parseMemoryStat("");
+    assertEquals(stat.pgfault, 0);
+    assertEquals(stat.pgmajfault, 0);
+    assertEquals(stat.rssInBytes, 0);
+    assertEquals(stat.cacheInBytes, 0);
+    assertEquals(stat.swapInBytes, 0);
+
+    stat = parseMemoryStat(null);
+    assertEquals(stat.pgfault, 0);
+    assertEquals(stat.pgmajfault, 0);
+    assertEquals(stat.rssInBytes, 0);
+    assertEquals(stat.cacheInBytes, 0);
+    assertEquals(stat.swapInBytes, 0);
+  }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
index 376db5b..6e1808b 100644
--- a/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/ConnOnActivityStartTest.java
@@ -117,7 +117,8 @@
     }
 
     @AfterClass
-    public static void tearDownOnce() {
+    public static void tearDownOnce() throws Exception {
+        batteryReset();
         if (mAppIdleConstsUpdated) {
             Settings.Global.putString(mContext.getContentResolver(),
                     Settings.Global.APP_IDLE_CONSTANTS, mOriginalAppIdleConsts);
@@ -213,12 +214,12 @@
     @Test
     public void testStartActivity_appStandby() throws Exception {
         try{
-            turnBatteryOff();
+            turnBatteryOn();
             setAppIdle(true);
             turnScreenOn();
             startActivityAndCheckNetworkAccess();
         } finally {
-            turnBatteryOn();
+            turnBatteryOff();
             finishActivity();
             setAppIdle(false);
         }
@@ -251,11 +252,11 @@
     // create a static library which can be used by both servicestests and cts.
     private void setBatterySaverMode(boolean enabled) throws Exception {
         if (enabled) {
-            turnBatteryOff();
+            turnBatteryOn();
             executeCommand("settings put global low_power 1");
         } else {
             executeCommand("settings put global low_power 0");
-            turnBatteryOn();
+            turnBatteryOff();
         }
         final String result = executeCommand("settings get global low_power");
         assertEquals(enabled ? "1" : "0", result);
@@ -271,12 +272,12 @@
 
     private void setDozeMode(boolean enabled) throws Exception {
         if (enabled) {
-            turnBatteryOff();
+            turnBatteryOn();
             turnScreenOff();
             executeCommand("dumpsys deviceidle force-idle deep");
         } else {
             turnScreenOn();
-            turnBatteryOn();
+            turnBatteryOff();
             executeCommand("dumpsys deviceidle unforce");
         }
         assertDelayedCommandResult("dumpsys deviceidle get deep", enabled ? "IDLE" : "ACTIVE",
@@ -320,12 +321,12 @@
                 + ". Full list: " + uids);
     }
 
-    private void turnBatteryOff() throws Exception {
+    private void turnBatteryOn() throws Exception {
         executeCommand("cmd battery unplug");
-        assertBatteryOff();
+        assertBatteryOn();
     }
 
-    private void assertBatteryOff() throws Exception {
+    private void assertBatteryOn() throws Exception {
         final long endTime = SystemClock.uptimeMillis() + BATTERY_OFF_TIMEOUT_MS;
         while (mBatteryManager.isCharging() && SystemClock.uptimeMillis() < endTime) {
             SystemClock.sleep(BATTERY_OFF_CHECK_INTERVAL_MS);
@@ -333,7 +334,11 @@
         assertFalse("Power should be disconnected", mBatteryManager.isCharging());
     }
 
-    private void turnBatteryOn() throws Exception {
+    private void turnBatteryOff() throws Exception {
+        executeCommand("cmd battery set ac " + BatteryManager.BATTERY_PLUGGED_AC);
+    }
+
+    private static void batteryReset() throws Exception {
         executeCommand("cmd battery reset");
     }
 
@@ -348,7 +353,7 @@
         SystemClock.sleep(SCREEN_ON_DELAY_MS);
     }
 
-    private String executeCommand(String cmd) throws IOException {
+    private static String executeCommand(String cmd) throws IOException {
         final String result = executeSilentCommand(cmd);
         Log.d(TAG, String.format("Result for '%s': %s", cmd, result));
         return result;
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
index 9cf6392..d9f4adf 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -31,7 +31,6 @@
 import android.support.test.filters.SmallTest;
 
 import java.io.File;
-import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.time.Clock;
@@ -1400,7 +1399,7 @@
     /**
      * A fake IntentHelper implementation for use in tests.
      */
-    private static class FakeIntentHelper implements IntentHelper {
+    private static class FakeIntentHelper implements PackageTrackerIntentHelper {
 
         private PackageTracker mPackageTracker;
         private String mUpdateAppPackageName;
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
index 1cfae1e..f5969f3 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -68,6 +68,7 @@
 
     private FakeExecutor mFakeExecutor;
     private PermissionHelper mMockPermissionHelper;
+    private RulesManagerIntentHelper mMockIntentHelper;
     private PackageTracker mMockPackageTracker;
     private TimeZoneDistroInstaller mMockTimeZoneDistroInstaller;
 
@@ -77,11 +78,13 @@
 
         mMockPackageTracker = mock(PackageTracker.class);
         mMockPermissionHelper = mock(PermissionHelper.class);
+        mMockIntentHelper = mock(RulesManagerIntentHelper.class);
         mMockTimeZoneDistroInstaller = mock(TimeZoneDistroInstaller.class);
 
         mRulesManagerService = new RulesManagerService(
                 mMockPermissionHelper,
                 mFakeExecutor,
+                mMockIntentHelper,
                 mMockPackageTracker,
                 mMockTimeZoneDistroInstaller);
     }
@@ -329,6 +332,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -353,6 +357,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -372,6 +377,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -394,6 +400,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -416,6 +423,7 @@
         callback.assertNoResultReceived();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS);
@@ -428,6 +436,7 @@
         // Verify the expected calls were made to other components.
         verifyStageInstallCalled();
         verifyPackageTrackerCalled(token, true /* success */);
+        verifyStagedOperationIntentSent();
 
         // Check the callback was called.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -450,6 +459,7 @@
         // Assert nothing has happened yet.
         verifyNoInstallerCallsMade();
         callback.assertNoResultReceived();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_SUCCESS);
@@ -462,6 +472,7 @@
         // Verify the expected calls were made to other components.
         verifyStageInstallCalled();
         verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
+        verifyStagedOperationIntentSent();
 
         // Check the callback was received.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -486,6 +497,7 @@
         // Assert nothing has happened yet.
         verifyNoInstallerCallsMade();
         callback.assertNoResultReceived();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageInstallExpectation(TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR);
@@ -502,6 +514,9 @@
         boolean expectedSuccess = true;
         verifyPackageTrackerCalled(token, expectedSuccess);
 
+        // Nothing should be staged, so no intents sent.
+        verifyNoIntentsSent();
+
         // Check the callback was received.
         callback.assertResultReceived(Callback.ERROR_INSTALL_VALIDATION_ERROR);
     }
@@ -529,6 +544,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -548,6 +564,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -566,6 +583,7 @@
         mFakeExecutor.assertNothingQueued();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -585,6 +603,7 @@
         callback.assertNoResultReceived();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_SUCCESS);
@@ -595,6 +614,7 @@
         // Verify the expected calls were made to other components.
         verifyStageUninstallCalled();
         verifyPackageTrackerCalled(token, true /* success */);
+        verifyStagedOperationIntentSent();
 
         // Check the callback was called.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -617,6 +637,7 @@
         callback.assertNoResultReceived();
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_NOTHING_INSTALLED);
@@ -627,6 +648,7 @@
         // Verify the expected calls were made to other components.
         verifyStageUninstallCalled();
         verifyPackageTrackerCalled(token, true /* success */);
+        verifyUnstagedOperationIntentSent();
 
         // Check the callback was called.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -645,6 +667,7 @@
         // Assert nothing has happened yet.
         verifyNoInstallerCallsMade();
         callback.assertNoResultReceived();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_SUCCESS);
@@ -655,6 +678,7 @@
         // Verify the expected calls were made to other components.
         verifyStageUninstallCalled();
         verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
+        verifyStagedOperationIntentSent();
 
         // Check the callback was received.
         callback.assertResultReceived(Callback.SUCCESS);
@@ -676,6 +700,7 @@
         // Assert nothing has happened yet.
         verifyNoInstallerCallsMade();
         callback.assertNoResultReceived();
+        verifyNoIntentsSent();
 
         // Set up the installer.
         configureStageUninstallExpectation(TimeZoneDistroInstaller.UNINSTALL_FAIL);
@@ -686,6 +711,7 @@
         // Verify the expected calls were made to other components.
         verifyStageUninstallCalled();
         verifyPackageTrackerCalled(token, false /* success */);
+        verifyNoIntentsSent();
 
         // Check the callback was received.
         callback.assertResultReceived(Callback.ERROR_UNKNOWN_FAILURE);
@@ -714,6 +740,7 @@
         // Verify the expected calls were made to other components.
         verifyPackageTrackerCalled(token, true /* success */);
         verifyNoInstallerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -734,6 +761,7 @@
         // Assert no other calls were made.
         verifyNoInstallerCallsMade();
         verifyNoPackageTrackerCallsMade();
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -749,6 +777,7 @@
         // Assert everything required was done.
         verifyNoInstallerCallsMade();
         verifyPackageTrackerCalled(token, false /* success */);
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -761,6 +790,7 @@
         // Assert everything required was done.
         verifyNoInstallerCallsMade();
         verifyPackageTrackerCalled(null /* token */, true /* success */);
+        verifyNoIntentsSent();
     }
 
     @Test
@@ -865,6 +895,21 @@
         reset(mMockPackageTracker);
     }
 
+    private void verifyNoIntentsSent() {
+        verifyNoMoreInteractions(mMockIntentHelper);
+        reset(mMockIntentHelper);
+    }
+
+    private void verifyStagedOperationIntentSent() {
+        verify(mMockIntentHelper).sendTimeZoneOperationStaged();
+        reset(mMockIntentHelper);
+    }
+
+    private void verifyUnstagedOperationIntentSent() {
+        verify(mMockIntentHelper).sendTimeZoneOperationUnstaged();
+        reset(mMockIntentHelper);
+    }
+
     private void configureCallerHasPermission() throws Exception {
         doNothing()
                 .when(mMockPermissionHelper)
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 000cf38..7a55904 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 
@@ -107,6 +108,13 @@
 
             sWm = WindowManagerService.main(context, ims, true, false,
                     false, new TestWindowManagerPolicy());
+
+            sWm.onInitReady();
+
+            // Display creation is driven by the ActivityManagerService via ActivityStackSupervisor.
+            // We emulate those steps here.
+            sWm.mRoot.createDisplayContent(sWm.mDisplayManager.getDisplay(DEFAULT_DISPLAY),
+                    mock(DisplayWindowController.class));
         }
         return sWm;
     }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
index 4d41718..74c72bf 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowStateTests.java
@@ -41,6 +41,10 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
 
 /**
  * Tests for the {@link WindowState} class.
@@ -240,11 +244,11 @@
     }
 
     private void testPrepareWindowToDisplayDuringRelayout(boolean wasVisible) {
+        reset(mPowerManagerWrapper);
         final WindowState root = createWindow(null, TYPE_APPLICATION, "root");
         root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
-        root.mTurnOnScreen = false;
 
         root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
-        assertTrue(root.mTurnOnScreen);
+        verify(mPowerManagerWrapper).wakeUp(anyLong(), anyString());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 69b1378..91d5ea4 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -29,6 +29,7 @@
 import org.junit.Assert;
 import org.junit.After;
 import org.junit.Before;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
 import android.content.Context;
@@ -84,6 +85,9 @@
     WindowState mChildAppWindowBelow;
     HashSet<WindowState> mCommonWindows;
 
+    @Mock
+    static WindowState.PowerManagerWrapper mPowerManagerWrapper;
+
     @Before
     public void setUp() throws Exception {
         if (!sOneTimeSetupDone) {
@@ -245,7 +249,7 @@
         attrs.setTitle(name);
 
         final WindowState w = new WindowState(sWm, sMockSession, sIWindow, token, parent, OP_NONE,
-                0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow);
+                0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, mPowerManagerWrapper);
         // TODO: Probably better to make this call in the WindowState ctor to avoid errors with
         // adding it to the token...
         token.addWindow(w);
@@ -284,7 +288,8 @@
         final int displayId = sNextDisplayId++;
         final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId,
                 mDisplayInfo, DEFAULT_DISPLAY_ADJUSTMENTS);
-        return new DisplayContent(display, sWm, new WallpaperController(sWm));
+        return new DisplayContent(display, sWm, new WallpaperController(sWm),
+                mock(DisplayWindowController.class));
     }
 
     /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index fcf04c9..af65c65 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -60,6 +60,26 @@
  * </service>
  * }
  * </pre>
+ * <p>
+ * In addition to implementing the {@link InCallService} API, you must also declare an activity in
+ * your manifest which handles the {@link Intent#ACTION_DIAL} intent.  The example below illustrates
+ * how this is done:
+ * <pre>
+ * {@code
+ * <activity android:name="your.package.YourDialerActivity"
+ *           android:label="@string/yourDialerActivityLabel">
+ *      <intent-filter>
+ *           <action android:name="android.intent.action.DIAL" />
+ *           <category android:name="android.intent.category.DEFAULT" />
+ *      </intent-filter>
+ * </activity>
+ * }
+ * </pre>
+ * <p>
+ * When a user installs your application and runs it for the first time, you should prompt the user
+ * to see if they would like your application to be the new default phone app.  See the
+ * {@link TelecomManager#ACTION_CHANGE_DEFAULT_DIALER} intent documentation for more information on
+ * how to do this.
  */
 public abstract class InCallService extends Service {
 
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 1fe5db5..a180da6 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1320,7 +1320,7 @@
     public boolean endCall() {
         try {
             if (isServiceConnected()) {
-                return getTelecomService().endCall();
+                return getTelecomService().endCall(mContext.getPackageName());
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling ITelecomService#endCall", e);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 3460754f..b4e7d56 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -187,7 +187,7 @@
     /**
      * @see TelecomServiceImpl#endCall
      */
-    boolean endCall();
+    boolean endCall(String callingPackage);
 
     /**
      * @see TelecomServiceImpl#acceptRingingCall
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 8c45724..63263bd 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -33,6 +33,7 @@
 import android.telephony.ServiceState;
 import android.telephony.SmsMessage;
 import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Patterns;
 
@@ -3345,73 +3346,118 @@
     }
 
     /**
-     * Contains carrier identification information.
-     * @hide
+     * Contains carrier identification information for the current subscriptions.
+     * @see SubscriptionManager#getActiveSubscriptionIdList()
      */
     public static final class CarrierIdentification implements BaseColumns {
         /**
-         * Numeric operator ID (as String). {@code MCC + MNC}
-         * <P>Type: TEXT </P>
+         * Not instantiable.
+         * @hide
          */
-        public static final String MCCMNC = "mccmnc";
+        private CarrierIdentification() {}
 
         /**
-         * Group id level 1 (as String).
-         * <P>Type: TEXT </P>
+         * The {@code content://} style URI for this provider.
          */
-        public static final String GID1 = "gid1";
+        public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification");
 
         /**
-         * Group id level 2 (as String).
-         * <P>Type: TEXT </P>
+         * The authority string for the CarrierIdentification Provider
+         * @hide
          */
-        public static final String GID2 = "gid2";
+        public static final String AUTHORITY = "carrier_identification";
+
 
         /**
-         * Public Land Mobile Network name.
-         * <P>Type: TEXT </P>
+         * Generates a content {@link Uri} used to receive updates on carrier identity change
+         * on the given subscriptionId
+         * <p>
+         * Use this {@link Uri} with a {@link ContentObserver} to be notified of changes to the
+         * carrier identity {@link TelephonyManager#getAndroidCarrierIdForSubscription()}
+         * while your app is running. You can also use a {@link JobService} to ensure your app
+         * is notified of changes to the {@link Uri} even when it is not running.
+         * Note, however, that using a {@link JobService} does not guarantee timely delivery of
+         * updates to the {@link Uri}.
+         *
+         * @param subscriptionId the subscriptionId to receive updates on
+         * @return the Uri used to observe carrier identity changes
          */
-        public static final String PLMN = "plmn";
+        public static Uri getUriForSubscriptionId(int subscriptionId) {
+            return CONTENT_URI.buildUpon().appendEncodedPath(
+                    String.valueOf(subscriptionId)).build();
+        }
 
         /**
-         * Prefix xpattern of IMSI (International Mobile Subscriber Identity).
-         * <P>Type: TEXT </P>
-         */
-        public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
-
-        /**
-         * Service Provider Name.
-         * <P>Type: TEXT </P>
-         */
-        public static final String SPN = "spn";
-
-        /**
-         * Prefer APN name.
-         * <P>Type: TEXT </P>
-         */
-        public static final String APN = "apn";
-
-        /**
-         * Prefix of Integrated Circuit Card Identifier.
-         * <P>Type: TEXT </P>
-         */
-        public static final String ICCID_PREFIX = "iccid_prefix";
-
-        /**
-         * User facing carrier name.
+         * A user facing carrier name.
+         * @see TelephonyManager#getAndroidCarrierNameForSubscription()
          * <P>Type: TEXT </P>
          */
         public static final String NAME = "carrier_name";
 
         /**
          * A unique carrier id
+         * @see TelephonyManager#getAndroidCarrierIdForSubscription()
          * <P>Type: INTEGER </P>
          */
         public static final String CID = "carrier_id";
 
         /**
-         * The {@code content://} URI for this table.
+         * Contains mappings between matching rules with carrier id for all carriers.
+         * @hide
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification");
+        public static final class All implements BaseColumns {
+            /**
+             * Numeric operator ID (as String). {@code MCC + MNC}
+             * <P>Type: TEXT </P>
+             */
+            public static final String MCCMNC = "mccmnc";
+
+            /**
+             * Group id level 1 (as String).
+             * <P>Type: TEXT </P>
+             */
+            public static final String GID1 = "gid1";
+
+            /**
+             * Group id level 2 (as String).
+             * <P>Type: TEXT </P>
+             */
+            public static final String GID2 = "gid2";
+
+            /**
+             * Public Land Mobile Network name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String PLMN = "plmn";
+
+            /**
+             * Prefix xpattern of IMSI (International Mobile Subscriber Identity).
+             * <P>Type: TEXT </P>
+             */
+            public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
+
+            /**
+             * Service Provider Name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String SPN = "spn";
+
+            /**
+             * Prefer APN name.
+             * <P>Type: TEXT </P>
+             */
+            public static final String APN = "apn";
+
+            /**
+             * Prefix of Integrated Circuit Card Identifier.
+             * <P>Type: TEXT </P>
+             */
+            public static final String ICCID_PREFIX = "iccid_prefix";
+
+            /**
+             * The {@code content://} URI for this table.
+             */
+            public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification/all");
+        }
     }
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 03a8f33..03d8b5c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -904,6 +904,61 @@
     public static final String EVENT_CALL_FORWARDED =
             "android.telephony.event.EVENT_CALL_FORWARDED";
 
+    /**
+     * {@link android.telecom.Connection} event used to indicate that a supplementary service
+     * notification has been received.
+     * <p>
+     * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}.
+     * The {@link Bundle} parameter is expected to include the following extras:
+     * <ul>
+     *     <li>{@link #EXTRA_NOTIFICATION_TYPE} - the notification type.</li>
+     *     <li>{@link #EXTRA_NOTIFICATION_CODE} - the notification code.</li>
+     *     <li>{@link #EXTRA_NOTIFICATION_MESSAGE} - human-readable message associated with the
+     *     supplementary service notification.</li>
+     * </ul>
+     * @hide
+     */
+    public static final String EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION =
+            "android.telephony.event.EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION";
+
+    /**
+     * Integer extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} which indicates
+     * the type of supplementary service notification which occurred.
+     * Will be either
+     * {@link com.android.internal.telephony.gsm.SuppServiceNotification#NOTIFICATION_TYPE_CODE_1}
+     * or
+     * {@link com.android.internal.telephony.gsm.SuppServiceNotification#NOTIFICATION_TYPE_CODE_2}
+     * <p>
+     * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event.
+     * @hide
+     */
+    public static final String EXTRA_NOTIFICATION_TYPE =
+            "android.telephony.extra.NOTIFICATION_TYPE";
+
+    /**
+     * Integer extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} which indicates
+     * the supplementary service notification which occurred.
+     * <p>
+     * Depending on the {@link #EXTRA_NOTIFICATION_TYPE}, the code will be one of the {@code CODE_*}
+     * codes defined in {@link com.android.internal.telephony.gsm.SuppServiceNotification}.
+     * <p>
+     * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event.
+     * @hide
+     */
+    public static final String EXTRA_NOTIFICATION_CODE =
+            "android.telephony.extra.NOTIFICATION_CODE";
+
+    /**
+     * {@link CharSequence} extra key used with {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION}
+     * which contains a human-readable message which can be displayed to the user for the
+     * supplementary service notification.
+     * <p>
+     * Set in the extras for the {@link #EVENT_SUPPLEMENTARY_SERVICE_NOTIFICATION} connection event.
+     * @hide
+     */
+    public static final String EXTRA_NOTIFICATION_MESSAGE =
+            "android.telephony.extra.NOTIFICATION_MESSAGE";
+
     /* Visual voicemail protocols */
 
     /**
diff --git a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
index 021e386..ec5a9c6 100644
--- a/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/test-app/AndroidManifest.xml
@@ -15,6 +15,9 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworks.perftests.amteststestapp">
+    <uses-sdk
+            android:minSdkVersion="21"
+            android:targetSdkVersion="27" />
     <application android:name=".TestApplication">
         <activity android:name=".TestActivity" android:exported="true"/>
         <provider
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml b/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml
index 4e194c6..a1ab33a 100644
--- a/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml
+++ b/tests/ActivityManagerPerfTests/tests/AndroidManifest.xml
@@ -15,6 +15,9 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.frameworks.perftests.amtests">
+    <uses-sdk
+            android:minSdkVersion="21"
+            android:targetSdkVersion="27" />
     <uses-permission android:name="android.permission.DUMP" />
     <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
 
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 669afe1..734a5ab 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -4848,6 +4848,7 @@
     const String16 pathInterpolator16("pathInterpolator");
     const String16 objectAnimator16("objectAnimator");
     const String16 gradient16("gradient");
+    const String16 animatedSelector16("animated-selector");
 
     const int minSdk = getMinSdkVersion(bundle);
     if (minSdk >= SDK_LOLLIPOP_MR1) {
@@ -4876,7 +4877,8 @@
                     node->getElementName() == animatedVector16 ||
                     node->getElementName() == objectAnimator16 ||
                     node->getElementName() == pathInterpolator16 ||
-                    node->getElementName() == gradient16)) {
+                    node->getElementName() == gradient16 ||
+                    node->getElementName() == animatedSelector16)) {
             // We were told not to version vector tags, so skip the children here.
             continue;
         }
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 1afd283..15c5eae 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -450,7 +450,7 @@
 
 static bool IsVectorElement(const std::string& name) {
   return name == "vector" || name == "animated-vector" || name == "pathInterpolator" ||
-         name == "objectAnimator" || name == "gradient";
+         name == "objectAnimator" || name == "gradient" || name == "animated-selector";
 }
 
 template <typename T>