universal7885: Move folders to subfolders

Change-Id: I109b02201607d12209180c7cf3356b4e2e3d7ce6
Signed-off-by: roynatech2544 <whiteshell2544@naver.com>
This commit is contained in:
roynatech2544 2022-03-31 21:58:33 +09:00
commit 8cc7aca046
No known key found for this signature in database
GPG key ID: 9675C32163D88D30
89 changed files with 0 additions and 0 deletions

View file

@ -0,0 +1,23 @@
//
// Copyright (C) 2021 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
cc_binary {
name: "android.hardware.light-service.samsung",
relative_install_path: "hw",
init_rc: ["android.hardware.light-service.samsung.rc"],
vintf_fragments: ["android.hardware.light-service.samsung.xml"],
local_include_dirs: ["include"],
srcs: [
"Lights.cpp",
"service.cpp",
],
shared_libs: [
"libbase",
"libbinder_ndk",
"android.hardware.light-V1-ndk_platform",
],
vendor: true,
}

View file

@ -0,0 +1,193 @@
/*
* Copyright (C) 2021 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "android.hardware.lights-service.samsung"
#include <android-base/stringprintf.h>
#include <fstream>
#include "Lights.h"
#define COLOR_MASK 0x00ffffff
#define MAX_INPUT_BRIGHTNESS 255
namespace aidl {
namespace android {
namespace hardware {
namespace light {
/*
* Write value to path and close file.
*/
template <typename T>
static void set(const std::string& path, const T& value) {
std::ofstream file(path);
file << value << std::endl;
}
template <typename T>
static T get(const std::string& path, const T& def) {
std::ifstream file(path);
T result;
file >> result;
return file.fail() ? def : result;
}
Lights::Lights() {
mLights.emplace(LightType::BACKLIGHT,
std::bind(&Lights::handleBacklight, this, std::placeholders::_1));
#ifdef BUTTON_BRIGHTNESS_NODE
mLights.emplace(LightType::BUTTONS,
std::bind(&Lights::handleButtons, this, std::placeholders::_1));
#endif /* BUTTON_BRIGHTNESS_NODE */
#ifdef LED_BLINK_NODE
mLights.emplace(LightType::BATTERY,
std::bind(&Lights::handleBattery, this, std::placeholders::_1));
mLights.emplace(LightType::NOTIFICATIONS,
std::bind(&Lights::handleNotifications, this, std::placeholders::_1));
mLights.emplace(LightType::ATTENTION,
std::bind(&Lights::handleAttention, this, std::placeholders::_1));
#endif /* LED_BLINK_NODE */
}
ndk::ScopedAStatus Lights::setLightState(int32_t id, const HwLightState& state) {
LightType type = static_cast<LightType>(id);
auto it = mLights.find(type);
if (it == mLights.end()) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
/*
* Lock global mutex until light state is updated.
*/
std::lock_guard<std::mutex> lock(mLock);
it->second(state);
return ndk::ScopedAStatus::ok();
}
void Lights::handleBacklight(const HwLightState& state) {
uint32_t max_brightness = get(PANEL_MAX_BRIGHTNESS_NODE, MAX_INPUT_BRIGHTNESS);
uint32_t brightness = rgbToBrightness(state);
if (max_brightness != MAX_INPUT_BRIGHTNESS) {
brightness = brightness * max_brightness / MAX_INPUT_BRIGHTNESS;
}
set(PANEL_BRIGHTNESS_NODE, brightness);
}
#ifdef BUTTON_BRIGHTNESS_NODE
void Lights::handleButtons(const HwLightState& state) {
#ifdef VAR_BUTTON_BRIGHTNESS
uint32_t brightness = rgbToBrightness(state);
#else
uint32_t brightness = (state.color & COLOR_MASK) ? 1 : 0;
#endif
set(BUTTON_BRIGHTNESS_NODE, brightness);
}
#endif
#ifdef LED_BLINK_NODE
void Lights::handleBattery(const HwLightState& state) {
mBatteryState = state;
setNotificationLED();
}
void Lights::handleNotifications(const HwLightState& state) {
mNotificationState = state;
setNotificationLED();
}
void Lights::handleAttention(const HwLightState& state) {
mAttentionState = state;
setNotificationLED();
}
void Lights::setNotificationLED() {
int32_t adjusted_brightness = MAX_INPUT_BRIGHTNESS;
HwLightState state;
#ifdef LED_BLN_NODE
bool bln = false;
#endif /* LED_BLN_NODE */
if (mNotificationState.color & COLOR_MASK) {
adjusted_brightness = LED_BRIGHTNESS_NOTIFICATION;
state = mNotificationState;
#ifdef LED_BLN_NODE
bln = true;
#endif /* LED_BLN_NODE */
} else if (mAttentionState.color & COLOR_MASK) {
adjusted_brightness = LED_BRIGHTNESS_ATTENTION;
state = mAttentionState;
if (state.flashMode == FlashMode::HARDWARE) {
if (state.flashOnMs > 0 && state.flashOffMs == 0) state.flashMode = FlashMode::NONE;
state.color = 0x000000ff;
}
if (state.flashMode == FlashMode::NONE) {
state.color = 0;
}
} else if (mBatteryState.color & COLOR_MASK) {
adjusted_brightness = LED_BRIGHTNESS_BATTERY;
state = mBatteryState;
} else {
set(LED_BLINK_NODE, "0x00000000 0 0");
return;
}
if (state.flashMode == FlashMode::NONE) {
state.flashOnMs = 0;
state.flashOffMs = 0;
}
state.color = calibrateColor(state.color & COLOR_MASK, adjusted_brightness);
set(LED_BLINK_NODE, ::android::base::StringPrintf("0x%08x %d %d", state.color, state.flashOnMs,
state.flashOffMs));
#ifdef LED_BLN_NODE
if (bln) {
set(LED_BLN_NODE, (state.color & COLOR_MASK) ? 1 : 0);
}
#endif /* LED_BLN_NODE */
}
uint32_t Lights::calibrateColor(uint32_t color, int32_t brightness) {
uint32_t red = ((color >> 16) & 0xFF) * LED_ADJUSTMENT_R;
uint32_t green = ((color >> 8) & 0xFF) * LED_ADJUSTMENT_G;
uint32_t blue = (color & 0xFF) * LED_ADJUSTMENT_B;
return (((red * brightness) / 255) << 16) + (((green * brightness) / 255) << 8) +
((blue * brightness) / 255);
}
#endif /* LED_BLINK_NODE */
#define AutoHwLight(light) \
{ .id = (int32_t)light, .type = light, .ordinal = 0 }
ndk::ScopedAStatus Lights::getLights(std::vector<HwLight>* _aidl_return) {
for (auto const& light : mLights) {
_aidl_return->push_back(AutoHwLight(light.first));
}
return ndk::ScopedAStatus::ok();
}
uint32_t Lights::rgbToBrightness(const HwLightState& state) {
uint32_t color = state.color & COLOR_MASK;
return ((77 * ((color >> 16) & 0xff)) + (150 * ((color >> 8) & 0xff)) +
(29 * (color & 0xff))) >>
8;
}
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View file

@ -0,0 +1,54 @@
/*
* Copyright (C) 2021 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/android/hardware/light/BnLights.h>
#include <unordered_map>
#include "samsung_lights.h"
using ::aidl::android::hardware::light::HwLight;
using ::aidl::android::hardware::light::HwLightState;
namespace aidl {
namespace android {
namespace hardware {
namespace light {
class Lights : public BnLights {
public:
Lights();
ndk::ScopedAStatus setLightState(int32_t id, const HwLightState& state) override;
ndk::ScopedAStatus getLights(std::vector<HwLight>* _aidl_return) override;
private:
void handleBacklight(const HwLightState& state);
#ifdef BUTTON_BRIGHTNESS_NODE
void handleButtons(const HwLightState& state);
#endif /* BUTTON_BRIGHTNESS_NODE */
#ifdef LED_BLINK_NODE
void handleBattery(const HwLightState& state);
void handleNotifications(const HwLightState& state);
void handleAttention(const HwLightState& state);
void setNotificationLED();
uint32_t calibrateColor(uint32_t color, int32_t brightness);
HwLightState mAttentionState;
HwLightState mBatteryState;
HwLightState mNotificationState;
#endif /* LED_BLINK_NODE */
uint32_t rgbToBrightness(const HwLightState& state);
std::mutex mLock;
std::unordered_map<LightType, std::function<void(const HwLightState&)>> mLights;
};
} // namespace light
} // namespace hardware
} // namespace android
} // namespace aidl

View file

@ -0,0 +1,5 @@
service vendor.light-default /vendor/bin/hw/android.hardware.light-service.samsung
class hal
user system
group system
shutdown critical

View file

@ -0,0 +1,6 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.light</name>
<fqname>ILights/default</fqname>
</hal>
</manifest>

View file

@ -0,0 +1,58 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2017 The LineageOS 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 SAMSUNG_LIGHTS_H
#define SAMSUNG_LIGHTS_H
/*
* Board specific nodes
*
* If your kernel exposes these controls in another place, you can either
* symlink to the locations given here, or override this header in your
* device tree.
*/
#define PANEL_BRIGHTNESS_NODE "/sys/class/backlight/panel/brightness"
#define PANEL_MAX_BRIGHTNESS_NODE "/sys/class/backlight/panel/max_brightness"
#define BUTTON_BRIGHTNESS_NODE "/sys/class/sec/sec_touchkey/brightness"
#define LED_BLINK_NODE "/sys/class/sec/led/led_blink"
#define LED_BLN_NODE "/sys/class/misc/backlightnotification/notification_led"
// Uncomment to enable variable button brightness
//#define VAR_BUTTON_BRIGHTNESS 1
/*
* Brightness adjustment factors
*
* If one of your device's LEDs is more powerful than the others, use these
* values to equalise them. This value is in the range 0.0-1.0.
*/
#define LED_ADJUSTMENT_R 1.0
#define LED_ADJUSTMENT_G 1.0
#define LED_ADJUSTMENT_B 1.0
/*
* Light brightness factors
*
* It might make sense for all colours to be scaled down (for example, if your
* LED is too bright). Use these values to adjust the brightness of each
* light. This value is within the range 0-255.
*/
#define LED_BRIGHTNESS_BATTERY 255
#define LED_BRIGHTNESS_NOTIFICATION 255
#define LED_BRIGHTNESS_ATTENTION 255
#endif // SAMSUNG_LIGHTS_H

View file

@ -0,0 +1,27 @@
/*
* Copyright (C) 2021 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#define LOG_TAG "android.hardware.light-service.samsung"
#include "Lights.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using ::aidl::android::hardware::light::Lights;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<Lights> lights = ndk::SharedRefBase::make<Lights>();
const std::string instance = std::string() + Lights::descriptor + "/default";
binder_status_t status = AServiceManager_addService(lights->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}

View file

@ -0,0 +1,45 @@
//
// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
soong_namespace {
imports: [
"hardware/google/pixel",
"hardware/google/interfaces",
],
}
cc_binary {
name: "android.hardware.power-service.samsung-libperfmgr",
relative_install_path: "hw",
init_rc: ["android.hardware.power-service.samsung-libperfmgr.rc"],
vintf_fragments: ["android.hardware.power-service.samsung.xml"],
vendor: true,
shared_libs: [
"android.hardware.power-V1-ndk_platform",
"libbase",
"libcutils",
"liblog",
"libutils",
"libbinder_ndk",
"libperfmgr",
"pixel-power-ext-V1-ndk_platform",
],
srcs: [
"service.cpp",
"Power.cpp",
"PowerExt.cpp",
"InteractionHandler.cpp"
],
}

View file

@ -0,0 +1,259 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.power@-service.samsung-libperfmgr"
#define ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
#include <fcntl.h>
#include <poll.h>
#include <sys/eventfd.h>
#include <time.h>
#include <unistd.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <memory>
#include "InteractionHandler.h"
#define MAX_LENGTH 64
#define MSINSEC 1000L
#define USINMS 1000000L
static const std::vector<std::string> fb_idle_patch = {"/sys/class/drm/card0/device/idle_state",
"/sys/class/graphics/fb0/idle_state"};
InteractionHandler::InteractionHandler(std::shared_ptr<HintManager> const& hint_manager)
: mState(INTERACTION_STATE_UNINITIALIZED),
mWaitMs(100),
mMinDurationMs(1400),
mMaxDurationMs(5650),
mDurationMs(0),
mHintManager(hint_manager) {}
InteractionHandler::~InteractionHandler() {
Exit();
}
static int fb_idle_open(void) {
int fd;
for (auto& path : fb_idle_patch) {
fd = open(path.c_str(), O_RDONLY);
if (fd >= 0) return fd;
}
ALOGE("Unable to open fb idle state path (%d)", errno);
return -1;
}
bool InteractionHandler::Init() {
std::lock_guard<std::mutex> lk(mLock);
if (mState != INTERACTION_STATE_UNINITIALIZED) return true;
mIdleFd = fb_idle_open();
mEventFd = eventfd(0, EFD_NONBLOCK);
if (mEventFd < 0) {
ALOGE("Unable to create event fd (%d)", errno);
if (mIdleFd >= 0) {
close(mIdleFd);
}
return false;
}
mState = INTERACTION_STATE_IDLE;
mThread = std::unique_ptr<std::thread>(new std::thread(&InteractionHandler::Routine, this));
return true;
}
void InteractionHandler::Exit() {
std::unique_lock<std::mutex> lk(mLock);
if (mState == INTERACTION_STATE_UNINITIALIZED) return;
AbortWaitLocked();
mState = INTERACTION_STATE_UNINITIALIZED;
lk.unlock();
mCond.notify_all();
mThread->join();
close(mEventFd);
if (mIdleFd >= 0) {
close(mIdleFd);
}
}
void InteractionHandler::PerfLock() {
ALOGV("%s: acquiring perf lock", __func__);
if (!mHintManager->DoHint("INTERACTION")) {
ALOGE("%s: do hint INTERACTION failed", __func__);
}
ATRACE_INT("interaction_lock", 1);
}
void InteractionHandler::PerfRel() {
ALOGV("%s: releasing perf lock", __func__);
if (!mHintManager->EndHint("INTERACTION")) {
ALOGE("%s: end hint INTERACTION failed", __func__);
}
ATRACE_INT("interaction_lock", 0);
}
size_t InteractionHandler::CalcTimespecDiffMs(struct timespec start, struct timespec end) {
size_t diff_in_us = 0;
diff_in_us += (end.tv_sec - start.tv_sec) * MSINSEC;
diff_in_us += (end.tv_nsec - start.tv_nsec) / USINMS;
return diff_in_us;
}
void InteractionHandler::Acquire(int32_t duration) {
ATRACE_CALL();
std::lock_guard<std::mutex> lk(mLock);
if (mState == INTERACTION_STATE_UNINITIALIZED) {
ALOGW("%s: called while uninitialized", __func__);
return;
}
int inputDuration = duration + 650;
int finalDuration;
if (inputDuration > mMaxDurationMs)
finalDuration = mMaxDurationMs;
else if (inputDuration > mMinDurationMs)
finalDuration = inputDuration;
else
finalDuration = mMinDurationMs;
struct timespec cur_timespec;
clock_gettime(CLOCK_MONOTONIC, &cur_timespec);
if (mState != INTERACTION_STATE_IDLE && finalDuration <= mDurationMs) {
size_t elapsed_time = CalcTimespecDiffMs(mLastTimespec, cur_timespec);
// don't hint if previous hint's duration covers this hint's duration
if (elapsed_time <= (mDurationMs - finalDuration)) {
ALOGV("%s: Previous duration (%d) cover this (%d) elapsed: %lld", __func__,
static_cast<int>(mDurationMs), static_cast<int>(finalDuration),
static_cast<long long>(elapsed_time));
return;
}
}
mLastTimespec = cur_timespec;
mDurationMs = finalDuration;
ALOGV("%s: input: %d final duration: %d", __func__, duration, finalDuration);
if (mState == INTERACTION_STATE_WAITING)
AbortWaitLocked();
else if (mState == INTERACTION_STATE_IDLE)
PerfLock();
mState = INTERACTION_STATE_INTERACTION;
mCond.notify_one();
}
void InteractionHandler::Release() {
std::lock_guard<std::mutex> lk(mLock);
if (mState == INTERACTION_STATE_WAITING) {
ATRACE_CALL();
PerfRel();
mState = INTERACTION_STATE_IDLE;
} else {
// clear any wait aborts pending in event fd
uint64_t val;
ssize_t ret = read(mEventFd, &val, sizeof(val));
ALOGW_IF(ret < 0, "%s: failed to clear eventfd (%zd, %d)", __func__, ret, errno);
}
}
// should be called while locked
void InteractionHandler::AbortWaitLocked() {
uint64_t val = 1;
ssize_t ret = write(mEventFd, &val, sizeof(val));
if (ret != sizeof(val)) ALOGW("Unable to write to event fd (%zd)", ret);
}
void InteractionHandler::WaitForIdle(int32_t wait_ms, int32_t timeout_ms) {
char data[MAX_LENGTH];
ssize_t ret;
struct pollfd pfd[2];
ATRACE_CALL();
ALOGV("%s: wait:%d timeout:%d", __func__, wait_ms, timeout_ms);
pfd[0].fd = mEventFd;
pfd[0].events = POLLIN;
pfd[1].fd = mIdleFd;
pfd[1].events = POLLPRI | POLLERR;
ret = poll(pfd, 1, wait_ms);
if (ret > 0) {
ALOGV("%s: wait aborted", __func__);
return;
} else if (ret < 0) {
ALOGE("%s: error in poll while waiting", __func__);
return;
}
if (mIdleFd < 0) {
ret = poll(pfd, 1, timeout_ms);
if (ret > 0) {
ALOGV("%s: wait for duration aborted", __func__);
return;
} else if (ret < 0) {
ALOGE("%s: Error on waiting for duration (%zd)", __func__, ret);
return;
}
return;
}
ret = pread(mIdleFd, data, sizeof(data), 0);
if (!ret) {
ALOGE("%s: Unexpected EOF!", __func__);
return;
}
if (!strncmp(data, "idle", 4)) {
ALOGV("%s: already idle", __func__);
return;
}
ret = poll(pfd, 2, timeout_ms);
if (ret < 0)
ALOGE("%s: Error on waiting for idle (%zd)", __func__, ret);
else if (ret == 0)
ALOGV("%s: timed out waiting for idle", __func__);
else if (pfd[0].revents)
ALOGV("%s: wait for idle aborted", __func__);
else if (pfd[1].revents)
ALOGV("%s: idle detected", __func__);
}
void InteractionHandler::Routine() {
std::unique_lock<std::mutex> lk(mLock, std::defer_lock);
while (true) {
lk.lock();
mCond.wait(lk, [&] { return mState != INTERACTION_STATE_IDLE; });
if (mState == INTERACTION_STATE_UNINITIALIZED) return;
mState = INTERACTION_STATE_WAITING;
lk.unlock();
WaitForIdle(mWaitMs, mDurationMs);
Release();
}
}

View file

@ -0,0 +1,74 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef POWER_LIBPERFMGR_INTERACTIONHANDLER_H_
#define POWER_LIBPERFMGR_INTERACTIONHANDLER_H_
#include <condition_variable>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <perfmgr/HintManager.h>
using ::android::perfmgr::HintManager;
enum interaction_state {
INTERACTION_STATE_UNINITIALIZED,
INTERACTION_STATE_IDLE,
INTERACTION_STATE_INTERACTION,
INTERACTION_STATE_WAITING,
};
class InteractionHandler {
public:
InteractionHandler(std::shared_ptr<HintManager> const& hint_manager);
~InteractionHandler();
bool Init();
void Exit();
void Acquire(int32_t duration);
private:
void Release();
void WaitForIdle(int32_t wait_ms, int32_t timeout_ms);
void AbortWaitLocked();
void Routine();
void PerfLock();
void PerfRel();
size_t CalcTimespecDiffMs(struct timespec start, struct timespec end);
enum interaction_state mState;
int mIdleFd;
int mEventFd;
int32_t mWaitMs;
int32_t mMinDurationMs;
int32_t mMaxDurationMs;
int32_t mDurationMs;
struct timespec mLastTimespec;
std::unique_ptr<std::thread> mThread;
std::mutex mLock;
std::condition_variable mCond;
std::shared_ptr<HintManager> mHintManager;
};
#endif // POWER_LIBPERFMGR_INTERACTIONHANDLER_H_

View file

@ -0,0 +1,262 @@
/*
* Copyright (C) 2020 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 ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
#define LOG_TAG "android.hardware.power-service.samsung-libperfmgr"
#include "Power.h"
#include <mutex>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <utils/Log.h>
#include <utils/Trace.h>
namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {
constexpr char kPowerHalStateProp[] = "vendor.powerhal.state";
constexpr char kPowerHalAudioProp[] = "vendor.powerhal.audio";
constexpr char kPowerHalRenderingProp[] = "vendor.powerhal.rendering";
Power::Power(std::shared_ptr<HintManager> hm)
: mHintManager(hm),
mInteractionHandler(nullptr),
mVRModeOn(false),
mSustainedPerfModeOn(false) {
mInteractionHandler = std::make_unique<InteractionHandler>(mHintManager);
mInteractionHandler->Init();
std::string state = ::android::base::GetProperty(kPowerHalStateProp, "");
if (state == "SUSTAINED_PERFORMANCE") {
ALOGI("Initialize with SUSTAINED_PERFORMANCE on");
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
mSustainedPerfModeOn = true;
} else if (state == "VR") {
ALOGI("Initialize with VR on");
mHintManager->DoHint(state);
mVRModeOn = true;
} else if (state == "VR_SUSTAINED_PERFORMANCE") {
ALOGI("Initialize with SUSTAINED_PERFORMANCE and VR on");
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
mSustainedPerfModeOn = true;
mVRModeOn = true;
} else {
ALOGI("Initialize PowerHAL");
}
state = ::android::base::GetProperty(kPowerHalAudioProp, "");
if (state == "AUDIO_STREAMING_LOW_LATENCY") {
ALOGI("Initialize with AUDIO_LOW_LATENCY on");
mHintManager->DoHint(state);
}
state = ::android::base::GetProperty(kPowerHalRenderingProp, "");
if (state == "EXPENSIVE_RENDERING") {
ALOGI("Initialize with EXPENSIVE_RENDERING on");
mHintManager->DoHint("EXPENSIVE_RENDERING");
}
// Now start to take powerhint
ALOGI("PowerHAL ready to process hints");
}
ndk::ScopedAStatus Power::setMode(Mode type, bool enabled) {
LOG(DEBUG) << "Power setMode: " << toString(type) << " to: " << enabled;
ATRACE_INT(toString(type).c_str(), enabled);
switch (type) {
case Mode::LOW_POWER:
if (enabled) {
mHintManager->DoHint(toString(type));
} else {
mHintManager->EndHint(toString(type));
}
break;
case Mode::SUSTAINED_PERFORMANCE:
if (enabled && !mSustainedPerfModeOn) {
if (!mVRModeOn) { // Sustained mode only.
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
} else { // Sustained + VR mode.
mHintManager->EndHint("VR");
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
}
mSustainedPerfModeOn = true;
} else if (!enabled && mSustainedPerfModeOn) {
mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
mHintManager->EndHint("SUSTAINED_PERFORMANCE");
if (mVRModeOn) { // Switch back to VR Mode.
mHintManager->DoHint("VR");
}
mSustainedPerfModeOn = false;
}
break;
case Mode::VR:
if (enabled && !mVRModeOn) {
if (!mSustainedPerfModeOn) { // VR mode only.
mHintManager->DoHint("VR");
} else { // Sustained + VR mode.
mHintManager->EndHint("SUSTAINED_PERFORMANCE");
mHintManager->DoHint("VR_SUSTAINED_PERFORMANCE");
}
mVRModeOn = true;
} else if (!enabled && mVRModeOn) {
mHintManager->EndHint("VR_SUSTAINED_PERFORMANCE");
mHintManager->EndHint("VR");
if (mSustainedPerfModeOn) { // Switch back to sustained Mode.
mHintManager->DoHint("SUSTAINED_PERFORMANCE");
}
mVRModeOn = false;
}
break;
case Mode::LAUNCH:
if (mVRModeOn || mSustainedPerfModeOn) {
break;
}
[[fallthrough]];
case Mode::DOUBLE_TAP_TO_WAKE:
[[fallthrough]];
case Mode::FIXED_PERFORMANCE:
[[fallthrough]];
case Mode::EXPENSIVE_RENDERING:
[[fallthrough]];
case Mode::INTERACTIVE:
[[fallthrough]];
case Mode::DEVICE_IDLE:
[[fallthrough]];
case Mode::DISPLAY_INACTIVE:
[[fallthrough]];
case Mode::AUDIO_STREAMING_LOW_LATENCY:
[[fallthrough]];
case Mode::CAMERA_STREAMING_SECURE:
[[fallthrough]];
case Mode::CAMERA_STREAMING_LOW:
[[fallthrough]];
case Mode::CAMERA_STREAMING_MID:
[[fallthrough]];
case Mode::CAMERA_STREAMING_HIGH:
[[fallthrough]];
default:
if (enabled) {
mHintManager->DoHint(toString(type));
} else {
mHintManager->EndHint(toString(type));
}
break;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Power::isModeSupported(Mode type, bool* _aidl_return) {
bool supported = mHintManager->IsHintSupported(toString(type));
switch (type) {
case Mode::LOW_POWER: // LOW_POWER handled insides PowerHAL specifically
supported = true;
break;
case Mode::DOUBLE_TAP_TO_WAKE:
supported = true;
break;
case Mode::INTERACTIVE:
supported = true;
break;
default:
break;
}
LOG(INFO) << "Power mode " << toString(type) << " isModeSupported: " << supported;
*_aidl_return = supported;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Power::setBoost(Boost type, int32_t durationMs) {
LOG(DEBUG) << "Power setBoost: " << toString(type) << " duration: " << durationMs;
ATRACE_INT(toString(type).c_str(), durationMs);
switch (type) {
case Boost::INTERACTION:
if (mVRModeOn || mSustainedPerfModeOn) {
break;
}
mInteractionHandler->Acquire(durationMs);
break;
case Boost::DISPLAY_UPDATE_IMMINENT:
[[fallthrough]];
case Boost::ML_ACC:
[[fallthrough]];
case Boost::AUDIO_LAUNCH:
[[fallthrough]];
case Boost::CAMERA_LAUNCH:
[[fallthrough]];
case Boost::CAMERA_SHOT:
[[fallthrough]];
default:
if (mVRModeOn || mSustainedPerfModeOn) {
break;
}
if (durationMs > 0) {
mHintManager->DoHint(toString(type), std::chrono::milliseconds(durationMs));
} else if (durationMs == 0) {
mHintManager->DoHint(toString(type));
} else {
mHintManager->EndHint(toString(type));
}
break;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Power::isBoostSupported(Boost type, bool* _aidl_return) {
bool supported = mHintManager->IsHintSupported(toString(type));
LOG(INFO) << "Power boost " << toString(type) << " isBoostSupported: " << supported;
*_aidl_return = supported;
return ndk::ScopedAStatus::ok();
}
constexpr const char* boolToString(bool b) {
return b ? "true" : "false";
}
binder_status_t Power::dump(int fd, const char**, uint32_t) {
std::string buf(::android::base::StringPrintf(
"HintManager Running: %s\n"
"VRMode: %s\n"
"SustainedPerformanceMode: %s\n",
boolToString(mHintManager->IsRunning()), boolToString(mVRModeOn),
boolToString(mSustainedPerfModeOn)));
// Dump nodes through libperfmgr
mHintManager->DumpToFd(fd);
if (!::android::base::WriteStringToFd(buf, fd)) {
PLOG(ERROR) << "Failed to dump state to fd";
}
fsync(fd);
return STATUS_OK;
}
} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl

View file

@ -0,0 +1,61 @@
/*
* Copyright (C) 2020 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.
*/
#pragma once
#include <atomic>
#include <memory>
#include <thread>
#include <aidl/android/hardware/power/BnPower.h>
#include <perfmgr/HintManager.h>
#include "InteractionHandler.h"
namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {
using ::InteractionHandler;
using ::aidl::android::hardware::power::Boost;
using ::aidl::android::hardware::power::Mode;
using ::android::perfmgr::HintManager;
class Power : public ::aidl::android::hardware::power::BnPower {
public:
Power(std::shared_ptr<HintManager> hm);
ndk::ScopedAStatus setMode(Mode type, bool enabled) override;
ndk::ScopedAStatus isModeSupported(Mode type, bool* _aidl_return) override;
ndk::ScopedAStatus setBoost(Boost type, int32_t durationMs) override;
ndk::ScopedAStatus isBoostSupported(Boost type, bool* _aidl_return) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
std::shared_ptr<HintManager> mHintManager;
std::unique_ptr<InteractionHandler> mInteractionHandler;
std::atomic<bool> mVRModeOn;
std::atomic<bool> mSustainedPerfModeOn;
};
} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl

View file

@ -0,0 +1,87 @@
/*
* Copyright (C) 2020 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 ATRACE_TAG (ATRACE_TAG_POWER | ATRACE_TAG_HAL)
#define LOG_TAG "android.hardware.power-service.samsung.ext-libperfmgr"
#include "PowerExt.h"
#include <mutex>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <utils/Log.h>
#include <utils/Trace.h>
namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {
ndk::ScopedAStatus PowerExt::setMode(const std::string& mode, bool enabled) {
LOG(DEBUG) << "PowerExt setMode: " << mode << " to: " << enabled;
ATRACE_INT(mode.c_str(), enabled);
if (enabled) {
mHintManager->DoHint(mode);
} else {
mHintManager->EndHint(mode);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus PowerExt::isModeSupported(const std::string& mode, bool* _aidl_return) {
bool supported = mHintManager->IsHintSupported(mode);
LOG(INFO) << "PowerExt mode " << mode << " isModeSupported: " << supported;
*_aidl_return = supported;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus PowerExt::setBoost(const std::string& boost, int32_t durationMs) {
LOG(DEBUG) << "PowerExt setBoost: " << boost << " duration: " << durationMs;
ATRACE_INT(boost.c_str(), durationMs);
if (durationMs > 0) {
mHintManager->DoHint(boost, std::chrono::milliseconds(durationMs));
} else if (durationMs == 0) {
mHintManager->DoHint(boost);
} else {
mHintManager->EndHint(boost);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus PowerExt::isBoostSupported(const std::string& boost, bool* _aidl_return) {
bool supported = mHintManager->IsHintSupported(boost);
LOG(INFO) << "PowerExt boost " << boost << " isBoostSupported: " << supported;
*_aidl_return = supported;
return ndk::ScopedAStatus::ok();
}
} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl

View file

@ -0,0 +1,52 @@
/*
* Copyright (C) 2020 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.
*/
#pragma once
#include <atomic>
#include <memory>
#include <thread>
#include <aidl/google/hardware/power/extension/pixel/BnPowerExt.h>
#include <perfmgr/HintManager.h>
namespace aidl {
namespace google {
namespace hardware {
namespace power {
namespace impl {
namespace pixel {
using ::android::perfmgr::HintManager;
class PowerExt : public ::aidl::google::hardware::power::extension::pixel::BnPowerExt {
public:
PowerExt(std::shared_ptr<HintManager> hm) : mHintManager(hm) {}
ndk::ScopedAStatus setMode(const std::string& mode, bool enabled) override;
ndk::ScopedAStatus isModeSupported(const std::string& mode, bool* _aidl_return) override;
ndk::ScopedAStatus setBoost(const std::string& boost, int32_t durationMs) override;
ndk::ScopedAStatus isBoostSupported(const std::string& boost, bool* _aidl_return) override;
private:
std::shared_ptr<HintManager> mHintManager;
};
} // namespace pixel
} // namespace impl
} // namespace power
} // namespace hardware
} // namespace google
} // namespace aidl

View file

@ -0,0 +1,28 @@
service vendor.power-hal-aidl /vendor/bin/hw/android.hardware.power-service.samsung-libperfmgr
class hal
user root
group system radio
priority -20
on late-fs
start vendor.power-hal-aidl
# restart powerHAL when framework died
on property:init.svc.zygote=restarting && property:vendor.powerhal.state=*
setprop vendor.powerhal.state ""
setprop vendor.powerhal.audio ""
setprop vendor.powerhal.rendering ""
restart vendor.power-hal-aidl
# Clean up after b/163539793 resolved
on property:vendor.powerhal.dalvik.vm.dex2oat-threads=*
setprop dalvik.vm.dex2oat-threads ${vendor.powerhal.dalvik.vm.dex2oat-threads}
setprop dalvik.vm.restore-dex2oat-threads ${vendor.powerhal.dalvik.vm.dex2oat-threads}
on property:vendor.powerhal.dalvik.vm.dex2oat-cpu-set=*
setprop dalvik.vm.dex2oat-cpu-set ${vendor.powerhal.dalvik.vm.dex2oat-cpu-set}
setprop dalvik.vm.restore-dex2oat-cpu-set ${vendor.powerhal.dalvik.vm.dex2oat-cpu-set}
# initialize powerHAL when boot is completed
on property:sys.boot_completed=1
setprop vendor.powerhal.init 1

View file

@ -0,0 +1,6 @@
<manifest version="1.0" type="device">
<hal format="aidl" override="true">
<name>android.hardware.power</name>
<fqname>IPower/default</fqname>
</hal>
</manifest>

View file

@ -0,0 +1,74 @@
/*
* Copyright (C) 2020 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 "android.hardware.power-service.samsung-libperfmgr"
#include <thread>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "Power.h"
#include "PowerExt.h"
using aidl::google::hardware::power::impl::pixel::Power;
using aidl::google::hardware::power::impl::pixel::PowerExt;
using ::android::perfmgr::HintManager;
constexpr char kPowerHalConfigPath[] = "/vendor/etc/powerhint.json";
constexpr char kPowerHalInitProp[] = "vendor.powerhal.init";
int main() {
LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is starting.";
// Parse config but do not start the looper
std::shared_ptr<HintManager> hm = HintManager::GetFromJSON(kPowerHalConfigPath, false);
if (!hm) {
LOG(FATAL) << "Invalid config: " << kPowerHalConfigPath;
}
// single thread
ABinderProcess_setThreadPoolMaxThreadCount(0);
// core service
std::shared_ptr<Power> pw = ndk::SharedRefBase::make<Power>(hm);
ndk::SpAIBinder pwBinder = pw->asBinder();
// extension service
std::shared_ptr<PowerExt> pwExt = ndk::SharedRefBase::make<PowerExt>(hm);
// attach the extension to the same binder we will be registering
CHECK(STATUS_OK == AIBinder_setExtension(pwBinder.get(), pwExt->asBinder().get()));
const std::string instance = std::string() + Power::descriptor + "/default";
binder_status_t status = AServiceManager_addService(pw->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
LOG(INFO) << "Pixel Power HAL AIDL Service with Extension is started.";
std::thread initThread([&]() {
::android::base::WaitForProperty(kPowerHalInitProp, "1");
hm->Start();
});
initThread.detach();
ABinderProcess_joinThreadPool();
// should not reach
LOG(ERROR) << "Pixel Power HAL AIDL Service with Extension just died.";
return EXIT_FAILURE;
}

View file

@ -0,0 +1,22 @@
//
// Copyright (C) 2021 The LineageOS Project
//
// SPDX-License-Identifier: Apache-2.0
//
cc_binary {
name: "android.hardware.vibrator-service.samsung",
relative_install_path: "hw",
init_rc: ["android.hardware.vibrator-service.samsung.rc"],
vintf_fragments: ["android.hardware.vibrator-service.samsung.xml"],
srcs: [
"Vibrator.cpp",
"service.cpp",
],
shared_libs: [
"libbase",
"libbinder_ndk",
"android.hardware.vibrator-V2-ndk_platform",
],
vendor: true,
}

View file

@ -0,0 +1,304 @@
/*
* Copyright (C) 2021 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Vibrator.h"
#include <android-base/logging.h>
#include <cmath>
#include <fstream>
#include <iostream>
#include <thread>
namespace aidl {
namespace android {
namespace hardware {
namespace vibrator {
/*
* Write value to path and close file.
*/
template <typename T>
static ndk::ScopedAStatus writeNode(const std::string& path, const T& value) {
std::ofstream node(path);
if (!node) {
LOG(ERROR) << "Failed to open: " << path;
return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_ERROR);
}
LOG(DEBUG) << "writeNode node: " << path << " value: " << value;
node << value << std::endl;
if (!node) {
LOG(ERROR) << "Failed to write: " << value;
return ndk::ScopedAStatus::fromStatus(STATUS_UNKNOWN_ERROR);
}
return ndk::ScopedAStatus::ok();
}
static bool nodeExists(const std::string& path) {
std::ofstream f(path.c_str());
return f.good();
}
Vibrator::Vibrator() {
mIsTimedOutVibrator = nodeExists(VIBRATOR_TIMEOUT_PATH);
mHasTimedOutIntensity = nodeExists(VIBRATOR_INTENSITY_PATH);
}
ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
*_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
IVibrator::CAP_EXTERNAL_CONTROL /*| IVibrator::CAP_COMPOSE_EFFECTS |
IVibrator::CAP_ALWAYS_ON_CONTROL*/
;
if (mHasTimedOutIntensity) {
*_aidl_return = *_aidl_return | IVibrator::CAP_AMPLITUDE_CONTROL |
IVibrator::CAP_EXTERNAL_AMPLITUDE_CONTROL;
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::off() {
return activate(0);
}
ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
const std::shared_ptr<IVibratorCallback>& callback) {
ndk::ScopedAStatus status = activate(timeoutMs);
if (callback != nullptr) {
std::thread([=] {
LOG(INFO) << "Starting on on another thread";
usleep(timeoutMs * 1000);
LOG(INFO) << "Notifying on complete";
if (!callback->onComplete().isOk()) {
LOG(ERROR) << "Failed to call onComplete";
}
}).detach();
}
return status;
}
ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
const std::shared_ptr<IVibratorCallback>& callback,
int32_t* _aidl_return) {
ndk::ScopedAStatus status;
uint8_t amplitude;
uint32_t ms;
amplitude = strengthToAmplitude(strength, &status);
if (!status.isOk()) {
return status;
}
setAmplitude(amplitude);
ms = effectToMs(effect, &status);
if (!status.isOk()) {
return status;
}
status = activate(ms);
if (callback != nullptr) {
std::thread([=] {
LOG(INFO) << "Starting perform on another thread";
usleep(ms * 1000);
LOG(INFO) << "Notifying perform complete";
callback->onComplete();
}).detach();
}
*_aidl_return = ms;
return status;
}
ndk::ScopedAStatus Vibrator::getSupportedEffects(std::vector<Effect>* _aidl_return) {
*_aidl_return = {
Effect::CLICK, Effect::DOUBLE_CLICK, Effect::HEAVY_CLICK, Effect::TICK,
Effect::TEXTURE_TICK, Effect::THUD, Effect::POP, Effect::RINGTONE_1,
Effect::RINGTONE_2, Effect::RINGTONE_3, Effect::RINGTONE_4, Effect::RINGTONE_5,
Effect::RINGTONE_6, Effect::RINGTONE_7, Effect::RINGTONE_7, Effect::RINGTONE_8,
Effect::RINGTONE_9, Effect::RINGTONE_10, Effect::RINGTONE_11, Effect::RINGTONE_12,
Effect::RINGTONE_13, Effect::RINGTONE_14, Effect::RINGTONE_15};
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::setAmplitude(float amplitude) {
uint32_t intensity;
if (amplitude == 0) {
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
LOG(DEBUG) << "Setting amplitude: " << (uint32_t)amplitude;
intensity = std::lround((amplitude - 1) * INTENSITY_MAX / 254.0);
if (intensity > INTENSITY_MAX) {
intensity = INTENSITY_MAX;
}
LOG(DEBUG) << "Setting intensity: " << intensity;
if (mHasTimedOutIntensity) {
return writeNode(VIBRATOR_INTENSITY_PATH, intensity);
}
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
if (mEnabled) {
LOG(WARNING) << "Setting external control while the vibrator is enabled is "
"unsupported!";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
LOG(INFO) << "ExternalControl: " << mExternalControl << " -> " << enabled;
mExternalControl = enabled;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Vibrator::getCompositionDelayMax(int32_t* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getCompositionSizeMax(int32_t* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getSupportedPrimitives(
std::vector<CompositePrimitive>* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getPrimitiveDuration(CompositePrimitive /*primitive*/,
int32_t* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::compose(const std::vector<CompositeEffect>& /*composite*/,
const std::shared_ptr<IVibratorCallback>& /*callback*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getSupportedAlwaysOnEffects(std::vector<Effect>* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::alwaysOnEnable(int32_t /*id*/, Effect /*effect*/,
EffectStrength /*strength*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::alwaysOnDisable(int32_t /*id*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getResonantFrequency(float* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getQFactor(float* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getFrequencyResolution(float* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getFrequencyMinimum(float* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getBandwidthAmplitudeMap(std::vector<float>* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getPwlePrimitiveDurationMax(int32_t* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getPwleCompositionSizeMax(int32_t* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::getSupportedBraking(std::vector<Braking>* /*_aidl_return*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::composePwle(const std::vector<PrimitivePwle>& /*composite*/,
const std::shared_ptr<IVibratorCallback>& /*callback*/) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
ndk::ScopedAStatus Vibrator::activate(uint32_t timeoutMs) {
std::lock_guard<std::mutex> lock{mMutex};
if (!mIsTimedOutVibrator) {
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
return writeNode(VIBRATOR_TIMEOUT_PATH, timeoutMs);
}
uint8_t Vibrator::strengthToAmplitude(EffectStrength strength, ndk::ScopedAStatus* status) {
*status = ndk::ScopedAStatus::ok();
switch (strength) {
case EffectStrength::LIGHT:
return 64;
case EffectStrength::MEDIUM:
return 128;
case EffectStrength::STRONG:
return 255;
}
*status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
return 0;
}
uint32_t Vibrator::effectToMs(Effect effect, ndk::ScopedAStatus* status) {
*status = ndk::ScopedAStatus::ok();
switch (effect) {
case Effect::CLICK:
return 20;
case Effect::DOUBLE_CLICK:
return 25;
case Effect::HEAVY_CLICK:
return 30;
case Effect::TICK:
case Effect::TEXTURE_TICK:
case Effect::THUD:
case Effect::POP:
return 15;
case Effect::RINGTONE_1:
case Effect::RINGTONE_2:
case Effect::RINGTONE_3:
case Effect::RINGTONE_4:
case Effect::RINGTONE_5:
case Effect::RINGTONE_6:
case Effect::RINGTONE_7:
case Effect::RINGTONE_8:
case Effect::RINGTONE_9:
case Effect::RINGTONE_10:
case Effect::RINGTONE_11:
case Effect::RINGTONE_12:
case Effect::RINGTONE_13:
case Effect::RINGTONE_14:
case Effect::RINGTONE_15:
return 300;
}
*status = ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
return 0;
}
} // namespace vibrator
} // namespace hardware
} // namespace android
} // namespace aidl

View file

@ -0,0 +1,82 @@
/*
* Copyright (C) 2021 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <aidl/android/hardware/vibrator/BnVibrator.h>
#define INTENSITY_MIN 1000
#define INTENSITY_MAX 10000
#define INTENSITY_DEFAULT INTENSITY_MAX
#define VIBRATOR_TIMEOUT_PATH "/sys/class/timed_output/vibrator/enable"
#define VIBRATOR_INTENSITY_PATH "/sys/class/timed_output/vibrator/intensity"
using ::aidl::android::hardware::vibrator::Braking;
using ::aidl::android::hardware::vibrator::CompositeEffect;
using ::aidl::android::hardware::vibrator::CompositePrimitive;
using ::aidl::android::hardware::vibrator::Effect;
using ::aidl::android::hardware::vibrator::EffectStrength;
using ::aidl::android::hardware::vibrator::IVibratorCallback;
using ::aidl::android::hardware::vibrator::PrimitivePwle;
namespace aidl {
namespace android {
namespace hardware {
namespace vibrator {
class Vibrator : public BnVibrator {
public:
Vibrator();
ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
ndk::ScopedAStatus off() override;
ndk::ScopedAStatus on(int32_t timeoutMs,
const std::shared_ptr<IVibratorCallback>& callback) override;
ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
const std::shared_ptr<IVibratorCallback>& callback,
int32_t* _aidl_return) override;
ndk::ScopedAStatus getSupportedEffects(std::vector<Effect>* _aidl_return) override;
ndk::ScopedAStatus setAmplitude(float amplitude) override;
ndk::ScopedAStatus setExternalControl(bool enabled) override;
ndk::ScopedAStatus getCompositionDelayMax(int32_t* _aidl_return) override;
ndk::ScopedAStatus getCompositionSizeMax(int32_t* _aidl_return) override;
ndk::ScopedAStatus getSupportedPrimitives(
std::vector<CompositePrimitive>* _aidl_return) override;
ndk::ScopedAStatus getPrimitiveDuration(CompositePrimitive primitive,
int32_t* _aidl_return) override;
ndk::ScopedAStatus compose(const std::vector<CompositeEffect>& composite,
const std::shared_ptr<IVibratorCallback>& callback) override;
ndk::ScopedAStatus getSupportedAlwaysOnEffects(std::vector<Effect>* _aidl_return) override;
ndk::ScopedAStatus alwaysOnEnable(int32_t id, Effect effect, EffectStrength strength) override;
ndk::ScopedAStatus alwaysOnDisable(int32_t id) override;
ndk::ScopedAStatus getResonantFrequency(float* _aidl_return) override;
ndk::ScopedAStatus getQFactor(float* _aidl_return) override;
ndk::ScopedAStatus getFrequencyResolution(float* _aidl_return) override;
ndk::ScopedAStatus getFrequencyMinimum(float* _aidl_return) override;
ndk::ScopedAStatus getBandwidthAmplitudeMap(std::vector<float>* _aidl_return) override;
ndk::ScopedAStatus getPwlePrimitiveDurationMax(int32_t* _aidl_return) override;
ndk::ScopedAStatus getPwleCompositionSizeMax(int32_t* _aidl_return) override;
ndk::ScopedAStatus getSupportedBraking(std::vector<Braking>* _aidl_return) override;
ndk::ScopedAStatus composePwle(const std::vector<PrimitivePwle>& composite,
const std::shared_ptr<IVibratorCallback>& callback) override;
private:
ndk::ScopedAStatus activate(uint32_t ms);
static uint32_t effectToMs(Effect effect, ndk::ScopedAStatus* status);
static uint8_t strengthToAmplitude(EffectStrength strength, ndk::ScopedAStatus* status);
bool mEnabled{false};
bool mExternalControl{false};
std::mutex mMutex;
bool mIsTimedOutVibrator;
bool mHasTimedOutIntensity;
};
} // namespace vibrator
} // namespace hardware
} // namespace android
} // namespace aidl

View file

@ -0,0 +1,5 @@
service vendor.vibrator-default /vendor/bin/hw/android.hardware.vibrator-service.samsung
class hal
user system
group system
shutdown critical

View file

@ -0,0 +1,6 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.vibrator</name>
<fqname>IVibrator/default</fqname>
</hal>
</manifest>

View file

@ -0,0 +1,26 @@
/*
* Copyright (C) 2021 The LineageOS Project
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "Vibrator.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using ::aidl::android::hardware::vibrator::Vibrator;
int main() {
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<Vibrator> vibrator = ndk::SharedRefBase::make<Vibrator>();
const std::string instance = std::string() + Vibrator::descriptor + "/default";
binder_status_t status =
AServiceManager_addService(vibrator->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}

View file

@ -0,0 +1,3 @@
LOCAL_PATH := $(call my-dir)
include $(call all-makefiles-under,$(LOCAL_PATH))

View file

@ -0,0 +1,45 @@
//
// Copyright (C) 2021 The LineageOS 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.
cc_binary {
name: "android.hardware.camera.provider@2.5-service.exynos7885",
defaults: [
"hidl_defaults",
],
compile_multilib: "32",
proprietary: true,
relative_install_path: "hw",
srcs: [
"SamsungCameraProvider.cpp",
"service.cpp"
],
init_rc: ["android.hardware.camera.provider@2.5-service.exynos7885.rc"],
shared_libs: [
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.4-legacy",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.5-legacy",
"libbinder",
"libcamera_metadata",
"libcutils",
"libhardware",
"libhidlbase",
"liblog",
"libutils",
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
],
}

View file

@ -0,0 +1,86 @@
/*
* Copyright (C) 2021 The LineageOS 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 "SamsungCameraProvider@2.5"
#include "SamsungCameraProvider.h"
#include <algorithm>
using ::android::NO_ERROR;
using ::android::OK;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
const int kMaxCameraIdLen = 16;
SamsungCameraProvider::SamsungCameraProvider() : LegacyCameraProviderImpl_2_5() {
mExtraIDs.push_back(50);
mDisabledIDs.push_back(2);
if (!mInitFailed) {
for (int i : mExtraIDs) {
struct camera_info info;
auto rc = mModule->getCameraInfo(i, &info);
if (rc != NO_ERROR) {
continue;
}
if (checkCameraVersion(i, info) != OK) {
ALOGE("Camera version check failed!");
mModule.clear();
mInitFailed = true;
return;
}
#ifdef SAMSUNG_CAMERA_DEBUG
ALOGI("ID=%d is at index %d", i, mNumberOfLegacyCameras);
#endif
char cameraId[kMaxCameraIdLen];
snprintf(cameraId, sizeof(cameraId), "%d", i);
std::string cameraIdStr(cameraId);
mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT;
addDeviceNames(i);
mNumberOfLegacyCameras++;
}
}
}
Return<void> SamsungCameraProvider::getCameraIdList(
ICameraProvider::getCameraIdList_cb _hidl_cb) {
std::vector<hidl_string> deviceNameList;
for (auto const& deviceNamePair : mCameraDeviceNames) {
int id = std::stoi(deviceNamePair.first);
if (id >= mNumberOfLegacyCameras || std::find(mDisabledIDs.begin(), mDisabledIDs.end(), id) != mDisabledIDs.end()) {
// External camera devices must be reported through the device status change callback,
// not in this list.
// Linux4: Also skip disabled camera IDs.
continue;
}
if (mCameraStatusMap[deviceNamePair.first] == CAMERA_DEVICE_STATUS_PRESENT) {
deviceNameList.push_back(deviceNamePair.second);
}
}
hidl_vec<hidl_string> hidlDeviceNameList(deviceNameList);
_hidl_cb(::android::hardware::camera::common::V1_0::Status::OK, hidlDeviceNameList);
return Void();
}
SamsungCameraProvider::~SamsungCameraProvider() {}

View file

@ -0,0 +1,38 @@
/*
* Copyright (C) 2021 The LineageOS 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 SAMSUNG_CAMERA_PROVIDER_H
#include "LegacyCameraProviderImpl_2_5.h"
#define SAMSUNG_CAMERA_DEBUG
using ::android::hardware::camera::provider::V2_5::ICameraProvider;
using ::android::hardware::camera::provider::V2_5::implementation::LegacyCameraProviderImpl_2_5;
using ::android::hardware::Return;
class SamsungCameraProvider : public LegacyCameraProviderImpl_2_5 {
public:
SamsungCameraProvider();
~SamsungCameraProvider();
Return<void> getCameraIdList(ICameraProvider::getCameraIdList_cb _hidl_cb);
private:
std::vector<int> mExtraIDs;
std::vector<int> mDisabledIDs;
};
#endif // SAMSUNG_CAMERA_PROVIDER_H

View file

@ -0,0 +1,9 @@
service vendor.camera-provider-2-5 /vendor/bin/hw/android.hardware.camera.provider@2.5-service.exynos7885
interface android.hardware.camera.provider@2.5::ICameraProvider legacy/0
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 MaxPerformance

View file

@ -0,0 +1,48 @@
/*
* Copyright 2019 The Android Open Source Project
* Copyright 2021 The LineageOS 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 "android.hardware.camera.provider@2.5-service.samsung"
#include <android/hardware/camera/provider/2.5/ICameraProvider.h>
#include <binder/ProcessState.h>
#include <hidl/HidlLazyUtils.h>
#include <hidl/HidlTransportSupport.h>
#include "CameraProvider_2_5.h"
#include "SamsungCameraProvider.h"
using android::status_t;
using android::hardware::camera::provider::V2_5::ICameraProvider;
int main()
{
using namespace android::hardware::camera::provider::V2_5::implementation;
ALOGI("CameraProvider@2.5 legacy service is starting.");
::android::hardware::configureRpcThreadpool(/*threads*/ HWBINDER_THREAD_COUNT, /*willJoin*/ true);
::android::sp<ICameraProvider> provider = new CameraProvider<SamsungCameraProvider>();
status_t status = provider->registerAsService("legacy/0");
LOG_ALWAYS_FATAL_IF(status != android::OK, "Error while registering provider service: %d",
status);
::android::hardware::joinRpcThreadpool();
return 0;
}

View file

@ -0,0 +1,24 @@
cc_binary {
name: "android.hardware.biometrics.fingerprint@2.3-service.samsung",
defaults: ["hidl_defaults"],
proprietary: true,
init_rc: ["android.hardware.biometrics.fingerprint@2.3-service.samsung.rc"],
vintf_fragments: ["android.hardware.biometrics.fingerprint@2.3-service.samsung.xml"],
relative_install_path: "hw",
cflags: ["-DHAS_FINGERPRINT_GESTURES"],
srcs: [
"BiometricsFingerprint.cpp",
"service.cpp",
],
shared_libs: [
"liblog",
"libcutils",
"libhardware",
"libbase",
"libutils",
"libhidlbase",
"android.hardware.biometrics.fingerprint@2.1",
"android.hardware.biometrics.fingerprint@2.2",
"android.hardware.biometrics.fingerprint@2.3",
],
}

View file

@ -0,0 +1,519 @@
/*
* Copyright (C) 2019 The LineageOS 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 "android.hardware.biometrics.fingerprint@2.3-service.samsung"
#include <android-base/logging.h>
#include <hardware/hw_auth_token.h>
#include <hardware/fingerprint.h>
#include <hardware/hardware.h>
#include "BiometricsFingerprint.h"
#include <dlfcn.h>
#include <inttypes.h>
#include <unistd.h>
#include <fstream>
#ifdef HAS_FINGERPRINT_GESTURES
#include <fcntl.h>
#endif
namespace android {
namespace hardware {
namespace biometrics {
namespace fingerprint {
namespace V2_3 {
namespace implementation {
using RequestStatus = android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
BiometricsFingerprint* BiometricsFingerprint::sInstance = nullptr;
BiometricsFingerprint::BiometricsFingerprint() : mClientCallback(nullptr) {
sInstance = this; // keep track of the most recent instance
if (!openHal()) {
LOG(ERROR) << "Can't open HAL module";
}
#ifdef HAS_FINGERPRINT_GESTURES
request(FINGERPRINT_REQUEST_NAVIGATION_MODE_START, 1);
uinputFd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (uinputFd < 0) {
LOG(ERROR) << "Unable to open uinput node";
return;
}
int err = ioctl(uinputFd, UI_SET_EVBIT, EV_KEY) | ioctl(uinputFd, UI_SET_KEYBIT, KEY_UP) |
ioctl(uinputFd, UI_SET_KEYBIT, KEY_DOWN);
if (err != 0) {
LOG(ERROR) << "Unable to enable key events";
return;
}
sprintf(uidev.name, "uinput-sec-fp");
uidev.id.bustype = BUS_VIRTUAL;
err = write(uinputFd, &uidev, sizeof(uidev));
if (err < 0) {
LOG(ERROR) << "Write user device to uinput node failed";
return;
}
err = ioctl(uinputFd, UI_DEV_CREATE);
if (err < 0) {
LOG(ERROR) << "Unable to create uinput device";
return;
}
LOG(INFO) << "Successfully registered uinput-sec-fp for fingerprint gestures";
#endif
}
BiometricsFingerprint::~BiometricsFingerprint() {
if (ss_fingerprint_close() != 0) {
LOG(ERROR) << "Can't close HAL module";
}
}
Return<bool> BiometricsFingerprint::isUdfps(uint32_t) {
std::ifstream in("/sys/devices/virtual/fingerprint/fingerprint/position");
if (in) {
in.close();
return true;
}
return false;
}
Return<void> BiometricsFingerprint::onFingerDown(uint32_t, uint32_t, float, float) {
return Void();
}
Return<void> BiometricsFingerprint::onFingerUp() {
return Void();
}
Return<RequestStatus> BiometricsFingerprint::ErrorFilter(int32_t error) {
switch (error) {
case 0:
return RequestStatus::SYS_OK;
case -2:
return RequestStatus::SYS_ENOENT;
case -4:
return RequestStatus::SYS_EINTR;
case -5:
return RequestStatus::SYS_EIO;
case -11:
return RequestStatus::SYS_EAGAIN;
case -12:
return RequestStatus::SYS_ENOMEM;
case -13:
return RequestStatus::SYS_EACCES;
case -14:
return RequestStatus::SYS_EFAULT;
case -16:
return RequestStatus::SYS_EBUSY;
case -22:
return RequestStatus::SYS_EINVAL;
case -28:
return RequestStatus::SYS_ENOSPC;
case -110:
return RequestStatus::SYS_ETIMEDOUT;
default:
LOG(ERROR) << "An unknown error returned from fingerprint vendor library: " << error;
return RequestStatus::SYS_UNKNOWN;
}
}
// Translate from errors returned by traditional HAL (see fingerprint.h) to
// HIDL-compliant FingerprintError.
FingerprintError BiometricsFingerprint::VendorErrorFilter(int32_t error, int32_t* vendorCode) {
*vendorCode = 0;
switch (error) {
case FINGERPRINT_ERROR_HW_UNAVAILABLE:
return FingerprintError::ERROR_HW_UNAVAILABLE;
case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
return FingerprintError::ERROR_UNABLE_TO_PROCESS;
case FINGERPRINT_ERROR_TIMEOUT:
return FingerprintError::ERROR_TIMEOUT;
case FINGERPRINT_ERROR_NO_SPACE:
return FingerprintError::ERROR_NO_SPACE;
case FINGERPRINT_ERROR_CANCELED:
return FingerprintError::ERROR_CANCELED;
case FINGERPRINT_ERROR_UNABLE_TO_REMOVE:
return FingerprintError::ERROR_UNABLE_TO_REMOVE;
case FINGERPRINT_ERROR_LOCKOUT:
return FingerprintError::ERROR_LOCKOUT;
default:
if (error >= FINGERPRINT_ERROR_VENDOR_BASE) {
// vendor specific code.
*vendorCode = error - FINGERPRINT_ERROR_VENDOR_BASE;
return FingerprintError::ERROR_VENDOR;
}
}
LOG(ERROR) << "Unknown error from fingerprint vendor library: " << error;
return FingerprintError::ERROR_UNABLE_TO_PROCESS;
}
// Translate acquired messages returned by traditional HAL (see fingerprint.h)
// to HIDL-compliant FingerprintAcquiredInfo.
FingerprintAcquiredInfo BiometricsFingerprint::VendorAcquiredFilter(int32_t info,
int32_t* vendorCode) {
*vendorCode = 0;
switch (info) {
case FINGERPRINT_ACQUIRED_GOOD:
return FingerprintAcquiredInfo::ACQUIRED_GOOD;
case FINGERPRINT_ACQUIRED_PARTIAL:
return FingerprintAcquiredInfo::ACQUIRED_PARTIAL;
case FINGERPRINT_ACQUIRED_INSUFFICIENT:
return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT;
case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
return FingerprintAcquiredInfo::ACQUIRED_IMAGER_DIRTY;
case FINGERPRINT_ACQUIRED_TOO_SLOW:
return FingerprintAcquiredInfo::ACQUIRED_TOO_SLOW;
case FINGERPRINT_ACQUIRED_TOO_FAST:
return FingerprintAcquiredInfo::ACQUIRED_TOO_FAST;
default:
if (info >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
// vendor specific code.
*vendorCode = info - FINGERPRINT_ACQUIRED_VENDOR_BASE;
return FingerprintAcquiredInfo::ACQUIRED_VENDOR;
}
}
LOG(ERROR) << "Unknown acquiredmsg from fingerprint vendor library: " << info;
return FingerprintAcquiredInfo::ACQUIRED_INSUFFICIENT;
}
Return<uint64_t> BiometricsFingerprint::setNotify(
const sp<IBiometricsFingerprintClientCallback>& clientCallback) {
std::lock_guard<std::mutex> lock(mClientCallbackMutex);
mClientCallback = clientCallback;
// This is here because HAL 2.3 doesn't have a way to propagate a
// unique token for its driver. Subsequent versions should send a unique
// token for each call to setNotify(). This is fine as long as there's only
// one fingerprint device on the platform.
return reinterpret_cast<uint64_t>(this);
}
Return<uint64_t> BiometricsFingerprint::preEnroll() {
return ss_fingerprint_pre_enroll();
}
Return<RequestStatus> BiometricsFingerprint::enroll(const hidl_array<uint8_t, 69>& hat,
uint32_t gid, uint32_t timeoutSec) {
const hw_auth_token_t* authToken = reinterpret_cast<const hw_auth_token_t*>(hat.data());
return ErrorFilter(ss_fingerprint_enroll(authToken, gid, timeoutSec));
}
Return<RequestStatus> BiometricsFingerprint::postEnroll() {
return ErrorFilter(ss_fingerprint_post_enroll());
}
Return<uint64_t> BiometricsFingerprint::getAuthenticatorId() {
return ss_fingerprint_get_auth_id();
}
Return<RequestStatus> BiometricsFingerprint::cancel() {
int32_t ret = ss_fingerprint_cancel();
#ifdef CALL_NOTIFY_ON_CANCEL
if (ret == 0) {
fingerprint_msg_t msg{};
msg.type = FINGERPRINT_ERROR;
msg.data.error = FINGERPRINT_ERROR_CANCELED;
notify(&msg);
}
#endif
return ErrorFilter(ret);
}
Return<RequestStatus> BiometricsFingerprint::enumerate() {
if (ss_fingerprint_enumerate != nullptr) {
return ErrorFilter(ss_fingerprint_enumerate());
}
return RequestStatus::SYS_UNKNOWN;
}
Return<RequestStatus> BiometricsFingerprint::remove(uint32_t gid, uint32_t fid) {
return ErrorFilter(ss_fingerprint_remove(gid, fid));
}
Return<RequestStatus> BiometricsFingerprint::setActiveGroup(uint32_t gid,
const hidl_string& storePath) {
if (storePath.size() >= PATH_MAX || storePath.size() <= 0) {
LOG(ERROR) << "Bad path length: " << storePath.size();
return RequestStatus::SYS_EINVAL;
}
if (access(storePath.c_str(), W_OK)) {
return RequestStatus::SYS_EINVAL;
}
return ErrorFilter(ss_fingerprint_set_active_group(gid, storePath.c_str()));
}
Return<RequestStatus> BiometricsFingerprint::authenticate(uint64_t operationId, uint32_t gid) {
return ErrorFilter(ss_fingerprint_authenticate(operationId, gid));
}
IBiometricsFingerprint* BiometricsFingerprint::getInstance() {
if (!sInstance) {
sInstance = new BiometricsFingerprint();
}
return sInstance;
}
bool BiometricsFingerprint::openHal() {
void* handle = dlopen("libbauthserver.so", RTLD_NOW);
if (handle) {
int err;
ss_fingerprint_close = reinterpret_cast<typeof(ss_fingerprint_close)>(
dlsym(handle, "ss_fingerprint_close"));
ss_fingerprint_open =
reinterpret_cast<typeof(ss_fingerprint_open)>(dlsym(handle, "ss_fingerprint_open"));
ss_set_notify_callback = reinterpret_cast<typeof(ss_set_notify_callback)>(
dlsym(handle, "ss_set_notify_callback"));
ss_fingerprint_pre_enroll = reinterpret_cast<typeof(ss_fingerprint_pre_enroll)>(
dlsym(handle, "ss_fingerprint_pre_enroll"));
ss_fingerprint_enroll = reinterpret_cast<typeof(ss_fingerprint_enroll)>(
dlsym(handle, "ss_fingerprint_enroll"));
ss_fingerprint_post_enroll = reinterpret_cast<typeof(ss_fingerprint_post_enroll)>(
dlsym(handle, "ss_fingerprint_post_enroll"));
ss_fingerprint_get_auth_id = reinterpret_cast<typeof(ss_fingerprint_get_auth_id)>(
dlsym(handle, "ss_fingerprint_get_auth_id"));
ss_fingerprint_cancel = reinterpret_cast<typeof(ss_fingerprint_cancel)>(
dlsym(handle, "ss_fingerprint_cancel"));
ss_fingerprint_enumerate = reinterpret_cast<typeof(ss_fingerprint_enumerate)>(
dlsym(handle, "ss_fingerprint_enumerate"));
ss_fingerprint_remove = reinterpret_cast<typeof(ss_fingerprint_remove)>(
dlsym(handle, "ss_fingerprint_remove"));
ss_fingerprint_set_active_group = reinterpret_cast<typeof(ss_fingerprint_set_active_group)>(
dlsym(handle, "ss_fingerprint_set_active_group"));
ss_fingerprint_authenticate = reinterpret_cast<typeof(ss_fingerprint_authenticate)>(
dlsym(handle, "ss_fingerprint_authenticate"));
ss_fingerprint_request = reinterpret_cast<typeof(ss_fingerprint_request)>(
dlsym(handle, "ss_fingerprint_request"));
if ((err = ss_fingerprint_open(nullptr)) != 0) {
LOG(ERROR) << "Can't open fingerprint, error: " << err;
return false;
}
if ((err = ss_set_notify_callback(BiometricsFingerprint::notify)) != 0) {
LOG(ERROR) << "Can't register fingerprint module callback, error: " << err;
return false;
}
return true;
}
return false;
}
void BiometricsFingerprint::notify(const fingerprint_msg_t* msg) {
BiometricsFingerprint* thisPtr =
static_cast<BiometricsFingerprint*>(BiometricsFingerprint::getInstance());
std::lock_guard<std::mutex> lock(thisPtr->mClientCallbackMutex);
if (thisPtr == nullptr || thisPtr->mClientCallback == nullptr) {
LOG(ERROR) << "Receiving callbacks before the client callback is registered.";
return;
}
const uint64_t devId = 1;
switch (msg->type) {
case FINGERPRINT_ERROR: {
int32_t vendorCode = 0;
FingerprintError result = VendorErrorFilter(msg->data.error, &vendorCode);
LOG(DEBUG) << "onError(" << static_cast<int>(result) << ")";
if (!thisPtr->mClientCallback->onError(devId, result, vendorCode).isOk()) {
LOG(ERROR) << "failed to invoke fingerprint onError callback";
}
} break;
case FINGERPRINT_ACQUIRED: {
if (msg->data.acquired.acquired_info > SEM_FINGERPRINT_EVENT_BASE) {
thisPtr->handleEvent(msg->data.acquired.acquired_info);
return;
}
int32_t vendorCode = 0;
FingerprintAcquiredInfo result =
VendorAcquiredFilter(msg->data.acquired.acquired_info, &vendorCode);
LOG(DEBUG) << "onAcquired(" << static_cast<int>(result) << ")";
if (!thisPtr->mClientCallback->onAcquired(devId, result, vendorCode).isOk()) {
LOG(ERROR) << "failed to invoke fingerprint onAcquired callback";
}
} break;
case FINGERPRINT_TEMPLATE_ENROLLING:
#ifdef USES_PERCENTAGE_SAMPLES
const_cast<fingerprint_msg_t*>(msg)->data.enroll.samples_remaining =
100 - msg->data.enroll.samples_remaining;
#endif
#ifdef CALL_CANCEL_ON_ENROLL_COMPLETION
if (msg->data.enroll.samples_remaining == 0) {
thisPtr->ss_fingerprint_cancel();
}
#endif
LOG(DEBUG) << "onEnrollResult(fid=" << msg->data.enroll.finger.fid
<< ", gid=" << msg->data.enroll.finger.gid
<< ", rem=" << msg->data.enroll.samples_remaining << ")";
if (!thisPtr->mClientCallback
->onEnrollResult(devId, msg->data.enroll.finger.fid,
msg->data.enroll.finger.gid,
msg->data.enroll.samples_remaining)
.isOk()) {
LOG(ERROR) << "failed to invoke fingerprint onEnrollResult callback";
}
break;
case FINGERPRINT_TEMPLATE_REMOVED:
LOG(DEBUG) << "onRemove(fid=" << msg->data.removed.finger.fid
<< ", gid=" << msg->data.removed.finger.gid
<< ", rem=" << msg->data.removed.remaining_templates << ")";
if (!thisPtr->mClientCallback
->onRemoved(devId, msg->data.removed.finger.fid,
msg->data.removed.finger.gid,
msg->data.removed.remaining_templates)
.isOk()) {
LOG(ERROR) << "failed to invoke fingerprint onRemoved callback";
}
break;
case FINGERPRINT_AUTHENTICATED:
LOG(DEBUG) << "onAuthenticated(fid=" << msg->data.authenticated.finger.fid
<< ", gid=" << msg->data.authenticated.finger.gid << ")";
if (msg->data.authenticated.finger.fid != 0) {
const uint8_t* hat = reinterpret_cast<const uint8_t*>(&msg->data.authenticated.hat);
const hidl_vec<uint8_t> token(
std::vector<uint8_t>(hat, hat + sizeof(msg->data.authenticated.hat)));
if (!thisPtr->mClientCallback
->onAuthenticated(devId, msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid, token)
.isOk()) {
LOG(ERROR) << "failed to invoke fingerprint onAuthenticated callback";
}
} else {
// Not a recognized fingerprint
if (!thisPtr->mClientCallback
->onAuthenticated(devId, msg->data.authenticated.finger.fid,
msg->data.authenticated.finger.gid,
hidl_vec<uint8_t>())
.isOk()) {
LOG(ERROR) << "failed to invoke fingerprint onAuthenticated callback";
}
}
break;
case FINGERPRINT_TEMPLATE_ENUMERATING:
LOG(DEBUG) << "onEnumerate(fid=" << msg->data.enumerated.finger.fid
<< ", gid=" << msg->data.enumerated.finger.gid
<< ", rem=" << msg->data.enumerated.remaining_templates << ")";
if (!thisPtr->mClientCallback
->onEnumerate(devId, msg->data.enumerated.finger.fid,
msg->data.enumerated.finger.gid,
msg->data.enumerated.remaining_templates)
.isOk()) {
LOG(ERROR) << "failed to invoke fingerprint onEnumerate callback";
}
break;
}
}
void BiometricsFingerprint::handleEvent(int eventCode) {
switch (eventCode) {
#ifdef HAS_FINGERPRINT_GESTURES
case SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_DOWN:
case SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_UP:
struct input_event event {};
int keycode = eventCode == SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_UP ? KEY_UP : KEY_DOWN;
int err;
// Report the key
event.type = EV_KEY;
event.code = keycode;
event.value = 1;
err = write(uinputFd, &event, sizeof(event));
if (err < 0) {
LOG(ERROR) << "Write EV_KEY to uinput node failed";
return;
}
// Force a flush with an EV_SYN
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
err = write(uinputFd, &event, sizeof(event));
if (err < 0) {
LOG(ERROR) << "Write EV_SYN to uinput node failed";
return;
}
// Report the key
event.type = EV_KEY;
event.code = keycode;
event.value = 0;
err = write(uinputFd, &event, sizeof(event));
if (err < 0) {
LOG(ERROR) << "Write EV_KEY to uinput node failed";
return;
}
// Force a flush with an EV_SYN
event.type = EV_SYN;
event.code = SYN_REPORT;
event.value = 0;
err = write(uinputFd, &event, sizeof(event));
if (err < 0) {
LOG(ERROR) << "Write EV_SYN to uinput node failed";
return;
}
break;
#endif
}
}
int BiometricsFingerprint::request(int cmd, int param) {
// TO-DO: input, output handling not implemented
int result = ss_fingerprint_request(cmd, nullptr, 0, nullptr, 0, param);
LOG(INFO) << "request(cmd=" << cmd << ", param=" << param << ", result=" << result << ")";
return result;
}
int BiometricsFingerprint::waitForSensor(std::chrono::milliseconds pollWait,
std::chrono::milliseconds timeOut) {
int sensorStatus = SEM_SENSOR_STATUS_WORKING;
std::chrono::milliseconds timeWaited = 0ms;
while (sensorStatus != SEM_SENSOR_STATUS_OK) {
if (sensorStatus == SEM_SENSOR_STATUS_CALIBRATION_ERROR ||
sensorStatus == SEM_SENSOR_STATUS_ERROR) {
return -1;
}
if (timeWaited >= timeOut) {
return -2;
}
sensorStatus = request(FINGERPRINT_REQUEST_GET_SENSOR_STATUS, 0);
std::this_thread::sleep_for(pollWait);
timeWaited += pollWait;
}
return 0;
}
} // namespace implementation
} // namespace V2_3
} // namespace fingerprint
} // namespace biometrics
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,126 @@
/*
* Copyright (C) 2019 The LineageOS 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_HARDWARE_BIOMETRICS_FINGERPRINT_V2_3_BIOMETRICSFINGERPRINT_H
#define ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_3_BIOMETRICSFINGERPRINT_H
#include <chrono>
#include <thread>
#ifdef HAS_FINGERPRINT_GESTURES
#include <linux/uinput.h>
#endif
#include <android/hardware/biometrics/fingerprint/2.1/types.h>
#include <android/hardware/biometrics/fingerprint/2.3/IBiometricsFingerprint.h>
#include <hardware/fingerprint.h>
#include <hardware/hardware.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include "VendorConstants.h"
namespace android {
namespace hardware {
namespace biometrics {
namespace fingerprint {
namespace V2_3 {
namespace implementation {
using namespace std::chrono_literals;
using ::android::sp;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::biometrics::fingerprint::V2_1::FingerprintAcquiredInfo;
using ::android::hardware::biometrics::fingerprint::V2_1::FingerprintError;
using ::android::hardware::biometrics::fingerprint::V2_1::IBiometricsFingerprintClientCallback;
using ::android::hardware::biometrics::fingerprint::V2_1::RequestStatus;
using ::android::hardware::biometrics::fingerprint::V2_3::IBiometricsFingerprint;
struct BiometricsFingerprint : public IBiometricsFingerprint {
BiometricsFingerprint();
~BiometricsFingerprint();
// Method to wrap legacy HAL with BiometricsFingerprint class
static IBiometricsFingerprint* getInstance();
// Methods from ::android::hardware::biometrics::fingerprint::V2_3::IBiometricsFingerprint
// follow.
Return<uint64_t> setNotify(
const sp<IBiometricsFingerprintClientCallback>& clientCallback) override;
Return<uint64_t> preEnroll() override;
Return<RequestStatus> enroll(const hidl_array<uint8_t, 69>& hat, uint32_t gid,
uint32_t timeoutSec) override;
Return<RequestStatus> postEnroll() override;
Return<uint64_t> getAuthenticatorId() override;
Return<RequestStatus> cancel() override;
Return<RequestStatus> enumerate() override;
Return<RequestStatus> remove(uint32_t gid, uint32_t fid) override;
Return<RequestStatus> setActiveGroup(uint32_t gid, const hidl_string& storePath) override;
Return<RequestStatus> authenticate(uint64_t operationId, uint32_t gid) override;
Return<bool> isUdfps(uint32_t sensorID) override;
Return<void> onFingerDown(uint32_t x, uint32_t y, float minor, float major) override;
Return<void> onFingerUp() override;
Return<void> onShowUdfpsOverlay() { return Void(); }
Return<void> onHideUdfpsOverlay() { return Void(); }
private:
bool openHal();
int request(int cmd, int param);
int waitForSensor(std::chrono::milliseconds pollWait, std::chrono::milliseconds timeOut);
static void notify(
const fingerprint_msg_t* msg); /* Static callback for legacy HAL implementation */
void handleEvent(int eventCode);
static Return<RequestStatus> ErrorFilter(int32_t error);
static FingerprintError VendorErrorFilter(int32_t error, int32_t* vendorCode);
static FingerprintAcquiredInfo VendorAcquiredFilter(int32_t error, int32_t* vendorCode);
static BiometricsFingerprint* sInstance;
std::mutex mClientCallbackMutex;
sp<IBiometricsFingerprintClientCallback> mClientCallback;
#ifdef HAS_FINGERPRINT_GESTURES
int uinputFd;
struct uinput_user_dev uidev {};
#endif
int (*ss_fingerprint_close)();
int (*ss_fingerprint_open)(const char* id);
int (*ss_set_notify_callback)(fingerprint_notify_t notify);
uint64_t (*ss_fingerprint_pre_enroll)();
int (*ss_fingerprint_enroll)(const hw_auth_token_t* hat, uint32_t gid, uint32_t timeout_sec);
int (*ss_fingerprint_post_enroll)();
uint64_t (*ss_fingerprint_get_auth_id)();
int (*ss_fingerprint_cancel)();
int (*ss_fingerprint_enumerate)();
int (*ss_fingerprint_remove)(uint32_t gid, uint32_t fid);
int (*ss_fingerprint_set_active_group)(uint32_t gid, const char* store_path);
int (*ss_fingerprint_authenticate)(uint64_t operation_id, uint32_t gid);
int (*ss_fingerprint_request)(uint32_t cmd, char* inBuf, uint32_t inBuf_length, char* outBuf,
uint32_t outBuf_length, uint32_t param);
};
} // namespace implementation
} // namespace V2_3
} // namespace fingerprint
} // namespace biometrics
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_BIOMETRICS_FINGERPRINT_V2_3_BIOMETRICSFINGERPRINT_H

View file

@ -0,0 +1,104 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2020 The LineageOS Project
#ifndef SAMSUNG_FINGERPRINT_CONSTANTS_H
#define SAMSUNG_FINGERPRINT_CONSTANTS_H
// Fingerprint requests
#define FINGERPRINT_REQUEST_ENROLL_SESSION 1002
#define FINGERPRINT_REQUEST_ENROLL_TYPE 18
#define FINGERPRINT_REQUEST_ENUMERATE 11
#define FINGERPRINT_REQUEST_GET_FP_IDS 1003
#define FINGERPRINT_REQUEST_GET_MAX_TEMPLATE_NUMBER 1004
#define FINGERPRINT_REQUEST_GET_SENSOR_INFO 5
#define FINGERPRINT_REQUEST_GET_SENSOR_STATUS 6
#define FINGERPRINT_REQUEST_GET_TOUCH_CNT 1007
#define FINGERPRINT_REQUEST_GET_UNIQUE_ID 7
#define FINGERPRINT_REQUEST_GET_USERIDS 12
#define FINGERPRINT_REQUEST_GET_VERSION 4
#define FINGERPRINT_REQUEST_HAS_FEATURE 1006
#define FINGERPRINT_REQUEST_LOCKOUT 1001
#define FINGERPRINT_REQUEST_NAVIGATION_LCD_ONOFF 17
#define FINGERPRINT_REQUEST_NAVIGATION_MODE_END 16
#define FINGERPRINT_REQUEST_NAVIGATION_MODE_START 15
#define FINGERPRINT_REQUEST_PAUSE 0
#define FINGERPRINT_REQUEST_PROCESS_FIDO 9
#define FINGERPRINT_REQUEST_REMOVE_FINGER 1000
#define FINGERPRINT_REQUEST_RESUME 1
#define FINGERPRINT_REQUEST_SENSOR_TEST_NORMALSCAN 3
#define FINGERPRINT_REQUEST_SESSION_OPEN 2
#define FINGERPRINT_REQUEST_SET_ACTIVE_GROUP 8
#define FINGERPRINT_REQUEST_UPDATE_SID 10
#define SEM_REQUEST_FORCE_CBGE 21
#define SEM_REQUEST_GET_FINGER_ICON_REMAIN_TIME 1010
#define SEM_REQUEST_GET_SECURITY_LEVEL 30
#define SEM_REQUEST_GET_SENSOR_TEST_RESULT 19
#define SEM_REQUEST_GET_TA_VERSION 10000
#define SEM_REQUEST_GET_TSP_BLOCK_STATUS 0x3F9
#define SEM_REQUEST_HIDE_INDISPLAY_AUTH_ANIMATION 0x3F4
#define SEM_REQUEST_INSTALL_TA 10001
#define SEM_REQUEST_IS_NEW_MATCHER 27
#define SEM_REQUEST_IS_TEMPLATE_CHANGED 25
#define SEM_REQUEST_MASK_CTL 0x3F5
#define SEM_REQUEST_MOVE_INDISPLAY_ICON 0x3F3
#define SEM_REQUEST_OPTICAL_CALIBRATION 0x3F8
#define SEM_REQUEST_REMOVE_ALL_USER 0x3F6
#define SEM_REQUEST_SET_ASP_LEVEL 20
#define SEM_REQUEST_SET_BOUNCER_SCREEN_STATUS 0x3FA
#define SEM_REQUEST_SET_SCREEN_STATUS 0x3F0
#define SEM_REQUEST_SHOW_INDISPLAY_AUTH_ANIMATION 1009
#define SEM_REQUEST_TOUCH_EVENT 22
#define SEM_REQUEST_TOUCH_SENSITIVE_CHANGE 0x3F7
#define SEM_REQUEST_UPDATE_MATCHER 28
#define SEM_REQUEST_VENDOR_EGIS_CALIBRATION 23
#define SEM_REQUEST_VENDOR_QCOM_REMOVE_CBGE 24
#define SEM_REQUEST_WIRELESS_CHARGER_STATUS 29
// Fingerprint aquired codes
#define SEM_FINGERPRINT_ACQUIRED_DUPLICATED_IMAGE 1002
#define SEM_FINGERPRINT_ACQUIRED_LIGHT_TOUCH 1003
#define SEM_FINGERPRINT_ACQUIRED_TSP_BLOCK 1004
#define SEM_FINGERPRINT_ACQUIRED_TSP_UNBLOCK 1005
#define SEM_FINGERPRINT_ACQUIRED_WET_FINGER 1001
// Fingerprint errors
#define SEM_FINGERPRINT_ERROR_CALIBRATION 1001
#define SEM_FINGERPRINT_ERROR_DISABLED_BIOMETRICS 5002
#define SEM_FINGERPRINT_ERROR_INVALID_HW 1005
#define SEM_FINGERPRINT_ERROR_NEED_TO_RETRY 5000
#define SEM_FINGERPRINT_ERROR_ONE_HAND_MODE 5001
#define SEM_FINGERPRINT_ERROR_PATTERN_DETECTED 1007
#define SEM_FINGERPRINT_ERROR_SERVICE_FAILURE 1003
#define SEM_FINGERPRINT_ERROR_SMART_VIEW 5003
#define SEM_FINGERPRINT_ERROR_SYSTEM_FAILURE 1002
#define SEM_FINGERPRINT_ERROR_TA_UPDATE -100
#define SEM_FINGERPRINT_ERROR_TEMPLATE_CORRUPTED 1004
#define SEM_FINGERPRINT_ERROR_TEMPLATE_FORMAT_CHANGED 1006
#define SEM_FINGERPRINT_ERROR_WIRELESS_CHARGING 5004
// Fingerprint events
#define SEM_FINGERPRINT_EVENT_BASE 10000
#define SEM_FINGERPRINT_EVENT_CAPTURE_COMPLETED 10003
#define SEM_FINGERPRINT_EVENT_CAPTURE_FAILED 10006
#define SEM_FINGERPRINT_EVENT_CAPTURE_READY 10001
#define SEM_FINGERPRINT_EVENT_CAPTURE_STARTED 10002
#define SEM_FINGERPRINT_EVENT_CAPTURE_SUCCESS 10005
#define SEM_FINGERPRINT_EVENT_FACTORY_SNSR_SCRIPT_END 10009
#define SEM_FINGERPRINT_EVENT_FACTORY_SNSR_SCRIPT_START 10008
#define SEM_FINGERPRINT_EVENT_FINGER_LEAVE 10004
#define SEM_FINGERPRINT_EVENT_FINGER_LEAVE_TIMEOUT 10007
#define SEM_FINGERPRINT_EVENT_GESTURE_DTAP 20003
#define SEM_FINGERPRINT_EVENT_GESTURE_LPRESS 20004
#define SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_DOWN 20002
#define SEM_FINGERPRINT_EVENT_GESTURE_SWIPE_UP 20001
#define SEM_FINGERPRINT_EVENT_SPEN_CONTROL_OFF 30002
#define SEM_FINGERPRINT_EVENT_SPEN_CONTROL_ON 30001
// Fingerprint sensor status codes
#define SEM_SENSOR_STATUS_CALIBRATION_ERROR 100045
#define SEM_SENSOR_STATUS_ERROR 100042
#define SEM_SENSOR_STATUS_OK 100040
#define SEM_SENSOR_STATUS_WORKING 100041
#endif // SAMSUNG_FINGERPRINT_CONSTANTS_H

View file

@ -0,0 +1,8 @@
service vendor.fps_hal /vendor/bin/hw/android.hardware.biometrics.fingerprint@2.3-service.samsung
# "class hal" causes a race condition on some devices due to files created
# in /data. As a workaround, postpone startup until later in boot once
# /data is mounted.
class late_start
user system
group system input uhid
writepid /dev/cpuset/system-background/tasks

View file

@ -0,0 +1,11 @@
<manifest version="1.0" type="device">
<hal format="hidl" override="true">
<name>android.hardware.biometrics.fingerprint</name>
<transport>hwbinder</transport>
<version>2.3</version>
<interface>
<name>IBiometricsFingerprint</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View file

@ -0,0 +1,51 @@
/*
* Copyright (C) 2019 The LineageOS 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 "android.hardware.biometrics.fingerprint@2.3-service.samsung"
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/Errors.h>
#include "BiometricsFingerprint.h"
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::biometrics::fingerprint::V2_3::IBiometricsFingerprint;
using android::hardware::biometrics::fingerprint::V2_3::implementation::BiometricsFingerprint;
using android::OK;
using android::sp;
int main() {
android::sp<IBiometricsFingerprint> bio = BiometricsFingerprint::getInstance();
configureRpcThreadpool(1, true);
if (bio == nullptr || bio->registerAsService() != OK) {
LOG(ERROR) << "Could not register service for Fingerprint HAL";
goto shutdown;
}
LOG(INFO) << "Fingerprint HAL service is Ready.";
joinRpcThreadpool();
shutdown:
// In normal operation, we don't expect the thread pool to shutdown
LOG(ERROR) << "Fingerprint HAL failed to join thread pool.";
return 1;
}

View file

@ -0,0 +1,42 @@
#
# Copyright (C) 2019 The LineageOS 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.
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
service.cpp
LOCAL_SHARED_LIBRARIES := \
android.hardware.keymaster@4.0 \
libbase \
libcutils \
libhardware \
libhidlbase \
libkeymaster4 \
liblog \
libskeymaster4device \
libutils
LOCAL_MODULE := android.hardware.keymaster@4.0-service.samsung
LOCAL_INIT_RC := android.hardware.keymaster@4.0-service.samsung.rc
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_OWNER := samsung
LOCAL_VENDOR_MODULE := true
include $(BUILD_EXECUTABLE)

View file

@ -0,0 +1,8 @@
service vendor.keymaster-4-0 /vendor/bin/hw/android.hardware.keymaster@4.0-service.samsung
class early_hal
user system
group system drmrpc
on post-fs-data
mkdir /mnt/vendor/efs/DAK 0775 system system
restorecon -R /mnt/vendor/efs/DAK

View file

@ -0,0 +1,58 @@
/*
* Copyright 2019 The LineageOS 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 "android.hardware.keymaster@4.0-service.samsung"
#include <android-base/logging.h>
#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
#include <hidl/HidlTransportSupport.h>
#include <AndroidKeymaster4Device.h>
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
using android::hardware::keymaster::V4_0::IKeymasterDevice;
using android::hardware::keymaster::V4_0::SecurityLevel;
using android::OK;
using android::status_t;
namespace skeymaster {
IKeymasterDevice* CreateSKeymasterDevice(SecurityLevel securityLevel);
} // namespace skeymaster
int main() {
IKeymasterDevice* keymaster =
skeymaster::CreateSKeymasterDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
configureRpcThreadpool(1, true);
status_t status = keymaster->registerAsService();
if (status != OK) {
LOG(ERROR) << "Could not register service for Keymaster HAL";
goto shutdown;
}
LOG(INFO) << "Keymaster HAL service is Ready.";
joinRpcThreadpool();
shutdown:
// In normal operation, we don't expect the thread pool to shutdown
LOG(ERROR) << "Keymaster HAL failed to join thread pool.";
return -1;
}

View file

@ -0,0 +1,20 @@
cc_library_shared {
name: "android.hardware.sensors@1.0-impl.samsung",
defaults: ["hidl_defaults"],
proprietary: true,
relative_install_path: "hw",
srcs: ["Sensors.cpp"],
shared_libs: [
"liblog",
"libcutils",
"libhardware",
"libbase",
"libutils",
"libhidlbase",
"android.hardware.sensors@1.0",
],
static_libs: [
"android.hardware.sensors@1.0-convert",
"multihal",
],
}

View file

@ -0,0 +1,354 @@
/*
* 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 VERBOSE
#include "Sensors.h"
#include <sensors/convert.h>
#include "multihal.h"
#include <android-base/logging.h>
#include <sys/stat.h>
namespace android {
namespace hardware {
namespace sensors {
namespace V1_0 {
namespace implementation {
/*
* If a multi-hal configuration file exists in the proper location,
* return true indicating we need to use multi-hal functionality.
*/
static bool UseMultiHal() {
const std::string& name = MULTI_HAL_CONFIG_FILE_PATH;
struct stat buffer;
return (stat(name.c_str(), &buffer) == 0);
}
static Result ResultFromStatus(status_t err) {
switch (err) {
case OK:
return Result::OK;
case PERMISSION_DENIED:
return Result::PERMISSION_DENIED;
case NO_MEMORY:
return Result::NO_MEMORY;
case BAD_VALUE:
return Result::BAD_VALUE;
default:
return Result::INVALID_OPERATION;
}
}
Sensors::Sensors() : mInitCheck(NO_INIT), mSensorModule(nullptr), mSensorDevice(nullptr) {
status_t err = OK;
if (UseMultiHal()) {
mSensorModule = ::get_multi_hal_module_info();
} else {
err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&mSensorModule);
}
if (mSensorModule == NULL) {
err = UNKNOWN_ERROR;
}
if (err != OK) {
LOG(ERROR) << "Couldn't load " << SENSORS_HARDWARE_MODULE_ID << " module ("
<< strerror(-err) << ")";
mInitCheck = err;
return;
}
err = sensors_open_1(&mSensorModule->common, &mSensorDevice);
if (err != OK) {
LOG(ERROR) << "Couldn't open device for module " << SENSORS_HARDWARE_MODULE_ID << " ("
<< strerror(-err) << ")";
mInitCheck = err;
return;
}
// Require all the old HAL APIs to be present except for injection, which
// is considered optional.
CHECK_GE(getHalDeviceVersion(), SENSORS_DEVICE_API_VERSION_1_3);
if (getHalDeviceVersion() == SENSORS_DEVICE_API_VERSION_1_4) {
if (mSensorDevice->inject_sensor_data == nullptr) {
LOG(ERROR) << "HAL specifies version 1.4, but does not implement inject_sensor_data()";
}
if (mSensorModule->set_operation_mode == nullptr) {
LOG(ERROR) << "HAL specifies version 1.4, but does not implement set_operation_mode()";
}
}
/* Get us all sensors */
setOperationMode(static_cast<hardware::sensors::V1_0::OperationMode>(5555));
mInitCheck = OK;
}
status_t Sensors::initCheck() const {
return mInitCheck;
}
Return<void> Sensors::getSensorsList(getSensorsList_cb _hidl_cb) {
sensor_t const* list;
size_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
hidl_vec<SensorInfo> out;
out.resize(count);
for (size_t i = 0; i < count; ++i) {
const sensor_t* src = &list[i];
SensorInfo* dst = &out[i];
convertFromSensor(*src, dst);
if (dst->requiredPermission == "com.samsung.permission.SSENSOR") {
dst->requiredPermission = "";
}
if (dst->typeAsString == "com.samsung.sensor.physical_proximity") {
LOG(INFO) << "Fixing com.samsung.sensor.physical_proximity";
dst->type = SensorType::PROXIMITY;
dst->typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
dst->maxRange = 1;
}
#ifdef VERBOSE
LOG(INFO) << "SENSOR NAME: " << dst->name;
LOG(INFO) << " VENDOR: " << dst->name;
LOG(INFO) << " TYPE: " << (uint32_t)dst->type;
LOG(INFO) << " TYPE_AS_STRING: " << dst->typeAsString;
LOG(INFO) << " FLAGS: " << std::hex << dst->flags;
LOG(INFO) << "";
#endif
}
_hidl_cb(out);
return Void();
}
int Sensors::getHalDeviceVersion() const {
if (!mSensorDevice) {
return -1;
}
return mSensorDevice->common.version;
}
Return<Result> Sensors::setOperationMode(OperationMode mode) {
if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4 ||
mSensorModule->set_operation_mode == nullptr) {
return Result::INVALID_OPERATION;
}
return ResultFromStatus(mSensorModule->set_operation_mode((uint32_t)mode));
}
Return<Result> Sensors::activate(int32_t sensor_handle, bool enabled) {
return ResultFromStatus(mSensorDevice->activate(
reinterpret_cast<sensors_poll_device_t*>(mSensorDevice), sensor_handle, enabled));
}
Return<void> Sensors::poll(int32_t maxCount, poll_cb _hidl_cb) {
hidl_vec<Event> out;
hidl_vec<SensorInfo> dynamicSensorsAdded;
std::unique_ptr<sensors_event_t[]> data;
int err = android::NO_ERROR;
{ // scope of reentry lock
// This enforces a single client, meaning that a maximum of one client can call poll().
// If this function is re-entred, it means that we are stuck in a state that may prevent
// the system from proceeding normally.
//
// Exit and let the system restart the sensor-hal-implementation hidl service.
//
// This function must not call _hidl_cb(...) or return until there is no risk of blocking.
std::unique_lock<std::mutex> lock(mPollLock, std::try_to_lock);
if (!lock.owns_lock()) {
// cannot get the lock, hidl service will go into deadlock if it is not restarted.
// This is guaranteed to not trigger in passthrough mode.
LOG(ERROR)
<< "ISensors::poll() re-entry. I do not know what to do except killing myself.";
::exit(-1);
}
if (maxCount <= 0) {
err = android::BAD_VALUE;
} else {
int bufferSize = maxCount <= kPollMaxBufferSize ? maxCount : kPollMaxBufferSize;
data.reset(new sensors_event_t[bufferSize]);
err = mSensorDevice->poll(reinterpret_cast<sensors_poll_device_t*>(mSensorDevice),
data.get(), bufferSize);
}
}
if (err < 0) {
_hidl_cb(ResultFromStatus(err), out, dynamicSensorsAdded);
return Void();
}
const size_t count = (size_t)err;
for (size_t i = 0; i < count; ++i) {
if (data[i].type != SENSOR_TYPE_DYNAMIC_SENSOR_META) {
continue;
}
const dynamic_sensor_meta_event_t* dyn = &data[i].dynamic_sensor_meta;
if (!dyn->connected) {
continue;
}
CHECK(dyn->sensor != nullptr);
CHECK_EQ(dyn->sensor->handle, dyn->handle);
SensorInfo info;
convertFromSensor(*dyn->sensor, &info);
size_t numDynamicSensors = dynamicSensorsAdded.size();
dynamicSensorsAdded.resize(numDynamicSensors + 1);
dynamicSensorsAdded[numDynamicSensors] = info;
}
out.resize(count);
convertFromSensorEvents(err, data.get(), &out);
_hidl_cb(Result::OK, out, dynamicSensorsAdded);
return Void();
}
Return<Result> Sensors::batch(int32_t sensor_handle, int64_t sampling_period_ns,
int64_t max_report_latency_ns) {
return ResultFromStatus(mSensorDevice->batch(mSensorDevice, sensor_handle, 0, /*flags*/
sampling_period_ns, max_report_latency_ns));
}
Return<Result> Sensors::flush(int32_t sensor_handle) {
return ResultFromStatus(mSensorDevice->flush(mSensorDevice, sensor_handle));
}
Return<Result> Sensors::injectSensorData(const Event& event) {
if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4 ||
mSensorDevice->inject_sensor_data == nullptr) {
return Result::INVALID_OPERATION;
}
sensors_event_t out;
convertToSensorEvent(event, &out);
return ResultFromStatus(mSensorDevice->inject_sensor_data(mSensorDevice, &out));
}
Return<void> Sensors::registerDirectChannel(const SharedMemInfo& mem,
registerDirectChannel_cb _hidl_cb) {
if (mSensorDevice->register_direct_channel == nullptr ||
mSensorDevice->config_direct_report == nullptr) {
// HAL does not support
_hidl_cb(Result::INVALID_OPERATION, -1);
return Void();
}
sensors_direct_mem_t m;
if (!convertFromSharedMemInfo(mem, &m)) {
_hidl_cb(Result::BAD_VALUE, -1);
return Void();
}
int err = mSensorDevice->register_direct_channel(mSensorDevice, &m, -1);
if (err < 0) {
_hidl_cb(ResultFromStatus(err), -1);
} else {
int32_t channelHandle = static_cast<int32_t>(err);
_hidl_cb(Result::OK, channelHandle);
}
return Void();
}
Return<Result> Sensors::unregisterDirectChannel(int32_t channelHandle) {
if (mSensorDevice->register_direct_channel == nullptr ||
mSensorDevice->config_direct_report == nullptr) {
// HAL does not support
return Result::INVALID_OPERATION;
}
mSensorDevice->register_direct_channel(mSensorDevice, nullptr, channelHandle);
return Result::OK;
}
Return<void> Sensors::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
RateLevel rate, configDirectReport_cb _hidl_cb) {
if (mSensorDevice->register_direct_channel == nullptr ||
mSensorDevice->config_direct_report == nullptr) {
// HAL does not support
_hidl_cb(Result::INVALID_OPERATION, -1);
return Void();
}
sensors_direct_cfg_t cfg = {.rate_level = convertFromRateLevel(rate)};
if (cfg.rate_level < 0) {
_hidl_cb(Result::BAD_VALUE, -1);
return Void();
}
int err = mSensorDevice->config_direct_report(mSensorDevice, sensorHandle, channelHandle, &cfg);
if (rate == RateLevel::STOP) {
_hidl_cb(ResultFromStatus(err), -1);
} else {
_hidl_cb(err > 0 ? Result::OK : ResultFromStatus(err), err);
}
return Void();
}
// static
void Sensors::convertFromSensorEvents(size_t count, const sensors_event_t* srcArray,
hidl_vec<Event>* dstVec) {
for (size_t i = 0; i < count; ++i) {
const sensors_event_t& src = srcArray[i];
Event* dst = &(*dstVec)[i];
convertFromSensorEvent(src, dst);
}
}
ISensors* HIDL_FETCH_ISensors(const char* /* hal */) {
Sensors* sensors = new Sensors;
if (sensors->initCheck() != OK) {
delete sensors;
sensors = nullptr;
return nullptr;
}
return sensors;
}
} // namespace implementation
} // namespace V1_0
} // namespace sensors
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,83 @@
/*
* 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 HARDWARE_INTERFACES_SENSORS_V1_0_SAMSUNG_SENSORS_H_
#define HARDWARE_INTERFACES_SENSORS_V1_0_SAMSUNG_SENSORS_H_
#include <android-base/macros.h>
#include <android/hardware/sensors/1.0/ISensors.h>
#include <hardware/sensors.h>
#include <mutex>
namespace android {
namespace hardware {
namespace sensors {
namespace V1_0 {
namespace implementation {
struct Sensors : public ::android::hardware::sensors::V1_0::ISensors {
Sensors();
status_t initCheck() const;
Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
Return<Result> setOperationMode(OperationMode mode) override;
Return<Result> activate(int32_t sensor_handle, bool enabled) override;
Return<void> poll(int32_t maxCount, poll_cb _hidl_cb) override;
Return<Result> batch(int32_t sensor_handle, int64_t sampling_period_ns,
int64_t max_report_latency_ns) override;
Return<Result> flush(int32_t sensor_handle) override;
Return<Result> injectSensorData(const Event& event) override;
Return<void> registerDirectChannel(const SharedMemInfo& mem,
registerDirectChannel_cb _hidl_cb) override;
Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
configDirectReport_cb _hidl_cb) override;
private:
static constexpr int32_t kPollMaxBufferSize = 128;
status_t mInitCheck;
sensors_module_t* mSensorModule;
sensors_poll_device_1_t* mSensorDevice;
std::mutex mPollLock;
int getHalDeviceVersion() const;
static void convertFromSensorEvents(size_t count, const sensors_event_t* src,
hidl_vec<Event>* dst);
DISALLOW_COPY_AND_ASSIGN(Sensors);
};
extern "C" ISensors* HIDL_FETCH_ISensors(const char* name);
} // namespace implementation
} // namespace V1_0
} // namespace sensors
} // namespace hardware
} // namespace android
#endif // HARDWARE_INTERFACES_SENSORS_V1_0_SAMSUNG_SENSORS_H_

View file

@ -0,0 +1,24 @@
//
// Copyright (C) 2021 The LineageOS 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.
//
cc_binary {
name: "secril_config_svc",
vendor: true,
srcs: ["secril_config_svc.cpp"],
shared_libs: [
"libbase",
],
}

View file

@ -0,0 +1,69 @@
/*
* Copyright (C) 2021, The LineageOS 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 "secril_config_svc"
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <fstream>
#define EFS_OLD "/efs/"
#define EFS_NEW "/mnt/vendor/efs/"
#define FACTORY_PROP "factory.prop"
#define TELEPHONY_PROP "telephony.prop"
void LoadProperties(std::string data) {
for (std::string line : android::base::Split(data, "\n")) {
if (line == "\0") break;
std::vector<std::string> parts = android::base::Split(line, "=");
if (parts.size() == 2) {
LOG(INFO) << "Setting property: " << line;
android::base::SetProperty(parts.at(0), parts.at(1));
} else {
LOG(ERROR) << "Invalid data: " << line;
}
}
}
int main(int argc, char* argv[]) {
std::string prop = FACTORY_PROP;
if (argc > 1 && std::string(argv[1]) == "NetworkConfig") prop = TELEPHONY_PROP;
std::ifstream in(EFS_NEW + prop);
if (in.good()) {
in.close();
prop = EFS_NEW + prop;
} else {
prop = EFS_OLD + prop;
}
LOG(INFO) << "Loading properties from " << prop;
std::string content;
if (android::base::ReadFileToString(prop, &content)) {
LoadProperties(content.c_str());
} else if (prop == FACTORY_PROP) {
LOG(WARNING) << "Could not read " << prop << ", setting defaults!";
LoadProperties("ro.vendor.multisim.simslotcount=1");
} else {
LOG(WARNING) << "Could not read " << prop << "!";
}
}

View file

@ -0,0 +1,31 @@
//
// Copyright (C) 2017-2018,2020 The LineageOS 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.
cc_binary {
name: "android.hardware.usb@1.0-service.a10",
relative_install_path: "hw",
init_rc: ["android.hardware.usb@1.0-service.a10.rc"],
vintf_fragments: ["android.hardware.usb@1.0-service.a10.xml"],
srcs: ["service.cpp", "Usb.cpp"],
shared_libs: [
"libbase",
"libcutils",
"libhidlbase",
"libutils",
"libhardware",
"android.hardware.usb@1.0",
],
proprietary: true,
}

View file

@ -0,0 +1,80 @@
/*
* Copyright (C) 2017-2018 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <android-base/logging.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include "Usb.h"
namespace android {
namespace hardware {
namespace usb {
namespace V1_0 {
namespace implementation {
Return<void> Usb::switchRole(const hidl_string& portName __unused,
const PortRole& newRole __unused) {
LOG(ERROR) << __func__ << ": Not supported";
return Void();
}
Return<void> Usb::queryPortStatus() {
hidl_vec<PortStatus> currentPortStatus;
currentPortStatus.resize(1);
currentPortStatus[0].portName = "otg_default";
currentPortStatus[0].currentDataRole = PortDataRole::DEVICE;
currentPortStatus[0].currentPowerRole = PortPowerRole::SINK;
currentPortStatus[0].currentMode = PortMode::UFP;
currentPortStatus[0].canChangeMode = false;
currentPortStatus[0].canChangeDataRole = false;
currentPortStatus[0].canChangePowerRole = false;
currentPortStatus[0].supportedModes = PortMode::UFP;
pthread_mutex_lock(&mLock);
if (mCallback != NULL) {
Return<void> ret = mCallback->notifyPortStatusChange(currentPortStatus, Status::SUCCESS);
if (!ret.isOk()) {
LOG(ERROR) << "queryPortStatus error " << ret.description();
}
} else {
LOG(INFO) << "Notifying userspace skipped. Callback is NULL";
}
pthread_mutex_unlock(&mLock);
return Void();
}
Return<void> Usb::setCallback(const sp<IUsbCallback>& callback) {
pthread_mutex_lock(&mLock);
mCallback = callback;
LOG(INFO) << "registering callback";
pthread_mutex_unlock(&mLock);
return Void();
}
} // namespace implementation
} // namespace V1_0
} // namespace usb
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,65 @@
/*
* Copyright (C) 2017-2018 The LineageOS 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_HARDWARE_USB_V1_0_USB_H
#define ANDROID_HARDWARE_USB_V1_0_USB_H
#include <android/hardware/usb/1.0/IUsb.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <utils/Log.h>
#ifdef LOG_TAG
#undef LOG_TAG
#endif
#define LOG_TAG "android.hardware.usb@1.0-service-a10"
#define UEVENT_MSG_LEN 2048
namespace android {
namespace hardware {
namespace usb {
namespace V1_0 {
namespace implementation {
using ::android::sp;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::usb::V1_0::IUsb;
using ::android::hardware::usb::V1_0::IUsbCallback;
using ::android::hardware::usb::V1_0::PortRole;
using ::android::hidl::base::V1_0::IBase;
struct Usb : public IUsb {
Return<void> switchRole(const hidl_string& portName, const PortRole& role) override;
Return<void> setCallback(const sp<IUsbCallback>& callback) override;
Return<void> queryPortStatus() override;
sp<IUsbCallback> mCallback;
pthread_mutex_t mLock = PTHREAD_MUTEX_INITIALIZER;
};
} // namespace implementation
} // namespace V1_0
} // namespace usb
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_USB_V1_0_USB_H

View file

@ -0,0 +1,5 @@
service vendor.usb-hal-1-0 /vendor/bin/hw/android.hardware.usb@1.0-service.a10
interface android.hardware.usb@1.0::IUsb default
class hal
user system
group system

View file

@ -0,0 +1,11 @@
<manifest version="1.0" type="device">
<hal format="hidl" override="true">
<name>android.hardware.usb</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>IUsb</name>
<instance>default</instance>
</interface>
</hal>
</manifest>

View file

@ -0,0 +1,47 @@
/*
* Copyright (C) 2017-2018 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include "Usb.h"
using android::sp;
// libhwbinder:
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
// Generated HIDL files
using android::hardware::usb::V1_0::IUsb;
using android::hardware::usb::V1_0::implementation::Usb;
int main() {
android::sp<IUsb> service = new Usb();
configureRpcThreadpool(1, true /*callerWillJoin*/);
android::status_t status = service->registerAsService();
if (status != android::OK) {
LOG(ERROR) << "Cannot register USB HAL service";
return 1;
}
LOG(INFO) << "USB HAL Ready.";
joinRpcThreadpool();
// Under normal cases, execution will not reach this line.
LOG(ERROR) << "USB HAL failed to join thread pool.";
return 1;
}

View file

@ -0,0 +1,35 @@
//
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
cc_binary {
name: "android.hardware.usb@1.1-service.exynos7885",
relative_install_path: "hw",
init_rc: ["android.hardware.usb@1.1-service.exynos7885.rc"],
srcs: ["service.cpp", "Usb.cpp"],
cflags: [
"-Wall",
"-Werror",
],
shared_libs: [
"libbase",
"libhidlbase",
"liblog",
"libutils",
"libhardware",
"android.hardware.usb@1.0",
"android.hardware.usb@1.1",
"libcutils",
],
proprietary: true,
}

View file

@ -0,0 +1,768 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "android.hardware.usb@1.1-service.typec"
#include <android-base/logging.h>
#include <assert.h>
#include <dirent.h>
#include <pthread.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <chrono>
#include <regex>
#include <thread>
#include <unordered_map>
#include <cutils/uevent.h>
#include <sys/epoll.h>
#include <utils/Errors.h>
#include <utils/StrongPointer.h>
#include "Usb.h"
namespace android {
namespace hardware {
namespace usb {
namespace V1_1 {
namespace implementation {
const char GOOGLE_USB_VENDOR_ID_STR[] = "18d1";
const char GOOGLE_USBC_35_ADAPTER_UNPLUGGED_ID_STR[] = "5029";
// Set by the signal handler to destroy the thread
volatile bool destroyThread;
static void checkUsbDeviceAutoSuspend(const std::string& devicePath);
static int32_t readFile(const std::string& filename, std::string* contents) {
FILE* fp;
ssize_t read = 0;
char* line = NULL;
size_t len = 0;
fp = fopen(filename.c_str(), "r");
if (fp != NULL) {
if ((read = getline(&line, &len, fp)) != -1) {
char* pos;
if ((pos = strchr(line, '\n')) != NULL) *pos = '\0';
*contents = line;
}
free(line);
fclose(fp);
return 0;
} else {
ALOGE("fopen failed in readFile %s, errno=%d", filename.c_str(), errno);
}
return -1;
}
static int32_t writeFile(const std::string& filename, const std::string& contents) {
FILE* fp;
int ret;
fp = fopen(filename.c_str(), "w");
if (fp != NULL) {
ret = fputs(contents.c_str(), fp);
fclose(fp);
if (ret == EOF) {
ALOGE("fputs failed in writeFile %s", filename.c_str());
return -1;
}
return 0;
} else {
ALOGE("fopen failed in writeFile %s, errno=%d", filename.c_str(), errno);
}
return -1;
}
std::string appendRoleNodeHelper(const std::string& portName, PortRoleType type) {
std::string node("/sys/class/typec/" + portName);
switch (type) {
case PortRoleType::DATA_ROLE:
return node + "/data_role";
case PortRoleType::POWER_ROLE:
return node + "/power_role";
case PortRoleType::MODE:
return node + "/port_type";
default:
return "";
}
}
std::string convertRoletoString(PortRole role) {
if (role.type == PortRoleType::POWER_ROLE) {
if (role.role == static_cast<uint32_t>(PortPowerRole::SOURCE))
return "source";
else if (role.role == static_cast<uint32_t>(PortPowerRole::SINK))
return "sink";
} else if (role.type == PortRoleType::DATA_ROLE) {
if (role.role == static_cast<uint32_t>(PortDataRole::HOST)) return "host";
if (role.role == static_cast<uint32_t>(PortDataRole::DEVICE)) return "device";
} else if (role.type == PortRoleType::MODE) {
if (role.role == static_cast<uint32_t>(PortMode_1_1::UFP)) return "sink";
if (role.role == static_cast<uint32_t>(PortMode_1_1::DFP)) return "source";
}
return "none";
}
void extractRole(std::string* roleName) {
std::size_t first, last;
first = roleName->find("[");
last = roleName->find("]");
if (first != std::string::npos && last != std::string::npos) {
*roleName = roleName->substr(first + 1, last - first - 1);
}
}
void switchToDrp(const std::string& portName) {
std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), PortRoleType::MODE);
FILE* fp;
if (filename != "") {
fp = fopen(filename.c_str(), "w");
if (fp != NULL) {
int ret = fputs("dual", fp);
fclose(fp);
if (ret == EOF) ALOGE("Fatal: Error while switching back to drp");
} else {
ALOGE("Fatal: Cannot open file to switch back to drp");
}
} else {
ALOGE("Fatal: invalid node type");
}
}
bool switchMode(const hidl_string& portName, const PortRole& newRole, struct Usb* usb) {
std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
std::string written;
FILE* fp;
bool roleSwitch = false;
if (filename == "") {
ALOGE("Fatal: invalid node type");
return false;
}
fp = fopen(filename.c_str(), "w");
if (fp != NULL) {
// Hold the lock here to prevent loosing connected signals
// as once the file is written the partner added signal
// can arrive anytime.
pthread_mutex_lock(&usb->mPartnerLock);
usb->mPartnerUp = false;
int ret = fputs(convertRoletoString(newRole).c_str(), fp);
fclose(fp);
if (ret != EOF) {
struct timespec to;
struct timespec now;
wait_again:
clock_gettime(CLOCK_MONOTONIC, &now);
to.tv_sec = now.tv_sec + PORT_TYPE_TIMEOUT;
to.tv_nsec = now.tv_nsec;
int err = pthread_cond_timedwait(&usb->mPartnerCV, &usb->mPartnerLock, &to);
// There are no uevent signals which implies role swap timed out.
if (err == ETIMEDOUT) {
ALOGI("uevents wait timedout");
// Sanity check.
} else if (!usb->mPartnerUp) {
goto wait_again;
// Role switch succeeded since usb->mPartnerUp is true.
} else {
roleSwitch = true;
}
} else {
ALOGI("Role switch failed while wrting to file");
}
pthread_mutex_unlock(&usb->mPartnerLock);
}
if (!roleSwitch) switchToDrp(std::string(portName.c_str()));
return roleSwitch;
}
Usb::Usb()
: mLock(PTHREAD_MUTEX_INITIALIZER),
mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER),
mPartnerLock(PTHREAD_MUTEX_INITIALIZER),
mPartnerUp(false) {
pthread_condattr_t attr;
if (pthread_condattr_init(&attr)) {
ALOGE("pthread_condattr_init failed: %s", strerror(errno));
abort();
}
if (pthread_condattr_setclock(&attr, CLOCK_MONOTONIC)) {
ALOGE("pthread_condattr_setclock failed: %s", strerror(errno));
abort();
}
if (pthread_cond_init(&mPartnerCV, &attr)) {
ALOGE("pthread_cond_init failed: %s", strerror(errno));
abort();
}
if (pthread_condattr_destroy(&attr)) {
ALOGE("pthread_condattr_destroy failed: %s", strerror(errno));
abort();
}
}
Return<void> Usb::switchRole(const hidl_string& portName, const PortRole& newRole) {
std::string filename = appendRoleNodeHelper(std::string(portName.c_str()), newRole.type);
std::string written;
FILE* fp;
bool roleSwitch = false;
if (filename == "") {
ALOGE("Fatal: invalid node type");
return Void();
}
pthread_mutex_lock(&mRoleSwitchLock);
ALOGI("filename write: %s role:%s", filename.c_str(), convertRoletoString(newRole).c_str());
if (newRole.type == PortRoleType::MODE) {
roleSwitch = switchMode(portName, newRole, this);
} else {
fp = fopen(filename.c_str(), "w");
if (fp != NULL) {
int ret = fputs(convertRoletoString(newRole).c_str(), fp);
fclose(fp);
if ((ret != EOF) && !readFile(filename, &written)) {
extractRole(&written);
ALOGI("written: %s", written.c_str());
if (written == convertRoletoString(newRole)) {
roleSwitch = true;
} else {
ALOGE("Role switch failed");
}
} else {
ALOGE("failed to update the new role");
}
} else {
ALOGE("fopen failed");
}
}
pthread_mutex_lock(&mLock);
if (mCallback_1_0 != NULL) {
Return<void> ret = mCallback_1_0->notifyRoleSwitchStatus(
portName, newRole, roleSwitch ? Status::SUCCESS : Status::ERROR);
if (!ret.isOk()) ALOGE("RoleSwitchStatus error %s", ret.description().c_str());
} else {
ALOGE("Not notifying the userspace. Callback is not set");
}
pthread_mutex_unlock(&mLock);
pthread_mutex_unlock(&mRoleSwitchLock);
return Void();
}
Status getAccessoryConnected(const std::string& portName, std::string* accessory) {
std::string filename = "/sys/class/typec/" + portName + "-partner/accessory_mode";
if (readFile(filename, accessory)) {
ALOGE("getAccessoryConnected: Failed to open filesystem node: %s", filename.c_str());
return Status::ERROR;
}
return Status::SUCCESS;
}
Status getCurrentRoleHelper(const std::string& portName, bool connected, PortRoleType type,
uint32_t* currentRole) {
std::string filename;
std::string roleName;
std::string accessory;
// Mode
if (type == PortRoleType::POWER_ROLE) {
filename = "/sys/class/typec/" + portName + "/power_role";
*currentRole = static_cast<uint32_t>(PortPowerRole::NONE);
} else if (type == PortRoleType::DATA_ROLE) {
filename = "/sys/class/typec/" + portName + "/data_role";
*currentRole = static_cast<uint32_t>(PortDataRole::NONE);
} else if (type == PortRoleType::MODE) {
filename = "/sys/class/typec/" + portName + "/data_role";
*currentRole = static_cast<uint32_t>(PortMode_1_1::NONE);
} else {
return Status::ERROR;
}
if (!connected) return Status::SUCCESS;
if (type == PortRoleType::MODE) {
if (getAccessoryConnected(portName, &accessory) != Status::SUCCESS) {
return Status::ERROR;
}
if (accessory == "analog_audio") {
*currentRole = static_cast<uint32_t>(PortMode_1_1::AUDIO_ACCESSORY);
return Status::SUCCESS;
} else if (accessory == "debug") {
*currentRole = static_cast<uint32_t>(PortMode_1_1::DEBUG_ACCESSORY);
return Status::SUCCESS;
}
}
if (readFile(filename, &roleName)) {
ALOGE("getCurrentRole: Failed to open filesystem node: %s", filename.c_str());
return Status::ERROR;
}
extractRole(&roleName);
if (roleName == "source") {
*currentRole = static_cast<uint32_t>(PortPowerRole::SOURCE);
} else if (roleName == "sink") {
*currentRole = static_cast<uint32_t>(PortPowerRole::SINK);
} else if (roleName == "host") {
if (type == PortRoleType::DATA_ROLE)
*currentRole = static_cast<uint32_t>(PortDataRole::HOST);
else
*currentRole = static_cast<uint32_t>(PortMode_1_1::DFP);
} else if (roleName == "device") {
if (type == PortRoleType::DATA_ROLE)
*currentRole = static_cast<uint32_t>(PortDataRole::DEVICE);
else
*currentRole = static_cast<uint32_t>(PortMode_1_1::UFP);
} else if (roleName != "none") {
/* case for none has already been addressed.
* so we check if the role isnt none.
*/
return Status::UNRECOGNIZED_ROLE;
}
return Status::SUCCESS;
}
Status getTypeCPortNamesHelper(std::unordered_map<std::string, bool>* names) {
DIR* dp;
dp = opendir("/sys/class/typec");
if (dp != NULL) {
struct dirent* ep;
while ((ep = readdir(dp))) {
if (ep->d_type == DT_LNK) {
if (std::string::npos == std::string(ep->d_name).find("-partner")) {
std::unordered_map<std::string, bool>::const_iterator portName =
names->find(ep->d_name);
if (portName == names->end()) {
names->insert({ep->d_name, false});
}
} else {
(*names)[std::strtok(ep->d_name, "-")] = true;
}
}
}
closedir(dp);
return Status::SUCCESS;
}
ALOGE("Failed to open /sys/class/typec");
return Status::ERROR;
}
bool canSwitchRoleHelper(const std::string& portName, PortRoleType /*type*/) {
std::string filename = "/sys/class/typec/" + portName + "-partner/supports_usb_power_delivery";
std::string supportsPD;
if (!readFile(filename, &supportsPD)) {
if (supportsPD == "yes") {
return true;
}
}
return false;
}
/*
* Reuse the same method for both V1_0 and V1_1 callback objects.
* The caller of this method would reconstruct the V1_0::PortStatus
* object if required.
*/
Status getPortStatusHelper(hidl_vec<PortStatus_1_1>* currentPortStatus_1_1, bool V1_0) {
std::unordered_map<std::string, bool> names;
Status result = getTypeCPortNamesHelper(&names);
int i = -1;
if (result == Status::SUCCESS) {
currentPortStatus_1_1->resize(names.size());
for (std::pair<std::string, bool> port : names) {
i++;
ALOGI("%s", port.first.c_str());
(*currentPortStatus_1_1)[i].status.portName = port.first;
uint32_t currentRole;
if (getCurrentRoleHelper(port.first, port.second, PortRoleType::POWER_ROLE,
&currentRole) == Status::SUCCESS) {
(*currentPortStatus_1_1)[i].status.currentPowerRole =
static_cast<PortPowerRole>(currentRole);
} else {
ALOGE("Error while retreiving portNames");
goto done;
}
if (getCurrentRoleHelper(port.first, port.second, PortRoleType::DATA_ROLE,
&currentRole) == Status::SUCCESS) {
(*currentPortStatus_1_1)[i].status.currentDataRole =
static_cast<PortDataRole>(currentRole);
} else {
ALOGE("Error while retreiving current port role");
goto done;
}
if (getCurrentRoleHelper(port.first, port.second, PortRoleType::MODE, &currentRole) ==
Status::SUCCESS) {
(*currentPortStatus_1_1)[i].currentMode = static_cast<PortMode_1_1>(currentRole);
(*currentPortStatus_1_1)[i].status.currentMode =
static_cast<V1_0::PortMode>(currentRole);
} else {
ALOGE("Error while retreiving current data role");
goto done;
}
(*currentPortStatus_1_1)[i].status.canChangeMode = true;
(*currentPortStatus_1_1)[i].status.canChangeDataRole =
port.second ? canSwitchRoleHelper(port.first, PortRoleType::DATA_ROLE) : false;
(*currentPortStatus_1_1)[i].status.canChangePowerRole =
port.second ? canSwitchRoleHelper(port.first, PortRoleType::POWER_ROLE) : false;
ALOGI("connected:%d canChangeMode:%d canChagedata:%d canChangePower:%d", port.second,
(*currentPortStatus_1_1)[i].status.canChangeMode,
(*currentPortStatus_1_1)[i].status.canChangeDataRole,
(*currentPortStatus_1_1)[i].status.canChangePowerRole);
if (V1_0) {
(*currentPortStatus_1_1)[i].status.supportedModes = V1_0::PortMode::DFP;
} else {
(*currentPortStatus_1_1)[i].supportedModes = PortMode_1_1::UFP | PortMode_1_1::DFP;
(*currentPortStatus_1_1)[i].status.supportedModes = V1_0::PortMode::NONE;
(*currentPortStatus_1_1)[i].status.currentMode = V1_0::PortMode::NONE;
}
}
return Status::SUCCESS;
}
done:
return Status::ERROR;
}
Return<void> Usb::queryPortStatus() {
hidl_vec<PortStatus_1_1> currentPortStatus_1_1;
hidl_vec<V1_0::PortStatus> currentPortStatus;
Status status;
sp<IUsbCallback> callback_V1_1 = IUsbCallback::castFrom(mCallback_1_0);
pthread_mutex_lock(&mLock);
if (mCallback_1_0 != NULL) {
if (callback_V1_1 != NULL) {
status = getPortStatusHelper(&currentPortStatus_1_1, false);
} else {
status = getPortStatusHelper(&currentPortStatus_1_1, true);
currentPortStatus.resize(currentPortStatus_1_1.size());
for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++)
currentPortStatus[i] = currentPortStatus_1_1[i].status;
}
Return<void> ret;
if (callback_V1_1 != NULL)
ret = callback_V1_1->notifyPortStatusChange_1_1(currentPortStatus_1_1, status);
else
ret = mCallback_1_0->notifyPortStatusChange(currentPortStatus, status);
if (!ret.isOk()) ALOGE("queryPortStatus_1_1 error %s", ret.description().c_str());
} else {
ALOGI("Notifying userspace skipped. Callback is NULL");
}
pthread_mutex_unlock(&mLock);
return Void();
}
struct data {
int uevent_fd;
android::hardware::usb::V1_1::implementation::Usb* usb;
};
static void uevent_event(uint32_t /*epevents*/, struct data* payload) {
char msg[UEVENT_MSG_LEN + 2];
char* cp;
int n;
n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN);
if (n <= 0) return;
if (n >= UEVENT_MSG_LEN) /* overflow -- discard */
return;
msg[n] = '\0';
msg[n + 1] = '\0';
cp = msg;
while (*cp) {
std::cmatch match;
if (std::regex_match(cp, std::regex("(add)(.*)(-partner)"))) {
ALOGI("partner added");
pthread_mutex_lock(&payload->usb->mPartnerLock);
payload->usb->mPartnerUp = true;
pthread_cond_signal(&payload->usb->mPartnerCV);
pthread_mutex_unlock(&payload->usb->mPartnerLock);
} else if (!strncmp(cp, "DEVTYPE=typec_", strlen("DEVTYPE=typec_"))) {
hidl_vec<PortStatus_1_1> currentPortStatus_1_1;
ALOGI("uevent received %s", cp);
pthread_mutex_lock(&payload->usb->mLock);
if (payload->usb->mCallback_1_0 != NULL) {
sp<IUsbCallback> callback_V1_1 =
IUsbCallback::castFrom(payload->usb->mCallback_1_0);
Return<void> ret;
// V1_1 callback
if (callback_V1_1 != NULL) {
Status status = getPortStatusHelper(&currentPortStatus_1_1, false);
ret = callback_V1_1->notifyPortStatusChange_1_1(currentPortStatus_1_1, status);
} else { // V1_0 callback
Status status = getPortStatusHelper(&currentPortStatus_1_1, true);
/*
* Copying the result from getPortStatusHelper
* into V1_0::PortStatus to pass back through
* the V1_0 callback object.
*/
hidl_vec<V1_0::PortStatus> currentPortStatus;
currentPortStatus.resize(currentPortStatus_1_1.size());
for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++)
currentPortStatus[i] = currentPortStatus_1_1[i].status;
ret = payload->usb->mCallback_1_0->notifyPortStatusChange(currentPortStatus,
status);
}
if (!ret.isOk()) ALOGE("error %s", ret.description().c_str());
} else {
ALOGI("Notifying userspace skipped. Callback is NULL");
}
pthread_mutex_unlock(&payload->usb->mLock);
// Role switch is not in progress and port is in disconnected state
if (!pthread_mutex_trylock(&payload->usb->mRoleSwitchLock)) {
for (unsigned long i = 0; i < currentPortStatus_1_1.size(); i++) {
DIR* dp = opendir(
std::string(
"/sys/class/typec/" +
std::string(currentPortStatus_1_1[i].status.portName.c_str()) +
"-partner")
.c_str());
if (dp == NULL) {
// PortRole role = {.role = static_cast<uint32_t>(PortMode::UFP)};
switchToDrp(currentPortStatus_1_1[i].status.portName);
} else {
closedir(dp);
}
}
pthread_mutex_unlock(&payload->usb->mRoleSwitchLock);
}
break;
} else if (std::regex_match(cp, match,
std::regex("add@(/devices/soc/a800000\\.ssusb/a800000\\.dwc3/"
"xhci-hcd\\.0\\.auto/"
"usb\\d/\\d-\\d)/.*"))) {
if (match.size() == 2) {
std::csub_match submatch = match[1];
checkUsbDeviceAutoSuspend("/sys" + submatch.str());
}
}
/* advance to after the next \0 */
while (*cp++) {
}
}
}
void* work(void* param) {
int epoll_fd, uevent_fd;
struct epoll_event ev;
int nevents = 0;
struct data payload;
ALOGE("creating thread");
uevent_fd = uevent_open_socket(64 * 1024, true);
if (uevent_fd < 0) {
ALOGE("uevent_init: uevent_open_socket failed\n");
return NULL;
}
payload.uevent_fd = uevent_fd;
payload.usb = (android::hardware::usb::V1_1::implementation::Usb*)param;
fcntl(uevent_fd, F_SETFL, O_NONBLOCK);
ev.events = EPOLLIN;
ev.data.ptr = (void*)uevent_event;
epoll_fd = epoll_create(64);
if (epoll_fd == -1) {
ALOGE("epoll_create failed; errno=%d", errno);
goto error;
}
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) {
ALOGE("epoll_ctl failed; errno=%d", errno);
goto error;
}
while (!destroyThread) {
struct epoll_event events[64];
nevents = epoll_wait(epoll_fd, events, 64, -1);
if (nevents == -1) {
if (errno == EINTR) continue;
ALOGE("usb epoll_wait failed; errno=%d", errno);
break;
}
for (int n = 0; n < nevents; ++n) {
if (events[n].data.ptr)
(*(void (*)(int, struct data* payload))events[n].data.ptr)(events[n].events,
&payload);
}
}
ALOGI("exiting worker thread");
error:
close(uevent_fd);
if (epoll_fd >= 0) close(epoll_fd);
return NULL;
}
void sighandler(int sig) {
if (sig == SIGUSR1) {
destroyThread = true;
ALOGI("destroy set");
return;
}
signal(SIGUSR1, sighandler);
}
Return<void> Usb::setCallback(const sp<V1_0::IUsbCallback>& callback) {
sp<IUsbCallback> callback_V1_1 = IUsbCallback::castFrom(callback);
if (callback != NULL)
if (callback_V1_1 == NULL) ALOGI("Registering 1.0 callback");
pthread_mutex_lock(&mLock);
/*
* When both the old callback and new callback values are NULL,
* there is no need to spin off the worker thread.
* When both the values are not NULL, we would already have a
* worker thread running, so updating the callback object would
* be suffice.
*/
if ((mCallback_1_0 == NULL && callback == NULL) ||
(mCallback_1_0 != NULL && callback != NULL)) {
/*
* Always store as V1_0 callback object. Type cast to V1_1
* when the callback is actually invoked.
*/
mCallback_1_0 = callback;
pthread_mutex_unlock(&mLock);
return Void();
}
mCallback_1_0 = callback;
ALOGI("registering callback");
// Kill the worker thread if the new callback is NULL.
if (mCallback_1_0 == NULL) {
pthread_mutex_unlock(&mLock);
if (!pthread_kill(mPoll, SIGUSR1)) {
pthread_join(mPoll, NULL);
ALOGI("pthread destroyed");
}
return Void();
}
destroyThread = false;
signal(SIGUSR1, sighandler);
/*
* Create a background thread if the old callback value is NULL
* and being updated with a new value.
*/
if (pthread_create(&mPoll, NULL, work, this)) {
ALOGE("pthread creation failed %d", errno);
mCallback_1_0 = NULL;
}
pthread_mutex_unlock(&mLock);
return Void();
}
/*
* whitelisting USB device idProduct and idVendor to allow auto suspend.
*/
static bool canProductAutoSuspend(const std::string& deviceIdVendor,
const std::string& deviceIdProduct) {
if (deviceIdVendor == GOOGLE_USB_VENDOR_ID_STR &&
deviceIdProduct == GOOGLE_USBC_35_ADAPTER_UNPLUGGED_ID_STR) {
return true;
}
return false;
}
static bool canUsbDeviceAutoSuspend(const std::string& devicePath) {
std::string deviceIdVendor;
std::string deviceIdProduct;
readFile(devicePath + "/idVendor", &deviceIdVendor);
readFile(devicePath + "/idProduct", &deviceIdProduct);
// deviceIdVendor and deviceIdProduct will be empty strings if readFile fails
return canProductAutoSuspend(deviceIdVendor, deviceIdProduct);
}
/*
* function to consume USB device plugin events (on receiving a
* USB device path string), and enable autosupend on the USB device if
* necessary.
*/
void checkUsbDeviceAutoSuspend(const std::string& devicePath) {
/*
* Currently we only actively enable devices that should be autosuspended, and leave others
* to the defualt.
*/
if (canUsbDeviceAutoSuspend(devicePath)) {
ALOGI("auto suspend usb device %s", devicePath.c_str());
writeFile(devicePath + "/power/control", "auto");
}
}
} // namespace implementation
} // namespace V1_1
} // namespace usb
} // namespace hardware
} // namespace android

View file

@ -0,0 +1,71 @@
#ifndef ANDROID_HARDWARE_USB_V1_1_USB_H
#define ANDROID_HARDWARE_USB_V1_1_USB_H
#include <android/hardware/usb/1.1/IUsb.h>
#include <android/hardware/usb/1.1/IUsbCallback.h>
#include <android/hardware/usb/1.1/types.h>
#include <hidl/Status.h>
#include <utils/Log.h>
#define UEVENT_MSG_LEN 2048
// The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd.
// The -partner directory would not be created until this is done.
// Having a margin of ~3 secs for the directory and other related bookeeping
// structures created and uvent fired.
#define PORT_TYPE_TIMEOUT 8
namespace android {
namespace hardware {
namespace usb {
namespace V1_1 {
namespace implementation {
using ::android::sp;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::usb::V1_0::PortDataRole;
using ::android::hardware::usb::V1_0::PortPowerRole;
using ::android::hardware::usb::V1_0::PortRole;
using ::android::hardware::usb::V1_0::PortRoleType;
using ::android::hardware::usb::V1_0::Status;
using ::android::hardware::usb::V1_1::IUsb;
using ::android::hardware::usb::V1_1::IUsbCallback;
using ::android::hardware::usb::V1_1::PortMode_1_1;
using ::android::hardware::usb::V1_1::PortStatus_1_1;
using ::android::hidl::base::V1_0::DebugInfo;
using ::android::hidl::base::V1_0::IBase;
struct Usb : public IUsb {
Usb();
Return<void> switchRole(const hidl_string& portName, const PortRole& role) override;
Return<void> setCallback(const sp<V1_0::IUsbCallback>& callback) override;
Return<void> queryPortStatus() override;
sp<V1_0::IUsbCallback> mCallback_1_0;
// Protects mCallback variable
pthread_mutex_t mLock;
// Protects roleSwitch operation
pthread_mutex_t mRoleSwitchLock;
// Threads waiting for the partner to come back wait here
pthread_cond_t mPartnerCV;
// lock protecting mPartnerCV
pthread_mutex_t mPartnerLock;
// Variable to signal partner coming back online after type switch
bool mPartnerUp;
private:
pthread_t mPoll;
};
} // namespace implementation
} // namespace V1_1
} // namespace usb
} // namespace hardware
} // namespace android
#endif // ANDROID_HARDWARE_USB_V1_1_USB_H

View file

@ -0,0 +1,14 @@
service vendor.usb-hal-1-1 /vendor/bin/hw/android.hardware.usb@1.1-service.exynos7885
interface android.hardware.usb@1.1::IUsb default
interface android.hardware.usb@1.0::IUsb default
class hal
user root
group root system
on boot
chown root system /sys/class/typec/port0/power_role
chown root system /sys/class/typec/port0/data_role
chown root system /sys/class/typec/port0/port_type
chmod 664 /sys/class/typec/port0/power_role
chmod 664 /sys/class/typec/port0/data_role
chmod 664 /sys/class/typec/port0/port_type

View file

@ -0,0 +1,51 @@
/*
* 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 "android.hardware.usb@1.1-service.exynos7885"
#include <hidl/HidlTransportSupport.h>
#include "Usb.h"
using android::sp;
// libhwbinder:
using android::hardware::configureRpcThreadpool;
using android::hardware::joinRpcThreadpool;
// Generated HIDL files
using android::hardware::usb::V1_1::IUsb;
using android::hardware::usb::V1_1::implementation::Usb;
using android::OK;
using android::status_t;
int main() {
android::sp<IUsb> service = new Usb();
configureRpcThreadpool(1, true /*callerWillJoin*/);
status_t status = service->registerAsService();
if (status != OK) {
ALOGE("Cannot register USB HAL service");
return 1;
}
ALOGI("USB HAL Ready.");
joinRpcThreadpool();
// Under noraml cases, execution will not reach this line.
ALOGI("USB HAL failed to join thread pool.");
return 1;
}