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 sync_thread(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, "2:%d", client); 83 rc = sendto(client_sockfd, data, strlen(data), 0, 84 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 85 } else { 86 snprintf(data, MAX_LENGTH, "3:%d", client); 87 rc = sendto(client_sockfd, data, strlen(data), 0, 88 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 89 } 90 91 if (rc < 0) { 92 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 93 } 94 } 95 96 static void coresonline(int off) 97 { 98 int rc; 99 pid_t client; 100 char data[MAX_LENGTH]; 101 102 if (client_sockfd < 0) { 103 ALOGE("%s: boost socket not created", __func__); 104 return; 105 } 106 107 client = getpid(); 108 109 if (!off) { 110 snprintf(data, MAX_LENGTH, "8:%d", client); 111 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 112 } else { 113 snprintf(data, MAX_LENGTH, "7:%d", client); 114 rc = sendto(client_sockfd, data, strlen(data), 0, (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 enc_boost(int off) 123 { 124 int rc; 125 pid_t client; 126 char data[MAX_LENGTH]; 127 128 if (client_sockfd < 0) { 129 ALOGE("%s: boost socket not created", __func__); 130 return; 131 } 132 133 client = getpid(); 134 135 if (!off) { 136 snprintf(data, MAX_LENGTH, "5:%d", client); 137 rc = sendto(client_sockfd, data, strlen(data), 0, 138 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 139 } else { 140 snprintf(data, MAX_LENGTH, "6:%d", client); 141 rc = sendto(client_sockfd, data, strlen(data), 0, 142 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 143 } 144 145 if (rc < 0) { 146 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 147 } 148 } 149 150 static void process_video_encode_hint(void *metadata) 151 { 152 153 socket_init(); 154 155 if (client_sockfd < 0) { 156 ALOGE("%s: boost socket not created", __func__); 157 return; 158 } 159 160 if (metadata) { 161 if (!strncmp(metadata, STATE_ON, sizeof(STATE_ON))) { 162 /* Video encode started */ 163 sync_thread(1); 164 enc_boost(1); 165 } else if (!strncmp(metadata, STATE_OFF, sizeof(STATE_OFF))) { 166 /* Video encode stopped */ 167 sync_thread(0); 168 enc_boost(0); 169 } else if (!strncmp(metadata, STATE_HDR_ON, sizeof(STATE_HDR_ON))) { 170 /* HDR usecase started */ 171 } else if (!strncmp(metadata, STATE_HDR_OFF, sizeof(STATE_HDR_OFF))) { 172 /* HDR usecase stopped */ 173 }else 174 return; 175 } else { 176 return; 177 } 178 } 179 180 181 static void touch_boost() 182 { 183 int rc, fd; 184 pid_t client; 185 char data[MAX_LENGTH]; 186 char buf[MAX_LENGTH]; 187 188 if (client_sockfd < 0) { 189 ALOGE("%s: boost socket not created", __func__); 190 return; 191 } 192 193 client = getpid(); 194 195 snprintf(data, MAX_LENGTH, "1:%d", client); 196 rc = sendto(client_sockfd, data, strlen(data), 0, 197 (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 198 if (rc < 0) { 199 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 200 } 201 } 202 203 static void low_power(int on) 204 { 205 int rc; 206 pid_t client; 207 char data[MAX_LENGTH]; 208 209 if (client_sockfd < 0) { 210 ALOGE("%s: boost socket not created", __func__); 211 return; 212 } 213 214 client = getpid(); 215 216 if (on) { 217 snprintf(data, MAX_LENGTH, "10:%d", client); 218 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 219 if (rc < 0) { 220 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 221 } 222 } else { 223 snprintf(data, MAX_LENGTH, "9:%d", client); 224 rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un)); 225 if (rc < 0) { 226 ALOGE("%s: failed to send: %s", __func__, strerror(errno)); 227 } 228 } 229 } 230 231 static void process_low_power_hint(void* data) 232 { 233 int on = (long) data; 234 if (client_sockfd < 0) { 235 ALOGE("%s: boost socket not created", __func__); 236 return; 237 } 238 239 low_power(on); 240 } 241 242 static void power_set_interactive(__attribute__((unused)) struct power_module *module, int on) 243 { 244 if (last_state == -1) { 245 last_state = on; 246 } else { 247 if (last_state == on) 248 return; 249 else 250 last_state = on; 251 } 252 253 ALOGV("%s %s", __func__, (on ? "ON" : "OFF")); 254 if (on) { 255 coresonline(0); 256 sync_thread(0); 257 touch_boost(); 258 } else { 259 sync_thread(1); 260 coresonline(1); 261 } 262 } 263 264 static void power_hint( __attribute__((unused)) struct power_module *module, 265 __attribute__((unused)) power_hint_t hint, 266 __attribute__((unused)) void *data) 267 { 268 switch (hint) { 269 case POWER_HINT_INTERACTION: 270 ALOGV("POWER_HINT_INTERACTION"); 271 touch_boost(); 272 break; 273 #if 0 274 case POWER_HINT_VSYNC: 275 ALOGV("POWER_HINT_VSYNC %s", (data ? "ON" : "OFF")); 276 break; 277 #endif 278 case POWER_HINT_VIDEO_ENCODE: 279 process_video_encode_hint(data); 280 break; 281 case POWER_HINT_LOW_POWER: 282 process_low_power_hint(data); 283 break; 284 default: 285 break; 286 } 287 } 288 289 static struct hw_module_methods_t power_module_methods = { 290 .open = NULL, 291 }; 292 293 struct power_module HAL_MODULE_INFO_SYM = { 294 .common = { 295 .tag = HARDWARE_MODULE_TAG, 296 .module_api_version = POWER_MODULE_API_VERSION_0_2, 297 .hal_api_version = HARDWARE_HAL_API_VERSION, 298 .id = POWER_HARDWARE_MODULE_ID, 299 .name = "Shamu Power HAL", 300 .author = "The Android Open Source Project", 301 .methods = &power_module_methods, 302 }, 303 304 .init = power_init, 305 .setInteractive = power_set_interactive, 306 .powerHint = power_hint, 307 }; 308