1 /*
2  * Copyright (C) 2012 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 
25 #define LOG_TAG "PowerHAL"
26 #include <utils/Log.h>
27 
28 #include <hardware/hardware.h>
29 #include <hardware/power.h>
30 
31 #define STATE_ON "state=1"
32 #define STATE_OFF "state=0"
33 #define STATE_HDR_ON "state=2"
34 #define STATE_HDR_OFF "state=3"
35 
36 #define MAX_LENGTH         50
37 #define BOOST_SOCKET       "/dev/socket/pb"
38 
39 static int client_sockfd;
40 static struct sockaddr_un client_addr;
41 static int last_state = -1;
42 
socket_init()43 static void socket_init()
44 {
45     if (!client_sockfd) {
46         client_sockfd = socket(PF_UNIX, SOCK_DGRAM, 0);
47         if (client_sockfd < 0) {
48             ALOGE("%s: failed to open: %s", __func__, strerror(errno));
49             return;
50         }
51         memset(&client_addr, 0, sizeof(struct sockaddr_un));
52         client_addr.sun_family = AF_UNIX;
53         snprintf(client_addr.sun_path, UNIX_PATH_MAX, BOOST_SOCKET);
54     }
55 }
56 
power_init(struct power_module * module)57 static void power_init(struct power_module *module)
58 {
59     ALOGI("%s", __func__);
60     socket_init();
61 }
62 
sync_thread(int off)63 static void sync_thread(int off)
64 {
65     int rc;
66     pid_t client;
67     char data[MAX_LENGTH];
68 
69     if (client_sockfd < 0) {
70         ALOGE("%s: boost socket not created", __func__);
71         return;
72     }
73 
74     client = getpid();
75 
76     if (!off) {
77         snprintf(data, MAX_LENGTH, "2:%d", client);
78         rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
79     } else {
80         snprintf(data, MAX_LENGTH, "3:%d", client);
81         rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
82     }
83 
84     if (rc < 0) {
85         ALOGE("%s: failed to send: %s", __func__, strerror(errno));
86     }
87 }
88 
enc_boost(int off)89 static void enc_boost(int off)
90 {
91     int rc;
92     pid_t client;
93     char data[MAX_LENGTH];
94 
95     if (client_sockfd < 0) {
96         ALOGE("%s: boost socket not created", __func__);
97         return;
98     }
99 
100     client = getpid();
101 
102     if (!off) {
103         snprintf(data, MAX_LENGTH, "5:%d", client);
104         rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
105     } else {
106         snprintf(data, MAX_LENGTH, "6:%d", client);
107         rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
108     }
109 
110     if (rc < 0) {
111         ALOGE("%s: failed to send: %s", __func__, strerror(errno));
112     }
113 }
114 
process_video_encode_hint(void * metadata)115 static void process_video_encode_hint(void *metadata)
116 {
117 
118     socket_init();
119 
120     if (client_sockfd < 0) {
121         ALOGE("%s: boost socket not created", __func__);
122         return;
123     }
124 
125     if (metadata) {
126         if (!strncmp(metadata, STATE_ON, sizeof(STATE_ON))) {
127             /* Video encode started */
128             sync_thread(1);
129             enc_boost(1);
130         } else if (!strncmp(metadata, STATE_OFF, sizeof(STATE_OFF))) {
131             /* Video encode stopped */
132             sync_thread(0);
133             enc_boost(0);
134         }  else if (!strncmp(metadata, STATE_HDR_ON, sizeof(STATE_HDR_ON))) {
135             /* HDR usecase started */
136         } else if (!strncmp(metadata, STATE_HDR_OFF, sizeof(STATE_HDR_OFF))) {
137             /* HDR usecase stopped */
138         }else
139             return;
140     } else {
141         return;
142     }
143 }
144 
145 
touch_boost()146 static void touch_boost()
147 {
148     int rc;
149     pid_t client;
150     char data[MAX_LENGTH];
151 
152     if (client_sockfd < 0) {
153         ALOGE("%s: boost socket not created", __func__);
154         return;
155     }
156 
157     client = getpid();
158 
159     snprintf(data, MAX_LENGTH, "1:%d", client);
160     rc = sendto(client_sockfd, data, strlen(data), 0, (const struct sockaddr *)&client_addr, sizeof(struct sockaddr_un));
161     if (rc < 0) {
162         ALOGE("%s: failed to send: %s", __func__, strerror(errno));
163     }
164 }
165 
power_set_interactive(struct power_module * module,int on)166 static void power_set_interactive(struct power_module *module, int on)
167 {
168     if (last_state == -1) {
169         last_state = on;
170     } else {
171         if (last_state == on)
172             return;
173         else
174             last_state = on;
175     }
176 
177     ALOGV("%s %s", __func__, (on ? "ON" : "OFF"));
178     if (on) {
179         sync_thread(0);
180         touch_boost();
181     } else {
182         sync_thread(1);
183     }
184 }
185 
power_hint(struct power_module * module,power_hint_t hint,void * data)186 static void power_hint(struct power_module *module, power_hint_t hint,
187                        void *data) {
188     switch (hint) {
189         case POWER_HINT_INTERACTION:
190             ALOGV("POWER_HINT_INTERACTION");
191             touch_boost();
192             break;
193 #if 0
194         case POWER_HINT_VSYNC:
195             ALOGV("POWER_HINT_VSYNC %s", (data ? "ON" : "OFF"));
196             break;
197 #endif
198         case POWER_HINT_VIDEO_ENCODE:
199             process_video_encode_hint(data);
200             break;
201         default:
202              break;
203     }
204 }
205 
206 static struct hw_module_methods_t power_module_methods = {
207     .open = NULL,
208 };
209 
210 struct power_module HAL_MODULE_INFO_SYM = {
211     .common = {
212         .tag = HARDWARE_MODULE_TAG,
213         .module_api_version = POWER_MODULE_API_VERSION_0_2,
214         .hal_api_version = HARDWARE_HAL_API_VERSION,
215         .id = POWER_HARDWARE_MODULE_ID,
216         .name = "Qualcomm Power HAL",
217         .author = "The Android Open Source Project",
218         .methods = &power_module_methods,
219     },
220 
221     .init = power_init,
222     .setInteractive = power_set_interactive,
223     .powerHint = power_hint,
224 };
225