Merge "[view compiler] Cleanup: Delete duplicate LayoutValidationVisitor::VisitStartTag"
diff --git a/api/system-current.txt b/api/system-current.txt
index 593b45d..9200ce5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -7424,6 +7424,7 @@
   public abstract class ImsFeature {
     ctor public ImsFeature();
     method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
+    method public final int getSlotIndex();
     method public abstract void onFeatureReady();
     method public abstract void onFeatureRemoved();
     method public final void setFeatureState(int);
@@ -7437,7 +7438,7 @@
     field public static final int STATE_UNAVAILABLE = 0; // 0x0
   }
 
-  @Deprecated public static class ImsFeature.Capabilities {
+  public static class ImsFeature.Capabilities {
     field @Deprecated protected int mCapabilities;
   }
 
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index e17f735..3e5877b 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -40,24 +40,6 @@
         "audioplay.cpp",
     ],
 
-    product_variables: {
-        product_is_iot: {
-            shared_libs: [
-                "libandroidthings",
-                "libchrome",
-            ],
-            srcs: [
-                "iot/iotbootanimation_main.cpp",
-                "iot/BootAction.cpp",
-                "iot/BootParameters.cpp",
-            ],
-            exclude_srcs: [
-                "bootanimation_main.cpp",
-                "audioplay.cpp",
-            ],
-        },
-    },
-
     init_rc: ["bootanim.rc"],
 }
 
@@ -77,10 +59,4 @@
         "libGLESv1_CM",
         "libgui",
     ],
-
-    product_variables: {
-        product_is_iot: {
-            init_rc: ["iot/bootanim_iot.rc"],
-        },
-    },
 }
diff --git a/cmds/bootanimation/iot/BootAction.cpp b/cmds/bootanimation/iot/BootAction.cpp
deleted file mode 100644
index fa79744..0000000
--- a/cmds/bootanimation/iot/BootAction.cpp
+++ /dev/null
@@ -1,109 +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 "BootAction.h"
-
-#define LOG_TAG "BootAction"
-
-#include <dlfcn.h>
-
-#include <pio/peripheral_manager_client.h>
-#include <utils/Log.h>
-
-namespace android {
-
-BootAction::~BootAction() {
-    if (mLibHandle != nullptr) {
-        dlclose(mLibHandle);
-    }
-}
-
-bool BootAction::init(const std::string& libraryPath,
-                      const std::vector<ABootActionParameter>& parameters) {
-    APeripheralManagerClient* client = nullptr;
-    ALOGD("Connecting to peripheralmanager");
-    // Wait for peripheral manager to come up.
-    while (client == nullptr) {
-        client = APeripheralManagerClient_new();
-        if (client == nullptr) {
-          ALOGV("peripheralmanager is not up, sleeping before we check again.");
-          usleep(250000);
-        }
-    }
-    ALOGD("Peripheralmanager is up.");
-    APeripheralManagerClient_delete(client);
-
-
-    ALOGI("Loading boot action %s", libraryPath.c_str());
-    mLibHandle = dlopen(libraryPath.c_str(), RTLD_NOW);
-    if (mLibHandle == nullptr) {
-        ALOGE("Unable to load library at %s :: %s",
-              libraryPath.c_str(), dlerror());
-        return false;
-    }
-
-    void* loaded = nullptr;
-    if (!loadSymbol("boot_action_init", &loaded) || loaded == nullptr) {
-        return false;
-    }
-    mLibInit = reinterpret_cast<libInit>(loaded);
-
-    loaded = nullptr;
-    if (!loadSymbol("boot_action_shutdown", &loaded) || loaded == nullptr) {
-        return false;
-    }
-    mLibShutdown = reinterpret_cast<libShutdown>(loaded);
-
-    // StartPart is considered optional, if it isn't exported by the library
-    // we will still call init and shutdown.
-    loaded = nullptr;
-    if (!loadSymbol("boot_action_start_part", &loaded) || loaded == nullptr) {
-        ALOGI("No boot_action_start_part found, action will not be told when "
-              "Animation parts change.");
-    } else {
-        mLibStartPart = reinterpret_cast<libStartPart>(loaded);
-    }
-
-    ALOGD("Entering boot_action_init");
-    bool result = mLibInit(parameters.data(), parameters.size());
-    ALOGD("Returned from boot_action_init");
-    return result;
-}
-
-void BootAction::startPart(int partNumber, int playNumber) {
-    if (mLibStartPart == nullptr) return;
-
-    ALOGD("Entering boot_action_start_part");
-    mLibStartPart(partNumber, playNumber);
-    ALOGD("Returned from boot_action_start_part");
-}
-
-void BootAction::shutdown() {
-    ALOGD("Entering boot_action_shutdown");
-    mLibShutdown();
-    ALOGD("Returned from boot_action_shutdown");
-}
-
-bool BootAction::loadSymbol(const char* symbol, void** loaded) {
-    *loaded = dlsym(mLibHandle, symbol);
-    if (loaded == nullptr) {
-        ALOGE("Unable to load symbol : %s :: %s", symbol, dlerror());
-        return false;
-    }
-    return true;
-}
-
-}  // namespace android
diff --git a/cmds/bootanimation/iot/BootAction.h b/cmds/bootanimation/iot/BootAction.h
deleted file mode 100644
index 5e2495f..0000000
--- a/cmds/bootanimation/iot/BootAction.h
+++ /dev/null
@@ -1,63 +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 _BOOTANIMATION_BOOTACTION_H
-#define _BOOTANIMATION_BOOTACTION_H
-
-#include <string>
-#include <vector>
-
-#include <boot_action/boot_action.h>  // libandroidthings native API.
-#include <utils/RefBase.h>
-
-namespace android {
-
-class BootAction : public RefBase {
-public:
-    ~BootAction();
-
-    // libraryPath is a fully qualified path to the target .so library.
-    bool init(const std::string& libraryPath,
-              const std::vector<ABootActionParameter>& parameters);
-
-    // The animation is going to start playing partNumber for the playCount'th
-    // time, update the action as needed.
-    // This is run in the same thread as the boot animation,
-    // you must not block here.
-    void startPart(int partNumber, int playCount);
-
-    // Shutdown the boot action, this will be called shortly before the
-    // process is shut down to allow time for cleanup.
-    void shutdown();
-
-private:
-    typedef bool (*libInit)(const ABootActionParameter* parameters,
-                            size_t num_parameters);
-    typedef void (*libStartPart)(int partNumber, int playNumber);
-    typedef void (*libShutdown)();
-
-    bool loadSymbol(const char* symbol, void** loaded);
-
-    void* mLibHandle = nullptr;
-    libInit mLibInit = nullptr;
-    libStartPart mLibStartPart = nullptr;
-    libShutdown mLibShutdown = nullptr;
-};
-
-}  // namespace android
-
-
-#endif  // _BOOTANIMATION_BOOTACTION_H
diff --git a/cmds/bootanimation/iot/BootParameters.cpp b/cmds/bootanimation/iot/BootParameters.cpp
deleted file mode 100644
index da6ad0d..0000000
--- a/cmds/bootanimation/iot/BootParameters.cpp
+++ /dev/null
@@ -1,124 +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 "BootParameters.h"
-
-#define LOG_TAG "BootParameters"
-
-#include <fcntl.h>
-
-#include <string>
-
-#include <android-base/file.h>
-#include <base/json/json_parser.h>
-#include <base/json/json_reader.h>
-#include <base/json/json_value_converter.h>
-#include <utils/Log.h>
-
-using android::base::RemoveFileIfExists;
-using android::base::ReadFileToString;
-using base::JSONReader;
-using base::JSONValueConverter;
-using base::Value;
-
-namespace android {
-
-namespace {
-
-// Brightness and volume are stored as integer strings in next_boot.json.
-// They are divided by this constant to produce the actual float values in
-// range [0.0, 1.0]. This constant must match its counterpart in
-// DeviceManager.
-constexpr const float kFloatScaleFactor = 1000.0f;
-
-constexpr const char* kNextBootFile = "/data/misc/bootanimation/next_boot.json";
-constexpr const char* kLastBootFile = "/data/misc/bootanimation/last_boot.json";
-
-void swapBootConfigs() {
-    // rename() will fail if next_boot.json doesn't exist, so delete
-    // last_boot.json manually first.
-    std::string err;
-    if (!RemoveFileIfExists(kLastBootFile, &err))
-        ALOGE("Unable to delete last boot file: %s", err.c_str());
-
-    if (rename(kNextBootFile, kLastBootFile) && errno != ENOENT)
-        ALOGE("Unable to swap boot files: %s", strerror(errno));
-
-    int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE);
-    if (fd == -1) {
-        ALOGE("Unable to create next boot file: %s", strerror(errno));
-    } else {
-        // Make next_boot.json writable to everyone so DeviceManagementService
-        // can save saved_parameters there.
-        if (fchmod(fd, DEFFILEMODE))
-            ALOGE("Unable to set next boot file permissions: %s", strerror(errno));
-        close(fd);
-    }
-}
-
-}  // namespace
-
-BootParameters::SavedBootParameters::SavedBootParameters()
-    : brightness(-kFloatScaleFactor), volume(-kFloatScaleFactor) {}
-
-void BootParameters::SavedBootParameters::RegisterJSONConverter(
-        JSONValueConverter<SavedBootParameters>* converter) {
-    converter->RegisterIntField("brightness", &SavedBootParameters::brightness);
-    converter->RegisterIntField("volume", &SavedBootParameters::volume);
-    converter->RegisterRepeatedString("param_names",
-                                      &SavedBootParameters::param_names);
-    converter->RegisterRepeatedString("param_values",
-                                      &SavedBootParameters::param_values);
-}
-
-BootParameters::BootParameters() {
-    swapBootConfigs();
-    loadParameters();
-}
-
-void BootParameters::loadParameters() {
-    std::string contents;
-    if (!ReadFileToString(kLastBootFile, &contents)) {
-        if (errno != ENOENT)
-            ALOGE("Unable to read from %s: %s", kLastBootFile, strerror(errno));
-
-        return;
-    }
-
-    std::unique_ptr<Value> json = JSONReader::Read(contents);
-    if (json.get() == nullptr) {
-        return;
-    }
-
-    JSONValueConverter<SavedBootParameters> converter;
-    if (converter.Convert(*(json.get()), &mRawParameters)) {
-        mBrightness = mRawParameters.brightness / kFloatScaleFactor;
-        mVolume = mRawParameters.volume / kFloatScaleFactor;
-
-        if (mRawParameters.param_names.size() == mRawParameters.param_values.size()) {
-            for (size_t i = 0; i < mRawParameters.param_names.size(); i++) {
-                mParameters.push_back({
-                        .key = mRawParameters.param_names[i]->c_str(),
-                        .value = mRawParameters.param_values[i]->c_str()
-                });
-            }
-        } else {
-            ALOGW("Parameter names and values size mismatch");
-        }
-    }
-}
-
-}  // namespace android
diff --git a/cmds/bootanimation/iot/BootParameters.h b/cmds/bootanimation/iot/BootParameters.h
deleted file mode 100644
index c10bd44..0000000
--- a/cmds/bootanimation/iot/BootParameters.h
+++ /dev/null
@@ -1,73 +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 _BOOTANIMATION_BOOT_PARAMETERS_H_
-#define _BOOTANIMATION_BOOT_PARAMETERS_H_
-
-#include <list>
-#include <vector>
-
-#include <base/json/json_value_converter.h>
-#include <boot_action/boot_action.h>  // libandroidthings native API.
-
-namespace android {
-
-// Provides access to the parameters set by DeviceManager.reboot().
-class BootParameters {
-public:
-    // Constructor loads the parameters for this boot and swaps the param files
-    // to clear the parameters for next boot.
-    BootParameters();
-
-    // Returns true if volume/brightness were explicitly set on reboot.
-    bool hasVolume() const { return mVolume >= 0; }
-    bool hasBrightness() const { return mBrightness >= 0; }
-
-    // Returns volume/brightness in [0,1], or -1 if unset.
-    float getVolume() const { return mVolume; }
-    float getBrightness() const { return mBrightness; }
-
-    // Returns the additional boot parameters that were set on reboot.
-    const std::vector<ABootActionParameter>& getParameters() const { return mParameters; }
-
-private:
-    // Raw boot saved_parameters loaded from .json.
-    struct SavedBootParameters {
-        int brightness;
-        int volume;
-        std::vector<std::unique_ptr<std::string>> param_names;
-        std::vector<std::unique_ptr<std::string>> param_values;
-
-        SavedBootParameters();
-        static void RegisterJSONConverter(
-                ::base::JSONValueConverter<SavedBootParameters>* converter);
-    };
-
-    void loadParameters();
-
-    float mVolume = -1.f;
-    float mBrightness = -1.f;
-    std::vector<ABootActionParameter> mParameters;
-
-    // ABootActionParameter is just a raw pointer so we need to keep the
-    // original strings around to avoid losing them.
-    SavedBootParameters mRawParameters;
-};
-
-}  // namespace android
-
-
-#endif  // _BOOTANIMATION_BOOT_PARAMETERS_H_
diff --git a/cmds/bootanimation/iot/bootanim_iot.rc b/cmds/bootanimation/iot/bootanim_iot.rc
deleted file mode 100644
index 2fc1336..0000000
--- a/cmds/bootanimation/iot/bootanim_iot.rc
+++ /dev/null
@@ -1,2 +0,0 @@
-on post-fs-data
-    mkdir /data/misc/bootanimation 0777 root root
diff --git a/cmds/bootanimation/iot/iotbootanimation_main.cpp b/cmds/bootanimation/iot/iotbootanimation_main.cpp
deleted file mode 100644
index 00cef43..0000000
--- a/cmds/bootanimation/iot/iotbootanimation_main.cpp
+++ /dev/null
@@ -1,124 +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.
- */
-
-#define LOG_TAG "IotBootAnimation"
-
-#include <base/files/file_util.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <cutils/properties.h>
-#include <sys/resource.h>
-#include <utils/Log.h>
-#include <utils/threads.h>
-#include <BootAnimation.h>
-
-#include "BootAction.h"
-#include "BootAnimationUtil.h"
-#include "BootParameters.h"
-
-using namespace android;
-
-// Create a typedef for readability.
-typedef android::BootAnimation::Animation Animation;
-
-namespace {
-
-constexpr const char* kDefaultLibName = "libbootaction.so";
-
-class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {
-public:
-    BootActionAnimationCallbacks(std::unique_ptr<BootParameters> bootParameters)
-        : mBootParameters(std::move(bootParameters)) {}
-
-    void init(const Vector<Animation::Part>&) override {
-        std::string library_path("/oem/lib/");
-
-        // This value is optionally provided by the user and will be written to
-        // /oem/oem.prop.
-        char property[PROP_VALUE_MAX] = {0};
-        property_get("ro.oem.bootactions.lib", property, kDefaultLibName);
-        library_path += property;
-
-        if (!::base::PathExists(::base::FilePath(library_path))) {
-            ALOGI("Skipping boot actions: %s does not exist", library_path.c_str());
-            return;
-        }
-
-        mBootAction = new BootAction();
-        if (!mBootAction->init(library_path, mBootParameters->getParameters())) {
-            mBootAction = NULL;
-        }
-    };
-
-    void playPart(int partNumber, const Animation::Part&, int playNumber) override {
-        if (mBootAction != nullptr) {
-            mBootAction->startPart(partNumber, playNumber);
-        }
-    };
-
-    void shutdown() override {
-        if (mBootAction != nullptr) {
-            // If we have a bootaction we want to wait until we are actually
-            // told to shut down. If the animation exits early keep the action
-            // running.
-            char value[PROPERTY_VALUE_MAX] = {0};
-            for (int exitRequested = 0; exitRequested == 0; ) {
-                property_get("service.bootanim.exit", value, "0");
-                exitRequested = atoi(value);
-
-                // Poll value at 10hz.
-                if (exitRequested == 0) {
-                  usleep(100000);
-                }
-            }
-
-            mBootAction->shutdown();
-            // Give it two seconds to shut down.
-            sleep(2);
-            mBootAction = nullptr;
-        }
-    };
-
-private:
-    std::unique_ptr<BootParameters> mBootParameters;
-    sp<BootAction> mBootAction = nullptr;
-};
-
-}  // namespace
-
-int main() {
-    setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
-
-    // Clear our params for next boot no matter what.
-    std::unique_ptr<BootParameters> bootParameters(new BootParameters());
-
-    if (bootAnimationDisabled()) {
-        ALOGI("boot animation disabled");
-        return 0;
-    }
-
-    waitForSurfaceFlinger();
-
-    sp<ProcessState> proc(ProcessState::self());
-    ProcessState::self()->startThreadPool();
-
-    sp<BootAnimation> boot = new BootAnimation(
-            new BootActionAnimationCallbacks(std::move(bootParameters)));
-
-    IPCThreadState::self()->joinThreadPool();
-    return 0;
-}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 984f22f..c712431 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -281,20 +281,7 @@
         mAbortIdleOptimization.set(false);
 
         long lowStorageThreshold = getLowStorageThreshold(context);
-        // Optimize primary apks.
-        int result = optimizePackages(pm, pkgs, lowStorageThreshold,
-            /*isForPrimaryDex=*/ true);
-        if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
-            return result;
-        }
-        if (supportSecondaryDex()) {
-            result = reconcileSecondaryDexFiles(pm.getDexManager());
-            if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
-                return result;
-            }
-            result = optimizePackages(pm, pkgs, lowStorageThreshold,
-                /*isForPrimaryDex=*/ false);
-        }
+        int result = idleOptimizePackages(pm, pkgs, lowStorageThreshold);
         return result;
     }
 
@@ -342,11 +329,20 @@
         return 0;
     }
 
-    private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
-            long lowStorageThreshold, boolean isForPrimaryDex) {
+    private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+            long lowStorageThreshold) {
         ArraySet<String> updatedPackages = new ArraySet<>();
 
         try {
+            final boolean supportSecondaryDex = supportSecondaryDex();
+
+            if (supportSecondaryDex) {
+                int result = reconcileSecondaryDexFiles(pm.getDexManager());
+                if (result == OPTIMIZE_ABORT_BY_JOB_SCHEDULER) {
+                    return result;
+                }
+            }
+
             // Only downgrade apps when space is low on device.
             // Threshold is selected above the lowStorageThreshold so that we can pro-actively clean
             // up disk before user hits the actual lowStorageThreshold.
@@ -359,43 +355,61 @@
                         pm.getUnusedPackages(mDowngradeUnusedAppsThresholdInMillis);
                 Log.d(TAG, "Unsused Packages " +  String.join(",", unusedPackages));
 
-                for (String pkg : unusedPackages) {
-                    int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1);
-                    if (abortCode != OPTIMIZE_CONTINUE) {
-                        // Should be aborted by the scheduler.
-                        return abortCode;
-                    }
-                    if (downgradePackage(pm, pkg, isForPrimaryDex)) {
-                        updatedPackages.add(pkg);
-                    }
-                }
-
                 if (!unusedPackages.isEmpty()) {
+                    for (String pkg : unusedPackages) {
+                        int abortCode = abortIdleOptimizations(/*lowStorageThreshold*/ -1);
+                        if (abortCode != OPTIMIZE_CONTINUE) {
+                            // Should be aborted by the scheduler.
+                            return abortCode;
+                        }
+                        if (downgradePackage(pm, pkg, /*isForPrimaryDex*/ true)) {
+                            updatedPackages.add(pkg);
+                        }
+                        if (supportSecondaryDex) {
+                            downgradePackage(pm, pkg, /*isForPrimaryDex*/ false);
+                        }
+                    }
+
                     pkgs = new ArraySet<>(pkgs);
                     pkgs.removeAll(unusedPackages);
                 }
             }
 
-            for (String pkg : pkgs) {
-                int abortCode = abortIdleOptimizations(lowStorageThreshold);
-                if (abortCode != OPTIMIZE_CONTINUE) {
-                    // Either aborted by the scheduler or no space left.
-                    return abortCode;
-                }
-
-                boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex);
-                if (dexOptPerformed) {
-                    updatedPackages.add(pkg);
-                }
+            int primaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
+                    /*isForPrimaryDex*/ true, updatedPackages);
+            if (primaryResult != OPTIMIZE_PROCESSED) {
+                return primaryResult;
             }
 
-            return OPTIMIZE_PROCESSED;
+            if (!supportSecondaryDex) {
+                return OPTIMIZE_PROCESSED;
+            }
+
+            int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
+                    /*isForPrimaryDex*/ false, updatedPackages);
+            return secondaryResult;
         } finally {
             // Always let the pinner service know about changes.
             notifyPinService(updatedPackages);
         }
     }
 
+    private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
+            long lowStorageThreshold, boolean isForPrimaryDex, ArraySet<String> updatedPackages) {
+        for (String pkg : pkgs) {
+            int abortCode = abortIdleOptimizations(lowStorageThreshold);
+            if (abortCode != OPTIMIZE_CONTINUE) {
+                // Either aborted by the scheduler or no space left.
+                return abortCode;
+            }
+
+            boolean dexOptPerformed = optimizePackage(pm, pkg, isForPrimaryDex);
+            if (dexOptPerformed) {
+                updatedPackages.add(pkg);
+            }
+        }
+        return OPTIMIZE_PROCESSED;
+    }
 
     /**
      * Try to downgrade the package to a smaller compilation filter.
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 09f9c04..499c42e 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -108,6 +108,12 @@
     case Instruction::Op::kSetStaticField:
       out << "kSetStaticField";
       return out;
+    case Instruction::Op::kGetInstanceField:
+      out << "kGetInstanceField";
+      return out;
+    case Instruction::Op::kSetInstanceField:
+      out << "kSetInstanceField";
+      return out;
   }
 }
 
@@ -246,6 +252,7 @@
   field->parent = GetOrAddType(parent);
   field->name = GetOrAddString(name);
   field->type = GetOrAddType(type);
+  field->orig_index = dex_file_->fields_indexes.AllocateIndex();
   dex_file_->fields_map[field->orig_index] = field;
   field_decls_by_key_[key] = field;
   return field;
@@ -384,7 +391,9 @@
       return EncodeCast(instruction);
     case Instruction::Op::kGetStaticField:
     case Instruction::Op::kSetStaticField:
-      return EncodeStaticFieldOp(instruction);
+    case Instruction::Op::kGetInstanceField:
+    case Instruction::Op::kSetInstanceField:
+      return EncodeFieldOp(instruction);
   }
 }
 
@@ -539,7 +548,8 @@
   Encode21c(::art::Instruction::CHECK_CAST, RegisterValue(*instruction.dest()), type.value());
 }
 
-void MethodBuilder::EncodeStaticFieldOp(const Instruction& instruction) {
+void MethodBuilder::EncodeFieldOp(const Instruction& instruction) {
+  const auto& args = instruction.args();
   switch (instruction.opcode()) {
     case Instruction::Op::kGetStaticField: {
       CHECK(instruction.dest().has_value());
@@ -553,18 +563,36 @@
     }
     case Instruction::Op::kSetStaticField: {
       CHECK(!instruction.dest().has_value());
-      const auto& args = instruction.args();
       CHECK_EQ(1, args.size());
       CHECK(args[0].is_variable());
 
-      Encode21c(::art::Instruction::SPUT,
+      Encode21c(::art::Instruction::SPUT, RegisterValue(args[0]), instruction.index_argument());
+      break;
+    }
+    case Instruction::Op::kGetInstanceField: {
+      CHECK(instruction.dest().has_value());
+      CHECK(instruction.dest()->is_variable());
+      CHECK_EQ(1, instruction.args().size());
+
+      Encode22c(::art::Instruction::IGET,
+                RegisterValue(*instruction.dest()),
                 RegisterValue(args[0]),
                 instruction.index_argument());
       break;
     }
-    default: {
-      LOG(FATAL) << "Unsupported static field operation";
+    case Instruction::Op::kSetInstanceField: {
+      CHECK(!instruction.dest().has_value());
+      CHECK_EQ(2, args.size());
+      CHECK(args[0].is_variable());
+      CHECK(args[1].is_variable());
+
+      Encode22c(::art::Instruction::IPUT,
+                RegisterValue(args[1]),
+                RegisterValue(args[0]),
+                instruction.index_argument());
+      break;
     }
+    default: { LOG(FATAL) << "Unsupported field operation"; }
   }
 }
 
diff --git a/startop/view_compiler/dex_builder.h b/startop/view_compiler/dex_builder.h
index 3f9ac43..292d659 100644
--- a/startop/view_compiler/dex_builder.h
+++ b/startop/view_compiler/dex_builder.h
@@ -153,6 +153,7 @@
     kBranchEqz,
     kBranchNEqz,
     kCheckCast,
+    kGetInstanceField,
     kGetStaticField,
     kInvokeDirect,
     kInvokeInterface,
@@ -163,6 +164,7 @@
     kNew,
     kReturn,
     kReturnObject,
+    kSetInstanceField,
     kSetStaticField
   };
 
@@ -195,8 +197,9 @@
   }
   // Returns an object
   template <typename... T>
-  static inline Instruction InvokeVirtualObject(size_t index_argument, std::optional<const Value> dest,
-                                                Value this_arg, T... args) {
+  static inline Instruction InvokeVirtualObject(size_t index_argument,
+                                                std::optional<const Value> dest, Value this_arg,
+                                                T... args) {
     return Instruction{
         Op::kInvokeVirtual, index_argument, /*result_is_object=*/true, dest, this_arg, args...};
   }
@@ -209,8 +212,9 @@
   }
   // Returns an object
   template <typename... T>
-  static inline Instruction InvokeDirectObject(size_t index_argument, std::optional<const Value> dest,
-                                               Value this_arg, T... args) {
+  static inline Instruction InvokeDirectObject(size_t index_argument,
+                                               std::optional<const Value> dest, Value this_arg,
+                                               T... args) {
     return Instruction{
         Op::kInvokeDirect, index_argument, /*result_is_object=*/true, dest, this_arg, args...};
   }
@@ -218,20 +222,21 @@
   template <typename... T>
   static inline Instruction InvokeStatic(size_t index_argument, std::optional<const Value> dest,
                                          T... args) {
-    return Instruction{Op::kInvokeStatic, index_argument, /*result_is_object=*/false, dest, args...};
+    return Instruction{
+        Op::kInvokeStatic, index_argument, /*result_is_object=*/false, dest, args...};
   }
   // Returns an object
   template <typename... T>
-  static inline Instruction InvokeStaticObject(size_t index_argument, std::optional<const Value> dest,
-                                               T... args) {
+  static inline Instruction InvokeStaticObject(size_t index_argument,
+                                               std::optional<const Value> dest, T... args) {
     return Instruction{Op::kInvokeStatic, index_argument, /*result_is_object=*/true, dest, args...};
   }
   // For static calls.
   template <typename... T>
   static inline Instruction InvokeInterface(size_t index_argument, std::optional<const Value> dest,
                                             T... args) {
-    return Instruction{Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...};
-
+    return Instruction{
+        Op::kInvokeInterface, index_argument, /*result_is_object=*/false, dest, args...};
   }
 
   static inline Instruction GetStaticField(size_t field_id, Value dest) {
@@ -239,9 +244,18 @@
   }
 
   static inline Instruction SetStaticField(size_t field_id, Value value) {
-    return Instruction{Op::kSetStaticField, field_id, /*result_is_object=*/false, /*dest=*/{}, value};
+    return Instruction{
+        Op::kSetStaticField, field_id, /*result_is_object=*/false, /*dest=*/{}, value};
   }
 
+  static inline Instruction GetField(size_t field_id, Value dest, Value object) {
+    return Instruction{Op::kGetInstanceField, field_id, /*result_is_object=*/false, dest, object};
+  }
+
+  static inline Instruction SetField(size_t field_id, Value object, Value value) {
+    return Instruction{
+        Op::kSetInstanceField, field_id, /*result_is_object=*/false, /*dest=*/{}, object, value};
+  }
 
   ///////////////
   // Accessors //
@@ -255,10 +269,14 @@
 
  private:
   inline Instruction(Op opcode, size_t index_argument, std::optional<const Value> dest)
-      : opcode_{opcode}, index_argument_{index_argument}, result_is_object_{false}, dest_{dest}, args_{} {}
+      : opcode_{opcode},
+        index_argument_{index_argument},
+        result_is_object_{false},
+        dest_{dest},
+        args_{} {}
 
   template <typename... T>
-  inline constexpr Instruction(Op opcode, size_t index_argument, bool result_is_object,
+  inline Instruction(Op opcode, size_t index_argument, bool result_is_object,
                                std::optional<const Value> dest, T... args)
       : opcode_{opcode},
         index_argument_{index_argument},
@@ -331,7 +349,7 @@
   void EncodeBranch(art::Instruction::Code op, const Instruction& instruction);
   void EncodeNew(const Instruction& instruction);
   void EncodeCast(const Instruction& instruction);
-  void EncodeStaticFieldOp(const Instruction& instruction);
+  void EncodeFieldOp(const Instruction& instruction);
 
   // Low-level instruction format encoding. See
   // https://source.android.com/devices/tech/dalvik/instruction-formats for documentation of
@@ -364,6 +382,14 @@
     buffer_.push_back(b);
   }
 
+  inline void Encode22c(art::Instruction::Code opcode, uint8_t a, uint8_t b, uint16_t c) {
+    // b|a|op|bbbb
+    CHECK(IsShortRegister(a));
+    CHECK(IsShortRegister(b));
+    buffer_.push_back((b << 12) | (a << 8) | opcode);
+    buffer_.push_back(c);
+  }
+
   inline void Encode32x(art::Instruction::Code opcode, uint16_t a, uint16_t b) {
     buffer_.push_back(opcode);
     buffer_.push_back(a);
diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
index 3138e71..93496d0 100644
--- a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
+++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java
@@ -190,4 +190,25 @@
     method.invoke(null);
     Assert.assertEquals(7, TestClass.staticInteger);
   }
+
+  @Test
+  public void readInstanceField() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("readInstanceField", TestClass.class);
+    TestClass obj = new TestClass();
+    obj.instanceField = 5;
+    Assert.assertEquals(5, method.invoke(null, obj));
+  }
+
+  @Test
+  public void setInstanceField() throws Exception {
+    ClassLoader loader = loadDexFile("simple.dex");
+    Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests");
+    Method method = clazz.getMethod("setInstanceField", TestClass.class);
+    TestClass obj = new TestClass();
+    obj.instanceField = 5;
+    method.invoke(null, obj);
+    Assert.assertEquals(7, obj.instanceField);
+  }
 }
diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc
index fee5e72..6dedf24 100644
--- a/startop/view_compiler/dex_testcase_generator.cc
+++ b/startop/view_compiler/dex_testcase_generator.cc
@@ -282,15 +282,15 @@
     method.Encode();
   }(castObjectToString);
 
+  TypeDescriptor test_class = TypeDescriptor::FromClassname("android.startop.test.TestClass");
+
   // Read a static field
-  // integer readStaticField() { return TestClass.staticInteger; }
+  // int readStaticField() { return TestClass.staticInteger; }
   MethodBuilder readStaticField{
       cbuilder.CreateMethod("readStaticField", Prototype{TypeDescriptor::Int()})};
   [&](MethodBuilder& method) {
     const ir::FieldDecl* field =
-        dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"),
-                               "staticInteger",
-                               TypeDescriptor::Int());
+        dex_file.GetOrAddField(test_class, "staticInteger", TypeDescriptor::Int());
     Value result{method.MakeRegister()};
     method.AddInstruction(Instruction::GetStaticField(field->orig_index, result));
     method.BuildReturn(result, /*is_object=*/false);
@@ -303,9 +303,7 @@
       cbuilder.CreateMethod("setStaticField", Prototype{TypeDescriptor::Void()})};
   [&](MethodBuilder& method) {
     const ir::FieldDecl* field =
-        dex_file.GetOrAddField(TypeDescriptor::FromClassname("android.startop.test.TestClass"),
-                               "staticInteger",
-                               TypeDescriptor::Int());
+        dex_file.GetOrAddField(test_class, "staticInteger", TypeDescriptor::Int());
     Value number{method.MakeRegister()};
     method.BuildConst4(number, 7);
     method.AddInstruction(Instruction::SetStaticField(field->orig_index, number));
@@ -313,6 +311,33 @@
     method.Encode();
   }(setStaticField);
 
+  // Read an instance field
+  // int readInstanceField(TestClass obj) { return obj.instanceField; }
+  MethodBuilder readInstanceField{
+      cbuilder.CreateMethod("readInstanceField", Prototype{TypeDescriptor::Int(), test_class})};
+  [&](MethodBuilder& method) {
+    const ir::FieldDecl* field =
+        dex_file.GetOrAddField(test_class, "instanceField", TypeDescriptor::Int());
+    Value result{method.MakeRegister()};
+    method.AddInstruction(Instruction::GetField(field->orig_index, result, Value::Parameter(0)));
+    method.BuildReturn(result, /*is_object=*/false);
+    method.Encode();
+  }(readInstanceField);
+
+  // Set an instance field
+  // void setInstanceField(TestClass obj) { obj.instanceField = 7; }
+  MethodBuilder setInstanceField{
+      cbuilder.CreateMethod("setInstanceField", Prototype{TypeDescriptor::Void(), test_class})};
+  [&](MethodBuilder& method) {
+    const ir::FieldDecl* field =
+        dex_file.GetOrAddField(test_class, "instanceField", TypeDescriptor::Int());
+    Value number{method.MakeRegister()};
+    method.BuildConst4(number, 7);
+    method.AddInstruction(Instruction::SetField(field->orig_index, Value::Parameter(0), number));
+    method.BuildReturn();
+    method.Encode();
+  }(setInstanceField);
+
   slicer::MemView image{dex_file.CreateImage()};
   std::ofstream out_file(outdir + "/simple.dex");
   out_file.write(image.ptr<const char>(), image.size());
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 74af6bf..3bec8b0 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -132,15 +132,20 @@
     public @interface ImsState {}
 
     /**
-     * This {@link ImsFeature}'s state is unavailable and should not be communicated with.
+     * This {@link ImsFeature}'s state is unavailable and should not be communicated with. This will
+     * remove all bindings back to the framework. Any attempt to communicate with the framework
+     * during this time will result in an {@link IllegalStateException}.
      */
     public static final int STATE_UNAVAILABLE = 0;
     /**
-     * This {@link ImsFeature} state is initializing and should not be communicated with.
+     * This {@link ImsFeature} state is initializing and should not be communicated with. This will
+     * remove all bindings back to the framework. Any attempt to communicate with the framework
+     * during this time will result in an {@link IllegalStateException}.
      */
     public static final int STATE_INITIALIZING = 1;
     /**
-     * This {@link ImsFeature} is ready for communication.
+     * This {@link ImsFeature} is ready for communication. Do not attempt to call framework methods
+     * until {@link #onFeatureReady()} is called.
      */
     public static final int STATE_READY = 2;
 
@@ -208,11 +213,14 @@
 
     /**
      * Contains the capabilities defined and supported by an ImsFeature in the form of a bit mask.
+     * <p>
+     * Typically this class is not used directly, but rather extended in subclasses of
+     * {@link ImsFeature} to provide service specific capabilities.
      * @hide
-     * @deprecated Use {@link MmTelFeature.MmTelCapabilities} instead.
      */
-    @SystemApi  // SystemApi only because it was leaked through type usage in a previous release.
+    @SystemApi
     public static class Capabilities {
+        /** @deprecated Use getters and accessors instead. */
         protected int mCapabilities = 0;
 
         /**
@@ -305,12 +313,12 @@
     /** @hide */
     protected final Object mLock = new Object();
 
-    private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap(
-            new WeakHashMap<IImsFeatureStatusCallback, Boolean>());
+    private final Set<IImsFeatureStatusCallback> mStatusCallbacks =
+            Collections.newSetFromMap(new WeakHashMap<>());
     private @ImsState int mState = STATE_UNAVAILABLE;
     private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
-    private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks
-            = new RemoteCallbackList<>();
+    private final RemoteCallbackList<IImsCapabilityCallback> mCapabilityCallbacks =
+            new RemoteCallbackList<>();
     private Capabilities mCapabilityStatus = new Capabilities();
 
     /**
@@ -322,6 +330,16 @@
     }
 
     /**
+     * @return The SIM slot index associated with this ImsFeature.
+     *
+     * @see SubscriptionManager#getSubscriptionIds(int) for more information on getting the
+     * subscription IDs associated with this slot.
+     */
+    public final int getSlotIndex() {
+        return mSlotId;
+    }
+
+    /**
      * @return The current state of the feature, defined as {@link #STATE_UNAVAILABLE},
      * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}.
      * @hide
@@ -490,7 +508,9 @@
     public abstract void onFeatureRemoved();
 
     /**
-     * Called when the feature has been initialized and communication with the framework is set up.
+     * Called after this ImsFeature has been initialized and has been set to the
+     * {@link ImsState#STATE_READY} state.
+     * <p>
      * Any attempt by this feature to access the framework before this method is called will return
      * with an {@link IllegalStateException}.
      * The IMS provider should use this method to trigger registration for this feature on the IMS