diff --git a/folio_daemon/Android.mk b/folio_daemon/Android.mk new file mode 100755 index 00000000..4ba85126 --- /dev/null +++ b/folio_daemon/Android.mk @@ -0,0 +1,22 @@ +LOCAL_PATH := $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SHARED_LIBRARIES := \ + libandroid \ + libcutils \ + liblog + +LOCAL_SRC_FILES := \ + main.cpp + +LOCAL_C_INCLUDES := + +LOCAL_CFLAGS := $(common_flags) -DLOG_TAG=\"folio_daemon\" -DLOG_NDEBUG=0 + +LOCAL_CLANG := true +LOCAL_MODULE := folio_daemon +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_OWNER := google +LOCAL_PROPRIETARY_MODULE := true + +include $(BUILD_EXECUTABLE) diff --git a/folio_daemon/main.cpp b/folio_daemon/main.cpp new file mode 100644 index 00000000..417cffe2 --- /dev/null +++ b/folio_daemon/main.cpp @@ -0,0 +1,147 @@ +/* + * Copyright 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +// Hall-effect sensor type +#define SENSOR_TYPE 33171016 + +/* + * This simple daemon listens for events from the Hall-effect sensor and writes + * the appropriate SW_LID event to a uinput node. This allows the screen to be + * locked with a magnetic folio case. + */ +int main(void) { + int uinputFd; + int err; + struct uinput_user_dev uidev; + ASensorManager *sensorManager = nullptr; + ASensorRef hallSensor; + ALooper *looper; + ASensorEventQueue *eventQueue = nullptr; + + ALOGI("Started"); + + uinputFd = TEMP_FAILURE_RETRY(open("/dev/uinput", O_WRONLY | O_NONBLOCK)); + if (uinputFd < 0) { + ALOGE("Unable to open uinput node: %s", strerror(errno)); + goto out; + } + + err = TEMP_FAILURE_RETRY(ioctl(uinputFd, UI_SET_EVBIT, EV_SW)) + | TEMP_FAILURE_RETRY(ioctl(uinputFd, UI_SET_EVBIT, EV_SYN)) + | TEMP_FAILURE_RETRY(ioctl(uinputFd, UI_SET_SWBIT, SW_LID)); + if (err != 0) { + ALOGE("Unable to enable SW_LID events: %s", strerror(errno)); + goto out; + } + + memset(&uidev, 0, sizeof (uidev)); + snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "uinput-folio"); + uidev.id.bustype = BUS_VIRTUAL; + uidev.id.vendor = 0; + uidev.id.product = 0; + uidev.id.version = 0; + + err = TEMP_FAILURE_RETRY(write(uinputFd, &uidev, sizeof (uidev))); + if (err < 0) { + ALOGE("Write user device to uinput node failed: %s", strerror(errno)); + goto out; + } + + err = TEMP_FAILURE_RETRY(ioctl(uinputFd, UI_DEV_CREATE)); + if (err < 0) { + ALOGE("Unable to create uinput device: %s", strerror(errno)); + goto out; + } + + ALOGI("Successfully registered uinput-folio for SW_LID events"); + + // Get Hall-effect sensor events from the NDK + sensorManager = ASensorManager_getInstanceForPackage(nullptr); + hallSensor = ASensorManager_getDefaultSensor(sensorManager, SENSOR_TYPE); + if (hallSensor == nullptr) { + ALOGE("Unable to get Hall-effect sensor"); + goto out; + } + + looper = ALooper_forThread(); + if (looper == nullptr) { + looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + } + + eventQueue = ASensorManager_createEventQueue(sensorManager, looper, 0, NULL, + NULL); + err = ASensorEventQueue_registerSensor(eventQueue, hallSensor, + ASensor_getMinDelay(hallSensor), + 10000); + if (err < 0) { + ALOGE("Unable to register for Hall-effect sensor events"); + goto out; + } + + ALOGI("Starting polling loop"); + + // Polling loop + while (ALooper_pollAll(-1, NULL, NULL, NULL) == 0) { + ASensorEvent sensorEvent; + while (ASensorEventQueue_getEvents(eventQueue, &sensorEvent, 1) > 0) { + // 1 means closed; 0 means open + int isClosed = sensorEvent.data[0] > 0.0f ? 1 : 0; + struct input_event event; + event.type = EV_SW; + event.code = SW_LID; + event.value = isClosed; + err = TEMP_FAILURE_RETRY(write(uinputFd, &event, sizeof (event))); + if (err < 0) { + ALOGE("Write EV_SW to uinput node failed: %s", strerror(errno)); + goto out; + } + + // Force a flush with an EV_SYN + event.type = EV_SYN; + event.code = SYN_REPORT; + event.value = 0; + err = TEMP_FAILURE_RETRY(write(uinputFd, &event, sizeof (event))); + if (err < 0) { + ALOGE("Write EV_SYN to uinput node failed: %s", + strerror(errno)); + goto out; + } + + ALOGI("Sent lid %s event", isClosed ? "closed" : "open"); + } + } + +out: + // Clean up + if (sensorManager != nullptr && eventQueue != nullptr) { + ASensorManager_destroyEventQueue(sensorManager, eventQueue); + } + + if (uinputFd >= 0) { + close(uinputFd); + } + + // The loop can only be exited via failure or signal + return 1; +} diff --git a/rootdir/etc/init.target.rc b/rootdir/etc/init.target.rc index 3ed157b6..5ad2d7ce 100755 --- a/rootdir/etc/init.target.rc +++ b/rootdir/etc/init.target.rc @@ -152,6 +152,18 @@ on boot chmod 660 /sys/devices/platform/kcal_ctrl.0/kcal_min chmod 660 /sys/devices/platform/kcal_ctrl.0/kcal +service vendor.folio_daemon /vendor/bin/folio_daemon + class late_start + user system + group system uhid + disabled + +on property:init.svc.zygote=running + start vendor.folio_daemon + +on property:init.svc.zygote=stopped + stop vendor.folio_daemon + #Peripheral manager service vendor.per_mgr /system/vendor/bin/pm-service class core diff --git a/sdm660.mk b/sdm660.mk index 92241dfd..eb3d7df7 100644 --- a/sdm660.mk +++ b/sdm660.mk @@ -242,6 +242,10 @@ PRODUCT_PACKAGES += \ PRODUCT_COPY_FILES += \ frameworks/native/data/etc/android.software.freeform_window_management.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.freeform_window_management.xml +# Folio +PRODUCT_PACKAGES += \ + folio_daemon + # GPS / Location PRODUCT_PACKAGES += \ android.hardware.gnss@1.0-impl-qti \ diff --git a/sepolicy/vendor/file_contexts b/sepolicy/vendor/file_contexts index cb1a0477..cb3548ed 100644 --- a/sepolicy/vendor/file_contexts +++ b/sepolicy/vendor/file_contexts @@ -22,6 +22,9 @@ /firmware u:object_r:firmware_file:s0 /bt_firmware u:object_r:bt_firmware_file:s0 +# Folio daemon +/vendor/bin/folio_daemon u:object_r:folio_daemon_exec:s0 + # HVDCP /sys/devices(/platform)?/soc/[a-z0-9]+\.i2c/i2c-[0-9]+/[0-9]+-[a-z0-9]+/[a-z0-9]+\.i2c:qcom,[a-z0-9]+@[a-z0-9]:qcom,smb[a-z0-9]+-parallel-slave@[0-9]+/power_supply/parallel(/.*)? u:object_r:sysfs_usb_supply:s0 diff --git a/sepolicy/vendor/folio_daemon.te b/sepolicy/vendor/folio_daemon.te new file mode 100644 index 00000000..a4d54447 --- /dev/null +++ b/sepolicy/vendor/folio_daemon.te @@ -0,0 +1,4 @@ +type folio_daemon, domain; +type folio_daemon_exec, exec_type, file_type; + +init_daemon_domain(folio_daemon)