sde: Implement sequence locker to lock across multiple APIs.

1. Lock prepare() and set() APIs using sequence entry and sequence
   exit lock respectively to prevent the critical section being
   accessed by other threads.
2. Wait for sequence wait lock on HotPlugEvent thread or any other
   binder threads(Eg. dumpsys), before it accesses the critical region.
3. Prevent deadlock during multiple prepare() calls before a set().

Change-Id: I5443675c870ed2967615ec383dd2d59ded30b52b
diff --git a/displayengine/include/utils/locker.h b/displayengine/include/utils/locker.h
index 2c1ef9a..549a282 100644
--- a/displayengine/include/utils/locker.h
+++ b/displayengine/include/utils/locker.h
@@ -1,5 +1,5 @@
 /*
-* Copyright (c) 2014, The Linux Foundation. All rights reserved.
+* Copyright (c) 2014 - 2015, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met:
@@ -28,7 +28,11 @@
 #include <stdint.h>
 #include <pthread.h>
 
-#define SCOPE_LOCK(locker) Locker::ScopeLock scopeLock(locker)
+#define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker)
+#define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker)
+#define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker)
+#define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker)
+#define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker)
 
 namespace sde {
 
@@ -48,7 +52,78 @@
     Locker &locker_;
   };
 
-  Locker() {
+  class SequenceEntryScopeLock {
+   public:
+    explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) {
+      locker_.Lock();
+      locker_.sequence_wait_ = 1;
+    }
+
+    ~SequenceEntryScopeLock() {
+      locker_.Unlock();
+    }
+
+   private:
+    Locker &locker_;
+  };
+
+  class SequenceExitScopeLock {
+   public:
+    explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) {
+      locker_.Lock();
+      locker_.sequence_wait_ = 0;
+    }
+
+    ~SequenceExitScopeLock() {
+      locker_.Broadcast();
+      locker_.Unlock();
+    }
+
+   private:
+    Locker &locker_;
+  };
+
+  class SequenceWaitScopeLock {
+   public:
+    explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) {
+      locker_.Lock();
+
+      if (locker_.sequence_wait_ == 1) {
+        locker_.Wait();
+        error_ = (locker_.sequence_wait_ == -1);
+      }
+    }
+
+    ~SequenceWaitScopeLock() {
+      locker_.Unlock();
+    }
+
+    bool IsError() {
+      return error_;
+    }
+
+   private:
+    Locker &locker_;
+    bool error_;
+  };
+
+  class SequenceCancelScopeLock {
+   public:
+    explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) {
+      locker_.Lock();
+      locker_.sequence_wait_ = -1;
+    }
+
+    ~SequenceCancelScopeLock() {
+      locker_.Broadcast();
+      locker_.Unlock();
+    }
+
+   private:
+    Locker &locker_;
+  };
+
+  Locker() : sequence_wait_(0) {
     pthread_mutex_init(&mutex_, 0);
     pthread_cond_init(&condition_, 0);
   }
@@ -63,7 +138,7 @@
   void Signal() { pthread_cond_signal(&condition_); }
   void Broadcast() { pthread_cond_broadcast(&condition_); }
   void Wait() { pthread_cond_wait(&condition_, &mutex_); }
-  int WaitFinite(long int ms) {
+  int WaitFinite(int ms) {
     struct timespec ts;
     struct timeval tv;
     gettimeofday(&tv, NULL);
@@ -77,6 +152,11 @@
  private:
   pthread_mutex_t mutex_;
   pthread_cond_t condition_;
+  int sequence_wait_;   // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel.
+                        // Some routines will wait for sequence of function calls to finish
+                        // so that capturing a transitionary snapshot of context is prevented.
+                        // If flag is set to -1, these routines will exit without doing any
+                        // further processing.
 };
 
 }  // namespace sde
diff --git a/displayengine/libs/hwc/hwc_session.cpp b/displayengine/libs/hwc/hwc_session.cpp
index 0b2f484..5a380b0 100644
--- a/displayengine/libs/hwc/hwc_session.cpp
+++ b/displayengine/libs/hwc/hwc_session.cpp
@@ -210,7 +210,7 @@
                         hwc_display_contents_1_t **displays) {
   DTRACE_SCOPED();
 
-  SCOPE_LOCK(locker_);
+  SEQUENCE_ENTRY_SCOPE_LOCK(locker_);
 
   if (!device || !displays) {
     return -EINVAL;
@@ -254,7 +254,7 @@
                     hwc_display_contents_1_t **displays) {
   DTRACE_SCOPED();
 
-  SCOPE_LOCK(locker_);
+  SEQUENCE_EXIT_SCOPE_LOCK(locker_);
 
   if (!device || !displays) {
     return -EINVAL;
@@ -289,7 +289,7 @@
 }
 
 int HWCSession::EventControl(hwc_composer_device_1 *device, int disp, int event, int enable) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
 
   if (!device) {
     return -EINVAL;
@@ -317,7 +317,7 @@
 }
 
 int HWCSession::SetPowerMode(hwc_composer_device_1 *device, int disp, int mode) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
 
   if (!device) {
     return -EINVAL;
@@ -348,6 +348,8 @@
 }
 
 int HWCSession::Query(hwc_composer_device_1 *device, int param, int *value) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device || !value) {
     return -EINVAL;
   }
@@ -365,7 +367,7 @@
 }
 
 void HWCSession::Dump(hwc_composer_device_1 *device, char *buffer, int length) {
-  SCOPE_LOCK(locker_);
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
 
   if (!device || !buffer || !length) {
     return;
@@ -376,6 +378,8 @@
 
 int HWCSession::GetDisplayConfigs(hwc_composer_device_1 *device, int disp, uint32_t *configs,
                                   size_t *num_configs) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device || !configs || !num_configs) {
     return -EINVAL;
   }
@@ -406,6 +410,8 @@
 
 int HWCSession::GetDisplayAttributes(hwc_composer_device_1 *device, int disp, uint32_t config,
                                      const uint32_t *attributes, int32_t *values) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device || !attributes || !values) {
     return -EINVAL;
   }
@@ -435,6 +441,8 @@
 }
 
 int HWCSession::GetActiveConfig(hwc_composer_device_1 *device, int disp) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device) {
     return -1;
   }
@@ -464,6 +472,8 @@
 }
 
 int HWCSession::SetActiveConfig(hwc_composer_device_1 *device, int disp, int index) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   if (!device) {
     return -EINVAL;
   }
@@ -549,6 +559,8 @@
 
 android::status_t HWCSession::notifyCallback(uint32_t command, const android::Parcel *input_parcel,
                                              android::Parcel */*output_parcel*/) {
+  SEQUENCE_WAIT_SCOPE_LOCK(locker_);
+
   switch (command) {
   case qService::IQService::DYNAMIC_DEBUG:
     DynamicDebug(input_parcel);
@@ -666,7 +678,7 @@
   }
 
   if (connected) {
-    SCOPE_LOCK(locker_);
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_);
     if (display_external_) {
      DLOGE("HDMI already connected");
      return -1;
@@ -683,7 +695,7 @@
       return -1;
     }
   } else {
-    SCOPE_LOCK(locker_);
+    SEQUENCE_WAIT_SCOPE_LOCK(locker_);
     if (!display_external_) {
      DLOGE("HDMI not connected");
      return -1;