Camera: Update camera service to use new HIDL HALs, part 1

- Add CameraProviderManager
  - Enumerates individual camera provider HAL instances, as well
    as the devices they provide
  - Handles dynamic provider and device appearance/disappearance
  - Maps device names to public API namespace
  - Add unit tests for CameraProviderManager
- Add logic to enable new HIDL path
- Switch various bits of service internals to use string camera IDs,
  though leaving most camera1-facing bits using int IDs, since that's
  what the old API uses.
- Update CameraService to use CameraProviderManager instead of
  the legacy camera HAL
- Update clients to pass through provider manager to devices instead
  of just camera module
- Still TODO:
  - Update Camera3Device to use new HIDL interface
  - Update CameraHardwareInterface to use new HIDL interface
  - Update dump()
  - Update vendor tag handling

Test: New unit tests pass, camera CTS passes with Treble disabled
Bug: 30985004
Bug: 32991422
Change-Id: I7ac41f13b9501d5e53256e28c0465ec70aa3980e
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 7e26153..93a584b 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -47,7 +47,7 @@
         const sp<CameraService>& cameraService,
         const sp<TCamCallbacks>& remoteCallback,
         const String16& clientPackageName,
-        int cameraId,
+        const String8& cameraId,
         int cameraFacing,
         int clientPid,
         uid_t clientUid,
@@ -55,10 +55,10 @@
         TClientBase(cameraService, remoteCallback, clientPackageName,
                 cameraId, cameraFacing, clientPid, clientUid, servicePid),
         mSharedCameraCallbacks(remoteCallback),
-        mDeviceVersion(cameraService->getDeviceVersion(cameraId)),
+        mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),
         mDeviceActive(false)
 {
-    ALOGI("Camera %d: Opened. Client: %s (PID %d, UID %d)", cameraId,
+    ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),
             String8(clientPackageName).string(), clientPid, clientUid);
 
     mInitialClientPid = clientPid;
@@ -80,9 +80,20 @@
 
 template <typename TClientBase>
 status_t Camera2ClientBase<TClientBase>::initialize(CameraModule *module) {
+    return initializeImpl(module);
+}
+
+template <typename TClientBase>
+status_t Camera2ClientBase<TClientBase>::initialize(sp<CameraProviderManager> manager) {
+    return initializeImpl(manager);
+}
+
+template <typename TClientBase>
+template <typename TProviderPtr>
+status_t Camera2ClientBase<TClientBase>::initializeImpl(TProviderPtr providerPtr) {
     ATRACE_CALL();
-    ALOGV("%s: Initializing client for camera %d", __FUNCTION__,
-          TClientBase::mCameraId);
+    ALOGV("%s: Initializing client for camera %s", __FUNCTION__,
+          TClientBase::mCameraIdStr.string());
     status_t res;
 
     // Verify ops permissions
@@ -92,15 +103,15 @@
     }
 
     if (mDevice == NULL) {
-        ALOGE("%s: Camera %d: No device connected",
-                __FUNCTION__, TClientBase::mCameraId);
+        ALOGE("%s: Camera %s: No device connected",
+                __FUNCTION__, TClientBase::mCameraIdStr.string());
         return NO_INIT;
     }
 
-    res = mDevice->initialize(module);
+    res = mDevice->initialize(providerPtr);
     if (res != OK) {
-        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
-                __FUNCTION__, TClientBase::mCameraId, strerror(-res), res);
+        ALOGE("%s: Camera %s: unable to initialize device: %s (%d)",
+                __FUNCTION__, TClientBase::mCameraIdStr.string(), strerror(-res), res);
         return res;
     }
 
@@ -118,8 +129,8 @@
 
     disconnect();
 
-    ALOGI("Closed Camera %d. Client was: %s (PID %d, UID %u)",
-            TClientBase::mCameraId,
+    ALOGI("Closed Camera %s. Client was: %s (PID %d, UID %u)",
+            TClientBase::mCameraIdStr.string(),
             String8(TClientBase::mClientPackageName).string(),
             mInitialClientPid, TClientBase::mClientUid);
 }
@@ -128,8 +139,8 @@
 status_t Camera2ClientBase<TClientBase>::dumpClient(int fd,
                                               const Vector<String16>& args) {
     String8 result;
-    result.appendFormat("Camera2ClientBase[%d] (%p) PID: %d, dump:\n",
-            TClientBase::mCameraId,
+    result.appendFormat("Camera2ClientBase[%s] (%p) PID: %d, dump:\n",
+            TClientBase::mCameraIdStr.string(),
             (TClientBase::getRemoteCallback() != NULL ?
                     IInterface::asBinder(TClientBase::getRemoteCallback()).get() : NULL),
             TClientBase::mClientPid);
@@ -180,13 +191,13 @@
     if (callingPid != TClientBase::mClientPid &&
         callingPid != TClientBase::mServicePid) return res;
 
-    ALOGV("Camera %d: Shutting down", TClientBase::mCameraId);
+    ALOGV("Camera %s: Shutting down", TClientBase::mCameraIdStr.string());
 
     detachDevice();
 
     CameraService::BasicClient::disconnect();
 
-    ALOGV("Camera %d: Shut down complete complete", TClientBase::mCameraId);
+    ALOGV("Camera %s: Shut down complete complete", TClientBase::mCameraIdStr.string());
 
     return res;
 }
@@ -198,7 +209,7 @@
 
     mDevice.clear();
 
-    ALOGV("Camera %d: Detach complete", TClientBase::mCameraId);
+    ALOGV("Camera %s: Detach complete", TClientBase::mCameraIdStr.string());
 }
 
 template <typename TClientBase>
@@ -211,10 +222,10 @@
     if (TClientBase::mClientPid != 0 &&
         getCallingPid() != TClientBase::mClientPid) {
 
-        ALOGE("%s: Camera %d: Connection attempt from pid %d; "
+        ALOGE("%s: Camera %s: Connection attempt from pid %d; "
                 "current locked to pid %d",
                 __FUNCTION__,
-                TClientBase::mCameraId,
+                TClientBase::mCameraIdStr.string(),
                 getCallingPid(),
                 TClientBase::mClientPid);
         return BAD_VALUE;
@@ -242,8 +253,7 @@
 void Camera2ClientBase<TClientBase>::notifyIdle() {
     if (mDeviceActive) {
         getCameraService()->updateProxyDeviceState(
-            ICameraServiceProxy::CAMERA_STATE_IDLE,
-            String8::format("%d", TClientBase::mCameraId));
+            ICameraServiceProxy::CAMERA_STATE_IDLE, TClientBase::mCameraIdStr);
     }
     mDeviceActive = false;
 
@@ -258,8 +268,7 @@
 
     if (!mDeviceActive) {
         getCameraService()->updateProxyDeviceState(
-            ICameraServiceProxy::CAMERA_STATE_ACTIVE,
-            String8::format("%d", TClientBase::mCameraId));
+            ICameraServiceProxy::CAMERA_STATE_ACTIVE, TClientBase::mCameraIdStr);
     }
     mDeviceActive = true;
 
@@ -322,7 +331,7 @@
 
 template <typename TClientBase>
 int Camera2ClientBase<TClientBase>::getCameraId() const {
-    return TClientBase::mCameraId;
+    return std::stoi(TClientBase::mCameraIdStr.string());
 }
 
 template <typename TClientBase>
@@ -337,7 +346,7 @@
 
 template <typename TClientBase>
 const sp<CameraService>& Camera2ClientBase<TClientBase>::getCameraService() {
-    return TClientBase::mCameraService;
+    return TClientBase::sCameraService;
 }
 
 template <typename TClientBase>
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 9fd0a78..a4c08ef 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -49,7 +49,7 @@
     Camera2ClientBase(const sp<CameraService>& cameraService,
                       const sp<TCamCallbacks>& remoteCallback,
                       const String16& clientPackageName,
-                      int cameraId,
+                      const String8& cameraId,
                       int cameraFacing,
                       int clientPid,
                       uid_t clientUid,
@@ -57,6 +57,7 @@
     virtual ~Camera2ClientBase();
 
     virtual status_t      initialize(CameraModule *module);
+    virtual status_t      initialize(sp<CameraProviderManager> manager);
     virtual status_t      dumpClient(int fd, const Vector<String16>& args);
 
     /**
@@ -140,6 +141,10 @@
     virtual void          detachDevice();
 
     bool                  mDeviceActive;
+
+private:
+    template<typename TProviderPtr>
+    status_t              initializeImpl(TProviderPtr providerPtr);
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index f30afe3..c4402f2 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -35,6 +35,8 @@
 
 namespace android {
 
+class CameraProviderManager;
+
 /**
  * Base interface for version >= 2 camera device classes, which interface to
  * camera HAL device versions >= 2.
@@ -49,6 +51,7 @@
     virtual int      getId() const = 0;
 
     virtual status_t initialize(CameraModule *module) = 0;
+    virtual status_t initialize(sp<CameraProviderManager> manager) = 0;
     virtual status_t disconnect() = 0;
 
     virtual status_t dump(int fd, const Vector<String16> &args) = 0;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
new file mode 100644
index 0000000..8b08f2d
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -0,0 +1,929 @@
+/*
+ * Copyright (C) 2016 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 "CameraProviderManager"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include "CameraProviderManager.h"
+
+#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+
+namespace android {
+
+using namespace ::android::hardware::camera;
+using namespace ::android::hardware::camera::common::V1_0;
+
+namespace {
+// Hardcoded name for the passthrough HAL implementation, since it can't be discovered via the
+// service manager
+const std::string kLegacyProviderName("legacy/0");
+
+// Slash-separated list of provider types to consider for use via the old camera API
+const std::string kStandardProviderTypes("internal/legacy");
+
+} // anonymous namespace
+
+CameraProviderManager::HardwareServiceInteractionProxy
+CameraProviderManager::sHardwareServiceInteractionProxy{};
+
+CameraProviderManager::~CameraProviderManager() {
+}
+
+status_t CameraProviderManager::initialize(wp<CameraProviderManager::StatusListener> listener,
+        ServiceInteractionProxy* proxy) {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    if (proxy == nullptr) {
+        ALOGE("%s: No valid service interaction proxy provided", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    mListener = listener;
+    mServiceProxy = proxy;
+
+    // Registering will trigger notifications for all already-known providers
+    bool success = mServiceProxy->registerForNotifications(
+        /* instance name, empty means no filter */ "",
+        this);
+    if (!success) {
+        ALOGE("%s: Unable to register with hardware service manager for notifications "
+                "about camera providers", __FUNCTION__);
+        return INVALID_OPERATION;
+    }
+
+    // Also see if there's a passthrough HAL, but let's not complain if there's not
+    addProvider(kLegacyProviderName, /*expected*/ false);
+
+    return OK;
+}
+
+int CameraProviderManager::getCameraCount() const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    int count = 0;
+    for (auto& provider : mProviders) {
+        count += provider->mDevices.size();
+    }
+    return count;
+}
+
+int CameraProviderManager::getStandardCameraCount() const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    int count = 0;
+    for (auto& provider : mProviders) {
+        if (kStandardProviderTypes.find(provider->getType()) != std::string::npos) {
+            count += provider->mDevices.size();
+        }
+    }
+    return count;
+}
+
+std::vector<std::string> CameraProviderManager::getCameraDeviceIds() const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    std::vector<std::string> deviceIds;
+    for (auto& provider : mProviders) {
+        for (auto& deviceInfo : provider->mDevices) {
+            deviceIds.push_back(deviceInfo->mId);
+        }
+    }
+    return deviceIds;
+}
+
+bool CameraProviderManager::isValidDevice(const std::string &id, uint16_t majorVersion) const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+    return isValidDeviceLocked(id, majorVersion);
+}
+
+bool CameraProviderManager::isValidDeviceLocked(const std::string &id, uint16_t majorVersion) const {
+    for (auto& provider : mProviders) {
+        for (auto& deviceInfo : provider->mDevices) {
+            if (deviceInfo->mId == id && deviceInfo->mVersion.get_major() == majorVersion) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool CameraProviderManager::hasFlashUnit(const std::string &id) const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id);
+    if (deviceInfo == nullptr) return false;
+
+    return deviceInfo->hasFlashUnit();
+}
+
+status_t CameraProviderManager::getResourceCost(const std::string &id,
+        CameraResourceCost* cost) const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id);
+    if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+    *cost = deviceInfo->mResourceCost;
+    return OK;
+}
+
+status_t CameraProviderManager::getCameraInfo(const std::string &id,
+        hardware::CameraInfo* info) const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id);
+    if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+    return deviceInfo->getCameraInfo(info);
+}
+
+status_t CameraProviderManager::getCameraCharacteristics(const std::string &id,
+        CameraMetadata* characteristics) const {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ hardware::hidl_version{3,0});
+    if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+    return deviceInfo->getCameraCharacteristics(characteristics);
+}
+
+status_t CameraProviderManager::getHighestSupportedVersion(const std::string &id,
+        hardware::hidl_version *v) {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    hardware::hidl_version maxVersion{0,0};
+    bool found = false;
+    for (auto& provider : mProviders) {
+        for (auto& deviceInfo : provider->mDevices) {
+            if (deviceInfo->mId == id) {
+                if (deviceInfo->mVersion > maxVersion) {
+                    maxVersion = deviceInfo->mVersion;
+                    found = true;
+                }
+            }
+        }
+    }
+    if (!found) {
+        return NAME_NOT_FOUND;
+    }
+    *v = maxVersion;
+    return OK;
+}
+
+
+status_t CameraProviderManager::setTorchMode(const std::string &id, bool enabled) {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    auto deviceInfo = findDeviceInfoLocked(id);
+    if (deviceInfo == nullptr) return NAME_NOT_FOUND;
+
+    return deviceInfo->setTorchMode(enabled);
+}
+
+hardware::Return<void> CameraProviderManager::onRegistration(
+        const hardware::hidl_string& /*fqName*/,
+        const hardware::hidl_string& name,
+        bool /*preexisting*/) {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    addProvider(name);
+    return hardware::Return<void>();
+}
+
+status_t CameraProviderManager::dump(int fd, const Vector<String16>& args) {
+    std::lock_guard<std::mutex> lock(mInterfaceMutex);
+
+    dprintf(fd, "Available camera providers and devices:\n");
+    for (auto& provider : mProviders) {
+        provider->dump(fd, args);
+    }
+    return OK;
+}
+
+CameraProviderManager::ProviderInfo::DeviceInfo* CameraProviderManager::findDeviceInfoLocked(
+        const std::string& id, hardware::hidl_version minVersion) const {
+    for (auto& provider : mProviders) {
+        for (auto& deviceInfo : provider->mDevices) {
+            if (deviceInfo->mId == id && minVersion <= deviceInfo->mVersion) {
+                return deviceInfo.get();
+            }
+        }
+    }
+    return nullptr;
+}
+
+
+status_t CameraProviderManager::addProvider(const std::string& newProvider, bool expected) {
+    for (const auto& providerInfo : mProviders) {
+        if (providerInfo->mProviderName == newProvider) {
+            ALOGW("%s: Camera provider HAL with name '%s' already registered", __FUNCTION__,
+                    newProvider.c_str());
+            return ALREADY_EXISTS;
+        }
+    }
+    sp<provider::V2_4::ICameraProvider> interface =
+            mServiceProxy->getService(newProvider);
+
+    if (interface == nullptr) {
+        if (expected) {
+            ALOGW("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,
+                    newProvider.c_str());
+            return BAD_VALUE;
+        } else {
+            // Not guaranteed to be found, so not an error if it wasn't
+            return OK;
+        }
+    }
+
+    sp<ProviderInfo> providerInfo =
+            new ProviderInfo(newProvider, interface, this);
+    status_t res = providerInfo->initialize();
+    if (res != OK) {
+        return res;
+    }
+
+    mProviders.push_back(providerInfo);
+
+    return OK;
+}
+
+status_t CameraProviderManager::removeProvider(const std::string& provider) {
+    for (auto it = mProviders.begin(); it != mProviders.end(); it++) {
+        if ((*it)->mProviderName == provider) {
+            mProviders.erase(it);
+            return OK;
+        }
+    }
+    ALOGW("%s: Camera provider HAL with name '%s' is not registered", __FUNCTION__,
+            provider.c_str());
+    return NAME_NOT_FOUND;
+}
+
+/**** Methods for ProviderInfo ****/
+
+
+CameraProviderManager::ProviderInfo::ProviderInfo(
+        const std::string &providerName,
+        sp<provider::V2_4::ICameraProvider>& interface,
+        CameraProviderManager *manager) :
+        mProviderName(providerName),
+        mInterface(interface),
+        mManager(manager) {
+    (void) mManager;
+}
+
+status_t CameraProviderManager::ProviderInfo::initialize() {
+    status_t res = parseProviderName(mProviderName, &mType, &mId);
+    if (res != OK) {
+        ALOGE("%s: Invalid provider name, ignoring", __FUNCTION__);
+        return BAD_VALUE;
+    }
+    ALOGI("Connecting to new camera provider: %s", mProviderName.c_str());
+    Status status = mInterface->setCallback(this);
+    if (status != Status::OK) {
+        ALOGE("%s: Unable to register callbacks with camera provider '%s'",
+                __FUNCTION__, mProviderName.c_str());
+        return mapToStatusT(status);
+    }
+    // TODO: Register for hw binder death notifications as well
+
+    // Get initial list of camera devices, if any
+    std::vector<std::string> devices;
+    mInterface->getCameraIdList([&status, &devices](
+            Status idStatus,
+            const hardware::hidl_vec<hardware::hidl_string>& cameraDeviceNames) {
+        status = idStatus;
+        if (status == Status::OK) {
+            for (size_t i = 0; i < cameraDeviceNames.size(); i++) {
+                devices.push_back(cameraDeviceNames[i]);
+            }
+        } });
+
+    if (status != Status::OK) {
+        ALOGE("%s: Unable to query for camera devices from provider '%s'",
+                __FUNCTION__, mProviderName.c_str());
+        return mapToStatusT(status);
+    }
+
+    for (auto& device : devices) {
+        status_t res = addDevice(device);
+        if (res != OK) {
+            ALOGE("%s: Unable to enumerate camera device '%s': %s (%d)",
+                    __FUNCTION__, device.c_str(), strerror(-res), res);
+        }
+    }
+
+    ALOGI("Camera provider %s ready with %zu camera devices",
+            mProviderName.c_str(), mDevices.size());
+
+    return OK;
+}
+
+const std::string& CameraProviderManager::ProviderInfo::getType() const {
+    return mType;
+}
+
+status_t CameraProviderManager::ProviderInfo::addDevice(const std::string& name,
+        CameraDeviceStatus initialStatus, /*out*/ std::string* parsedId) {
+
+    ALOGI("Enumerating new camera device: %s", name.c_str());
+
+    uint16_t major, minor;
+    std::string type, id;
+
+    status_t res = parseDeviceName(name, &major, &minor, &type, &id);
+    if (res != OK) {
+        return res;
+    }
+    if (type != mType) {
+        ALOGE("%s: Device type %s does not match provider type %s", __FUNCTION__,
+                type.c_str(), mType.c_str());
+        return BAD_VALUE;
+    }
+    if (mManager->isValidDeviceLocked(id, major)) {
+        ALOGE("%s: Device %s: ID %s is already in use for device major version %d", __FUNCTION__,
+                name.c_str(), id.c_str(), major);
+        return BAD_VALUE;
+    }
+
+    std::unique_ptr<DeviceInfo> deviceInfo;
+    switch (major) {
+        case 1:
+            deviceInfo = initializeDeviceInfo<DeviceInfo1>(name, id, minor);
+            break;
+        case 3:
+            deviceInfo = initializeDeviceInfo<DeviceInfo3>(name, id, minor);
+            break;
+        default:
+            ALOGE("%s: Device %s: Unknown HIDL device HAL major version %d:", __FUNCTION__,
+                    name.c_str(), major);
+            return BAD_VALUE;
+    }
+    if (deviceInfo == nullptr) return BAD_VALUE;
+    deviceInfo->mStatus = initialStatus;
+
+    mDevices.push_back(std::move(deviceInfo));
+
+    if (parsedId != nullptr) {
+        *parsedId = id;
+    }
+    return OK;
+}
+
+status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
+    dprintf(fd, "    %s: v%d.%d, %zu devices:\n", mProviderName.c_str(),
+            mInterface->version.get_major(), mInterface->version.get_minor(), mDevices.size());
+
+    for (auto& device : mDevices) {
+        dprintf(fd, "        %s: Resource cost: %d\n", device->mName.c_str(),
+                device->mResourceCost.resourceCost);
+        if (device->mResourceCost.conflictingDevices.size() > 0) {
+            dprintf(fd, "            Conflicting devices:\n");
+            for (size_t i = 0; i < device->mResourceCost.conflictingDevices.size(); i++) {
+                dprintf(fd, "              %s\n",
+                        device->mResourceCost.conflictingDevices[i].c_str());
+            }
+        }
+    }
+    return OK;
+}
+
+hardware::Return<void> CameraProviderManager::ProviderInfo::cameraDeviceStatusChange(
+        const hardware::hidl_string& cameraDeviceName,
+        CameraDeviceStatus newStatus) {
+    sp<StatusListener> listener;
+    std::string id;
+    {
+        std::lock_guard<std::mutex> lock(mManager->mInterfaceMutex);
+        bool known = false;
+        for (auto& deviceInfo : mDevices) {
+            if (deviceInfo->mName == cameraDeviceName) {
+                ALOGI("Camera device %s status is now %s, was %s", cameraDeviceName.c_str(),
+                        deviceStatusToString(newStatus), deviceStatusToString(deviceInfo->mStatus));
+                deviceInfo->mStatus = newStatus;
+                // TODO: Handle device removal (NOT_PRESENT)
+                id = deviceInfo->mId;
+                known = true;
+                break;
+            }
+        }
+        // Previously unseen device; status must not be NOT_PRESENT
+        if (!known) {
+            if (newStatus == CameraDeviceStatus::NOT_PRESENT) {
+                ALOGW("Camera provider %s says an unknown camera device %s is not present. Curious.",
+                    mProviderName.c_str(), cameraDeviceName.c_str());
+                return hardware::Void();
+            }
+            addDevice(cameraDeviceName, newStatus, &id);
+        }
+        listener = mManager->mListener.promote();
+    }
+    // Call without lock held to allow reentrancy into provider manager
+    if (listener != nullptr) {
+        listener->onDeviceStatusChanged(String8(id.c_str()), newStatus);
+    }
+    return hardware::Void();
+}
+
+hardware::Return<void> CameraProviderManager::ProviderInfo::torchModeStatusChange(
+        const hardware::hidl_string& cameraDeviceName,
+        TorchModeStatus newStatus) {
+    sp<StatusListener> listener;
+    std::string id;
+    {
+        std::lock_guard<std::mutex> lock(mManager->mInterfaceMutex);
+        bool known = false;
+        for (auto& deviceInfo : mDevices) {
+            if (deviceInfo->mName == cameraDeviceName) {
+                ALOGI("Camera device %s torch status is now %s", cameraDeviceName.c_str(),
+                        torchStatusToString(newStatus));
+                id = deviceInfo->mId;
+                known = true;
+                break;
+            }
+        }
+        if (!known) {
+            ALOGW("Camera provider %s says an unknown camera %s now has torch status %d. Curious.",
+                    mProviderName.c_str(), cameraDeviceName.c_str(), newStatus);
+            return hardware::Void();
+        }
+        listener = mManager->mListener.promote();
+    }
+    // Call without lock held to allow reentrancy into provider manager
+    if (listener != nullptr) {
+        listener->onTorchStatusChanged(String8(id.c_str()), newStatus);
+    }
+    return hardware::Void();
+}
+
+
+template<class DeviceInfoT>
+std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
+    CameraProviderManager::ProviderInfo::initializeDeviceInfo(
+        const std::string &name,
+        const std::string &id, uint16_t minorVersion) const {
+    Status status;
+
+    auto cameraInterface =
+            getDeviceInterface<typename DeviceInfoT::InterfaceT>(name);
+    if (cameraInterface == nullptr) return nullptr;
+
+    CameraResourceCost resourceCost;
+    cameraInterface->getResourceCost([&status, &resourceCost](
+        Status s, CameraResourceCost cost) {
+                status = s;
+                resourceCost = cost;
+            });
+    if (status != Status::OK) {
+        ALOGE("%s: Unable to obtain resource costs for camera device %s: %s", __FUNCTION__,
+                name.c_str(), statusToString(status));
+        return nullptr;
+    }
+    return std::unique_ptr<DeviceInfo>(
+        new DeviceInfoT(name, id, minorVersion, resourceCost, cameraInterface));
+}
+
+template<class InterfaceT>
+sp<InterfaceT>
+CameraProviderManager::ProviderInfo::getDeviceInterface(const std::string &name) const {
+    ALOGE("%s: Device %s: Unknown HIDL device HAL major version %d:", __FUNCTION__,
+            name.c_str(), InterfaceT::version.get_major());
+    return nullptr;
+}
+
+template<>
+sp<device::V1_0::ICameraDevice>
+CameraProviderManager::ProviderInfo::getDeviceInterface
+        <device::V1_0::ICameraDevice>(const std::string &name) const {
+    Status status;
+    sp<device::V1_0::ICameraDevice> cameraInterface;
+    mInterface->getCameraDeviceInterface_V1_x(name, [&status, &cameraInterface](
+        Status s, sp<device::V1_0::ICameraDevice> interface) {
+                status = s;
+                cameraInterface = interface;
+            });
+    if (status != Status::OK) {
+        ALOGE("%s: Unable to obtain interface for camera device %s: %s", __FUNCTION__,
+                name.c_str(), statusToString(status));
+        return nullptr;
+    }
+    return cameraInterface;
+}
+
+template<>
+sp<device::V3_2::ICameraDevice>
+CameraProviderManager::ProviderInfo::getDeviceInterface
+        <device::V3_2::ICameraDevice>(const std::string &name) const {
+    Status status;
+    sp<device::V3_2::ICameraDevice> cameraInterface;
+    mInterface->getCameraDeviceInterface_V3_x(name, [&status, &cameraInterface](
+        Status s, sp<device::V3_2::ICameraDevice> interface) {
+                status = s;
+                cameraInterface = interface;
+            });
+    if (status != Status::OK) {
+        ALOGE("%s: Unable to obtain interface for camera device %s: %s", __FUNCTION__,
+                name.c_str(), statusToString(status));
+        return nullptr;
+    }
+    return cameraInterface;
+}
+
+CameraProviderManager::ProviderInfo::DeviceInfo::~DeviceInfo() {}
+
+template<class InterfaceT>
+status_t CameraProviderManager::ProviderInfo::DeviceInfo::setTorchMode(InterfaceT& interface,
+        bool enabled) {
+    Status s = interface->setTorchMode(enabled ? TorchMode::ON : TorchMode::OFF);
+    return mapToStatusT(s);
+}
+
+CameraProviderManager::ProviderInfo::DeviceInfo1::DeviceInfo1(const std::string& name,
+        const std::string &id,
+        uint16_t minorVersion,
+        const CameraResourceCost& resourceCost,
+        sp<InterfaceT> interface) :
+        DeviceInfo(name, id, hardware::hidl_version{1, minorVersion}, resourceCost),
+        mInterface(interface) {
+    // Get default parameters and initialize flash unit availability
+    // Requires powering on the camera device
+    Status status = mInterface->open(nullptr);
+    if (status != Status::OK) {
+        ALOGE("%s: Unable to open camera device %s to check for a flash unit: %s (%d)", __FUNCTION__,
+                mId.c_str(), CameraProviderManager::statusToString(status), status);
+        return;
+    }
+    mInterface->getParameters([this](const hardware::hidl_string& parms) {
+                mDefaultParameters.unflatten(String8(parms.c_str()));
+            });
+
+    const char *flashMode =
+            mDefaultParameters.get(CameraParameters::KEY_SUPPORTED_FLASH_MODES);
+    if (flashMode && strstr(flashMode, CameraParameters::FLASH_MODE_TORCH)) {
+        mHasFlashUnit = true;
+    } else {
+        mHasFlashUnit = false;
+    }
+
+    mInterface->close();
+}
+
+CameraProviderManager::ProviderInfo::DeviceInfo1::~DeviceInfo1() {}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo1::setTorchMode(bool enabled) {
+    return DeviceInfo::setTorchMode(mInterface, enabled);
+}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo1::getCameraInfo(
+        hardware::CameraInfo *info) const {
+    if (info == nullptr) return BAD_VALUE;
+
+    Status status;
+    device::V1_0::CameraInfo cInfo;
+    mInterface->getCameraInfo([&status, &cInfo](Status s, device::V1_0::CameraInfo camInfo) {
+                status = s;
+                cInfo = camInfo;
+            });
+    if (status != Status::OK) {
+        return mapToStatusT(status);
+    }
+
+    switch(cInfo.facing) {
+        case device::V1_0::CameraFacing::BACK:
+            info->facing = hardware::CAMERA_FACING_BACK;
+            break;
+        case device::V1_0::CameraFacing::EXTERNAL:
+            // Map external to front for legacy API
+        case device::V1_0::CameraFacing::FRONT:
+            info->facing = hardware::CAMERA_FACING_FRONT;
+            break;
+        default:
+            ALOGW("%s: Unknown camera facing: %d", __FUNCTION__, cInfo.facing);
+            info->facing = hardware::CAMERA_FACING_BACK;
+    }
+    info->orientation = cInfo.orientation;
+
+    return OK;
+}
+
+CameraProviderManager::ProviderInfo::DeviceInfo3::DeviceInfo3(const std::string& name,
+        const std::string &id,
+        uint16_t minorVersion,
+        const CameraResourceCost& resourceCost,
+        sp<InterfaceT> interface) :
+        DeviceInfo(name, id, hardware::hidl_version{3, minorVersion}, resourceCost),
+        mInterface(interface) {
+    // Get camera characteristics and initialize flash unit availability
+    Status status;
+    mInterface->getCameraCharacteristics([&status, this](Status s,
+                    device::V3_2::CameraMetadata metadata) {
+                status = s;
+                if (s == Status::OK) {
+                    camera_metadata_t *buffer =
+                            reinterpret_cast<camera_metadata_t*>(metadata.data());
+                    mCameraCharacteristics = buffer;
+                }
+            });
+    if (status != Status::OK) {
+        ALOGE("%s: Unable to get camera characteristics for device %s: %s (%d)",
+                __FUNCTION__, mId.c_str(), CameraProviderManager::statusToString(status), status);
+        return;
+    }
+    camera_metadata_entry flashAvailable =
+            mCameraCharacteristics.find(ANDROID_FLASH_INFO_AVAILABLE);
+    if (flashAvailable.count == 1 &&
+            flashAvailable.data.u8[0] == ANDROID_FLASH_INFO_AVAILABLE_TRUE) {
+        mHasFlashUnit = true;
+    } else {
+        mHasFlashUnit = false;
+    }
+}
+
+CameraProviderManager::ProviderInfo::DeviceInfo3::~DeviceInfo3() {}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::setTorchMode(bool enabled) {
+    return DeviceInfo::setTorchMode(mInterface, enabled);
+}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraInfo(
+        hardware::CameraInfo *info) const {
+    if (info == nullptr) return BAD_VALUE;
+
+    camera_metadata_ro_entry facing =
+            mCameraCharacteristics.find(ANDROID_LENS_FACING);
+    if (facing.count == 1) {
+        switch (facing.data.u8[0]) {
+            case ANDROID_LENS_FACING_BACK:
+                info->facing = hardware::CAMERA_FACING_BACK;
+                break;
+            case ANDROID_LENS_FACING_EXTERNAL:
+                // Map external to front for legacy API
+            case ANDROID_LENS_FACING_FRONT:
+                info->facing = hardware::CAMERA_FACING_FRONT;
+                break;
+        }
+    } else {
+        ALOGE("%s: Unable to find android.lens.facing static metadata", __FUNCTION__);
+        return NAME_NOT_FOUND;
+    }
+
+    camera_metadata_ro_entry orientation =
+            mCameraCharacteristics.find(ANDROID_SENSOR_ORIENTATION);
+    if (orientation.count == 1) {
+        info->orientation = orientation.data.i32[0];
+    } else {
+        ALOGE("%s: Unable to find android.sensor.orientation static metadata", __FUNCTION__);
+        return NAME_NOT_FOUND;
+    }
+
+    return OK;
+}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::getCameraCharacteristics(
+        CameraMetadata *characteristics) const {
+    if (characteristics == nullptr) return BAD_VALUE;
+
+    *characteristics = mCameraCharacteristics;
+    return OK;
+}
+
+status_t CameraProviderManager::ProviderInfo::parseProviderName(const std::string& name,
+        std::string *type, uint32_t *id) {
+    // Format must be "<type>/<id>"
+#define ERROR_MSG_PREFIX "%s: Invalid provider name '%s'. "       \
+    "Should match '<type>/<id>' - "
+
+    if (!type || !id) return INVALID_OPERATION;
+
+    std::string::size_type slashIdx = name.find('/');
+    if (slashIdx == std::string::npos || slashIdx == name.size() - 1) {
+        ALOGE(ERROR_MSG_PREFIX
+                "does not have / separator between type and id",
+                __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+
+    std::string typeVal = name.substr(0, slashIdx);
+
+    char *endPtr;
+    errno = 0;
+    long idVal = strtol(name.c_str() + slashIdx + 1, &endPtr, 10);
+    if (errno != 0) {
+        ALOGE(ERROR_MSG_PREFIX
+                "cannot parse provider id as an integer: %s (%d)",
+                __FUNCTION__, name.c_str(), strerror(errno), errno);
+        return BAD_VALUE;
+    }
+    if (endPtr != name.c_str() + name.size()) {
+        ALOGE(ERROR_MSG_PREFIX
+                "provider id has unexpected length",
+                __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+    if (idVal < 0) {
+        ALOGE(ERROR_MSG_PREFIX
+                "id is negative: %ld",
+                __FUNCTION__, name.c_str(), idVal);
+        return BAD_VALUE;
+    }
+
+#undef ERROR_MSG_PREFIX
+
+    *type = typeVal;
+    *id = static_cast<uint32_t>(idVal);
+
+    return OK;
+}
+
+status_t CameraProviderManager::ProviderInfo::parseDeviceName(const std::string& name,
+        uint16_t *major, uint16_t *minor, std::string *type, std::string *id) {
+
+    // Format must be "device@<major>.<minor>/<type>/<id>"
+
+#define ERROR_MSG_PREFIX "%s: Invalid device name '%s'. " \
+    "Should match 'device@<major>.<minor>/<type>/<id>' - "
+
+    if (!major || !minor || !type || !id) return INVALID_OPERATION;
+
+    // Verify starting prefix
+    const char expectedPrefix[] = "device@";
+
+    if (name.find(expectedPrefix) != 0) {
+        ALOGE(ERROR_MSG_PREFIX
+                "does not start with '%s'",
+                __FUNCTION__, name.c_str(), expectedPrefix);
+        return BAD_VALUE;
+    }
+
+    // Extract major/minor versions
+    constexpr std::string::size_type atIdx = sizeof(expectedPrefix) - 2;
+    std::string::size_type dotIdx = name.find('.', atIdx);
+    if (dotIdx == std::string::npos) {
+        ALOGE(ERROR_MSG_PREFIX
+                "does not have @<major>. version section",
+                __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+    std::string::size_type typeSlashIdx = name.find('/', dotIdx);
+    if (typeSlashIdx == std::string::npos) {
+        ALOGE(ERROR_MSG_PREFIX
+                "does not have .<minor>/ version section",
+                __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+
+    char *endPtr;
+    errno = 0;
+    long majorVal = strtol(name.c_str() + atIdx + 1, &endPtr, 10);
+    if (errno != 0) {
+        ALOGE(ERROR_MSG_PREFIX
+                "cannot parse major version: %s (%d)",
+                __FUNCTION__, name.c_str(), strerror(errno), errno);
+        return BAD_VALUE;
+    }
+    if (endPtr != name.c_str() + dotIdx) {
+        ALOGE(ERROR_MSG_PREFIX
+                "major version has unexpected length",
+                __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+    long minorVal = strtol(name.c_str() + dotIdx + 1, &endPtr, 10);
+    if (errno != 0) {
+        ALOGE(ERROR_MSG_PREFIX
+                "cannot parse minor version: %s (%d)",
+                __FUNCTION__, name.c_str(), strerror(errno), errno);
+        return BAD_VALUE;
+    }
+    if (endPtr != name.c_str() + typeSlashIdx) {
+        ALOGE(ERROR_MSG_PREFIX
+                "minor version has unexpected length",
+                __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+    if (majorVal < 0 || majorVal > UINT16_MAX || minorVal < 0 || minorVal > UINT16_MAX) {
+        ALOGE(ERROR_MSG_PREFIX
+                "major/minor version is out of range of uint16_t: %ld.%ld",
+                __FUNCTION__, name.c_str(), majorVal, minorVal);
+        return BAD_VALUE;
+    }
+
+    // Extract type and id
+
+    std::string::size_type instanceSlashIdx = name.find('/', typeSlashIdx + 1);
+    if (instanceSlashIdx == std::string::npos) {
+        ALOGE(ERROR_MSG_PREFIX
+                "does not have /<type>/ component",
+                __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+    std::string typeVal = name.substr(typeSlashIdx + 1, instanceSlashIdx - typeSlashIdx - 1);
+
+    if (instanceSlashIdx == name.size() - 1) {
+        ALOGE(ERROR_MSG_PREFIX
+                "does not have an /<id> component",
+                __FUNCTION__, name.c_str());
+        return BAD_VALUE;
+    }
+    std::string idVal = name.substr(instanceSlashIdx + 1);
+
+#undef ERROR_MSG_PREFIX
+
+    *major = static_cast<uint16_t>(majorVal);
+    *minor = static_cast<uint16_t>(minorVal);
+    *type = typeVal;
+    *id = idVal;
+
+    return OK;
+}
+
+
+
+CameraProviderManager::ProviderInfo::~ProviderInfo() {
+    // Destruction of ProviderInfo is only supposed to happen when the respective
+    // CameraProvider interface dies, so do not unregister callbacks.
+
+}
+
+status_t CameraProviderManager::mapToStatusT(const Status& s)  {
+    switch(s) {
+        case Status::OK:
+            return OK;
+        case Status::ILLEGAL_ARGUMENT:
+            return BAD_VALUE;
+        case Status::CAMERA_IN_USE:
+            return -EBUSY;
+        case Status::MAX_CAMERAS_IN_USE:
+            return -EUSERS;
+        case Status::METHOD_NOT_SUPPORTED:
+            return UNKNOWN_TRANSACTION;
+        case Status::OPERATION_NOT_SUPPORTED:
+            return INVALID_OPERATION;
+        case Status::CAMERA_DISCONNECTED:
+            return DEAD_OBJECT;
+        case Status::INTERNAL_ERROR:
+            return INVALID_OPERATION;
+    }
+    ALOGW("Unexpected HAL status code %d", s);
+    return INVALID_OPERATION;
+}
+
+const char* CameraProviderManager::statusToString(const Status& s) {
+    switch(s) {
+        case Status::OK:
+            return "OK";
+        case Status::ILLEGAL_ARGUMENT:
+            return "ILLEGAL_ARGUMENT";
+        case Status::CAMERA_IN_USE:
+            return "CAMERA_IN_USE";
+        case Status::MAX_CAMERAS_IN_USE:
+            return "MAX_CAMERAS_IN_USE";
+        case Status::METHOD_NOT_SUPPORTED:
+            return "METHOD_NOT_SUPPORTED";
+        case Status::OPERATION_NOT_SUPPORTED:
+            return "OPERATION_NOT_SUPPORTED";
+        case Status::CAMERA_DISCONNECTED:
+            return "CAMERA_DISCONNECTED";
+        case Status::INTERNAL_ERROR:
+            return "INTERNAL_ERROR";
+    }
+    ALOGW("Unexpected HAL status code %d", s);
+    return "UNKNOWN_ERROR";
+}
+
+const char* CameraProviderManager::deviceStatusToString(const CameraDeviceStatus& s) {
+    switch(s) {
+        case CameraDeviceStatus::NOT_PRESENT:
+            return "NOT_PRESENT";
+        case CameraDeviceStatus::PRESENT:
+            return "PRESENT";
+        case CameraDeviceStatus::ENUMERATING:
+            return "ENUMERATING";
+    }
+    ALOGW("Unexpected HAL device status code %d", s);
+    return "UNKNOWN_STATUS";
+}
+
+const char* CameraProviderManager::torchStatusToString(const TorchModeStatus& s) {
+    switch(s) {
+        case TorchModeStatus::NOT_AVAILABLE:
+            return "NOT_AVAILABLE";
+        case TorchModeStatus::AVAILABLE_OFF:
+            return "AVAILABLE_OFF";
+        case TorchModeStatus::AVAILABLE_ON:
+            return "AVAILABLE_ON";
+    }
+    ALOGW("Unexpected HAL torch mode status code %d", s);
+    return "UNKNOWN_STATUS";
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
new file mode 100644
index 0000000..b095ad7
--- /dev/null
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2016 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 ANDROID_SERVERS_CAMERA_CAMERAPROVIDER_H
+#define ANDROID_SERVERS_CAMERA_CAMERAPROVIDER_H
+
+#include <vector>
+#include <string>
+#include <mutex>
+
+#include <camera/CameraParameters2.h>
+#include <camera/CameraMetadata.h>
+#include <camera/CameraBase.h>
+#include <utils/Errors.h>
+#include <android/hardware/camera/common/1.0/types.h>
+#include <android/hardware/camera/provider/2.4/ICameraProvider.h>
+//#include <android/hardware/camera/provider/2.4/ICameraProviderCallbacks.h>
+#include <android/hidl/manager/1.0/IServiceNotification.h>
+
+namespace android {
+
+/**
+ * A manager for all camera providers available on an Android device.
+ *
+ * Responsible for enumerating providers and the individual camera devices
+ * they export, both at startup and as providers and devices are added/removed.
+ *
+ * Provides methods for requesting information about individual devices and for
+ * opening them for active use.
+ *
+ */
+class CameraProviderManager : virtual public hidl::manager::V1_0::IServiceNotification {
+public:
+
+    ~CameraProviderManager();
+
+    // Tiny proxy for the static methods in a HIDL interface that communicate with the hardware
+    // service manager, to be replacable in unit tests with a fake.
+    struct ServiceInteractionProxy {
+        virtual bool registerForNotifications(
+                const std::string &serviceName,
+                const sp<hidl::manager::V1_0::IServiceNotification>
+                &notification) = 0;
+        virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
+                const std::string &serviceName) = 0;
+        virtual ~ServiceInteractionProxy() {}
+    };
+
+    // Standard use case - call into the normal generated static methods which invoke
+    // the real hardware service manager
+    struct HardwareServiceInteractionProxy : public ServiceInteractionProxy {
+        virtual bool registerForNotifications(
+                const std::string &serviceName,
+                const sp<hidl::manager::V1_0::IServiceNotification>
+                &notification) override {
+            return hardware::camera::provider::V2_4::ICameraProvider::registerForNotifications(
+                    serviceName, notification);
+        }
+        virtual sp<hardware::camera::provider::V2_4::ICameraProvider> getService(
+                const std::string &serviceName) override {
+            return hardware::camera::provider::V2_4::ICameraProvider::getService(serviceName);
+        }
+    };
+
+    /**
+     * Listener interface for device/torch status changes
+     */
+    struct StatusListener : virtual public RefBase {
+        ~StatusListener() {}
+
+        virtual void onDeviceStatusChanged(const String8 &cameraId,
+                hardware::camera::common::V1_0::CameraDeviceStatus newStatus) = 0;
+        virtual void onTorchStatusChanged(const String8 &cameraId,
+                hardware::camera::common::V1_0::TorchModeStatus newStatus) = 0;
+    };
+
+    /**
+     * Initialize the manager and give it a status listener; optionally accepts a service
+     * interaction proxy.
+     *
+     * The default proxy communicates via the hardware service manager; alternate proxies can be
+     * used for testing. The lifetime of the proxy must exceed the lifetime of the manager.
+     */
+    status_t initialize(wp<StatusListener> listener,
+            ServiceInteractionProxy *proxy = &sHardwareServiceInteractionProxy);
+
+    /**
+     * Retrieve the total number of available cameras. This value may change dynamically as cameras
+     * are added or removed.
+     */
+    int getCameraCount() const;
+
+    /**
+     * Retrieve the number of 'standard' cameras; these are internal and
+     * backwards-compatible. This is the set of cameras that will be
+     * accessible via the old camera API, with IDs in range of
+     * [0, getStandardCameraCount()-1]. This value is not expected to change dynamically.
+     */
+    int getStandardCameraCount() const;
+
+    std::vector<std::string> getCameraDeviceIds() const;
+
+    /**
+     * Return true if a device with a given ID and major version exists
+     */
+    bool isValidDevice(const std::string &id, uint16_t majorVersion) const;
+
+    /**
+     * Return true if a device with a given ID has a flash unit. Returns false
+     * for devices that are unknown.
+     */
+    bool hasFlashUnit(const std::string &id) const;
+
+    /**
+     * Return the resource cost of this camera device
+     */
+    status_t getResourceCost(const std::string &id,
+            hardware::camera::common::V1_0::CameraResourceCost* cost) const;
+
+    /**
+     * Return the old camera API camera info
+     */
+    status_t getCameraInfo(const std::string &id,
+            hardware::CameraInfo* info) const;
+
+    /**
+     * Return API2 camera characteristics - returns NAME_NOT_FOUND if a device ID does
+     * not have a v3 or newer HAL version.
+     */
+    status_t getCameraCharacteristics(const std::string &id,
+            CameraMetadata* characteristics) const;
+
+    /**
+     * Return the highest supported device interface version for this ID
+     */
+    status_t getHighestSupportedVersion(const std::string &id,
+            hardware::hidl_version *v);
+
+    /**
+     * Turn on or off the flashlight on a given camera device.
+     * May fail if the device is in active use, or if the device doesn't exist, etc.
+     */
+    status_t setTorchMode(const std::string &id, bool enabled);
+
+    /**
+     * IServiceNotification::onRegistration
+     * Invoked by the hardware service manager when a new camera provider is registered
+     */
+    virtual hardware::Return<void> onRegistration(const hardware::hidl_string& fqName,
+            const hardware::hidl_string& name,
+            bool preexisting) override;
+
+    /**
+     * Dump out information about available providers and devices
+     */
+    status_t dump(int fd, const Vector<String16>& args);
+
+private:
+    // All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
+    mutable std::mutex mInterfaceMutex;
+
+    wp<StatusListener> mListener;
+    ServiceInteractionProxy* mServiceProxy;
+
+    static HardwareServiceInteractionProxy sHardwareServiceInteractionProxy;
+
+    struct ProviderInfo : virtual public hardware::camera::provider::V2_4::ICameraProviderCallback {
+        const std::string mProviderName;
+        const sp<hardware::camera::provider::V2_4::ICameraProvider> mInterface;
+
+        ProviderInfo(const std::string &providerName,
+                sp<hardware::camera::provider::V2_4::ICameraProvider>& interface,
+                CameraProviderManager *manager);
+        ~ProviderInfo();
+
+        status_t initialize();
+
+        const std::string& getType() const;
+
+        status_t addDevice(const std::string& name,
+                hardware::camera::common::V1_0::CameraDeviceStatus initialStatus =
+                hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT,
+                /*out*/ std::string *parsedId = nullptr);
+
+        status_t dump(int fd, const Vector<String16>& args) const;
+
+        // ICameraProviderCallbacks interface - these lock the parent mInterfaceMutex
+        virtual hardware::Return<void> cameraDeviceStatusChange(
+                const hardware::hidl_string& cameraDeviceName,
+                hardware::camera::common::V1_0::CameraDeviceStatus newStatus) override;
+        virtual hardware::Return<void> torchModeStatusChange(
+                const hardware::hidl_string& cameraDeviceName,
+                hardware::camera::common::V1_0::TorchModeStatus newStatus) override;
+
+        // Basic device information, common to all camera devices
+        struct DeviceInfo {
+            const std::string mName;  // Full instance name
+            const std::string mId;    // ID section of full name
+            const hardware::hidl_version mVersion;
+
+            const hardware::camera::common::V1_0::CameraResourceCost mResourceCost;
+
+            hardware::camera::common::V1_0::CameraDeviceStatus mStatus;
+
+            bool hasFlashUnit() const { return mHasFlashUnit; }
+            virtual status_t setTorchMode(bool enabled) = 0;
+            virtual status_t getCameraInfo(hardware::CameraInfo *info) const = 0;
+            virtual status_t getCameraCharacteristics(CameraMetadata *characteristics) const {
+                (void) characteristics;
+                return INVALID_OPERATION;
+            }
+
+            DeviceInfo(const std::string& name, const std::string &id,
+                    const hardware::hidl_version& version,
+                    const hardware::camera::common::V1_0::CameraResourceCost& resourceCost) :
+                    mName(name), mId(id), mVersion(version), mResourceCost(resourceCost),
+                    mStatus(hardware::camera::common::V1_0::CameraDeviceStatus::PRESENT),
+                    mHasFlashUnit(false) {}
+            virtual ~DeviceInfo();
+        protected:
+            bool mHasFlashUnit;
+
+            template<class InterfaceT>
+            static status_t setTorchMode(InterfaceT& interface, bool enabled);
+        };
+        std::vector<std::unique_ptr<DeviceInfo>> mDevices;
+
+    private:
+        std::string mType;
+        uint32_t mId;
+
+        CameraProviderManager *mManager;
+
+        // HALv1-specific camera fields, including the actual device interface
+        struct DeviceInfo1 : public DeviceInfo {
+            typedef hardware::camera::device::V1_0::ICameraDevice InterfaceT;
+            const sp<InterfaceT> mInterface;
+
+            virtual status_t setTorchMode(bool enabled) override;
+            virtual status_t getCameraInfo(hardware::CameraInfo *info) const override;
+
+            DeviceInfo1(const std::string& name, const std::string &id,
+                    uint16_t minorVersion,
+                    const hardware::camera::common::V1_0::CameraResourceCost& resourceCost,
+                    sp<InterfaceT> interface);
+            virtual ~DeviceInfo1();
+        private:
+            CameraParameters2 mDefaultParameters;
+        };
+
+        // HALv3-specific camera fields, including the actual device interface
+        struct DeviceInfo3 : public DeviceInfo {
+            typedef hardware::camera::device::V3_2::ICameraDevice InterfaceT;
+            const sp<InterfaceT> mInterface;
+
+            virtual status_t setTorchMode(bool enabled) override;
+            virtual status_t getCameraInfo(hardware::CameraInfo *info) const override;
+            virtual status_t getCameraCharacteristics(
+                    CameraMetadata *characteristics) const override;
+
+            DeviceInfo3(const std::string& name, const std::string &id,
+                    uint16_t minorVersion,
+                    const hardware::camera::common::V1_0::CameraResourceCost& resourceCost,
+                    sp<InterfaceT> interface);
+            virtual ~DeviceInfo3();
+        private:
+            CameraMetadata mCameraCharacteristics;
+        };
+
+        // Templated method to instantiate the right kind of DeviceInfo and call the
+        // right CameraProvider getCameraDeviceInterface_* method.
+        template<class DeviceInfoT>
+        std::unique_ptr<DeviceInfo> initializeDeviceInfo(const std::string &name,
+                const std::string &id, uint16_t minorVersion) const;
+
+        // Helper for initializeDeviceInfo to use the right CameraProvider get method.
+        template<class InterfaceT>
+        sp<InterfaceT> getDeviceInterface(const std::string &name) const;
+
+        // Parse provider instance name for type and id
+        static status_t parseProviderName(const std::string& name,
+                std::string *type, uint32_t *id);
+
+        // Parse device instance name for device version, type, and id.
+        static status_t parseDeviceName(const std::string& name,
+                uint16_t *major, uint16_t *minor, std::string *type, std::string *id);
+    };
+
+    // Utility to find a DeviceInfo by ID; pointer is only valid while mInterfaceMutex is held
+    // and the calling code doesn't mutate the list of providers or their lists of devices.
+    ProviderInfo::DeviceInfo* findDeviceInfoLocked(const std::string& id,
+            hardware::hidl_version minVersion = hardware::hidl_version{0,0}) const;
+
+    status_t addProvider(const std::string& newProvider, bool expected = true);
+    status_t removeProvider(const std::string& provider);
+
+    bool isValidDeviceLocked(const std::string &id, uint16_t majorVersion) const;
+
+    std::vector<sp<ProviderInfo>> mProviders;
+
+    static status_t mapToStatusT(const hardware::camera::common::V1_0::Status& s);
+    static const char* statusToString(const hardware::camera::common::V1_0::Status&);
+    static const char* deviceStatusToString(
+        const hardware::camera::common::V1_0::CameraDeviceStatus&);
+    static const char* torchStatusToString(
+        const hardware::camera::common::V1_0::TorchModeStatus&);
+
+};
+
+} // namespace android
+
+#endif