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