Home | History | Annotate | Download | only in power
      1 /*
      2  * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *     * Redistributions of source code must retain the above copyright
      8  *       notice, this list of conditions and the following disclaimer.
      9  *     * Redistributions in binary form must reproduce the above
     10  *       copyright notice, this list of conditions and the following
     11  *       disclaimer in the documentation and/or other materials provided
     12  *       with the distribution.
     13  *     * Neither the name of The Linux Foundation nor the names of its
     14  *       contributors may be used to endorse or promote products derived
     15  *       from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     24  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     25  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     26  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     27  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #define LOG_NDEBUG 1
     31 
     32 #include <errno.h>
     33 #include <inttypes.h>
     34 #include <string.h>
     35 #include <unistd.h>
     36 #include <sys/types.h>
     37 #include <sys/stat.h>
     38 #include <fcntl.h>
     39 #include <dlfcn.h>
     40 #include <stdlib.h>
     41 #include <time.h>
     42 
     43 #define LOG_TAG "QCOM PowerHAL"
     44 #include <utils/Log.h>
     45 #include <hardware/power.h>
     46 #include <cutils/properties.h>
     47 
     48 #include "utils.h"
     49 #include "metadata-defs.h"
     50 #include "hint-data.h"
     51 #include "performance.h"
     52 #include "power-common.h"
     53 #include "power-helper.h"
     54 
     55 #define USINSEC 1000000L
     56 #define NSINUS 1000L
     57 
     58 #ifndef RPM_STAT
     59 #define RPM_STAT "/d/rpm_stats"
     60 #endif
     61 
     62 #ifndef RPM_MASTER_STAT
     63 #define RPM_MASTER_STAT "/d/rpm_master_stats"
     64 #endif
     65 
     66 #ifndef WLAN_POWER_STAT
     67 #define WLAN_POWER_STAT "/d/wlan_wcnss/power_stats"
     68 #endif
     69 
     70 static const char *rpm_param_names[] = {
     71     "vlow_count",
     72     "accumulated_vlow_time",
     73     "vmin_count",
     74     "accumulated_vmin_time"
     75 };
     76 
     77 static const char *rpm_master_param_names[] = {
     78     "xo_accumulated_duration",
     79     "xo_count",
     80     "xo_accumulated_duration",
     81     "xo_count",
     82     "xo_accumulated_duration",
     83     "xo_count",
     84     "xo_accumulated_duration",
     85     "xo_count"
     86 };
     87 
     88 static const char *wlan_param_names[] = {
     89     "cumulative_sleep_time_ms",
     90     "cumulative_total_on_time_ms",
     91     "deep_sleep_enter_counter",
     92     "last_deep_sleep_enter_tstamp_ms"
     93 };
     94 
     95 
     96 static int saved_dcvs_cpu0_slack_max = -1;
     97 static int saved_dcvs_cpu0_slack_min = -1;
     98 static int saved_mpdecision_slack_max = -1;
     99 static int saved_mpdecision_slack_min = -1;
    100 static int saved_interactive_mode = -1;
    101 static int slack_node_rw_failed = 0;
    102 static int display_hint_sent;
    103 int display_boost;
    104 static int sustained_mode_handle = 0;
    105 static int vr_mode_handle = 0;
    106 int sustained_performance_mode = 0;
    107 int vr_mode = 0;
    108 
    109 //interaction boost global variables
    110 static struct timespec s_previous_boost_timespec;
    111 static int s_previous_duration;
    112 
    113 void power_init(void)
    114 {
    115     ALOGV("QCOM power HAL initing.");
    116 
    117     int fd;
    118     char buf[10] = {0};
    119 
    120     fd = open("/sys/devices/soc0/soc_id", O_RDONLY);
    121     if (fd >= 0) {
    122         if (read(fd, buf, sizeof(buf) - 1) == -1) {
    123             ALOGW("Unable to read soc_id");
    124         } else {
    125             int soc_id = atoi(buf);
    126             if (soc_id == 194 || (soc_id >= 208 && soc_id <= 218) || soc_id == 178) {
    127                 display_boost = 1;
    128             }
    129         }
    130         close(fd);
    131     }
    132 }
    133 
    134 int __attribute__ ((weak)) power_hint_override(power_hint_t UNUSED(hint),
    135         void * UNUSED(data))
    136 {
    137     return HINT_NONE;
    138 }
    139 
    140 /* Declare function before use */
    141 void interaction(int duration, int num_args, int opt_list[]);
    142 void release_request(int lock_handle);
    143 
    144 static long long calc_timespan_us(struct timespec start, struct timespec end) {
    145     long long diff_in_us = 0;
    146     diff_in_us += (end.tv_sec - start.tv_sec) * USINSEC;
    147     diff_in_us += (end.tv_nsec - start.tv_nsec) / NSINUS;
    148     return diff_in_us;
    149 }
    150 
    151 void power_hint(power_hint_t hint, void *data)
    152 {
    153     /* Check if this hint has been overridden. */
    154     if (power_hint_override(hint, data) == HINT_HANDLED) {
    155         /* The power_hint has been handled. We can skip the rest. */
    156         return;
    157     }
    158 
    159     switch(hint) {
    160         case POWER_HINT_VSYNC:
    161         break;
    162         /* Sustained performance mode:
    163          * All CPUs are capped to ~1.2GHz
    164          * GPU frequency is capped to 315MHz
    165          */
    166         /* VR+Sustained performance mode:
    167          * All CPUs are locked to ~1.2GHz
    168          * GPU frequency is locked to 315MHz
    169          * GPU BW min_freq is raised to 775MHz
    170          */
    171         case POWER_HINT_SUSTAINED_PERFORMANCE:
    172         {
    173             int duration = 0;
    174             if (data && sustained_performance_mode == 0) {
    175                 int* resources;
    176                 if (vr_mode == 0) { // Sustained mode only.
    177                     // Ensure that POWER_HINT_LAUNCH is not in progress.
    178                     if (launch_mode == 1) {
    179                         release_request(launch_handle);
    180                         launch_mode = 0;
    181                     }
    182                     // 0x40804000: cpu0 max freq
    183                     // 0x40804100: cpu2 max freq
    184                     // 0x42C20000: gpu max freq
    185                     // 0x42C24000: gpu min freq
    186                     // 0x42C28000: gpu bus min freq
    187                     int resources[] = {0x40804000, 1209, 0x40804100, 1209,
    188                                        0x42C24000, 133,  0x42C20000, 315,
    189                                        0x42C28000, 7759};
    190                     sustained_mode_handle = interaction_with_handle(
    191                         sustained_mode_handle, duration,
    192                         sizeof(resources) / sizeof(resources[0]), resources);
    193                 } else if (vr_mode == 1) { // Sustained + VR mode.
    194                     release_request(vr_mode_handle);
    195                     // 0x40804000: cpu0 max freq
    196                     // 0x40804100: cpu2 max freq
    197                     // 0x40800000: cpu0 min freq
    198                     // 0x40800100: cpu2 min freq
    199                     // 0x42C20000: gpu max freq
    200                     // 0x42C24000: gpu min freq
    201                     // 0x42C28000: gpu bus min freq
    202                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
    203                                        0x40804000, 1209, 0x40804100, 1209,
    204                                        0x42C24000, 315,  0x42C20000, 315,
    205                                        0x42C28000, 7759};
    206                     sustained_mode_handle = interaction_with_handle(
    207                         sustained_mode_handle, duration,
    208                         sizeof(resources) / sizeof(resources[0]), resources);
    209                 }
    210                 sustained_performance_mode = 1;
    211             } else if (sustained_performance_mode == 1) {
    212                 release_request(sustained_mode_handle);
    213                 if (vr_mode == 1) { // Switch back to VR Mode.
    214                     // 0x40804000: cpu0 max freq
    215                     // 0x40804100: cpu2 max freq
    216                     // 0x40800000: cpu0 min freq
    217                     // 0x40800100: cpu2 min freq
    218                     // 0x42C20000: gpu max freq
    219                     // 0x42C24000: gpu min freq
    220                     // 0x42C28000: gpu bus min freq
    221                     int resources[] = {0x40804000, 1440, 0x40804100, 1440,
    222                                        0x40800000, 1440, 0x40800100, 1440,
    223                                        0x42C20000, 510,  0x42C24000, 510,
    224                                        0x42C28000, 7759};
    225                     vr_mode_handle = interaction_with_handle(
    226                         vr_mode_handle, duration,
    227                         sizeof(resources) / sizeof(resources[0]), resources);
    228                 }
    229                 sustained_performance_mode = 0;
    230             }
    231         }
    232         break;
    233         /* VR mode:
    234          * All CPUs are locked at ~1.4GHz
    235          * GPU frequency is locked  to 510MHz
    236          * GPU BW min_freq is raised to 775MHz
    237          */
    238         case POWER_HINT_VR_MODE:
    239         {
    240             int duration = 0;
    241             if (data && vr_mode == 0) {
    242                 if (sustained_performance_mode == 0) { // VR mode only.
    243                     // Ensure that POWER_HINT_LAUNCH is not in progress.
    244                     if (launch_mode == 1) {
    245                         release_request(launch_handle);
    246                         launch_mode = 0;
    247                     }
    248                     // 0x40804000: cpu0 max freq
    249                     // 0x40804100: cpu2 max freq
    250                     // 0x40800000: cpu0 min freq
    251                     // 0x40800100: cpu2 min freq
    252                     // 0x42C20000: gpu max freq
    253                     // 0x42C24000: gpu min freq
    254                     // 0x42C28000: gpu bus min freq
    255                     int resources[] = {0x40800000, 1440, 0x40800100, 1440,
    256                                        0x40804000, 1440, 0x40804100, 1440,
    257                                        0x42C20000, 510,  0x42C24000, 510,
    258                                        0x42C28000, 7759};
    259                     vr_mode_handle = interaction_with_handle(
    260                         vr_mode_handle, duration,
    261                         sizeof(resources) / sizeof(resources[0]), resources);
    262                 } else if (sustained_performance_mode == 1) { // Sustained + VR mode.
    263                     release_request(sustained_mode_handle);
    264                     // 0x40804000: cpu0 max freq
    265                     // 0x40804100: cpu2 max freq
    266                     // 0x40800000: cpu0 min freq
    267                     // 0x40800100: cpu2 min freq
    268                     // 0x42C20000: gpu max freq
    269                     // 0x42C24000: gpu min freq
    270                     // 0x42C28000: gpu bus min freq
    271                     int resources[] = {0x40800000, 1209, 0x40800100, 1209,
    272                                        0x40804000, 1209, 0x40804100, 1209,
    273                                        0x42C24000, 315,  0x42C20000, 315,
    274                                        0x42C28000, 7759};
    275 
    276                     vr_mode_handle = interaction_with_handle(
    277                         vr_mode_handle, duration,
    278                         sizeof(resources) / sizeof(resources[0]), resources);
    279                 }
    280                 vr_mode = 1;
    281             } else if (vr_mode == 1) {
    282                 release_request(vr_mode_handle);
    283                 if (sustained_performance_mode == 1) { // Switch back to sustained Mode.
    284                     // 0x40804000: cpu0 max freq
    285                     // 0x40804100: cpu2 max freq
    286                     // 0x40800000: cpu0 min freq
    287                     // 0x40800100: cpu2 min freq
    288                     // 0x42C20000: gpu max freq
    289                     // 0x42C24000: gpu min freq
    290                     // 0x42C28000: gpu bus min freq
    291                     int resources[] = {0x40800000, 0,    0x40800100, 0,
    292                                        0x40804000, 1209, 0x40804100, 1209,
    293                                        0x42C24000, 133,  0x42C20000, 315,
    294                                        0x42C28000, 0};
    295                     sustained_mode_handle = interaction_with_handle(
    296                         sustained_mode_handle, duration,
    297                         sizeof(resources) / sizeof(resources[0]), resources);
    298                 }
    299                 vr_mode = 0;
    300             }
    301         }
    302         break;
    303         case POWER_HINT_INTERACTION:
    304         {
    305             char governor[80];
    306 
    307             if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    308                 ALOGE("Can't obtain scaling governor.");
    309                 return;
    310             }
    311 
    312             if (sustained_performance_mode || vr_mode) {
    313                 return;
    314             }
    315 
    316             int duration = 1500; // 1.5s by default
    317             if (data) {
    318                 int input_duration = *((int*)data) + 750;
    319                 if (input_duration > duration) {
    320                     duration = (input_duration > 5750) ? 5750 : input_duration;
    321                 }
    322             }
    323 
    324             struct timespec cur_boost_timespec;
    325             clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
    326 
    327             long long elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
    328             // don't hint if previous hint's duration covers this hint's duration
    329             if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
    330                 return;
    331             }
    332             s_previous_boost_timespec = cur_boost_timespec;
    333             s_previous_duration = duration;
    334 
    335             // Scheduler is EAS.
    336             if (true || strncmp(governor, SCHED_GOVERNOR, strlen(SCHED_GOVERNOR)) == 0) {
    337                 // Setting the value of foreground schedtune boost to 50 and
    338                 // scaling_min_freq to 1100MHz.
    339                 int resources[] = {0x40800000, 1100, 0x40800100, 1100, 0x42C0C000, 0x32, 0x41800000, 0x33};
    340                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
    341             } else { // Scheduler is HMP.
    342                 int resources[] = {0x41800000, 0x33, 0x40800000, 1000, 0x40800100, 1000, 0x40C00000, 0x1};
    343                 interaction(duration, sizeof(resources)/sizeof(resources[0]), resources);
    344             }
    345         }
    346         break;
    347         default:
    348         break;
    349     }
    350 }
    351 
    352 int __attribute__ ((weak)) set_interactive_override(int UNUSED(on))
    353 {
    354     return HINT_NONE;
    355 }
    356 
    357 void power_set_interactive(int on)
    358 {
    359     char governor[80];
    360     char tmp_str[NODE_MAX];
    361     struct video_encode_metadata_t video_encode_metadata;
    362     int rc = 0;
    363 
    364     if (set_interactive_override(on) == HINT_HANDLED) {
    365         return;
    366     }
    367 
    368     ALOGV("Got set_interactive hint");
    369 
    370     if (get_scaling_governor(governor, sizeof(governor)) == -1) {
    371         ALOGE("Can't obtain scaling governor.");
    372 
    373         return;
    374     }
    375 
    376     if (!on) {
    377         /* Display off. */
    378         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    379                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    380             int resource_values[] = {DISPLAY_OFF, MS_500, THREAD_MIGRATION_SYNC_OFF};
    381 
    382             if (!display_hint_sent) {
    383                 perform_hint_action(DISPLAY_STATE_HINT_ID,
    384                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    385                 display_hint_sent = 1;
    386             }
    387         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    388                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    389             int resource_values[] = {TR_MS_50, THREAD_MIGRATION_SYNC_OFF};
    390 
    391             if (!display_hint_sent) {
    392                 perform_hint_action(DISPLAY_STATE_HINT_ID,
    393                         resource_values, sizeof(resource_values)/sizeof(resource_values[0]));
    394                 display_hint_sent = 1;
    395             }
    396         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
    397                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
    398             if (saved_interactive_mode == 1){
    399                 /* Display turned off. */
    400                 if (sysfs_read(DCVS_CPU0_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
    401                     if (!slack_node_rw_failed) {
    402                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MAX_NODE);
    403                     }
    404 
    405                     rc = 1;
    406                 } else {
    407                     saved_dcvs_cpu0_slack_max = atoi(tmp_str);
    408                 }
    409 
    410                 if (sysfs_read(DCVS_CPU0_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
    411                     if (!slack_node_rw_failed) {
    412                         ALOGE("Failed to read from %s", DCVS_CPU0_SLACK_MIN_NODE);
    413                     }
    414 
    415                     rc = 1;
    416                 } else {
    417                     saved_dcvs_cpu0_slack_min = atoi(tmp_str);
    418                 }
    419 
    420                 if (sysfs_read(MPDECISION_SLACK_MAX_NODE, tmp_str, NODE_MAX - 1)) {
    421                     if (!slack_node_rw_failed) {
    422                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MAX_NODE);
    423                     }
    424 
    425                     rc = 1;
    426                 } else {
    427                     saved_mpdecision_slack_max = atoi(tmp_str);
    428                 }
    429 
    430                 if (sysfs_read(MPDECISION_SLACK_MIN_NODE, tmp_str, NODE_MAX - 1)) {
    431                     if(!slack_node_rw_failed) {
    432                         ALOGE("Failed to read from %s", MPDECISION_SLACK_MIN_NODE);
    433                     }
    434 
    435                     rc = 1;
    436                 } else {
    437                     saved_mpdecision_slack_min = atoi(tmp_str);
    438                 }
    439 
    440                 /* Write new values. */
    441                 if (saved_dcvs_cpu0_slack_max != -1) {
    442                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_max);
    443 
    444                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
    445                         if (!slack_node_rw_failed) {
    446                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
    447                         }
    448 
    449                         rc = 1;
    450                     }
    451                 }
    452 
    453                 if (saved_dcvs_cpu0_slack_min != -1) {
    454                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_dcvs_cpu0_slack_min);
    455 
    456                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
    457                         if(!slack_node_rw_failed) {
    458                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
    459                         }
    460 
    461                         rc = 1;
    462                     }
    463                 }
    464 
    465                 if (saved_mpdecision_slack_max != -1) {
    466                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_max);
    467 
    468                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
    469                         if(!slack_node_rw_failed) {
    470                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
    471                         }
    472 
    473                         rc = 1;
    474                     }
    475                 }
    476 
    477                 if (saved_mpdecision_slack_min != -1) {
    478                     snprintf(tmp_str, NODE_MAX, "%d", 10 * saved_mpdecision_slack_min);
    479 
    480                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
    481                         if(!slack_node_rw_failed) {
    482                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
    483                         }
    484 
    485                         rc = 1;
    486                     }
    487                 }
    488             }
    489 
    490             slack_node_rw_failed = rc;
    491         }
    492     } else {
    493         /* Display on. */
    494         if ((strncmp(governor, ONDEMAND_GOVERNOR, strlen(ONDEMAND_GOVERNOR)) == 0) &&
    495                 (strlen(governor) == strlen(ONDEMAND_GOVERNOR))) {
    496             undo_hint_action(DISPLAY_STATE_HINT_ID);
    497             display_hint_sent = 0;
    498         } else if ((strncmp(governor, INTERACTIVE_GOVERNOR, strlen(INTERACTIVE_GOVERNOR)) == 0) &&
    499                 (strlen(governor) == strlen(INTERACTIVE_GOVERNOR))) {
    500             undo_hint_action(DISPLAY_STATE_HINT_ID);
    501             display_hint_sent = 0;
    502         } else if ((strncmp(governor, MSMDCVS_GOVERNOR, strlen(MSMDCVS_GOVERNOR)) == 0) &&
    503                 (strlen(governor) == strlen(MSMDCVS_GOVERNOR))) {
    504             if (saved_interactive_mode == -1 || saved_interactive_mode == 0) {
    505                 /* Display turned on. Restore if possible. */
    506                 if (saved_dcvs_cpu0_slack_max != -1) {
    507                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_max);
    508 
    509                     if (sysfs_write(DCVS_CPU0_SLACK_MAX_NODE, tmp_str) != 0) {
    510                         if (!slack_node_rw_failed) {
    511                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MAX_NODE);
    512                         }
    513 
    514                         rc = 1;
    515                     }
    516                 }
    517 
    518                 if (saved_dcvs_cpu0_slack_min != -1) {
    519                     snprintf(tmp_str, NODE_MAX, "%d", saved_dcvs_cpu0_slack_min);
    520 
    521                     if (sysfs_write(DCVS_CPU0_SLACK_MIN_NODE, tmp_str) != 0) {
    522                         if (!slack_node_rw_failed) {
    523                             ALOGE("Failed to write to %s", DCVS_CPU0_SLACK_MIN_NODE);
    524                         }
    525 
    526                         rc = 1;
    527                     }
    528                 }
    529 
    530                 if (saved_mpdecision_slack_max != -1) {
    531                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_max);
    532 
    533                     if (sysfs_write(MPDECISION_SLACK_MAX_NODE, tmp_str) != 0) {
    534                         if (!slack_node_rw_failed) {
    535                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MAX_NODE);
    536                         }
    537 
    538                         rc = 1;
    539                     }
    540                 }
    541 
    542                 if (saved_mpdecision_slack_min != -1) {
    543                     snprintf(tmp_str, NODE_MAX, "%d", saved_mpdecision_slack_min);
    544 
    545                     if (sysfs_write(MPDECISION_SLACK_MIN_NODE, tmp_str) != 0) {
    546                         if (!slack_node_rw_failed) {
    547                             ALOGE("Failed to write to %s", MPDECISION_SLACK_MIN_NODE);
    548                         }
    549 
    550                         rc = 1;
    551                     }
    552                 }
    553             }
    554 
    555             slack_node_rw_failed = rc;
    556         }
    557     }
    558 
    559     saved_interactive_mode = !!on;
    560 }
    561 
    562 
    563 static int extract_stats(uint64_t *list, char *file, const char**param_names,
    564                          unsigned int num_parameters, int isHex) {
    565     FILE *fp;
    566     ssize_t read;
    567     size_t len;
    568     size_t index = 0;
    569     char *line;
    570     int ret;
    571 
    572     fp = fopen(file, "r");
    573     if (fp == NULL) {
    574         ret = -errno;
    575         ALOGE("%s: failed to open: %s Error = %s", __func__, file, strerror(errno));
    576         return ret;
    577     }
    578 
    579     for (line = NULL, len = 0;
    580          ((read = getline(&line, &len, fp) != -1) && (index < num_parameters));
    581          free(line), line = NULL, len = 0) {
    582         uint64_t value;
    583         char* offset;
    584 
    585         size_t begin = strspn(line, " \t");
    586         if (strncmp(line + begin, param_names[index], strlen(param_names[index]))) {
    587             continue;
    588         }
    589 
    590         offset = memchr(line, ':', len);
    591         if (!offset) {
    592             continue;
    593         }
    594 
    595         if (isHex) {
    596             sscanf(offset, ":%" SCNx64, &value);
    597         } else {
    598             sscanf(offset, ":%" SCNu64, &value);
    599         }
    600         list[index] = value;
    601         index++;
    602     }
    603 
    604     free(line);
    605     fclose(fp);
    606 
    607     return 0;
    608 }
    609 
    610 
    611 int extract_platform_stats(uint64_t *list) {
    612 
    613     int ret;
    614 
    615     //Data is located in two files
    616 
    617     ret = extract_stats(list, RPM_STAT, rpm_param_names, RPM_PARAM_COUNT, false);
    618     if (ret) {
    619         for (size_t i=0; i < RPM_PARAM_COUNT; i++)
    620             list[i] = 0;
    621     }
    622 
    623     ret = extract_stats(list + RPM_PARAM_COUNT, RPM_MASTER_STAT,
    624                         rpm_master_param_names, PLATFORM_PARAM_COUNT - RPM_PARAM_COUNT, true);
    625     if (ret) {
    626         for (size_t i=RPM_PARAM_COUNT; i < PLATFORM_PARAM_COUNT; i++)
    627         list[i] = 0;
    628     }
    629 
    630     return 0;
    631 }
    632 
    633 int extract_wlan_stats(uint64_t *list) {
    634 
    635     int ret;
    636 
    637     ret = extract_stats(list, WLAN_POWER_STAT, wlan_param_names, WLAN_PARAM_COUNT, false);
    638     if (ret) {
    639         for (size_t i=0; i < WLAN_PARAM_COUNT; i++)
    640             list[i] = 0;
    641     }
    642 
    643     return 0;
    644 }
    645