• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 
17 #define LOG_TAG "VrHALImpl"
18 
19 #include <cutils/log.h>
20 
21 #include <dlfcn.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 
29 #include <hardware/vr.h>
30 #include <hardware/hardware.h>
31 
32 #include "thermal_client.h"
33 
34 
35 static void *dlhandle;
36 static int (*p_thermal_client_config_query)(char *, struct config_instance **);
37 static int (*p_thermal_client_config_set)(struct config_instance *, unsigned int);
38 static void (*p_thermal_client_config_cleanup)(struct config_instance *, unsigned int);
39 
40 static int max_string_size = 36;
41 static int error_state = 0; //global error state - don't do anything if set!
42 
43 // List thermal configs in format {name, algo_type}
44 // This list is manually synced with the thermal config
45 #define NUM_NON_VR_CONFIGS 4
46 static char *non_vr_thermal_configs[NUM_NON_VR_CONFIGS][2] =
47     {{"SKIN-HIGH-FLOOR",     "ss"},
48      {"SKIN-MID-FLOOR",      "ss"},
49      {"SKIN-LOW-FLOOR",      "ss"},
50      {"VIRTUAL-SS-GPU-SKIN", "ss"}};
51 #define NUM_VR_CONFIGS 1
52 static char *vr_thermal_configs[NUM_VR_CONFIGS][2] =
53     {{"VR-EMMC",     "monitor"}};
54 
55 #define DEBUG 0
56 
57 /**
58  * Debug function for printing out a log instance
59  */
log_config_instance(struct config_instance * instance)60 static void log_config_instance(struct config_instance *instance ){
61     ALOGI("logging config_instance 0x%p", instance);
62     ALOGI("config_instance: cfg_desc = %s", instance->cfg_desc);
63     ALOGI("config_instance: algo_type = %s", instance->algo_type);
64     ALOGI("config_instance: fields_mask = 0x%x", instance->fields_mask);
65     ALOGI("config_instance: num_fields = %u", instance->num_fields);
66     for (uint32_t i = 0; i < instance->num_fields; i++) {
67         ALOGI("config_instance: field_data[%d]", i);
68         ALOGI("\tfield_name = %s", instance->fields[i].field_name);
69         ALOGI("\tdata_type = %u", instance->fields[i].data_type);
70         ALOGI("\tnum_data = %u", instance->fields[i].num_data);
71         switch (instance->fields[i].data_type){
72           case FIELD_INT: ALOGI("\tdata = %d", *(int*)(instance->fields[i].data)); break;
73           case FIELD_STR: ALOGI("\tdata = %s", (char*)(instance->fields[i].data)); break;
74           default: ALOGI("\tdata = 0x%p", instance->fields[i].data); break;
75         }
76     }
77 }
78 
79 /**
80  * Debug function for printing out all instances of "ss" and "monitor" algos
81  */
query_thermal_config()82 static void query_thermal_config(){
83     struct config_instance *instances;
84 
85     int num_configs = (*p_thermal_client_config_query)("ss", &instances);
86     if (num_configs <= 0) {
87         return;
88     }
89     for (int i = 0; i < num_configs; i++) {
90         log_config_instance(&(instances[i]));
91     }
92     if (num_configs > 0) {
93         (*p_thermal_client_config_cleanup)(instances,num_configs);
94     }
95 
96     num_configs = (*p_thermal_client_config_query)("monitor", &instances);
97     if (num_configs <= 0) {
98         return;
99     }
100     for (int i = 0; i < num_configs; i++) {
101         log_config_instance(&(instances[i]));
102     }
103     if (num_configs > 0) {
104         (*p_thermal_client_config_cleanup)(instances,num_configs);
105     }
106 }
107 
108 /**
109  * Load the thermal client library
110  * returns 0 on success
111  */
load_thermal_client(void)112 static int load_thermal_client(void)
113 {
114     char *thermal_client_so = "vendor/lib64/libthermalclient.so";
115 
116     dlhandle = dlopen(thermal_client_so, RTLD_NOW | RTLD_LOCAL);
117     if (dlhandle) {
118         dlerror();
119         p_thermal_client_config_query = (int (*) (char *, struct config_instance **))
120             dlsym(dlhandle, "thermal_client_config_query");
121         if (dlerror()) {
122             ALOGE("Unable to load thermal_client_config_query");
123             goto error_handle;
124         }
125 
126         p_thermal_client_config_set = (int (*) (struct config_instance *, unsigned int))
127             dlsym(dlhandle, "thermal_client_config_set");
128         if (dlerror()) {
129             ALOGE("Unable to load thermal_client_config_set");
130             goto error_handle;
131         }
132 
133         p_thermal_client_config_cleanup = (void (*) (struct config_instance *, unsigned int))
134             dlsym(dlhandle, "thermal_client_config_cleanup");
135         if (dlerror()) {
136             ALOGE("Unable to load thermal_client_config_cleanup");
137             goto error_handle;
138         }
139     } else {
140         ALOGE("unable to open %s", thermal_client_so);
141         return -1;
142     }
143 
144     return 0;
145 
146 error_handle:
147     ALOGE("Error opening functions from %s", thermal_client_so);
148     p_thermal_client_config_query = NULL;
149     p_thermal_client_config_set = NULL;
150     p_thermal_client_config_cleanup = NULL;
151     dlclose(dlhandle);
152     dlhandle = NULL;
153     return -1;
154 }
155 
156 /**
157  *  Allocate a new struct config_instance for modifying the disable field
158  */
allocate_config_instance()159 static struct config_instance *allocate_config_instance(){
160     struct config_instance *config = (struct config_instance *)malloc(sizeof(struct config_instance));
161     memset(config, 0, sizeof(*config));
162 
163     config->cfg_desc = (char *)malloc(sizeof(char)*max_string_size);
164     memset(config->cfg_desc, 0, sizeof(char)*max_string_size);
165 
166     config->algo_type = (char *)malloc(sizeof(char)*max_string_size);
167     memset(config->algo_type, 0, sizeof(char) * max_string_size);
168 
169     config->fields = (struct field_data *)malloc(sizeof(struct field_data));
170     memset(config->fields, 0, sizeof(*config->fields));
171 
172     config->fields[0].field_name = (char*)malloc(sizeof(char)*max_string_size);
173     memset(config->fields[0].field_name, 0, sizeof(char)*max_string_size);
174 
175     config->fields[0].data = (void*)malloc(sizeof(int));
176 
177     return config;
178 }
179 /**
180  *  Free the config_instance as allocated in allocate_config_instance
181  */
free_config_instance(struct config_instance * config)182 static void free_config_instance(struct config_instance *config){
183 
184     free(config->fields[0].data);
185     free(config->fields[0].field_name);
186     free(config->fields);
187     free(config->algo_type);
188     free(config->cfg_desc);
189     free(config);
190 }
191 
192 /**
193  *  disable a thermal config
194  *  returns 1 on success, anything else is a failure
195  */
disable_config(char * config_name,char * algo_type)196 static int disable_config(char *config_name, char *algo_type){
197     int result = 0;
198     if (error_state) {
199         return 0;
200     }
201     struct config_instance *config = allocate_config_instance();
202     strlcpy(config->cfg_desc, config_name, max_string_size);
203     strlcpy(config->algo_type, algo_type, max_string_size);
204     strlcpy(config->fields[0].field_name, "disable", max_string_size);
205 
206     config->fields_mask |= DISABLE_FIELD;
207     config->num_fields = 1;
208     config->fields[0].data_type = FIELD_INT;
209     config->fields[0].num_data = 1;
210     *(int*)(config->fields[0].data) = 1; //DISABLE
211 
212 
213     result = (*p_thermal_client_config_set)(config, 1);
214     if (DEBUG) {
215         ALOGE("disable profile: name = %s, algo_type = %s, success = %d", config_name, algo_type, result);
216     }
217     free_config_instance(config);
218 
219     return result;
220 }
221 
222 /**
223  *  enable a thermal config
224  *  returns 1 on success, anything else is failure
225  */
enable_config(char * config_name,char * algo_type)226 static int enable_config(char *config_name, char *algo_type){
227     int result = 0;
228     if (error_state) {
229         return 0;
230     }
231     struct config_instance *config = allocate_config_instance();
232     strlcpy(config->cfg_desc, config_name, max_string_size);
233     strlcpy(config->algo_type, algo_type, max_string_size);
234     strlcpy(config->fields[0].field_name, "disable", max_string_size);
235 
236     config->fields_mask |= DISABLE_FIELD;
237     config->num_fields = 1;
238     config->fields[0].data_type = FIELD_INT;
239     config->fields[0].num_data = 1;
240     *(int*)(config->fields[0].data) = 0;  //ENABLE
241 
242     result = (*p_thermal_client_config_set)(config, 1);
243     if (DEBUG) {
244         ALOGE("enable profile: name = %s, algo_type = %s, success = %d",
245           config_name, algo_type, result);
246     }
247 
248     free_config_instance(config);
249 
250     return result;
251 }
252 
253 /**
254  * Call this if there is a compoenent-fatal error
255  * Attempts to clean up any outstanding thermal config state
256  */
error_cleanup()257 static void error_cleanup(){
258     //disable VR configs, best-effort so ignore return values
259     for (unsigned int i = 0; i < NUM_VR_CONFIGS; i++) {
260         disable_config(vr_thermal_configs[i][0], vr_thermal_configs[i][1]);
261     }
262 
263     // enable non-VR profile, best-effort so ignore return values
264     for (unsigned int i = 0; i < NUM_NON_VR_CONFIGS; i++) {
265         enable_config(non_vr_thermal_configs[i][0], non_vr_thermal_configs[i][1]);
266     }
267 
268     // set global error flag
269     error_state = 1;
270 }
271 
272 /*
273  * Set global display/GPU/scheduler configuration to used for VR apps.
274  */
set_vr_thermal_configuration()275 static void set_vr_thermal_configuration() {
276     int result = 1;
277     if (error_state) {
278         return;
279     }
280 
281     //disable non-VR configs
282     for (unsigned int i = 0; i < NUM_NON_VR_CONFIGS; i++) {
283         result = disable_config(non_vr_thermal_configs[i][0], non_vr_thermal_configs[i][1]);
284         if (result != 1) {
285             goto error;
286         }
287     }
288 
289     //enable VR configs
290     for (unsigned int i = 0; i < NUM_VR_CONFIGS; i++) {
291         result = enable_config(vr_thermal_configs[i][0], vr_thermal_configs[i][1]);
292         if (result != 1) {
293             goto error;
294         }
295     }
296 
297     if (DEBUG) {
298         query_thermal_config();
299     }
300 
301     return;
302 
303 error:
304     error_cleanup();
305     return;
306 }
307 
308 /*
309  * Reset to default global display/GPU/scheduler configuration.
310  */
unset_vr_thermal_configuration()311 static void unset_vr_thermal_configuration() {
312     int result = 1;
313     if (error_state) {
314         return;
315     }
316 
317     //disable VR configs
318     for (unsigned int i = 0; i < NUM_VR_CONFIGS; i++) {
319         result = disable_config(vr_thermal_configs[i][0], vr_thermal_configs[i][1]);
320         if (result != 1) {
321             goto error;
322         }
323     }
324 
325     // enable non-VR profile
326     for (unsigned int i = 0; i < NUM_NON_VR_CONFIGS; i++) {
327         result = enable_config(non_vr_thermal_configs[i][0], non_vr_thermal_configs[i][1]);
328         if (result != 1) {
329             goto error;
330         }
331     }
332 
333     if (DEBUG) {
334         query_thermal_config();
335     }
336 
337     return;
338 
339 error:
340     error_cleanup();
341     return;
342 }
343 
vr_init(struct vr_module * module)344 static void vr_init(struct vr_module *module) {
345     int success = load_thermal_client();
346     if (success != 0) {
347         ALOGE("failed to load thermal client");
348         error_state = 1;
349     }
350 }
351 
vr_set_vr_mode(struct vr_module * module,bool enabled)352 static void vr_set_vr_mode(struct vr_module *module, bool enabled) {
353     if (enabled) {
354         set_vr_thermal_configuration();
355     } else {
356         unset_vr_thermal_configuration();
357     }
358 }
359 
360 static struct hw_module_methods_t vr_module_methods = {
361     .open = NULL, // There are no devices for this HAL interface.
362 };
363 
364 
365 vr_module_t HAL_MODULE_INFO_SYM = {
366     .common = {
367         .tag                = HARDWARE_MODULE_TAG,
368         .module_api_version = VR_MODULE_API_VERSION_1_0,
369         .hal_api_version    = HARDWARE_HAL_API_VERSION,
370         .id                 = VR_HARDWARE_MODULE_ID,
371         .name               = "Marlin / Sailfish VR HAL",
372         .author             = "The Android Open Source Project",
373         .methods            = &vr_module_methods,
374     },
375 
376     .init = vr_init,
377     .set_vr_mode = vr_set_vr_mode,
378 };
379