Merge "Bugreport: Fix SystemUI service from being dumped twice 2/2"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 94eaf05..56b5649 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -262,6 +262,9 @@
 static const char* k_printTgidPath =
     "options/print-tgid";
 
+static const char* k_recordTgidPath =
+    "options/record-tgid";
+
 static const char* k_funcgraphAbsTimePath =
     "options/funcgraph-abstime";
 
@@ -524,9 +527,15 @@
 
 static bool setPrintTgidEnableIfPresent(bool enable)
 {
+    // Pre-4.13 this was options/print-tgid as an android-specific option.
+    // In 4.13+ this is an upstream option called options/record-tgid
+    // Both options produce the same ftrace format change
     if (fileExists(k_printTgidPath)) {
         return setKernelOptionEnable(k_printTgidPath, enable);
     }
+    if (fileExists(k_recordTgidPath)) {
+        return setKernelOptionEnable(k_recordTgidPath, enable);
+    }
     return true;
 }
 
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 9be1077..5903656 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -19,6 +19,8 @@
     chmod 0666 /sys/kernel/tracing/options/overwrite
     chmod 0666 /sys/kernel/debug/tracing/options/print-tgid
     chmod 0666 /sys/kernel/tracing/options/print-tgid
+    chmod 0666 /sys/kernel/debug/tracing/options/record-tgid
+    chmod 0666 /sys/kernel/tracing/options/record-tgid
     chmod 0666 /sys/kernel/debug/tracing/saved_cmdlines_size
     chmod 0666 /sys/kernel/tracing/saved_cmdlines_size
     chmod 0666 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 91a56f0..dec767d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1239,10 +1239,12 @@
     RunCommand("LIBRANK", {"librank"}, CommandOptions::AS_ROOT);
 
     if (ds.IsZipping()) {
-        RunCommand("HARDWARE HALS", {"lshal"}, CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
+        RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z"},
+                   CommandOptions::WithTimeout(2).AsRootIfAvailable().Build());
         DumpHals();
     } else {
-        RunCommand("HARDWARE HALS", {"lshal", "--debug"}, CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
+        RunCommand("HARDWARE HALS", {"lshal", "-lVSietrpc", "--types=b,c,l,z", "--debug"},
+                   CommandOptions::WithTimeout(10).AsRootIfAvailable().Build());
     }
 
     RunCommand("PRINTENV", {"printenv"});
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 92e9151..09eeaa8 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -57,6 +57,19 @@
     return (p == Partition::SYSTEM) ? vintf::SchemaType::FRAMEWORK : vintf::SchemaType::DEVICE;
 }
 
+Partition toPartition(vintf::SchemaType t) {
+    switch (t) {
+        case vintf::SchemaType::FRAMEWORK: return Partition::SYSTEM;
+        // TODO(b/71555570): Device manifest does not distinguish HALs from vendor or ODM.
+        case vintf::SchemaType::DEVICE: return Partition::VENDOR;
+    }
+    return Partition::UNKNOWN;
+}
+
+std::string getPackageAndVersion(const std::string& fqInstance) {
+    return splitFirst(fqInstance, ':').first;
+}
+
 NullableOStream<std::ostream> ListCommand::out() const {
     return mLshal.out();
 }
@@ -77,6 +90,8 @@
 }
 
 const std::string &ListCommand::getCmdline(pid_t pid) {
+    static const std::string kEmptyString{};
+    if (pid == NO_PID) return kEmptyString;
     auto pair = mCmdlines.find(pid);
     if (pair != mCmdlines.end()) {
         return pair->second;
@@ -93,6 +108,7 @@
 }
 
 Partition ListCommand::getPartition(pid_t pid) {
+    if (pid == NO_PID) return Partition::UNKNOWN;
     auto it = mPartitions.find(pid);
     if (it != mPartitions.end()) {
         return it->second;
@@ -176,7 +192,7 @@
     FqInstance fqInstance;
     if (!fqInstance.setTo(fqInstanceName) &&
         // Ignore interface / instance for passthrough libs
-        !fqInstance.setTo(splitFirst(fqInstanceName, ':').first)) {
+        !fqInstance.setTo(getPackageAndVersion(fqInstanceName))) {
         err() << "Warning: Cannot parse '" << fqInstanceName << "'; no VINTF info." << std::endl;
         return VINTF_INFO_EMPTY;
     }
@@ -283,36 +299,39 @@
     return &pair.first->second;
 }
 
-bool ListCommand::shouldReportHalType(const HalType &type) const {
-    return (std::find(mListTypes.begin(), mListTypes.end(), type) != mListTypes.end());
+bool ListCommand::shouldFetchHalType(const HalType &type) const {
+    return (std::find(mFetchTypes.begin(), mFetchTypes.end(), type) != mFetchTypes.end());
+}
+
+Table* ListCommand::tableForType(HalType type) {
+    switch (type) {
+        case HalType::BINDERIZED_SERVICES:
+            return &mServicesTable;
+        case HalType::PASSTHROUGH_CLIENTS:
+            return &mPassthroughRefTable;
+        case HalType::PASSTHROUGH_LIBRARIES:
+            return &mImplementationsTable;
+        case HalType::VINTF_MANIFEST:
+            return &mManifestHalsTable;
+        case HalType::LAZY_HALS:
+            return &mLazyHalsTable;
+        default:
+            LOG(FATAL) << "Unknown HAL type " << static_cast<int64_t>(type);
+            return nullptr;
+    }
+}
+const Table* ListCommand::tableForType(HalType type) const {
+    return const_cast<ListCommand*>(this)->tableForType(type);
 }
 
 void ListCommand::forEachTable(const std::function<void(Table &)> &f) {
     for (const auto& type : mListTypes) {
-        switch (type) {
-            case HalType::BINDERIZED_SERVICES:
-                f(mServicesTable); break;
-            case HalType::PASSTHROUGH_CLIENTS:
-                f(mPassthroughRefTable); break;
-            case HalType::PASSTHROUGH_LIBRARIES:
-                f(mImplementationsTable); break;
-            default:
-                LOG(FATAL) << __func__ << "Unknown HAL type.";
-        }
+        f(*tableForType(type));
     }
 }
 void ListCommand::forEachTable(const std::function<void(const Table &)> &f) const {
     for (const auto& type : mListTypes) {
-        switch (type) {
-            case HalType::BINDERIZED_SERVICES:
-                f(mServicesTable); break;
-            case HalType::PASSTHROUGH_CLIENTS:
-                f(mPassthroughRefTable); break;
-            case HalType::PASSTHROUGH_LIBRARIES:
-                f(mImplementationsTable); break;
-            default:
-                LOG(FATAL) << __func__ << "Unknown HAL type.";
-        }
+        f(*tableForType(type));
     }
 }
 
@@ -329,7 +348,9 @@
             }
         }
         for (TableEntry& entry : table) {
-            entry.partition = getPartition(entry.serverPid);
+            if (entry.partition == Partition::UNKNOWN) {
+                entry.partition = getPartition(entry.serverPid);
+            }
             entry.vintfInfo = getVintfInfo(entry.interfaceName, {entry.transport, entry.arch});
         }
     });
@@ -366,6 +387,12 @@
     mImplementationsTable.setDescription(
             "All available passthrough implementations (all -impl.so files).\n"
             "These may return subclasses through their respective HIDL_FETCH_I* functions.");
+    mManifestHalsTable.setDescription(
+            "All HALs that are in VINTF manifest.");
+    mLazyHalsTable.setDescription(
+            "All HALs that are declared in VINTF manifest:\n"
+            "   - as hwbinder HALs but are not registered to hwservicemanager, and\n"
+            "   - as hwbinder/passthrough HALs with no implementation.");
 }
 
 bool ListCommand::addEntryWithInstance(const TableEntry& entry,
@@ -416,7 +443,7 @@
 
 bool ListCommand::addEntryWithoutInstance(const TableEntry& entry,
                                           const vintf::HalManifest* manifest) const {
-    const auto& packageAndVersion = splitFirst(splitFirst(entry.interfaceName, ':').first, '@');
+    const auto& packageAndVersion = splitFirst(getPackageAndVersion(entry.interfaceName), '@');
     const auto& package = packageAndVersion.first;
     vintf::Version version;
     if (!vintf::parse(packageAndVersion.second, &version)) {
@@ -446,6 +473,8 @@
         if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
     for (const TableEntry& entry : mPassthroughRefTable)
         if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
+    for (const TableEntry& entry : mManifestHalsTable)
+        if (!addEntryWithInstance(entry, &manifest)) error.push_back(entry.interfaceName);
 
     std::vector<std::string> passthrough;
     for (const TableEntry& entry : mImplementationsTable)
@@ -503,8 +532,11 @@
 
 void ListCommand::dumpTable(const NullableOStream<std::ostream>& out) const {
     if (mNeat) {
-        MergedTable({&mServicesTable, &mPassthroughRefTable, &mImplementationsTable})
-            .createTextTable().dump(out.buf());
+        std::vector<const Table*> tables;
+        forEachTable([&tables](const Table &table) {
+            tables.push_back(&table);
+        });
+        MergedTable(std::move(tables)).createTextTable().dump(out.buf());
         return;
     }
 
@@ -552,25 +584,12 @@
     return OK;
 }
 
-void ListCommand::putEntry(TableEntrySource source, TableEntry &&entry) {
-    Table *table = nullptr;
-    switch (source) {
-        case HWSERVICEMANAGER_LIST :
-            table = &mServicesTable; break;
-        case PTSERVICEMANAGER_REG_CLIENT :
-            table = &mPassthroughRefTable; break;
-        case LIST_DLLIB :
-            table = &mImplementationsTable; break;
-        default:
-            err() << "Error: Unknown source of entry " << source << std::endl;
-    }
-    if (table) {
-        table->add(std::forward<TableEntry>(entry));
-    }
+void ListCommand::putEntry(HalType type, TableEntry &&entry) {
+    tableForType(type)->add(std::forward<TableEntry>(entry));
 }
 
 Status ListCommand::fetchAllLibraries(const sp<IServiceManager> &manager) {
-    if (!shouldReportHalType(HalType::PASSTHROUGH_LIBRARIES)) { return OK; }
+    if (!shouldFetchHalType(HalType::PASSTHROUGH_LIBRARIES)) { return OK; }
 
     using namespace ::android::hardware;
     using namespace ::android::hidl::manager::V1_0;
@@ -588,7 +607,7 @@
             }).first->second.arch |= fromBaseArchitecture(info.arch);
         }
         for (auto &&pair : entries) {
-            putEntry(LIST_DLLIB, std::move(pair.second));
+            putEntry(HalType::PASSTHROUGH_LIBRARIES, std::move(pair.second));
         }
     });
     if (!ret.isOk()) {
@@ -600,7 +619,7 @@
 }
 
 Status ListCommand::fetchPassthrough(const sp<IServiceManager> &manager) {
-    if (!shouldReportHalType(HalType::PASSTHROUGH_CLIENTS)) { return OK; }
+    if (!shouldFetchHalType(HalType::PASSTHROUGH_CLIENTS)) { return OK; }
 
     using namespace ::android::hardware;
     using namespace ::android::hardware::details;
@@ -611,7 +630,7 @@
             if (info.clientPids.size() <= 0) {
                 continue;
             }
-            putEntry(PTSERVICEMANAGER_REG_CLIENT, {
+            putEntry(HalType::PASSTHROUGH_CLIENTS, {
                 .interfaceName =
                         std::string{info.interfaceName.c_str()} + "/" +
                         std::string{info.instanceName.c_str()},
@@ -633,7 +652,7 @@
 Status ListCommand::fetchBinderized(const sp<IServiceManager> &manager) {
     using vintf::operator<<;
 
-    if (!shouldReportHalType(HalType::BINDERIZED_SERVICES)) { return OK; }
+    if (!shouldFetchHalType(HalType::BINDERIZED_SERVICES)) { return OK; }
 
     const vintf::Transport mode = vintf::Transport::HWBINDER;
     hidl_vec<hidl_string> fqInstanceNames;
@@ -654,12 +673,13 @@
         TableEntry& entry = allTableEntries[fqInstanceName];
         entry.interfaceName = fqInstanceName;
         entry.transport = mode;
+        entry.serviceStatus = ServiceStatus::NON_RESPONSIVE;
 
         status |= fetchBinderizedEntry(manager, &entry);
     }
 
     for (auto& pair : allTableEntries) {
-        putEntry(HWSERVICEMANAGER_LIST, std::move(pair.second));
+        putEntry(HalType::BINDERIZED_SERVICES, std::move(pair.second));
     }
     return status;
 }
@@ -759,9 +779,100 @@
             handleError(TRANSACTION_ERROR, "getHashChain failed: " + hashRet.description());
         }
     } while (0);
+    if (status == OK) {
+        entry->serviceStatus = ServiceStatus::ALIVE;
+    }
     return status;
 }
 
+Status ListCommand::fetchManifestHals() {
+    if (!shouldFetchHalType(HalType::VINTF_MANIFEST)) { return OK; }
+    Status status = OK;
+
+    for (auto manifest : {getDeviceManifest(), getFrameworkManifest()}) {
+        if (manifest == nullptr) {
+            status |= VINTF_ERROR;
+            continue;
+        }
+
+        std::map<std::string, TableEntry> entries;
+
+        manifest->forEachInstance([&] (const vintf::ManifestInstance& manifestInstance) {
+            TableEntry entry{
+                .interfaceName = manifestInstance.getFqInstance().string(),
+                .transport = manifestInstance.transport(),
+                .arch = manifestInstance.arch(),
+                // TODO(b/71555570): Device manifest does not distinguish HALs from vendor or ODM.
+                .partition = toPartition(manifest->type()),
+                .serviceStatus = ServiceStatus::DECLARED};
+            std::string key = entry.interfaceName;
+            entries.emplace(std::move(key), std::move(entry));
+            return true;
+        });
+
+        for (auto&& pair : entries)
+            mManifestHalsTable.add(std::move(pair.second));
+    }
+    return status;
+}
+
+Status ListCommand::fetchLazyHals() {
+    using vintf::operator<<;
+
+    if (!shouldFetchHalType(HalType::LAZY_HALS)) { return OK; }
+    Status status = OK;
+
+    for (const TableEntry& manifestEntry : mManifestHalsTable) {
+        if (manifestEntry.transport == vintf::Transport::HWBINDER) {
+            if (!hasHwbinderEntry(manifestEntry)) {
+                mLazyHalsTable.add(TableEntry(manifestEntry));
+            }
+            continue;
+        }
+        if (manifestEntry.transport == vintf::Transport::PASSTHROUGH) {
+            if (!hasPassthroughEntry(manifestEntry)) {
+                mLazyHalsTable.add(TableEntry(manifestEntry));
+            }
+            continue;
+        }
+        err() << "Warning: unrecognized transport in VINTF manifest: "
+              << manifestEntry.transport;
+        status |= VINTF_ERROR;
+    }
+    return status;
+}
+
+bool ListCommand::hasHwbinderEntry(const TableEntry& entry) const {
+    for (const TableEntry& existing : mServicesTable) {
+        if (existing.interfaceName == entry.interfaceName) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool ListCommand::hasPassthroughEntry(const TableEntry& entry) const {
+    FqInstance entryFqInstance;
+    if (!entryFqInstance.setTo(entry.interfaceName)) {
+        return false; // cannot parse, so add it anyway.
+    }
+    for (const TableEntry& existing : mImplementationsTable) {
+        FqInstance existingFqInstance;
+        if (!existingFqInstance.setTo(getPackageAndVersion(existing.interfaceName))) {
+            continue;
+        }
+
+        // For example, manifest may say graphics.mapper@2.1 but passthroughServiceManager
+        // can only list graphics.mapper@2.0.
+        if (entryFqInstance.getPackage() == existingFqInstance.getPackage() &&
+            vintf::Version{entryFqInstance.getVersion()}
+                .minorAtLeast(vintf::Version{existingFqInstance.getVersion()})) {
+            return true;
+        }
+    }
+    return false;
+}
+
 Status ListCommand::fetch() {
     Status status = OK;
     auto bManager = mLshal.serviceManager();
@@ -781,9 +892,27 @@
     } else {
         status |= fetchAllLibraries(pManager);
     }
+    status |= fetchManifestHals();
+    status |= fetchLazyHals();
     return status;
 }
 
+void ListCommand::initFetchTypes() {
+    // TODO: refactor to do polymorphism on each table (so that dependency graph is not hardcoded).
+    static const std::map<HalType, std::set<HalType>> kDependencyGraph{
+        {HalType::LAZY_HALS, {HalType::BINDERIZED_SERVICES,
+                              HalType::PASSTHROUGH_LIBRARIES,
+                              HalType::VINTF_MANIFEST}},
+    };
+    mFetchTypes.insert(mListTypes.begin(), mListTypes.end());
+    for (HalType listType : mListTypes) {
+        auto it = kDependencyGraph.find(listType);
+        if (it != kDependencyGraph.end()) {
+            mFetchTypes.insert(it->second.begin(), it->second.end());
+        }
+    }
+}
+
 void ListCommand::registerAllOptions() {
     int v = mOptions.size();
     // A list of acceptable command line options
@@ -847,6 +976,14 @@
        "    - DC: device compatibility matrix\n"
        "    - FM: framework manifest\n"
        "    - FC: framework compatibility matrix"});
+    mOptions.push_back({'S', "service-status", no_argument, v++, [](ListCommand* thiz, const char*) {
+        thiz->mSelectedColumns.push_back(TableColumnType::SERVICE_STATUS);
+        return OK;
+    }, "print service status column. Possible values are:\n"
+       "    - alive: alive and running hwbinder service;\n"
+       "    - registered;dead: registered to hwservicemanager but is not responsive;\n"
+       "    - declared: only declared in VINTF manifest but is not registered to hwservicemanager;\n"
+       "    - N/A: no information for passthrough HALs."});
 
     // long options without short alternatives
     mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
@@ -887,7 +1024,11 @@
             {"passthrough_clients", HalType::PASSTHROUGH_CLIENTS},
             {"c", HalType::PASSTHROUGH_CLIENTS},
             {"passthrough_libs", HalType::PASSTHROUGH_LIBRARIES},
-            {"l", HalType::PASSTHROUGH_LIBRARIES}
+            {"l", HalType::PASSTHROUGH_LIBRARIES},
+            {"vintf", HalType::VINTF_MANIFEST},
+            {"v", HalType::VINTF_MANIFEST},
+            {"lazy", HalType::LAZY_HALS},
+            {"z", HalType::LAZY_HALS},
         };
 
         std::vector<std::string> halTypesArgs = split(std::string(arg), ',');
@@ -911,9 +1052,9 @@
 
         if (thiz->mListTypes.empty()) { return USAGE; }
         return OK;
-    }, "comma-separated list of one or more HAL types.\nThe output is restricted to the selected "
-       "association(s). Valid options\nare: (b|binderized), (c|passthrough_clients), and (l|"
-       "passthrough_libs).\nBy default, lists all available HALs."});
+    }, "comma-separated list of one or more sections.\nThe output is restricted to the selected "
+       "section(s). Valid options\nare: (b|binderized), (c|passthrough_clients), (l|"
+       "passthrough_libs), and (v|vintf).\nDefault is `bcl`."});
 }
 
 // Create 'longopts' argument to getopt_long. Caller is responsible for maintaining
@@ -1030,6 +1171,7 @@
         mListTypes = {HalType::BINDERIZED_SERVICES, HalType::PASSTHROUGH_CLIENTS,
                       HalType::PASSTHROUGH_LIBRARIES};
     }
+    initFetchTypes();
 
     forEachTable([this] (Table& table) {
         table.setSelectedColumns(this->mSelectedColumns);
@@ -1068,7 +1210,7 @@
     err() << "list:" << std::endl
           << "    lshal" << std::endl
           << "    lshal list" << std::endl
-          << "        List all hals with default ordering and columns (`lshal list -riepc`)" << std::endl
+          << "        List all hals with default ordering and columns (`lshal list -liepc`)" << std::endl
           << "    lshal list [-h|--help]" << std::endl
           << "        -h, --help: Print help message for list (`lshal help list`)" << std::endl
           << "    lshal [list] [OPTIONS...]" << std::endl;
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 87d93b5..3f7321d 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -50,7 +50,9 @@
 enum class HalType {
     BINDERIZED_SERVICES = 0,
     PASSTHROUGH_CLIENTS,
-    PASSTHROUGH_LIBRARIES
+    PASSTHROUGH_LIBRARIES,
+    VINTF_MANIFEST,
+    LAZY_HALS,
 };
 
 class ListCommand : public Command {
@@ -93,10 +95,12 @@
     // Retrieve derived information base on existing table
     virtual void postprocess();
     Status dump();
-    void putEntry(TableEntrySource source, TableEntry &&entry);
+    void putEntry(HalType type, TableEntry &&entry);
     Status fetchPassthrough(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchBinderized(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
     Status fetchAllLibraries(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager);
+    Status fetchManifestHals();
+    Status fetchLazyHals();
 
     Status fetchBinderizedEntry(const sp<::android::hidl::manager::V1_0::IServiceManager> &manager,
                                 TableEntry *entry);
@@ -134,6 +138,8 @@
 
     void forEachTable(const std::function<void(Table &)> &f);
     void forEachTable(const std::function<void(const Table &)> &f) const;
+    Table* tableForType(HalType type);
+    const Table* tableForType(HalType type) const;
 
     NullableOStream<std::ostream> err() const;
     NullableOStream<std::ostream> out() const;
@@ -144,12 +150,20 @@
     bool addEntryWithInstance(const TableEntry &entry, vintf::HalManifest *manifest) const;
     bool addEntryWithoutInstance(const TableEntry &entry, const vintf::HalManifest *manifest) const;
 
-    // Helper function. Whether to list entries corresponding to a given HAL type.
-    bool shouldReportHalType(const HalType &type) const;
+    // Helper function. Whether to fetch entries corresponding to a given HAL type.
+    bool shouldFetchHalType(const HalType &type) const;
+
+    void initFetchTypes();
+
+    // Helper functions ti add HALs that are listed in VINTF manifest to LAZY_HALS table.
+    bool hasHwbinderEntry(const TableEntry& entry) const;
+    bool hasPassthroughEntry(const TableEntry& entry) const;
 
     Table mServicesTable{};
     Table mPassthroughRefTable{};
     Table mImplementationsTable{};
+    Table mManifestHalsTable{};
+    Table mLazyHalsTable{};
 
     std::string mFileOutputPath;
     TableEntryCompare mSortColumn = nullptr;
@@ -163,9 +177,10 @@
     // If true, explanatory text are not emitted.
     bool mNeat = false;
 
-    // Type(s) of HAL associations to list. By default, report all.
-    std::vector<HalType> mListTypes{HalType::BINDERIZED_SERVICES, HalType::PASSTHROUGH_CLIENTS,
-                                    HalType::PASSTHROUGH_LIBRARIES};
+    // Type(s) of HAL associations to list.
+    std::vector<HalType> mListTypes{};
+    // Type(s) of HAL associations to fetch.
+    std::set<HalType> mFetchTypes{};
 
     // If an entry does not exist, need to ask /proc/{pid}/cmdline to get it.
     // If an entry exist but is an empty string, process might have died.
diff --git a/cmds/lshal/TableEntry.cpp b/cmds/lshal/TableEntry.cpp
index 4ad3e92..8e21975 100644
--- a/cmds/lshal/TableEntry.cpp
+++ b/cmds/lshal/TableEntry.cpp
@@ -62,6 +62,7 @@
         case TableColumnType::RELEASED:         return "R";
         case TableColumnType::HASH:             return "Hash";
         case TableColumnType::VINTF:            return "VINTF";
+        case TableColumnType::SERVICE_STATUS:   return "Status";
         default:
             LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
             return "";
@@ -94,6 +95,8 @@
             return hash;
         case TableColumnType::VINTF:
             return getVintfInfo();
+        case TableColumnType::SERVICE_STATUS:
+            return lshal::to_string(serviceStatus);
         default:
             LOG(FATAL) << __func__ << "Should not reach here. " << static_cast<int>(type);
             return "";
@@ -129,6 +132,18 @@
     return joined.empty() ? "X" : joined;
 }
 
+std::string to_string(ServiceStatus s) {
+    switch (s) {
+        case ServiceStatus::ALIVE: return "alive";
+        case ServiceStatus::NON_RESPONSIVE: return "non-responsive";
+        case ServiceStatus::DECLARED: return "declared";
+        case ServiceStatus::UNKNOWN: return "N/A";
+    }
+
+    LOG(FATAL) << __func__ << "Should not reach here." << static_cast<int>(s);
+    return "";
+}
+
 TextTable Table::createTextTable(bool neat,
     const std::function<std::string(const std::string&)>& emitDebugInfo) const {
 
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index c9a6a23..7294b0a 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -35,13 +35,6 @@
 using android::procpartition::Partition;
 using Pids = std::vector<int32_t>;
 
-enum : unsigned int {
-    HWSERVICEMANAGER_LIST, // through defaultServiceManager()->list()
-    PTSERVICEMANAGER_REG_CLIENT, // through registerPassthroughClient
-    LIST_DLLIB, // through listing dynamic libraries
-};
-using TableEntrySource = unsigned int;
-
 enum class TableColumnType : unsigned int {
     INTERFACE_NAME,
     TRANSPORT,
@@ -55,6 +48,7 @@
     RELEASED,
     HASH,
     VINTF,
+    SERVICE_STATUS,
 };
 
 enum : unsigned int {
@@ -71,6 +65,14 @@
     NO_PTR = 0
 };
 
+enum class ServiceStatus {
+    UNKNOWN, // For passthrough
+    ALIVE,
+    NON_RESPONSIVE, // registered but not respond to calls
+    DECLARED, // in VINTF manifest
+};
+std::string to_string(ServiceStatus s);
+
 struct TableEntry {
     std::string interfaceName{};
     vintf::Transport transport{vintf::Transport::EMPTY};
@@ -86,6 +88,8 @@
     std::string hash{};
     Partition partition{Partition::UNKNOWN};
     VintfInfo vintfInfo{VINTF_INFO_EMPTY};
+    // true iff hwbinder and service started
+    ServiceStatus serviceStatus{ServiceStatus::UNKNOWN};
 
     static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
         return a.interfaceName < b.interfaceName;
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 501c04d..8d7405b 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -226,12 +226,13 @@
     void SetUp() override {
         mockLshal = std::make_unique<NiceMock<MockLshal>>();
         mockList = std::make_unique<MockListCommand>(mockLshal.get());
+        ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(err)));
         // ListCommand::parseArgs should parse arguments from the second element
         optind = 1;
     }
     std::unique_ptr<MockLshal> mockLshal;
     std::unique_ptr<MockListCommand> mockList;
-    std::stringstream output;
+    std::stringstream err;
 };
 
 TEST_F(ListParseArgsTest, Args) {
@@ -241,6 +242,7 @@
                                    TableColumnType::SERVER_ADDR, TableColumnType::CLIENT_PIDS}),
                   table.getSelectedColumns());
     });
+    EXPECT_EQ("", err.str());
 }
 
 TEST_F(ListParseArgsTest, Cmds) {
@@ -255,12 +257,12 @@
         EXPECT_THAT(table.getSelectedColumns(), Contains(TableColumnType::CLIENT_CMDS))
                 << "should print client cmds with -m";
     });
+    EXPECT_EQ("", err.str());
 }
 
 TEST_F(ListParseArgsTest, DebugAndNeat) {
-    ON_CALL(*mockLshal, err()).WillByDefault(Return(NullableOStream<std::ostream>(output)));
     EXPECT_NE(0u, mockList->parseArgs(createArg({"lshal", "--neat", "-d"})));
-    EXPECT_THAT(output.str(), StrNe(""));
+    EXPECT_THAT(err.str(), HasSubstr("--neat should not be used with --debug."));
 }
 
 /// Fetch Test
@@ -325,7 +327,7 @@
 
 class ListTest : public ::testing::Test {
 public:
-    void SetUp() override {
+    virtual void SetUp() override {
         initMockServiceManager();
         lshal = std::make_unique<Lshal>(out, err, serviceManager, passthruManager);
         initMockList();
@@ -349,13 +351,13 @@
         ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
 
         ON_CALL(*mockList, getDeviceManifest())
-                .WillByDefault(Return(VintfObject::GetDeviceHalManifest()));
+                .WillByDefault(Return(std::make_shared<HalManifest>()));
         ON_CALL(*mockList, getDeviceMatrix())
-                .WillByDefault(Return(VintfObject::GetDeviceCompatibilityMatrix()));
+                .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
         ON_CALL(*mockList, getFrameworkManifest())
-                .WillByDefault(Return(VintfObject::GetFrameworkHalManifest()));
+                .WillByDefault(Return(std::make_shared<HalManifest>()));
         ON_CALL(*mockList, getFrameworkMatrix())
-                .WillByDefault(Return(VintfObject::GetFrameworkCompatibilityMatrix()));
+                .WillByDefault(Return(std::make_shared<CompatibilityMatrix>()));
     }
 
     void initMockServiceManager() {
@@ -409,16 +411,22 @@
 }
 
 TEST_F(ListTest, Fetch) {
-    EXPECT_EQ(0u, mockList->fetch());
+    optind = 1; // mimic Lshal::parseArg()
+    ASSERT_EQ(0u, mockList->parseArgs(createArg({"lshal"})));
+    ASSERT_EQ(0u, mockList->fetch());
     vintf::TransportArch hwbinder{Transport::HWBINDER, Arch::ARCH_64};
     vintf::TransportArch passthrough{Transport::PASSTHROUGH, Arch::ARCH_32};
     std::array<vintf::TransportArch, 6> transportArchs{{hwbinder, hwbinder, passthrough,
                                                         passthrough, passthrough, passthrough}};
-    int id = 1;
+    int i = 0;
     mockList->forEachTable([&](const Table& table) {
-        ASSERT_EQ(2u, table.size());
         for (const auto& entry : table) {
-            auto transport = transportArchs.at(id - 1).transport;
+            if (i >= transportArchs.size()) {
+                break;
+            }
+
+            int id = i + 1;
+            auto transport = transportArchs.at(i).transport;
             TableEntry expected{
                 .interfaceName = getFqInstanceName(id),
                 .transport = transport,
@@ -431,14 +439,16 @@
                 .serverObjectAddress = transport == Transport::HWBINDER ? getPtr(id) : NO_PTR,
                 .clientPids = getClients(id),
                 .clientCmdlines = {},
-                .arch = transportArchs.at(id - 1).arch,
+                .arch = transportArchs.at(i).arch,
             };
             EXPECT_EQ(expected, entry) << expected.to_string() << " vs. " << entry.to_string();
 
-            ++id;
+            ++i;
         }
     });
 
+    EXPECT_EQ(transportArchs.size(), i) << "Not all entries are tested.";
+
 }
 
 TEST_F(ListTest, DumpVintf) {
@@ -756,6 +766,60 @@
     EXPECT_EQ("", err.str());
 }
 
+class ListVintfTest : public ListTest {
+public:
+    virtual void SetUp() override {
+        ListTest::SetUp();
+        const std::string mockManifestXml =
+                "<manifest version=\"1.0\" type=\"device\">\n"
+                "    <hal format=\"hidl\">\n"
+                "        <name>a.h.foo1</name>\n"
+                "        <transport>hwbinder</transport>\n"
+                "        <fqname>@1.0::IFoo/1</fqname>\n"
+                "    </hal>\n"
+                "    <hal format=\"hidl\">\n"
+                "        <name>a.h.bar1</name>\n"
+                "        <transport>hwbinder</transport>\n"
+                "        <fqname>@1.0::IBar/1</fqname>\n"
+                "    </hal>\n"
+                "    <hal format=\"hidl\">\n"
+                "        <name>a.h.bar2</name>\n"
+                "        <transport arch=\"32+64\">passthrough</transport>\n"
+                "        <fqname>@2.0::IBar/2</fqname>\n"
+                "    </hal>\n"
+                "</manifest>";
+        auto manifest = std::make_shared<HalManifest>();
+        EXPECT_TRUE(gHalManifestConverter(manifest.get(), mockManifestXml));
+        EXPECT_CALL(*mockList, getDeviceManifest())
+            .Times(AnyNumber())
+            .WillRepeatedly(Return(manifest));
+    }
+};
+
+TEST_F(ListVintfTest, ManifestHals) {
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=v", "--neat"})));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder    ?"));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.foo1@1.0::IFoo/1 declared hwbinder    ?"));
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListVintfTest, Lazy) {
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=z", "--neat"})));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.bar1@1.0::IBar/1 declared hwbinder    ?"));
+    EXPECT_THAT(out.str(), HasSubstr("a.h.bar2@2.0::IBar/2 declared passthrough 32+64"));
+    EXPECT_EQ("", err.str());
+}
+
+TEST_F(ListVintfTest, NoLazy) {
+    optind = 1; // mimic Lshal::parseArg()
+    EXPECT_EQ(0u, mockList->main(createArg({"lshal", "-iStr", "--types=b,c,l", "--neat"})));
+    EXPECT_THAT(out.str(), Not(HasSubstr("IBar")));
+    EXPECT_EQ("", err.str());
+}
+
 class HelpTest : public ::testing::Test {
 public:
     void SetUp() override {
diff --git a/cmds/lshal/utils.h b/cmds/lshal/utils.h
index c09e8b1..240155e 100644
--- a/cmds/lshal/utils.h
+++ b/cmds/lshal/utils.h
@@ -46,6 +46,8 @@
     TRANSACTION_ERROR                       = 1 << 8,
     // No transaction error, but return value is unexpected.
     BAD_IMPL                                = 1 << 9,
+    // Cannot fetch VINTF data.
+    VINTF_ERROR                             = 1 << 10,
 };
 using Status = unsigned int;
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 8efbef5..6237aa0 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -46,7 +46,6 @@
 #include <utils/Trace.h>
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
 
@@ -82,26 +81,6 @@
 Mutex GLConsumer::sStaticInitLock;
 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
 
-static bool hasEglAndroidImageCropImpl() {
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(CROP_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(CROP_EXT_STR, exts);
-    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
-    bool atEnd = (cropExtLen+1) < extsLen &&
-            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
-    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
-    return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglAndroidImageCrop() {
-    // Only compute whether the extension is present once the first time this
-    // function is called.
-    static bool hasIt = hasEglAndroidImageCropImpl();
-    return hasIt;
-}
-
 static bool hasEglProtectedContentImpl() {
     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
@@ -122,10 +101,6 @@
     return hasIt;
 }
 
-static bool isEglImageCroppable(const Rect& crop) {
-    return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
-}
-
 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
         uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
     ConsumerBase(bq, isControlledByApp),
@@ -406,7 +381,7 @@
     // ConsumerBase.
     // We may have to do this even when item.mGraphicBuffer == NULL (which
     // means the buffer was previously acquired).
-    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay);
     if (err != NO_ERROR) {
         GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
                 mEglDisplay, slot);
@@ -496,8 +471,7 @@
         return NO_INIT;
     }
 
-    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
-                                                        mCurrentCrop);
+    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
     if (err != NO_ERROR) {
         GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
                 mEglDisplay, mCurrentTexture);
@@ -511,9 +485,7 @@
     // forcing the creation of a new image.
     if ((error = glGetError()) != GL_NO_ERROR) {
         glBindTexture(mTexTarget, mTexName);
-        status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay,
-                                                               mCurrentCrop,
-                                                               true);
+        status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
         if (result != NO_ERROR) {
             GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
                     mEglDisplay, mCurrentTexture);
@@ -769,8 +741,7 @@
         GLC_LOGD("computeCurrentTransformMatrixLocked: "
                 "mCurrentTextureImage is NULL");
     }
-    computeTransformMatrix(mCurrentTransformMatrix, buf,
-        isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
+    computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
         mCurrentTransform, mFilteringEnabled);
 }
 
@@ -1063,8 +1034,7 @@
 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
     mGraphicBuffer(graphicBuffer),
     mEglImage(EGL_NO_IMAGE_KHR),
-    mEglDisplay(EGL_NO_DISPLAY),
-    mCropRect(Rect::EMPTY_RECT) {
+    mEglDisplay(EGL_NO_DISPLAY) {
 }
 
 GLConsumer::EglImage::~EglImage() {
@@ -1077,13 +1047,11 @@
 }
 
 status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
-                                              const Rect& cropRect,
                                               bool forceCreation) {
     // If there's an image and it's no longer valid, destroy it.
     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
     bool displayInvalid = mEglDisplay != eglDisplay;
-    bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
-    if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
+    if (haveImage && (displayInvalid || forceCreation)) {
         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
         }
@@ -1095,14 +1063,12 @@
     // If there's no image, create one.
     if (mEglImage == EGL_NO_IMAGE_KHR) {
         mEglDisplay = eglDisplay;
-        mCropRect = cropRect;
-        mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
+        mEglImage = createImage(mEglDisplay, mGraphicBuffer);
     }
 
     // Fail if we can't create a valid image.
     if (mEglImage == EGL_NO_IMAGE_KHR) {
         mEglDisplay = EGL_NO_DISPLAY;
-        mCropRect.makeInvalid();
         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
             buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
@@ -1119,37 +1085,18 @@
 }
 
 EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
-        const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
+        const sp<GraphicBuffer>& graphicBuffer) {
     EGLClientBuffer cbuf =
             static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
     const bool createProtectedImage =
             (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) &&
             hasEglProtectedContent();
     EGLint attrs[] = {
-        EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
-        EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
-        EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
-        EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
-        EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
+        EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
         createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
         createProtectedImage ? EGL_TRUE : EGL_NONE,
         EGL_NONE,
     };
-    if (!crop.isValid()) {
-        // No crop rect to set, so leave the crop out of the attrib array. Make
-        // sure to propagate the protected content attrs if they are set.
-        attrs[2] = attrs[10];
-        attrs[3] = attrs[11];
-        attrs[4] = EGL_NONE;
-    } else if (!isEglImageCroppable(crop)) {
-        // The crop rect is not at the origin, so we can't set the crop on the
-        // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
-        // extension.  In the future we can add a layered extension that
-        // removes this restriction if there is hardware that can support it.
-        attrs[2] = attrs[10];
-        attrs[3] = attrs[11];
-        attrs[4] = EGL_NONE;
-    }
     eglInitialize(dpy, nullptr, nullptr);
     EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
             EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 71ed3bf..25f9d6b 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -140,7 +140,8 @@
 
     // Scale the crop down horizontally or vertically such that it has the
     // same aspect ratio as the buffer does.
-    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
+    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
+            uint32_t bufferHeight);
 
     // getTimestamp retrieves the timestamp associated with the texture image
     // set by the most recent call to updateTexImage.
@@ -305,7 +306,6 @@
         // createIfNeeded creates an EGLImage if required (we haven't created
         // one yet, or the EGLDisplay or crop-rect has changed).
         status_t createIfNeeded(EGLDisplay display,
-                                const Rect& cropRect,
                                 bool forceCreate = false);
 
         // This calls glEGLImageTargetTexture2DOES to bind the image to the
@@ -324,7 +324,7 @@
 
         // createImage creates a new EGLImage from a GraphicBuffer.
         EGLImageKHR createImage(EGLDisplay dpy,
-                const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+                const sp<GraphicBuffer>& graphicBuffer);
 
         // Disallow copying
         EglImage(const EglImage& rhs);
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index d5b2f00..d8c9bcf 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -29,7 +29,6 @@
 #include <utils/Thread.h>
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
 
 namespace android {
 
@@ -638,18 +637,6 @@
 }
 
 TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
-    // Query to see if the image crop extension exists
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(CROP_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(CROP_EXT_STR, exts);
-    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
-    bool atEnd = (cropExtLen+1) < extsLen &&
-            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
-    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
-    bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle;
-
     android_native_buffer_t* buf[3];
     float mtx[16] = {};
     android_native_rect_t crop;
@@ -669,17 +656,15 @@
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
     mST->getTransformMatrix(mtx);
 
-    // If the egl image crop extension is not present, this accounts for the
-    // .5 texel shrink for each edge that's included in the transform matrix
-    // to avoid texturing outside the crop region. Otherwise the crop is not
-    // included in the transform matrix.
-    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]);
+    // This accounts for the .5 texel shrink for each edge that's included in
+    // the transform matrix to avoid texturing outside the crop region.
+    EXPECT_EQ(0.5f, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]);
+    EXPECT_EQ(-0.5f, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -688,8 +673,8 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]);
-    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]);
+    EXPECT_EQ(0.0625f, mtx[12]);
+    EXPECT_EQ(0.5625f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
 }
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 44f4dbc..0fd91eb 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -1285,17 +1285,6 @@
 #define EGL_NATIVE_SURFACE_TIZEN          0x32A1
 #endif /* EGL_TIZEN_image_native_surface */
 
-/* This is a private Android extension that does not exist in the EGL registry,
- * formerly used to work around a hardware issue on Nexus 4. It is deprecated
- * and unimplemented. It has been added to this header manually. */
-#ifndef EGL_ANDROID_image_crop
-#define EGL_ANDROID_image_crop 1
-#define EGL_IMAGE_CROP_LEFT_ANDROID       0x3148
-#define EGL_IMAGE_CROP_TOP_ANDROID        0x3149
-#define EGL_IMAGE_CROP_RIGHT_ANDROID      0x314A
-#define EGL_IMAGE_CROP_BOTTOM_ANDROID     0x314B
-#endif
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 3312b03..f73967c 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -136,7 +136,6 @@
 //      "EGL_IMG_hibernate_process "            // optional
 //      "EGL_ANDROID_native_fence_sync "        // strongly recommended
 //      "EGL_ANDROID_framebuffer_target "       // mandatory for HWC 1.1
-//      "EGL_ANDROID_image_crop "               // optional
 
 /*
  * EGL Extensions entry-points exposed to 3rd party applications
diff --git a/opengl/specs/README b/opengl/specs/README
index fdafb1b..6d597d5 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -19,10 +19,7 @@
 0x3145               EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3146               EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3147               EGL_FRAMEBUFFER_TARGET_ANDROID (EGL_ANDROID_framebuffer_target)
-0x3148               EGL_IMAGE_CROP_LEFT_ANDROID (EGL_ANDROID_image_crop)
-0x3149               EGL_IMAGE_CROP_TOP_ANDROID (EGL_ANDROID_image_crop)
-0x314A               EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
-0x314B               EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
+0x3148 - 0x314B      previously used by the undocumented, deprecated extension EGL_ANDROID_image_crop
 0x314C               EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
 0x314D               EGL_GL_COLORSPACE_DEFAULT_EXT (EGL_EXT_image_gl_colorspace)
 0x314E - 0x314F      (unused)
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 87333d0..d231790 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -280,14 +280,6 @@
     return NO_ERROR;
 }
 
-bool BufferLayerConsumer::canUseImageCrop(const Rect& crop) const {
-    // If the crop rect is not at the origin, we can't set the crop on the
-    // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
-    // extension.  In the future we can add a layered extension that
-    // removes this restriction if there is hardware that can support it.
-    return mRE.supportsImageCrop() && crop.left == 0 && crop.top == 0;
-}
-
 status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
                                                      PendingRelease* pendingRelease) {
     status_t err = NO_ERROR;
@@ -365,8 +357,7 @@
         return NO_INIT;
     }
 
-    const Rect& imageCrop = canUseImageCrop(mCurrentCrop) ? mCurrentCrop : Rect::EMPTY_RECT;
-    status_t err = mCurrentTextureImage->createIfNeeded(imageCrop);
+    status_t err = mCurrentTextureImage->createIfNeeded();
     if (err != NO_ERROR) {
         BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
         mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
@@ -435,9 +426,8 @@
         BLC_LOGD("computeCurrentTransformMatrixLocked: "
                  "mCurrentTextureImage is nullptr");
     }
-    const Rect& cropRect = canUseImageCrop(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop;
-    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, cropRect, mCurrentTransform,
-                                       mFilteringEnabled);
+    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
+                                       mCurrentTransform, mFilteringEnabled);
 }
 
 nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -615,23 +605,12 @@
 
 BufferLayerConsumer::Image::~Image() = default;
 
-status_t BufferLayerConsumer::Image::createIfNeeded(const Rect& imageCrop) {
-    const int32_t cropWidth = imageCrop.width();
-    const int32_t cropHeight = imageCrop.height();
-    if (mCreated && mCropWidth == cropWidth && mCropHeight == cropHeight) {
-        return OK;
-    }
+status_t BufferLayerConsumer::Image::createIfNeeded() {
+    if (mCreated) return OK;
 
     mCreated = mImage->setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
-                                             mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED,
-                                             cropWidth, cropHeight);
-    if (mCreated) {
-        mCropWidth = cropWidth;
-        mCropHeight = cropHeight;
-    } else {
-        mCropWidth = 0;
-        mCropHeight = 0;
-
+                                             mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    if (!mCreated) {
         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
               buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index f81cdb1..943b8a8 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -228,9 +228,8 @@
         Image(const Image& rhs) = delete;
         Image& operator=(const Image& rhs) = delete;
 
-        // createIfNeeded creates an RE::Image if required (we haven't created
-        // one yet, or the crop-rect has changed).
-        status_t createIfNeeded(const Rect& imageCrop);
+        // createIfNeeded creates an RE::Image if we haven't created one yet.
+        status_t createIfNeeded();
 
         const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
         const native_handle* graphicBufferHandle() {
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index 0e4ad91..12bbae2 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -45,13 +45,12 @@
         mExpensiveDisplays.erase(displayId);
     }
 
-    const sp<V1_3::IPower> powerHal = getPowerHal();
-    if (powerHal == nullptr) {
-        return;
-    }
-
     const bool expectsExpensiveRendering = !mExpensiveDisplays.empty();
     if (mNotifiedExpensiveRendering != expectsExpensiveRendering) {
+        const sp<V1_3::IPower> powerHal = getPowerHal();
+        if (powerHal == nullptr) {
+            return;
+        }
         auto ret = powerHal->powerHintAsync_1_3(PowerHint::EXPENSIVE_RENDERING,
                                                 expectsExpensiveRendering);
         // If Power HAL 1.3 was available previously but now fails,
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index dc09a37..23480b4 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -99,10 +99,6 @@
     if (hasEGLExtension("EGL_KHR_wait_sync")) {
         mHasWaitSync = true;
     }
-
-    if (hasEGLExtension("EGL_ANDROID_image_crop")) {
-        mHasImageCrop = true;
-    }
     if (hasEGLExtension("EGL_EXT_protected_content")) {
         mHasProtectedContent = true;
     }
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index 0d8c10b..a6a5053 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -39,7 +39,6 @@
     bool mHasNativeFenceSync = false;
     bool mHasFenceSync = false;
     bool mHasWaitSync = false;
-    bool mHasImageCrop = false;
     bool mHasProtectedContent = false;
     bool mHasContextPriority = false;
 
@@ -66,7 +65,6 @@
     bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
     bool hasFenceSync() const { return mHasFenceSync; }
     bool hasWaitSync() const { return mHasWaitSync; }
-    bool hasImageCrop() const { return mHasImageCrop; }
     bool hasProtectedContent() const { return mHasProtectedContent; }
     bool hasContextPriority() const { return mHasContextPriority; }
 
diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/Image.cpp
index 0d06422..6e0a880 100644
--- a/services/surfaceflinger/RenderEngine/Image.cpp
+++ b/services/surfaceflinger/RenderEngine/Image.cpp
@@ -33,11 +33,10 @@
 Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
 
 Image::~Image() {
-    setNativeWindowBuffer(nullptr, false, 0, 0);
+    setNativeWindowBuffer(nullptr, false);
 }
 
-static std::vector<EGLint> buildAttributeList(bool isProtected, int32_t cropWidth,
-                                              int32_t cropHeight) {
+static std::vector<EGLint> buildAttributeList(bool isProtected) {
     std::vector<EGLint> attrs;
     attrs.reserve(16);
 
@@ -49,24 +48,12 @@
         attrs.push_back(EGL_TRUE);
     }
 
-    if (cropWidth > 0 && cropHeight > 0) {
-        attrs.push_back(EGL_IMAGE_CROP_LEFT_ANDROID);
-        attrs.push_back(0);
-        attrs.push_back(EGL_IMAGE_CROP_TOP_ANDROID);
-        attrs.push_back(0);
-        attrs.push_back(EGL_IMAGE_CROP_RIGHT_ANDROID);
-        attrs.push_back(cropWidth);
-        attrs.push_back(EGL_IMAGE_CROP_BOTTOM_ANDROID);
-        attrs.push_back(cropHeight);
-    }
-
     attrs.push_back(EGL_NONE);
 
     return attrs;
 }
 
-bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
-                                  int32_t cropHeight) {
+bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) {
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
         if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
             ALOGE("failed to destroy image: %#x", eglGetError());
@@ -75,7 +62,7 @@
     }
 
     if (buffer) {
-        std::vector<EGLint> attrs = buildAttributeList(isProtected, cropWidth, cropHeight);
+        std::vector<EGLint> attrs = buildAttributeList(isProtected);
         mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
                                       static_cast<EGLClientBuffer>(buffer), attrs.data());
         if (mEGLImage == EGL_NO_IMAGE_KHR) {
diff --git a/services/surfaceflinger/RenderEngine/Image.h b/services/surfaceflinger/RenderEngine/Image.h
index 1ae7e09..c38fe0a 100644
--- a/services/surfaceflinger/RenderEngine/Image.h
+++ b/services/surfaceflinger/RenderEngine/Image.h
@@ -29,8 +29,7 @@
 class Image {
 public:
     virtual ~Image() = 0;
-    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected,
-                                       int32_t cropWidth, int32_t cropHeight) = 0;
+    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0;
 };
 
 namespace impl {
@@ -45,8 +44,7 @@
     Image(const Image&) = delete;
     Image& operator=(const Image&) = delete;
 
-    bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
-                               int32_t cropHeight) override;
+    bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override;
 
 private:
     // methods internal to RenderEngine
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index d745770..0b8b838 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -175,10 +175,6 @@
     return mEGLConfig;
 }
 
-bool RenderEngine::supportsImageCrop() const {
-    return GLExtensions::getInstance().hasImageCrop();
-}
-
 bool RenderEngine::isCurrent() const {
     return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
 }
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 1786155..95b9ec8 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -69,8 +69,6 @@
     // dump the extension strings. always call the base class.
     virtual void dump(String8& result) = 0;
 
-    virtual bool supportsImageCrop() const = 0;
-
     virtual bool isCurrent() const = 0;
     virtual bool setCurrentSurface(const RE::Surface& surface) = 0;
     virtual void resetCurrentSurface() = 0;
@@ -192,8 +190,6 @@
     // dump the extension strings. always call the base class.
     void dump(String8& result) override;
 
-    bool supportsImageCrop() const override;
-
     bool isCurrent() const;
     bool setCurrentSurface(const RE::Surface& surface) override;
     void resetCurrentSurface() override;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 32dc4f6..e107f42 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -888,7 +888,7 @@
     static bool useVrFlinger;
     std::thread::id mMainThreadId;
 
-    DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::MANAGED;
+    DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED;
     // Applied on Display P3 layers when the render intent is non-colorimetric.
     mat4 mEnhancedSaturationMatrix;
 
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index ac08293..7caf864 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -37,7 +37,6 @@
     MOCK_METHOD0(createImage, std::unique_ptr<RE::Image>());
     MOCK_CONST_METHOD0(primeCache, void());
     MOCK_METHOD1(dump, void(String8&));
-    MOCK_CONST_METHOD0(supportsImageCrop, bool());
     MOCK_CONST_METHOD0(isCurrent, bool());
     MOCK_METHOD1(setCurrentSurface, bool(const RE::Surface&));
     MOCK_METHOD0(resetCurrentSurface, void());
@@ -98,9 +97,8 @@
     Image();
     ~Image() override;
 
-    MOCK_METHOD4(setNativeWindowBuffer,
-                 bool(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
-                      int32_t cropHeight));
+    MOCK_METHOD2(setNativeWindowBuffer,
+                 bool(ANativeWindowBuffer* buffer, bool isProtected));
 };
 
 } // namespace mock