Home | History | Annotate | Download | only in vr
      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  */
     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  */
     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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 
    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 
    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