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 
coresonline(int off)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 
enc_boost(int off)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 
process_video_encode_hint(void * metadata)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 
touch_boost()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 
low_power(int on)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 
process_low_power_hint(void * data)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 
power_set_interactive(struct power_module * module,int on)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 
power_hint(struct power_module * module,power_hint_t hint,void * data)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