SipService: add wake lock for incoming INVITE packets.

+ Keep the wake lock for 500ms. (Some measurements on N1 indicate 160~180ms
  needed to bring up InCallScreen but since INVITE doesn't come in frequently
  we can be more generous just to be safe.)
+ Move MyWakeupLock out of SipService so SipSessionGroup can use it without
  awkward inter-dependency with SipService.
  + Add acquire(int timeout) to be used to create the "timed" wake lock.

http://b/issue?id=3081828

Change-Id: Iffd1d78d1a5cae9f795252ada75310917095204d
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index f41f156c..1df08c0 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -55,7 +55,6 @@
 import java.util.Collection;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Timer;
@@ -67,8 +66,8 @@
  * @hide
  */
 public final class SipService extends ISipService.Stub {
-    private static final String TAG = "SipService";
-    private static final boolean DEBUGV = false;
+    static final String TAG = "SipService";
+    static final boolean DEBUGV = false;
     private static final boolean DEBUG = true;
     private static final boolean DEBUG_TIMER = DEBUG && false;
     private static final int EXPIRY_TIME = 3600;
@@ -95,7 +94,7 @@
 
     private ConnectivityReceiver mConnectivityReceiver;
     private boolean mWifiEnabled;
-    private MyWakeLock mMyWakeLock;
+    private SipWakeLock mMyWakeLock;
 
     /**
      * Starts the SIP service. Do nothing if the SIP API is not supported on the
@@ -117,7 +116,7 @@
                 new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
         context.registerReceiver(mWifiStateReceiver,
                 new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION));
-        mMyWakeLock = new MyWakeLock((PowerManager)
+        mMyWakeLock = new SipWakeLock((PowerManager)
                 context.getSystemService(Context.POWER_SERVICE));
 
         mTimer = new WakeupTimer(context);
@@ -459,7 +458,8 @@
         private SipSessionGroup createSipSessionGroup(String localIp,
                 SipProfile localProfile, String password) throws SipException {
             try {
-                return new SipSessionGroup(localIp, localProfile, password);
+                return new SipSessionGroup(localIp, localProfile, password,
+                        mMyWakeLock);
             } catch (IOException e) {
                 // network disconnected
                 Log.w(TAG, "createSipSessionGroup(): network disconnected?");
@@ -546,6 +546,7 @@
         @Override
         public void onRinging(ISipSession s, SipProfile caller,
                 String sessionDescription) {
+            if (DEBUGV) Log.d(TAG, "<<<<< onRinging()");
             SipSessionGroup.SipSessionImpl session =
                     (SipSessionGroup.SipSessionImpl) s;
             synchronized (SipService.this) {
@@ -1360,41 +1361,4 @@
             }
         }
     }
-
-    private static class MyWakeLock {
-        private PowerManager mPowerManager;
-        private PowerManager.WakeLock mWakeLock;
-        private HashSet<Object> mHolders = new HashSet<Object>();
-
-        MyWakeLock(PowerManager powerManager) {
-            mPowerManager = powerManager;
-        }
-
-        synchronized void reset() {
-            mHolders.clear();
-            release(null);
-            if (DEBUGV) Log.v(TAG, "~~~ hard reset wakelock");
-        }
-
-        synchronized void acquire(Object holder) {
-            mHolders.add(holder);
-            if (mWakeLock == null) {
-                mWakeLock = mPowerManager.newWakeLock(
-                        PowerManager.PARTIAL_WAKE_LOCK, "SipWakeLock");
-            }
-            if (!mWakeLock.isHeld()) mWakeLock.acquire();
-            if (DEBUGV) Log.v(TAG, "acquire wakelock: holder count="
-                    + mHolders.size());
-        }
-
-        synchronized void release(Object holder) {
-            mHolders.remove(holder);
-            if ((mWakeLock != null) && mHolders.isEmpty()
-                    && mWakeLock.isHeld()) {
-                mWakeLock.release();
-            }
-            if (DEBUGV) Log.v(TAG, "release wakelock: holder count="
-                    + mHolders.size());
-        }
-    }
 }
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 2b8058f..d861fa5 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -84,6 +84,7 @@
     private static final String ANONYMOUS = "anonymous";
     private static final int EXPIRY_TIME = 3600; // in seconds
     private static final int CANCEL_CALL_TIMER = 3; // in seconds
+    private static final long WAKE_LOCK_HOLDING_TIME = 500; // in milliseconds
 
     private static final EventObject DEREGISTER = new EventObject("Deregister");
     private static final EventObject END_CALL = new EventObject("End call");
@@ -101,6 +102,8 @@
     private SipSessionImpl mCallReceiverSession;
     private String mLocalIp;
 
+    private SipWakeLock mWakeLock;
+
     // call-id-to-SipSession map
     private Map<String, SipSessionImpl> mSessionMap =
             new HashMap<String, SipSessionImpl>();
@@ -110,10 +113,11 @@
      * @param password the password of the profile
      * @throws IOException if cannot assign requested address
      */
-    public SipSessionGroup(String localIp, SipProfile myself, String password)
-            throws SipException, IOException {
+    public SipSessionGroup(String localIp, SipProfile myself, String password,
+            SipWakeLock wakeLock) throws SipException, IOException {
         mLocalProfile = myself;
         mPassword = password;
+        mWakeLock = wakeLock;
         reset(localIp);
     }
 
@@ -271,7 +275,14 @@
         }
     }
 
-    public void processRequest(RequestEvent event) {
+    public void processRequest(final RequestEvent event) {
+        if (isRequestEvent(Request.INVITE, event)) {
+            if (DEBUG) Log.d(TAG, "<<<<< got INVITE, thread:"
+                    + Thread.currentThread());
+            // Acquire a wake lock and keep it for WAKE_LOCK_HOLDING_TIME;
+            // should be large enough to bring up the app.
+            mWakeLock.acquire(WAKE_LOCK_HOLDING_TIME);
+        }
         process(event);
     }
 
diff --git a/voip/java/com/android/server/sip/SipWakeLock.java b/voip/java/com/android/server/sip/SipWakeLock.java
new file mode 100644
index 0000000..52bc094
--- /dev/null
+++ b/voip/java/com/android/server/sip/SipWakeLock.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.sip;
+
+import android.os.PowerManager;
+import android.util.Log;
+
+import java.util.HashSet;
+
+class SipWakeLock {
+    private static final boolean DEBUGV = SipService.DEBUGV;
+    private static final String TAG = SipService.TAG;
+    private PowerManager mPowerManager;
+    private PowerManager.WakeLock mWakeLock;
+    private PowerManager.WakeLock mTimerWakeLock;
+    private HashSet<Object> mHolders = new HashSet<Object>();
+
+    SipWakeLock(PowerManager powerManager) {
+        mPowerManager = powerManager;
+    }
+
+    synchronized void reset() {
+        mHolders.clear();
+        release(null);
+        if (DEBUGV) Log.v(TAG, "~~~ hard reset wakelock");
+    }
+
+    synchronized void acquire(long timeout) {
+        if (mTimerWakeLock == null) {
+            mTimerWakeLock = mPowerManager.newWakeLock(
+                    PowerManager.PARTIAL_WAKE_LOCK, "SipWakeLock.timer");
+            mTimerWakeLock.setReferenceCounted(true);
+        }
+        mTimerWakeLock.acquire(timeout);
+    }
+
+    synchronized void acquire(Object holder) {
+        mHolders.add(holder);
+        if (mWakeLock == null) {
+            mWakeLock = mPowerManager.newWakeLock(
+                    PowerManager.PARTIAL_WAKE_LOCK, "SipWakeLock");
+        }
+        if (!mWakeLock.isHeld()) mWakeLock.acquire();
+        if (DEBUGV) Log.v(TAG, "acquire wakelock: holder count="
+                + mHolders.size());
+    }
+
+    synchronized void release(Object holder) {
+        mHolders.remove(holder);
+        if ((mWakeLock != null) && mHolders.isEmpty()
+                && mWakeLock.isHeld()) {
+            mWakeLock.release();
+        }
+        if (DEBUGV) Log.v(TAG, "release wakelock: holder count="
+                + mHolders.size());
+    }
+}