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 
43 #define MAX_LENGTH         50
44 #define BOOST_SOCKET       "/dev/socket/pb"
45 
46 #define UEVENT_MSG_LEN 2048
47 #define TOTAL_CPUS 4
48 #define RETRY_TIME_CHANGING_FREQ 20
49 #define SLEEP_USEC_BETWN_RETRY 200
50 #define LOW_POWER_MAX_FREQ "1026000"
51 #define LOW_POWER_MIN_FREQ "384000"
52 #define NORMAL_MAX_FREQ "1512000"
53 #define UEVENT_STRING "online@/devices/system/cpu/"
54 
55 static int client_sockfd;
56 static struct sockaddr_un client_addr;
57 static int last_state = -1;
58 
59 static struct pollfd pfd;
60 static char *cpu_path_min[] = {
61     "/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq",
62     "/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq",
63     "/sys/devices/system/cpu/cpu2/cpufreq/scaling_min_freq",
64     "/sys/devices/system/cpu/cpu3/cpufreq/scaling_min_freq",
65 };
66 static char *cpu_path_max[] = {
67     "/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq",
68     "/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq",
69     "/sys/devices/system/cpu/cpu2/cpufreq/scaling_max_freq",
70     "/sys/devices/system/cpu/cpu3/cpufreq/scaling_max_freq",
71 };
72 static bool freq_set[TOTAL_CPUS];
73 static bool low_power_mode = false;
74 static pthread_mutex_t low_power_mode_lock = PTHREAD_MUTEX_INITIALIZER;
75 
socket_init()76 static void socket_init()
77 {
78     if (!client_sockfd) {
79         client_sockfd = socket(PF_UNIX, SOCK_DGRAM, 0);
80         if (client_sockfd < 0) {
81             ALOGE("%s: failed to open: %s", __func__, strerror(errno));
82             return;
83         }
84         memset(&client_addr, 0, sizeof(struct sockaddr_un));
85         client_addr.sun_family = AF_UNIX;
86         snprintf(client_addr.sun_path, UNIX_PATH_MAX, BOOST_SOCKET);
87     }
88 }
89 
sysfs_write(const char * path,char * s)90 static int sysfs_write(const char *path, char *s)
91 {
92     char buf[80];
93     int len;
94     int fd = open(path, O_WRONLY);
95 
96     if (fd < 0) {
97         strerror_r(errno, buf, sizeof(buf));
98         ALOGE("Error opening %s: %s\n", path, buf);
99         return -1;
100     }
101 
102     len = write(fd, s, strlen(s));
103     if (len < 0) {
104         strerror_r(errno, buf, sizeof(buf));
105         ALOGE("Error writing to %s: %s\n", path, buf);
106         return -1;
107     }
108 
109     close(fd);
110     return 0;
111 }
112 
uevent_event()113 static int uevent_event()
114 {
115     char msg[UEVENT_MSG_LEN];
116     char *cp;
117     int n, cpu, ret, retry = RETRY_TIME_CHANGING_FREQ;
118 
119     n = recv(pfd.fd, msg, UEVENT_MSG_LEN, MSG_DONTWAIT);
120     if (n <= 0) {
121         return -1;
122     }
123     if (n >= UEVENT_MSG_LEN) {   /* overflow -- discard */
124         return -1;
125     }
126 
127     cp = msg;
128 
129     if (strstr(cp, UEVENT_STRING)) {
130         n = strlen(cp);
131         errno = 0;
132         cpu = strtol(cp + n - 1, NULL, 10);
133 
134         if (errno == EINVAL || errno == ERANGE || cpu < 0 || cpu >= TOTAL_CPUS) {
135             return -1;
136         }
137 
138         pthread_mutex_lock(&low_power_mode_lock);
139         if (low_power_mode && !freq_set[cpu]) {
140             while (retry) {
141                 sysfs_write(cpu_path_min[cpu], LOW_POWER_MIN_FREQ);
142                 ret = sysfs_write(cpu_path_max[cpu], LOW_POWER_MAX_FREQ);
143                 if (!ret) {
144                     freq_set[cpu] = true;
145                     break;
146                 }
147                 usleep(SLEEP_USEC_BETWN_RETRY);
148                 retry--;
149            }
150         } else if (!low_power_mode && freq_set[cpu]) {
151              while (retry) {
152                   ret = sysfs_write(cpu_path_max[cpu], NORMAL_MAX_FREQ);
153                   if (!ret) {
154                       freq_set[cpu] = false;
155                       break;
156                   }
157                   usleep(SLEEP_USEC_BETWN_RETRY);
158                   retry--;
159              }
160         }
161         pthread_mutex_unlock(&low_power_mode_lock);
162     }
163     return 0;
164 }
165 
thread_uevent(void * x)166 void *thread_uevent(__attribute__((unused)) void *x)
167 {
168     while (1) {
169         int nevents, ret;
170 
171         nevents = poll(&pfd, 1, -1);
172 
173         if (nevents == -1) {
174             if (errno == EINTR)
175                 continue;
176             ALOGE("powerhal: thread_uevent: poll_wait failed\n");
177             break;
178         }
179         ret = uevent_event();
180         if (ret < 0)
181             ALOGE("Error processing the uevent event");
182     }
183     return NULL;
184 }
185 
uevent_init()186 static void uevent_init()
187 {
188     struct sockaddr_nl client;
189     pthread_t tid;
190     pfd.fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
191 
192     if (pfd.fd < 0) {
193         ALOGE("%s: failed to open: %s", __func__, strerror(errno));
194         return;
195     }
196     memset(&client, 0, sizeof(struct sockaddr_nl));
197     pthread_create(&tid, NULL, thread_uevent, NULL);
198     client.nl_family = AF_NETLINK;
199     client.nl_pid = tid;
200     client.nl_groups = -1;
201     pfd.events = POLLIN;
202     bind(pfd.fd, (void *)&client, sizeof(struct sockaddr_nl));
203     return;
204 }
205 
power_init(struct power_module * module)206 static void power_init(__attribute__((unused)) struct power_module *module)
207 {
208     ALOGI("%s", __func__);
209     socket_init();
210     uevent_init();
211 }
212 
sync_thread(int off)213 static void sync_thread(int off)
214 {
215     int rc;
216     pid_t client;
217     char data[MAX_LENGTH];
218 
219     if (client_sockfd < 0) {
220         ALOGE("%s: boost socket not created", __func__);
221         return;
222     }
223 
224     client = getpid();
225 
226     if (!off) {
227         snprintf(data, MAX_LENGTH, "2:%d", client);
228         rc = sendto(client_sockfd, data, strlen(data), 0,
229             (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
230     } else {
231         snprintf(data, MAX_LENGTH, "3:%d", client);
232         rc = sendto(client_sockfd, data, strlen(data), 0,
233             (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
234     }
235 
236     if (rc < 0) {
237         ALOGE("%s: failed to send: %s", __func__, strerror(errno));
238     }
239 }
240 
enc_boost(int off)241 static void enc_boost(int off)
242 {
243     int rc;
244     pid_t client;
245     char data[MAX_LENGTH];
246 
247     if (client_sockfd < 0) {
248         ALOGE("%s: boost socket not created", __func__);
249         return;
250     }
251 
252     client = getpid();
253 
254     if (!off) {
255         snprintf(data, MAX_LENGTH, "5:%d", client);
256         rc = sendto(client_sockfd, data, strlen(data), 0,
257             (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
258     } else {
259         snprintf(data, MAX_LENGTH, "6:%d", client);
260         rc = sendto(client_sockfd, data, strlen(data), 0,
261             (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
262     }
263 
264     if (rc < 0) {
265         ALOGE("%s: failed to send: %s", __func__, strerror(errno));
266     }
267 }
268 
process_video_encode_hint(void * metadata)269 static void process_video_encode_hint(void *metadata)
270 {
271 
272     socket_init();
273 
274     if (client_sockfd < 0) {
275         ALOGE("%s: boost socket not created", __func__);
276         return;
277     }
278 
279     if (metadata) {
280         if (!strncmp(metadata, STATE_ON, sizeof(STATE_ON))) {
281             /* Video encode started */
282             sync_thread(1);
283             enc_boost(1);
284         } else if (!strncmp(metadata, STATE_OFF, sizeof(STATE_OFF))) {
285             /* Video encode stopped */
286             sync_thread(0);
287             enc_boost(0);
288         }  else if (!strncmp(metadata, STATE_HDR_ON, sizeof(STATE_HDR_ON))) {
289             /* HDR usecase started */
290         } else if (!strncmp(metadata, STATE_HDR_OFF, sizeof(STATE_HDR_OFF))) {
291             /* HDR usecase stopped */
292         }else
293             return;
294     } else {
295         return;
296     }
297 }
298 
299 
touch_boost()300 static void touch_boost()
301 {
302     int rc;
303     pid_t client;
304     char data[MAX_LENGTH];
305 
306     if (client_sockfd < 0) {
307         ALOGE("%s: boost socket not created", __func__);
308         return;
309     }
310 
311     client = getpid();
312 
313     snprintf(data, MAX_LENGTH, "1:%d", client);
314     rc = sendto(client_sockfd, data, strlen(data), 0,
315         (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
316     if (rc < 0) {
317         ALOGE("%s: failed to send: %s", __func__, strerror(errno));
318     }
319 }
320 
power_set_interactive(struct power_module * module,int on)321 static void power_set_interactive(__attribute__((unused)) struct power_module *module, int on)
322 {
323     if (last_state == -1) {
324         last_state = on;
325     } else {
326         if (last_state == on)
327             return;
328         else
329             last_state = on;
330     }
331 
332     ALOGV("%s %s", __func__, (on ? "ON" : "OFF"));
333     if (on) {
334         sync_thread(0);
335         touch_boost();
336     } else {
337         sync_thread(1);
338     }
339 }
340 
power_hint(struct power_module * module,power_hint_t hint,void * data)341 static void power_hint( __attribute__((unused)) struct power_module *module,
342                       power_hint_t hint, __attribute__((unused)) void *data)
343 {
344     int cpu, ret;
345 
346     switch (hint) {
347         case POWER_HINT_INTERACTION:
348             ALOGV("POWER_HINT_INTERACTION");
349             touch_boost();
350             break;
351 #if 0
352         case POWER_HINT_VSYNC:
353             ALOGV("POWER_HINT_VSYNC %s", (data ? "ON" : "OFF"));
354             break;
355 #endif
356         case POWER_HINT_VIDEO_ENCODE:
357             process_video_encode_hint(data);
358             break;
359 
360         case POWER_HINT_LOW_POWER:
361              pthread_mutex_lock(&low_power_mode_lock);
362              if (data) {
363                  low_power_mode = true;
364                  for (cpu = 0; cpu < TOTAL_CPUS; cpu++) {
365                      sysfs_write(cpu_path_min[cpu], LOW_POWER_MIN_FREQ);
366                      ret = sysfs_write(cpu_path_max[cpu], LOW_POWER_MAX_FREQ);
367                      if (!ret) {
368                          freq_set[cpu] = true;
369                      }
370                  }
371              } else {
372                  low_power_mode = false;
373                  for (cpu = 0; cpu < TOTAL_CPUS; cpu++) {
374                      ret = sysfs_write(cpu_path_max[cpu], NORMAL_MAX_FREQ);
375                      if (!ret) {
376                          freq_set[cpu] = false;
377                      }
378                  }
379              }
380              pthread_mutex_unlock(&low_power_mode_lock);
381              break;
382         default:
383              break;
384     }
385 }
386 
387 static struct hw_module_methods_t power_module_methods = {
388     .open = NULL,
389 };
390 
391 struct power_module HAL_MODULE_INFO_SYM = {
392     .common = {
393         .tag = HARDWARE_MODULE_TAG,
394         .module_api_version = POWER_MODULE_API_VERSION_0_2,
395         .hal_api_version = HARDWARE_HAL_API_VERSION,
396         .id = POWER_HARDWARE_MODULE_ID,
397         .name = "Mako Power HAL",
398         .author = "The Android Open Source Project",
399         .methods = &power_module_methods,
400     },
401 
402     .init = power_init,
403     .setInteractive = power_set_interactive,
404     .powerHint = power_hint,
405 };
406