1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #include <errno.h> 17 #include <string.h> 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <sys/socket.h> 21 #include <sys/un.h> 22 #include <fcntl.h> 23 #include <dlfcn.h> 24 #include <cutils/uevent.h> 25 #include <errno.h> 26 #include <sys/poll.h> 27 #include <pthread.h> 28 #include <linux/netlink.h> 29 #include <stdlib.h> 30 #include <stdbool.h> 31 32 #define LOG_TAG "PowerHAL" 33 #include <utils/Log.h> 34 35 #include <hardware/hardware.h> 36 #include <hardware/power.h> 37 38 #define STATE_ON "state=1" 39 #define STATE_OFF "state=0" 40 #define STATE_HDR_ON "state=2" 41 #define STATE_HDR_OFF "state=3" 42 #define MAX_LENGTH 50 43 #define BOOST_SOCKET "/dev/socket/mpdecision/pb" 44 static int client_sockfd; 45 static struct sockaddr_un client_addr; 46 static int last_state = -1; 47 48 static void socket_init() 49 { 50 if (!client_sockfd) { 51 client_sockfd = socket(PF_UNIX, SOCK_DGRAM, 0); 52 if (client_sockfd < 0) { 53 ALOGE("%s: failed to open: %s", __func__, strerror(errno)); 54 return; 55 } 56 memset(&client_addr, 0, sizeof(struct sockaddr_un)); 57 client_addr.sun_family = AF_UNIX; 58 snprintf(client_addr.sun_path, UNIX_PATH_MAX, BOOST_SOCKET); 59 } 60 } 61 62 static void power_init(__attribute__((unused)) struct power_module *module) 63 { 64 ALOGI("%s", __func__); 65 socket_init(); 66 } 67 68 static void coresonline(int off) 69 { 70 int rc; 71 pid_t client; 72 char data[MAX_LENGTH]; 73 74 if (client_sockfd < 0) { 75 ALOGE("%s: boost socket not created", __func__); 76 return; 77 } 78 79 client = getpid(); 80 81 if (!off) { 82 snprintf(data, MAX_LENGTH, "8:%d", client); 83 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 84 } else { 85 snprintf(data, MAX_LENGTH, "7:%d", client); 86 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 87 } 88 89 if (rc < 0) { 90 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 91 } 92 } 93 94 static void enc_boost(int off) 95 { 96 int rc; 97 pid_t client; 98 char data[MAX_LENGTH]; 99 100 if (client_sockfd < 0) { 101 ALOGE("%s: boost socket not created", __func__); 102 return; 103 } 104 105 client = getpid(); 106 107 if (!off) { 108 snprintf(data, MAX_LENGTH, "5:%d", client); 109 rc = sendto(client_sockfd, data, strlen(data), 0, 110 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 111 } else { 112 snprintf(data, MAX_LENGTH, "6:%d", client); 113 rc = sendto(client_sockfd, data, strlen(data), 0, 114 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 115 } 116 117 if (rc < 0) { 118 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 119 } 120 } 121 122 static void process_video_encode_hint(void *metadata) 123 { 124 125 socket_init(); 126 127 if (client_sockfd < 0) { 128 ALOGE("%s: boost socket not created", __func__); 129 return; 130 } 131 132 if (metadata) { 133 if (!strncmp(metadata, STATE_ON, sizeof(STATE_ON))) { 134 /* Video encode started */ 135 enc_boost(1); 136 } else if (!strncmp(metadata, STATE_OFF, sizeof(STATE_OFF))) { 137 /* Video encode stopped */ 138 enc_boost(0); 139 } else if (!strncmp(metadata, STATE_HDR_ON, sizeof(STATE_HDR_ON))) { 140 /* HDR usecase started */ 141 } else if (!strncmp(metadata, STATE_HDR_OFF, sizeof(STATE_HDR_OFF))) { 142 /* HDR usecase stopped */ 143 }else 144 return; 145 } else { 146 return; 147 } 148 } 149 150 151 static void touch_boost() 152 { 153 int rc, fd; 154 pid_t client; 155 char data[MAX_LENGTH]; 156 char buf[MAX_LENGTH]; 157 158 if (client_sockfd < 0) { 159 ALOGE("%s: boost socket not created", __func__); 160 return; 161 } 162 163 client = getpid(); 164 165 snprintf(data, MAX_LENGTH, "1:%d", client); 166 rc = sendto(client_sockfd, data, strlen(data), 0, 167 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 168 if (rc < 0) { 169 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 170 } 171 } 172 173 static void low_power(int on) 174 { 175 int rc; 176 pid_t client; 177 char data[MAX_LENGTH]; 178 179 if (client_sockfd < 0) { 180 ALOGE("%s: boost socket not created", __func__); 181 return; 182 } 183 184 client = getpid(); 185 186 if (on) { 187 snprintf(data, MAX_LENGTH, "10:%d", client); 188 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 189 if (rc < 0) { 190 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 191 } 192 } else { 193 snprintf(data, MAX_LENGTH, "9:%d", client); 194 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 195 if (rc < 0) { 196 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 197 } 198 } 199 } 200 201 static void process_low_power_hint(void* data) 202 { 203 int on = (long) data; 204 if (client_sockfd < 0) { 205 ALOGE("%s: boost socket not created", __func__); 206 return; 207 } 208 209 low_power(on); 210 } 211 212 static void power_set_interactive(__attribute__((unused)) struct power_module *module, int on) 213 { 214 if (last_state == -1) { 215 last_state = on; 216 } else { 217 if (last_state == on) 218 return; 219 else 220 last_state = on; 221 } 222 223 ALOGV("%s %s", __func__, (on ? "ON" : "OFF")); 224 if (on) { 225 coresonline(0); 226 touch_boost(); 227 } else { 228 coresonline(1); 229 } 230 } 231 232 static void power_hint( __attribute__((unused)) struct power_module *module, 233 __attribute__((unused)) power_hint_t hint, 234 __attribute__((unused)) void *data) 235 { 236 switch (hint) { 237 case POWER_HINT_INTERACTION: 238 ALOGV("POWER_HINT_INTERACTION"); 239 touch_boost(); 240 break; 241 #if 0 242 case POWER_HINT_VSYNC: 243 ALOGV("POWER_HINT_VSYNC %s", (data ? "ON" : "OFF")); 244 break; 245 #endif 246 case POWER_HINT_VIDEO_ENCODE: 247 process_video_encode_hint(data); 248 break; 249 case POWER_HINT_LOW_POWER: 250 process_low_power_hint(data); 251 break; 252 default: 253 break; 254 } 255 } 256 257 static struct hw_module_methods_t power_module_methods = { 258 .open = NULL, 259 }; 260 261 struct power_module HAL_MODULE_INFO_SYM = { 262 .common = { 263 .tag = HARDWARE_MODULE_TAG, 264 .module_api_version = POWER_MODULE_API_VERSION_0_2, 265 .hal_api_version = HARDWARE_HAL_API_VERSION, 266 .id = POWER_HARDWARE_MODULE_ID, 267 .name = "Shamu Power HAL", 268 .author = "The Android Open Source Project", 269 .methods = &power_module_methods, 270 }, 271 272 .init = power_init, 273 .setInteractive = power_set_interactive, 274 .powerHint = power_hint, 275 }; 276