Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 578eb7fe authored by Connor O'Brien's avatar Connor O'Brien
Browse files

Recover cleanly from power HAL service crashes



Currently if the binderized power HAL service crashes, services that
call the HAL will crash as well. To fix this:
- Before calling power HAL functions, check that the handle to the
  power HAL service is still valid, and reload using getService() if
  necessary.
- When a call to a power HAL function fails, log the failure and mark
  the handle as invalid.

Bug: 35728909
Test: adb shell kill -9 $(adb shell pidof android.hardware.power@1.0-service)
Change-Id: Id2dd1a6507b9f5044d928483cdb6b736c701f8ba
Signed-off-by: default avatarConnor O'Brien <connoro@google.com>
parent 84d7e77a
Loading
Loading
Loading
Loading
+51 −40
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ namespace android
static bool wakeup_init = false;
static sem_t wakeup_sem;
extern sp<IPower> gPowerHal;
extern std::mutex gPowerHalMutex;
extern bool getPowerHal();

static void wakeup_callback(bool success)
{
@@ -191,12 +193,14 @@ static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject o
        return -1;
    }

    if (gPowerHal == nullptr) {
        ALOGE("gPowerHal not loaded");
    {
        std::lock_guard<std::mutex> lock(gPowerHalMutex);
        if (!getPowerHal()) {
            ALOGE("Power Hal not loaded");
            return -1;
        }

    gPowerHal->getPlatformLowPowerStats(
        Return<void> ret = gPowerHal->getPlatformLowPowerStats(
            [&offset, &remaining, &total_added](hidl_vec<PowerStatePlatformSleepState> states,
                    Status status) {
                if (status != Status::SUCCESS)
@@ -247,6 +251,13 @@ static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject o
                }
            }
        );

        if (!ret.isOk()) {
            ALOGE("getPlatformLowPowerStats() failed: power HAL service not available");
            gPowerHal = nullptr;
            return -1;
        }
    }
    *offset = 0;
    total_added += 1;
    return total_added;
+49 −28
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ using android::hardware::Void;
using android::hardware::power::V1_0::IPower;
using android::hardware::power::V1_0::PowerHint;
using android::hardware::power::V1_0::Feature;
using android::hardware::hidl_vec;
using android::String8;

namespace android {

@@ -56,7 +56,8 @@ static struct {
// ----------------------------------------------------------------------------

static jobject gPowerManagerServiceObj;
sp<IPower> gPowerHal;
sp<IPower> gPowerHal = nullptr;
std::mutex gPowerHalMutex;
static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];

// Throttling interval for user activity calls.
@@ -74,11 +75,37 @@ static bool checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodNa
    return false;
}

// Check validity of current handle to the power HAL service, and call getService() if necessary.
// The caller must be holding gPowerHalMutex.
bool getPowerHal() {
    if (gPowerHal == nullptr) {
        gPowerHal = IPower::getService();
        if (gPowerHal != nullptr) {
            ALOGI("Loaded power HAL service");
        } else {
            ALOGI("Couldn't load power HAL service");
        }
    }
    return gPowerHal != nullptr;
}

// Check if a call to a power HAL function failed; if so, log the failure and invalidate the
// current handle to the power HAL service. The caller must be holding gPowerHalMutex.
static void processReturn(const Return<void> &ret, const char* functionName) {
    if (!ret.isOk()) {
        ALOGE("%s() failed: power HAL service not available.", functionName);
        gPowerHal = nullptr;
    }
}

void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
    // Tell the power HAL when user activity occurs.
    if (gPowerHal != nullptr) {
        gPowerHal->powerHint(PowerHint::INTERACTION, 0);
    gPowerHalMutex.lock();
    if (getPowerHal()) {
        Return<void> ret = gPowerHal->powerHint(PowerHint::INTERACTION, 0);
        processReturn(ret, "powerHint");
    }
    gPowerHalMutex.unlock();

    if (gPowerManagerServiceObj) {
        // Throttle calls into user activity by event type.
@@ -106,14 +133,13 @@ void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t
}

// ----------------------------------------------------------------------------
//TODO(b/31632518)

static void nativeInit(JNIEnv* env, jobject obj) {
    gPowerManagerServiceObj = env->NewGlobalRef(obj);

    gPowerHal = IPower::getService();
    if (gPowerHal == nullptr) {
        ALOGE("Couldn't load PowerHAL module");
    }
    gPowerHalMutex.lock();
    getPowerHal();
    gPowerHalMutex.unlock();
}

static void nativeAcquireSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring nameStr) {
@@ -127,14 +153,12 @@ static void nativeReleaseSuspendBlocker(JNIEnv *env, jclass /* clazz */, jstring
}

static void nativeSetInteractive(JNIEnv* /* env */, jclass /* clazz */, jboolean enable) {
    if (gPowerHal != nullptr) {
        if (enable) {
            ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(true) while turning screen on");
            gPowerHal->setInteractive(true);
        } else {
            ALOGD_IF_SLOW(20, "Excessive delay in setInteractive(false) while turning screen off");
            gPowerHal->setInteractive(false);
        }
    std::lock_guard<std::mutex> lock(gPowerHalMutex);
    if (getPowerHal()) {
        String8 err("Excessive delay in setInteractive(%s) while turning screen %s");
        ALOGD_IF_SLOW(20, String8::format(err, enable ? "true" : "false", enable ? "on" : "off"));
        Return<void> ret = gPowerHal->setInteractive(enable);
        processReturn(ret, "setInteractive");
    }
}

@@ -149,20 +173,18 @@ static void nativeSetAutoSuspend(JNIEnv* /* env */, jclass /* clazz */, jboolean
}

static void nativeSendPowerHint(JNIEnv *env, jclass clazz, jint hintId, jint data) {
    if (gPowerHal != nullptr) {
        if(data)
            gPowerHal->powerHint((PowerHint)hintId, data);
        else {
            gPowerHal->powerHint((PowerHint)hintId, 0);
        }
    std::lock_guard<std::mutex> lock(gPowerHalMutex);
    if (getPowerHal()) {
        Return<void> ret =  gPowerHal->powerHint((PowerHint)hintId, data);
        processReturn(ret, "powerHint");
    }
}

static void nativeSetFeature(JNIEnv *env, jclass clazz, jint featureId, jint data) {
    int data_param = data;

    if (gPowerHal != nullptr) {
        gPowerHal->setFeature((Feature)featureId, data_param ? true : false);
    std::lock_guard<std::mutex> lock(gPowerHalMutex);
    if (getPowerHal()) {
        Return<void> ret = gPowerHal->setFeature((Feature)featureId, static_cast<bool>(data));
        processReturn(ret, "setFeature");
    }
}

@@ -217,7 +239,6 @@ int register_android_server_PowerManagerService(JNIEnv* env) {
        gLastEventTime[i] = LLONG_MIN;
    }
    gPowerManagerServiceObj = NULL;
    gPowerHal = NULL;
    return 0;
}