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
socket_init()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
power_init(struct power_module * module)62 static void power_init(__attribute__((unused)) struct power_module *module)
63 {
64 ALOGI("%s", __func__);
65 socket_init();
66 }
67
sync_thread(int off)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
coresonline(int off)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
enc_boost(int off)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
process_video_encode_hint(void * metadata)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
touch_boost()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
low_power(int on)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
process_low_power_hint(void * data)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
power_set_interactive(struct power_module * module,int on)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
power_hint(struct power_module * module,power_hint_t hint,void * data)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