power: Handle launch and interaction hints for perf HAL platforms

 * MP-CTL does not handle POWER_HINT_INTERACTION and POWER_HINT_LAUNCH
   directly. Requests for processing are sent by Qualcomm BoostFramework
   (QPerformance) at the framework service level. Since we do not have
   BoostFramework, process POWER_HINT_INTERACTION and POWER_HINT_LAUNCH
   in PowerHAL to ensure a sufficient level of performance.
 * For proper operation, perfboostsconfig.xml file is required.

Change-Id: I4c67d886c9dd74ae07094d32bdffc8ef403e04e7
diff --git a/performance.h b/performance.h
index 970d42e..461ae31 100644
--- a/performance.h
+++ b/performance.h
@@ -42,6 +42,22 @@
 #define VENDOR_HINT_DISPLAY_OFF      0x00001040
 #define VENDOR_HINT_DISPLAY_ON       0x00001041
 
+#define VENDOR_HINT_FIRST_LAUNCH_BOOST  0x00001081
+#define VENDOR_HINT_SCROLL_BOOST        0x00001080
+
+enum LAUNCH_BOOST_TYPE {
+    LAUNCH_BOOST_V1 = 1,
+    LAUNCH_BOOST_V2 = 2,
+    LAUNCH_BOOST_V3 = 3
+};
+
+enum SCROLL_BOOST_TYPE {
+    SCROLL_VERTICAL     = 1,
+    SCROLL_HORIZONTAL   = 2,
+    SCROLL_PANEL_VIEW   = 3,
+    SCROLL_PREFILING    = 4
+};
+
 enum SCREEN_DISPLAY_TYPE {
     DISPLAY_OFF = 0x00FF,
 };
diff --git a/power-660.c b/power-660.c
index 0bec132..0a297e2 100644
--- a/power-660.c
+++ b/power-660.c
@@ -31,6 +31,7 @@
 #define LOG_NIDEBUG 0
 
 #include <errno.h>
+#include <time.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -51,6 +52,10 @@
 
 #define MIN_VAL(X,Y) ((X>Y)?(Y):(X))
 
+const int kMaxInteractiveDuration = 5000; /* ms */
+const int kMinInteractiveDuration = 500; /* ms */
+const int kMinFlingDuration = 1500; /* ms */
+
 static int video_encode_hint_sent;
 
 static int current_power_profile = PROFILE_BALANCED;
@@ -244,6 +249,45 @@
     }
 }
 
+static void process_activity_launch_hint(void *UNUSED(data))
+{
+    perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+}
+
+static void process_interaction_hint(void *data)
+{
+    static struct timespec s_previous_boost_timespec;
+    static int s_previous_duration = 0;
+
+    struct timespec cur_boost_timespec;
+    long long elapsed_time;
+    int duration = kMinInteractiveDuration;
+
+    if (data) {
+        int input_duration = *((int*)data);
+        if (input_duration > duration) {
+            duration = (input_duration > kMaxInteractiveDuration) ?
+                    kMaxInteractiveDuration : input_duration;
+        }
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
+
+    elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
+    // don't hint if previous hint's duration covers this hint's duration
+    if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
+        return;
+    }
+    s_previous_boost_timespec = cur_boost_timespec;
+    s_previous_duration = duration;
+
+    if (duration >= kMinFlingDuration) {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, -1, SCROLL_PREFILING);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
+    }
+}
+
 int power_hint_override(power_hint_t hint, void *data)
 {
     if (hint == POWER_HINT_SET_PROFILE) {
@@ -264,6 +308,12 @@
         case POWER_HINT_VIDEO_ENCODE:
             process_video_encode_hint(data);
             return HINT_HANDLED;
+        case POWER_HINT_INTERACTION:
+            process_interaction_hint(data);
+            return HINT_HANDLED;
+        case POWER_HINT_LAUNCH:
+            process_activity_launch_hint(data);
+            return HINT_HANDLED;
         default:
             break;
     }
diff --git a/power-845.c b/power-845.c
index dce15a5..235ab81 100644
--- a/power-845.c
+++ b/power-845.c
@@ -31,6 +31,7 @@
 #define LOG_NIDEBUG 0
 
 #include <errno.h>
+#include <time.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -54,6 +55,10 @@
 
 #define SYS_DISPLAY_PWR "/sys/kernel/hbtp/display_pwr"
 
+const int kMaxInteractiveDuration = 5000; /* ms */
+const int kMinInteractiveDuration = 100; /* ms */
+const int kMinFlingDuration = 1500; /* ms */
+
 static int display_fd;
 
 typedef enum {
@@ -187,6 +192,56 @@
     return HINT_NONE;
 }
 
+static int process_activity_launch_hint(void *UNUSED(data))
+{
+    if (current_mode != NORMAL_MODE) {
+        ALOGV("%s: ignoring due to other active perf hints", __func__);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+    }
+    return HINT_HANDLED;
+}
+
+static int process_interaction_hint(void *data)
+{
+    static struct timespec s_previous_boost_timespec;
+    static int s_previous_duration = 0;
+
+    struct timespec cur_boost_timespec;
+    long long elapsed_time;
+    int duration = kMinInteractiveDuration;
+
+    if (current_mode != NORMAL_MODE) {
+        ALOGV("%s: ignoring due to other active perf hints", __func__);
+        return HINT_HANDLED;
+    }
+
+    if (data) {
+        int input_duration = *((int*)data);
+        if (input_duration > duration) {
+            duration = (input_duration > kMaxInteractiveDuration) ?
+                    kMaxInteractiveDuration : input_duration;
+        }
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
+
+    elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
+    // don't hint if previous hint's duration covers this hint's duration
+    if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
+        return HINT_HANDLED;
+    }
+    s_previous_boost_timespec = cur_boost_timespec;
+    s_previous_duration = duration;
+
+    if (duration >= kMinFlingDuration) {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, -1, SCROLL_PREFILING);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
+    }
+    return HINT_HANDLED;
+}
+
 int power_hint_override(power_hint_t hint, void *data)
 {
     int ret_val = HINT_NONE;
@@ -201,14 +256,10 @@
             ret_val = process_perf_hint(data, VR_MODE);
             break;
         case POWER_HINT_INTERACTION:
-        {
-            int resources[] = {
-                MIN_FREQ_LITTLE_CORE_0, 0x514
-            };
-            int duration = 100;
-            interaction(duration, ARRAY_SIZE(resources), resources);
-            ret_val = HINT_HANDLED;
-        }
+            ret_val = process_interaction_hint(data);
+            break;
+        case POWER_HINT_LAUNCH:
+            ret_val = process_activity_launch_hint(data);
             break;
         default:
             break;
diff --git a/power-8937.c b/power-8937.c
index 5b1b542..abf0f8e 100644
--- a/power-8937.c
+++ b/power-8937.c
@@ -31,6 +31,7 @@
 #define LOG_NIDEBUG 0
 
 #include <errno.h>
+#include <time.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -49,6 +50,10 @@
 #include "performance.h"
 #include "power-common.h"
 
+const int kMaxInteractiveDuration = 5000; /* ms */
+const int kMinInteractiveDuration = 500; /* ms */
+const int kMinFlingDuration = 1500; /* ms */
+
 static int video_encode_hint_sent;
 
 static int current_power_profile = PROFILE_BALANCED;
@@ -191,6 +196,46 @@
     }
 }
 
+static void process_activity_launch_hint(void *UNUSED(data))
+{
+    perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+}
+
+static void process_interaction_hint(void *data)
+{
+    static struct timespec s_previous_boost_timespec;
+    static int s_previous_duration = 0;
+
+    struct timespec cur_boost_timespec;
+    long long elapsed_time;
+    int duration = kMinInteractiveDuration;
+
+    if (data) {
+        int input_duration = *((int*)data);
+        if (input_duration > duration) {
+            duration = (input_duration > kMaxInteractiveDuration) ?
+                    kMaxInteractiveDuration : input_duration;
+        }
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
+
+    elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
+    // don't hint if previous hint's duration covers this hint's duration
+    if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
+        return;
+    }
+    s_previous_boost_timespec = cur_boost_timespec;
+    s_previous_duration = duration;
+
+    if (duration >= kMinFlingDuration) {
+        // Use launch boost resources for fling boost
+        perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
+    }
+}
+
 int power_hint_override(power_hint_t hint, void *data)
 {
     if (hint == POWER_HINT_SET_PROFILE) {
@@ -209,6 +254,12 @@
         case POWER_HINT_VIDEO_ENCODE:
             process_video_encode_hint(data);
             return HINT_HANDLED;
+        case POWER_HINT_INTERACTION:
+            process_interaction_hint(data);
+            return HINT_HANDLED;
+        case POWER_HINT_LAUNCH:
+            process_activity_launch_hint(data);
+            return HINT_HANDLED;
         default:
             break;
     }
diff --git a/power-8953.c b/power-8953.c
index 78ee3df..5dacc03 100644
--- a/power-8953.c
+++ b/power-8953.c
@@ -31,6 +31,7 @@
 #define LOG_NIDEBUG 0
 
 #include <errno.h>
+#include <time.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -52,6 +53,10 @@
 #define CHECK_HANDLE(x) ((x)>0)
 #define NUM_PERF_MODES  3
 
+const int kMaxInteractiveDuration = 5000; /* ms */
+const int kMinInteractiveDuration = 500; /* ms */
+const int kMinFlingDuration = 1500; /* ms */
+
 static int current_power_profile = PROFILE_BALANCED;
 
 static int profile_high_performance[] = {
@@ -274,6 +279,58 @@
     return HINT_NONE;
 }
 
+static int process_activity_launch_hint(void *UNUSED(data))
+{
+    if (current_mode != NORMAL_MODE) {
+        ALOGV("%s: ignoring due to other active perf hints", __func__);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+    }
+    return HINT_HANDLED;
+}
+
+static int process_interaction_hint(void *data)
+{
+    static struct timespec s_previous_boost_timespec;
+    static int s_previous_duration = 0;
+
+    struct timespec cur_boost_timespec;
+    long long elapsed_time;
+    int duration = kMinInteractiveDuration;
+
+    if (current_mode != NORMAL_MODE) {
+        ALOGV("%s: ignoring due to other active perf hints", __func__);
+        return HINT_HANDLED;
+    }
+
+    if (data) {
+        int input_duration = *((int*)data);
+        if (input_duration > duration) {
+            duration = (input_duration > kMaxInteractiveDuration) ?
+                    kMaxInteractiveDuration : input_duration;
+        }
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
+
+    elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
+    // don't hint if previous hint's duration covers this hint's duration
+    if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
+        return HINT_HANDLED;
+    }
+    s_previous_boost_timespec = cur_boost_timespec;
+    s_previous_duration = duration;
+
+    if (duration >= kMinFlingDuration) {
+        // Use launch boost resources for fling boost
+        perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
+    }
+
+    return HINT_HANDLED;
+}
+
 int power_hint_override(power_hint_t hint, void *data)
 {
     int ret_val = HINT_NONE;
@@ -302,6 +359,12 @@
         case POWER_HINT_VR_MODE:
             ret_val = process_perf_hint(data, VR_MODE);
             break;
+        case POWER_HINT_INTERACTION:
+            ret_val = process_interaction_hint(data);
+            break;
+        case POWER_HINT_LAUNCH:
+            ret_val = process_activity_launch_hint(data);
+            break;
         default:
             break;
     }
diff --git a/power-8996.c b/power-8996.c
index f782299..c3acab8 100644
--- a/power-8996.c
+++ b/power-8996.c
@@ -31,6 +31,7 @@
 #define LOG_NIDEBUG 0
 
 #include <errno.h>
+#include <time.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -52,6 +53,10 @@
 #define CHECK_HANDLE(x) ((x)>0)
 #define NUM_PERF_MODES  3
 
+const int kMaxInteractiveDuration = 5000; /* ms */
+const int kMinInteractiveDuration = 500; /* ms */
+const int kMinFlingDuration = 1500; /* ms */
+
 static int current_power_profile = PROFILE_BALANCED;
 
 static int profile_high_performance[] = {
@@ -265,6 +270,58 @@
     return HINT_NONE;
 }
 
+static int process_activity_launch_hint(void *UNUSED(data))
+{
+    if (current_mode != NORMAL_MODE) {
+        ALOGV("%s: ignoring due to other active perf hints", __func__);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+    }
+    return HINT_HANDLED;
+}
+
+static int process_interaction_hint(void *data)
+{
+    static struct timespec s_previous_boost_timespec;
+    static int s_previous_duration = 0;
+
+    struct timespec cur_boost_timespec;
+    long long elapsed_time;
+    int duration = kMinInteractiveDuration;
+
+    if (current_mode != NORMAL_MODE) {
+        ALOGV("%s: ignoring due to other active perf hints", __func__);
+        return HINT_HANDLED;
+    }
+
+    if (data) {
+        int input_duration = *((int*)data);
+        if (input_duration > duration) {
+            duration = (input_duration > kMaxInteractiveDuration) ?
+                    kMaxInteractiveDuration : input_duration;
+        }
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
+
+    elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
+    // don't hint if previous hint's duration covers this hint's duration
+    if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
+        return HINT_HANDLED;
+    }
+    s_previous_boost_timespec = cur_boost_timespec;
+    s_previous_duration = duration;
+
+    if (duration >= kMinFlingDuration) {
+        // Use launch boost resources for fling boost
+        perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
+    }
+
+    return HINT_HANDLED;
+}
+
 int power_hint_override(power_hint_t hint, void *data)
 {
     int ret_val = HINT_NONE;
@@ -291,6 +348,12 @@
         case POWER_HINT_VR_MODE:
             ret_val = process_perf_hint(data, VR_MODE);
             break;
+        case POWER_HINT_INTERACTION:
+            ret_val = process_interaction_hint(data);
+            break;
+        case POWER_HINT_LAUNCH:
+            ret_val = process_activity_launch_hint(data);
+            break;
         default:
             break;
     }
diff --git a/power-8998.c b/power-8998.c
index af14e67..20804ab 100644
--- a/power-8998.c
+++ b/power-8998.c
@@ -31,6 +31,7 @@
 #define LOG_NIDEBUG 0
 
 #include <errno.h>
+#include <time.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -53,6 +54,10 @@
 #define CHECK_HANDLE(x) ((x)>0)
 #define NUM_PERF_MODES  3
 
+const int kMaxInteractiveDuration = 5000; /* ms */
+const int kMinInteractiveDuration = 500; /* ms */
+const int kMinFlingDuration = 1500; /* ms */
+
 static int current_power_profile = PROFILE_BALANCED;
 
 static int profile_high_performance[] = {
@@ -261,6 +266,57 @@
     return HINT_NONE;
 }
 
+static int process_activity_launch_hint(void *UNUSED(data))
+{
+    if (current_mode != NORMAL_MODE) {
+        ALOGV("%s: ignoring due to other active perf hints", __func__);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_FIRST_LAUNCH_BOOST, -1, LAUNCH_BOOST_V1);
+    }
+    return HINT_HANDLED;
+}
+
+static int process_interaction_hint(void *data)
+{
+    static struct timespec s_previous_boost_timespec;
+    static int s_previous_duration = 0;
+
+    struct timespec cur_boost_timespec;
+    long long elapsed_time;
+    int duration = kMinInteractiveDuration;
+
+    if (current_mode != NORMAL_MODE) {
+        ALOGV("%s: ignoring due to other active perf hints", __func__);
+        return HINT_HANDLED;
+    }
+
+    if (data) {
+        int input_duration = *((int*)data);
+        if (input_duration > duration) {
+            duration = (input_duration > kMaxInteractiveDuration) ?
+                    kMaxInteractiveDuration : input_duration;
+        }
+    }
+
+    clock_gettime(CLOCK_MONOTONIC, &cur_boost_timespec);
+
+    elapsed_time = calc_timespan_us(s_previous_boost_timespec, cur_boost_timespec);
+    // don't hint if previous hint's duration covers this hint's duration
+    if ((s_previous_duration * 1000) > (elapsed_time + duration * 1000)) {
+        return HINT_HANDLED;
+    }
+    s_previous_boost_timespec = cur_boost_timespec;
+    s_previous_duration = duration;
+
+    if (duration >= kMinFlingDuration) {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, -1, SCROLL_PREFILING);
+    } else {
+        perf_hint_enable_with_type(VENDOR_HINT_SCROLL_BOOST, duration, SCROLL_VERTICAL);
+    }
+
+    return HINT_HANDLED;
+}
+
 int power_hint_override(power_hint_t hint, void *data)
 {
     int ret_val = HINT_NONE;
@@ -288,9 +344,10 @@
             ret_val = process_perf_hint(data, VR_MODE);
             break;
         case POWER_HINT_INTERACTION:
-            if (current_mode != NORMAL_MODE) {
-                ret_val = HINT_HANDLED;
-            }
+            ret_val = process_interaction_hint(data);
+            break;
+        case POWER_HINT_LAUNCH:
+            ret_val = process_activity_launch_hint(data);
             break;
         default:
             break;
diff --git a/utils.c b/utils.c
index ffa3e34..d86ffd8 100644
--- a/utils.c
+++ b/utils.c
@@ -273,6 +273,21 @@
     return lock_handle;
 }
 
+//Same as perf_hint_enable, but with the ability to
+//choose the type
+int perf_hint_enable_with_type(int hint_id, int duration, int type)
+{
+    int lock_handle = 0;
+
+    if (qcopt_handle) {
+        if (perf_hint) {
+            lock_handle = perf_hint(hint_id, NULL, duration, type);
+            if (lock_handle == -1)
+                ALOGE("Failed to acquire lock.");
+        }
+    }
+    return lock_handle;
+}
 
 void release_request(int lock_handle) {
     if (qcopt_handle && perf_lock_rel)
diff --git a/utils.h b/utils.h
index 79ebd33..6975b41 100644
--- a/utils.h
+++ b/utils.h
@@ -42,6 +42,7 @@
 void release_request(int lock_handle);
 void interaction(int duration, int num_args, int opt_list[]);
 int perf_hint_enable(int hint_id, int duration);
+int perf_hint_enable_with_type(int hint_id, int duration, int type);
 
 long long calc_timespan_us(struct timespec start, struct timespec end);
 int get_soc_id(void);