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/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;
     }