Android R camera Hal Start

Keywords: Android

Preface

Previously, I was ready to write a bit of code following the camera APP calling API 1/2 interface. After writing a few articles locally, I found that it is not good to start writing the API calling process directly without finishing the initialization of camera server and hal. Let's start writing from the initialization of the service.

Code Flow Analysis

I'll follow the way I'm used to learning a new module.
Let's first see what the current camera hal is running through the ps command.

cameraserver    946      1  0 S android.hardware.camera.provider@2.4-service_64

Looking at the progress of the mobile phone, the current running camera Hal is android.hardware.camera.provider@2.4-service_64
Search through the code under this name and define it in hardware/interfaces/camera/provider/2.4/default/Android.bp.

cc_binary {
    name: "android.hardware.camera.provider@2.4-service_64",
    defaults: ["camera_service_defaults"],
    compile_multilib: "64",
    init_rc: ["android.hardware.camera.provider@2.4-service_64.rc"],
}

Android.hardware.camera is used.provider@2.4The -service_64.rc, RC file is not very analytic, just tells the init process where to go and how to start it.
Look at the contents of rc:

service vendor.camera-provider-2-4 /vendor/bin/hw/android.hardware.camera.provider@2.4-service_64
    interface android.hardware.camera.provider@2.4::ICameraProvider legacy/0
    class hal
    user cameraserver
    group audio camera input drmrpc
    ioprio rt 4
    capabilities SYS_NICE
    task_profiles CameraServiceCapacity HighPerformance

Defaults: ["camera_service_defaults"] Compile correlation

cc_defaults {
    name: "camera_service_defaults",
    defaults: ["hidl_defaults"],
    proprietary: true,
    relative_install_path: "hw",
    srcs: ["service.cpp"],
...

As you can see from srcs: ["service.cpp"], android.hardware.camera.provider@2.4-service_64 is mainly generated by compiling with this cpp. Check service.cpp again.

#ifdef LAZY_SERVICE
const bool kLazyService = true;
#else
const bool kLazyService = false;
#endif

int main()
{
    ALOGI("CameraProvider@2.4 legacy service is starting.");
    // The camera HAL may communicate to other vendor components via
    // /dev/vndbinder
    android::ProcessState::initWithDriver("/dev/vndbinder");
    status_t status;
    if (kLazyService) {
        status = defaultLazyPassthroughServiceImplementation<ICameraProvider>("legacy/0",
                                                                              /*maxThreads*/ 6);
    } else {
        status = defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0",
                                                                          /*maxThreads*/ 6);
    }
    return status;
}

LAZY_SERVICE's macro is not sure if it's defined, so go back and look at android.bp

cc_binary {
    name: "android.hardware.camera.provider@2.4-service-lazy",
    overrides: ["android.hardware.camera.provider@2.4-service"],
    defaults: ["camera_service_defaults"],
    compile_multilib: "32",
    init_rc: ["android.hardware.camera.provider@2.4-service-lazy.rc"],
    cflags: ["-DLAZY_SERVICE"],
}

cc_binary {
    name: "android.hardware.camera.provider@2.4-service-lazy_64",
    overrides: ["android.hardware.camera.provider@2.4-service_64"],
    defaults: ["camera_service_defaults"],
    compile_multilib: "64",
    init_rc: ["android.hardware.camera.provider@2.4-service-lazy_64.rc"],
    cflags: ["-DLAZY_SERVICE"],
}

Only the two places above that define LAZY_SERVICE were found, so kLazyService must be false here. Default Passthrough ServiceImplementation will eventually be called
This is registering the hidl service and calling into system/libhidl/transport/include/hidl/LegacySupport.h.

template <class Interface, class ExpectInterface = Interface>
__attribute__((warn_unused_result)) status_t defaultPassthroughServiceImplementation(
        const std::string& name, size_t maxThreads = 1) {
    configureRpcThreadpool(maxThreads, true);
    status_t result = registerPassthroughServiceImplementation<Interface, ExpectInterface>(name);

    if (result != OK) {
        return result;
    }

    joinRpcThreadpool();
    return UNKNOWN_ERROR;
}

Call registerPassthrough ServiceImplementation

template <class Interface, class ExpectInterface = Interface>
__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& name = "default") {
    return registerPassthroughServiceImplementation(Interface::descriptor,
                                                    ExpectInterface::descriptor, name);
}

Call registerPassthrough ServiceImplementation

__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& interfaceName, const std::string& expectInterfaceName,
        const std::string& serviceName) {
    return details::registerPassthroughServiceImplementation(
            interfaceName, expectInterfaceName,
            [](const sp<IBase>& service, const std::string& name) {
                return details::registerAsServiceInternal(service, name);
            },
            serviceName);
}

Call registerPassthrough ServiceImplementation

__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& interfaceName, const std::string& expectInterfaceName,
        RegisterServiceCb registerServiceCb, const std::string& serviceName) {
    sp<IBase> service =
            getRawServiceInternal(interfaceName, serviceName, true /*retry*/, true /*getStub*/);

    if (service == nullptr) {
        ALOGE("Could not get passthrough implementation for %s/%s.", interfaceName.c_str(),
             serviceName.c_str());
        return EXIT_FAILURE;
    }
    if (service->isRemote()) {
        ALOGE("Implementation of %s/%s is remote!", interfaceName.c_str(), serviceName.c_str());
        return EXIT_FAILURE;
    }

    std::string actualName;
    Return<void> result = service->interfaceDescriptor(
            [&actualName](const hidl_string& descriptor) { actualName = descriptor; });
    if (!result.isOk()) {
        ALOGE("Error retrieving interface name from %s/%s: %s", interfaceName.c_str(),
              serviceName.c_str(), result.description().c_str());
        return EXIT_FAILURE;
    }
    if (actualName != expectInterfaceName) {
         ALOGE("Implementation of %s/%s is actually %s, not a %s!", interfaceName.c_str(),
              serviceName.c_str(), actualName.c_str(), expectInterfaceName.c_str());
        return EXIT_FAILURE;
    }

    status_t status = registerServiceCb(service, serviceName);
    if (status == OK) {
        ALOGI("Registration complete for %s/%s.", interfaceName.c_str(), serviceName.c_str());
    } else {
        ALOGE("Could not register service %s/%s (%d).", interfaceName.c_str(), serviceName.c_str(),
              status);
    }

    return status;
}

Call getRawServiceInternal

sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
                                                             const std::string& instance,
                                                             bool retry, bool getStub) {
    using Transport = IServiceManager1_0::Transport;
    sp<Waiter> waiter;

    sp<IServiceManager1_1> sm;
    Transport transport = Transport::EMPTY;
    if (kIsRecovery) {
        transport = Transport::PASSTHROUGH;
    } else {
        sm = defaultServiceManager1_1();
        if (sm == nullptr) {
            ALOGE("getService: defaultServiceManager() is null");
            return nullptr;
        }

        Return<Transport> transportRet = sm->getTransport(descriptor, instance);

        if (!transportRet.isOk()) {
            ALOGE("getService: defaultServiceManager()->getTransport returns %s",
                  transportRet.description().c_str());
            return nullptr;
        }
        transport = transportRet;
    }

    const bool vintfHwbinder = (transport == Transport::HWBINDER);
    const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
    const bool trebleTestingOverride = isTrebleTestingOverride();
    const bool allowLegacy = !kEnforceVintfManifest || (trebleTestingOverride && kDebuggable);
    const bool vintfLegacy = (transport == Transport::EMPTY) && allowLegacy;

    if (!kEnforceVintfManifest) {
        ALOGE("getService: Potential race detected. The VINTF manifest is not being enforced. If "
              "a HAL server has a delay in starting and it is not in the manifest, it will not be "
              "retrieved. Please make sure all HALs on this device are in the VINTF manifest and "
              "enable PRODUCT_ENFORCE_VINTF_MANIFEST on this device (this is also enabled by "
              "PRODUCT_FULL_TREBLE). PRODUCT_ENFORCE_VINTF_MANIFEST will ensure that no race "
              "condition is possible here.");
        sleep(1);
    }

    for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
        if (waiter == nullptr && tries > 0) {
            waiter = new Waiter(descriptor, instance, sm);
        }
        if (waiter != nullptr) {
            waiter->reset();  // don't reorder this -- see comments on reset()
        }
        Return<sp<IBase>> ret = sm->get(descriptor, instance);
        if (!ret.isOk()) {
            ALOGE("getService: defaultServiceManager()->get returns %s for %s/%s.",
                  ret.description().c_str(), descriptor.c_str(), instance.c_str());
            break;
        }
        sp<IBase> base = ret;
        if (base != nullptr) {
            Return<bool> canCastRet =
                details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);

            if (canCastRet.isOk() && canCastRet) {
                if (waiter != nullptr) {
                    waiter->done();
                }
                return base; // still needs to be wrapped by Bp class.
            }

            if (!handleCastError(canCastRet, descriptor, instance)) break;
        }

        // In case of legacy or we were not asked to retry, don't.
        if (vintfLegacy || !retry) break;

        if (waiter != nullptr) {
            ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
            waiter->wait(true /* timeout */);
        }
    }

    if (waiter != nullptr) {
        waiter->done();
    }

    if (getStub || vintfPassthru || vintfLegacy) {
        const sp<IServiceManager1_0> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
            sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
            if (!getStub || trebleTestingOverride) {
                base = wrapPassthrough(base);
            }
            return base;
        }
    }

    return nullptr;
}

Because getStub is true, get of IServiceManager1_0 is called

Return<sp<IBase>> get(const hidl_string& fqName,
					  const hidl_string& name) override {
	sp<IBase> ret = nullptr;

	openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
		IBase* (*generator)(const char* name);
		*(void **)(&generator) = dlsym(handle, sym.c_str());
		if(!generator) {
			const char* error = dlerror();
			LOG(ERROR) << "Passthrough lookup opened " << lib
					   << " but could not find symbol " << sym << ": "
					   << (error == nullptr ? "unknown error" : error);
			dlclose(handle);
			return true;
		}

		ret = (*generator)(name.c_str());

		if (ret == nullptr) {
			dlclose(handle);
			return true; // this module doesn't provide this instance name
		}

		// Actual fqname might be a subclass.
		// This assumption is tested in vts_treble_vintf_test
		using ::android::hardware::details::getDescriptor;
		std::string actualFqName = getDescriptor(ret.get());
		CHECK(actualFqName.size() > 0);
		registerReference(actualFqName, name);
		return false;
	});

	return ret;
}

Implementation of openLibs:

static void openLibs(
	const std::string& fqName,
	const std::function<bool /* continue */ (void* /* handle */, const std::string& /* lib */,
											 const std::string& /* sym */)>& eachLib) {
	//fqName looks like android.hardware.foo@1.0::IFoo
	size_t idx = fqName.find("::");

	if (idx == std::string::npos ||
			idx + strlen("::") + 1 >= fqName.size()) {
		LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName;
		return;
	}

	std::string packageAndVersion = fqName.substr(0, idx);
	std::string ifaceName = fqName.substr(idx + strlen("::"));

	const std::string prefix = packageAndVersion + "-impl";
	const std::string sym = "HIDL_FETCH_" + ifaceName;

	constexpr int dlMode = RTLD_LAZY;
	void* handle = nullptr;

	dlerror(); // clear

	static std::string halLibPathVndkSp = android::base::StringPrintf(
		HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION, details::getVndkVersionStr().c_str());
	std::vector<std::string> paths = {
		HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, halLibPathVndkSp,
#ifndef __ANDROID_VNDK__
		HAL_LIBRARY_PATH_SYSTEM,
#endif
	};

#ifdef LIBHIDL_TARGET_DEBUGGABLE
	const char* env = std::getenv("TREBLE_TESTING_OVERRIDE");
	const bool trebleTestingOverride = env && !strcmp(env, "true");
	if (trebleTestingOverride) {
		// Load HAL implementations that are statically linked
		handle = dlopen(nullptr, dlMode);
		if (handle == nullptr) {
			const char* error = dlerror();
			LOG(ERROR) << "Failed to dlopen self: "
					   << (error == nullptr ? "unknown error" : error);
		} else if (!eachLib(handle, "SELF", sym)) {
			return;
		}
	}
#endif

	for (const std::string& path : paths) {
		std::vector<std::string> libs = findFiles(path, prefix, ".so");

		for (const std::string &lib : libs) {
			const std::string fullPath = path + lib;

			if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
				handle = dlopen(fullPath.c_str(), dlMode);
			} else {
#if !defined(__ANDROID_RECOVERY__) && defined(__ANDROID__)
				handle = android_load_sphal_library(fullPath.c_str(), dlMode);
#endif
			}

			if (handle == nullptr) {
				const char* error = dlerror();
				LOG(ERROR) << "Failed to dlopen " << lib << ": "
						   << (error == nullptr ? "unknown error" : error);
				continue;
			}

			if (!eachLib(handle, lib, sym)) {
				return;
			}
		}
	}
}

The purpose of openLibs is to find so with-impl in these directories, and find the following paths:

#define HAL_LIBRARY_PATH_SYSTEM_64BIT "/system/lib64/hw/"
#define HAL_LIBRARY_PATH_VNDK_SP_64BIT_FOR_VERSION "/apex/com.android.vndk.v%s/lib64/hw/"
#define HAL_LIBRARY_PATH_VENDOR_64BIT "/vendor/lib64/hw/"
#define HAL_LIBRARY_PATH_ODM_64BIT    "/odm/lib64/hw/"
#define HAL_LIBRARY_PATH_SYSTEM_32BIT "/system/lib/hw/"
#define HAL_LIBRARY_PATH_VNDK_SP_32BIT_FOR_VERSION "/apex/com.android.vndk.v%s/lib/hw/"
#define HAL_LIBRARY_PATH_VENDOR_32BIT "/vendor/lib/hw/"
#define HAL_LIBRARY_PATH_ODM_32BIT    "/odm/lib/hw/"

#if defined(__LP64__)
#define HAL_LIBRARY_PATH_SYSTEM HAL_LIBRARY_PATH_SYSTEM_64BIT
#define HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION HAL_LIBRARY_PATH_VNDK_SP_64BIT_FOR_VERSION
#define HAL_LIBRARY_PATH_VENDOR HAL_LIBRARY_PATH_VENDOR_64BIT
#define HAL_LIBRARY_PATH_ODM    HAL_LIBRARY_PATH_ODM_64BIT
#else
#define HAL_LIBRARY_PATH_SYSTEM HAL_LIBRARY_PATH_SYSTEM_32BIT
#define HAL_LIBRARY_PATH_VNDK_SP_FOR_VERSION HAL_LIBRARY_PATH_VNDK_SP_32BIT_FOR_VERSION
#define HAL_LIBRARY_PATH_VENDOR HAL_LIBRARY_PATH_VENDOR_32BIT
#define HAL_LIBRARY_PATH_ODM    HAL_LIBRARY_PATH_ODM_32BIT
#endif

Finally, android.hardware.camera is found in the / vendor/lib64/hw directory.provider@2.4-impl.so, then open him through dlopen and HIDL_FETCH_ICameraProvider through dlsym.
Take a look at android.hardware.camera.provider@2.4-impl.so's bp file:

cc_library_shared {
    name: "android.hardware.camera.provider@2.4-impl",
    defaults: ["hidl_defaults"],
    proprietary: true,
    relative_install_path: "hw",
    srcs: ["CameraProvider_2_4.cpp"],
...

Relative_install_path:'hw'determines android.hardware.camera.provider@2.4The path where -impl.so stores, compiles so mainly for CameraProvider_2_4.cpp, in which you can see the HIDL_FETCH_ICameraProvider function above.

ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {
    using namespace android::hardware::camera::provider::V2_4::implementation;
    ICameraProvider* provider = nullptr;
    if (strcmp(name, kLegacyProviderName) == 0) {
        provider = getProviderImpl<LegacyCameraProviderImpl_2_4>();
    } else if (strcmp(name, kExternalProviderName) == 0) {
        provider = getProviderImpl<ExternalCameraProviderImpl_2_4>();
    } else {
        ALOGE("%s: unknown instance name: %s", __FUNCTION__, name);
    }

    return provider;
}

Because const char *kLegacyProviderName = "legacy/0";So go provider = getProviderImpl <LegacyCameraProviderImpl_2_4>();This branch, let's look at the implementation of getProviderImpl:

template<typename IMPL>
CameraProvider<IMPL>* getProviderImpl() {
    CameraProvider<IMPL> *provider = new CameraProvider<IMPL>();
    if (provider == nullptr) {
        ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);
        return nullptr;
    }
    if (provider->isInitFailed()) {
        ALOGE("%s: camera provider init failed!", __FUNCTION__);
        delete provider;
        return nullptr;
    }
    return provider;
}

So the end result is a CameraProvider object. Don't go any further until this point, but look back where you started registering the hidl service. The registerPassthrough ServiceImplementation function gets the CameraProvider object.
In registerPassthrough ServiceImplementation, after you get the CameraProvider, compile the generated file based on hidl and call interfaceDescriptor to get the descriptor.
out/soong/.intermediates/hardware/interfaces/camera/provider/2.4/android.hardware.camera.provider@2.4_genc++/gen/android/hardware/camera/provider/2.4/CameraProviderAll.cpp

 const char* ICameraProvider::descriptor("android.hardware.camera.provider@2.4::ICameraProvider");
 
::android::hardware::Return<void> ICameraProvider::interfaceDescriptor(interfaceDescriptor_cb _hidl_cb){
    _hidl_cb(::android::hardware::camera::provider::V2_4::ICameraProvider::descriptor);
    return ::android::hardware::Void();
}

Then compare the descriptor with ICameraProvider::descriptor of defaultPassthrough ServiceImplementation, which is just a check. Then call registerServiceCb, which is actually a lambda expression in registerPassthrough ServiceImplementation:

[](const sp<IBase>& service, const std::string& name) {
               return details::registerAsServiceInternal(service, name);
           },

So it still depends on the implementation of registerAsServiceInternal:

status_t registerAsServiceInternal(const sp<IBase>& service, const std::string& name) {
    if (service == nullptr) {
        return UNEXPECTED_NULL;
    }

    sp<IServiceManager1_2> sm = defaultServiceManager1_2();
    if (sm == nullptr) {
        return INVALID_OPERATION;
    }

    const std::string descriptor = getDescriptor(service.get());

    if (kEnforceVintfManifest && !isTrebleTestingOverride()) {
        using Transport = IServiceManager1_0::Transport;
        Transport transport = sm->getTransport(descriptor, name);

        if (transport != Transport::HWBINDER) {
            LOG(ERROR) << "Service " << descriptor << "/" << name
                       << " must be in VINTF manifest in order to register/get.";
            return UNKNOWN_ERROR;
        }
    }

    bool registered = false;
    Return<void> ret = service->interfaceChain([&](const auto& chain) {
        registered = sm->addWithChain(name.c_str(), service, chain).withDefault(false);
    });

    if (!ret.isOk()) {
        LOG(ERROR) << "Could not retrieve interface chain: " << ret.description();
    }

    if (registered) {
        onRegistrationImpl(descriptor, name);
    }

    return registered ? OK : UNKNOWN_ERROR;
}

There's nothing to say here. The rest is to complete the registration. It has nothing to do with camera itself.

summary

This is actually just about the main function of the camera provider. It was originally intended to be finished, but the longer it was written, the longer it would be.. So let's write it separately, and eventually it will be written until the camera Hal initialization on the Qualcomm platform ends.

Posted by daimoore on Wed, 29 Sep 2021 09:56:03 -0700