Enable NSRM (network socket request manager)

NSRM is a feature to synchronize app socket requests
to reduce network signalling and there by save some power.

Change-Id: Ice992713994045d0582f8cfb7b6761e2689f2555
Conflicts:
services/core/java/com/android/server/AlarmManagerService.java
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index c15e6c2..e894f63 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -114,6 +115,9 @@
 
     final Object mLock = new Object();
 
+    private final ArrayList<Integer> mTriggeredUids = new ArrayList<Integer>();
+    private final ArrayList<Integer> mBlockedUids = new ArrayList<Integer>();
+
     long mNativeData;
     private long mNextWakeup;
     private long mNextRtcWakeup;
@@ -560,9 +564,10 @@
         final BroadcastStats mBroadcastStats;
         final FilterStats mFilterStats;
         final int mAlarmType;
+        final int mUid;
 
         InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource,
-                int alarmType, String tag) {
+                int alarmType, String tag, int uid) {
             mPendingIntent = pendingIntent;
             mWorkSource = workSource;
             mTag = tag;
@@ -574,6 +579,7 @@
             }
             mFilterStats = fs;
             mAlarmType = alarmType;
+            mUid = uid;
         }
     }
 
@@ -1280,6 +1286,44 @@
         }
     }
 
+    /* updates the blocked uids, so if a wake lock is acquired to only fire
+     * alarm for it, it can be released.
+     */
+    void updateBlockedUids(int uid, boolean isBlocked) {
+        if (localLOGV) Slog.v(TAG, "UpdateBlockedUids: uid = "+uid +" isBlocked = "+isBlocked);
+        synchronized(mLock) {
+            if(isBlocked) {
+                mBlockedUids.add(new Integer(uid));
+                if (checkReleaseWakeLock()) {
+                    /* all the uids for which the alarms are triggered
+                     * are either blocked or have called onSendFinished.
+                     */
+                    if (mWakeLock.isHeld()) {
+                        mWakeLock.release();
+                        if (localLOGV)
+                            Slog.v(TAG, "AM WakeLock Released Internally in updateBlockedUids");
+                    }
+                }
+            } else {
+               mBlockedUids.clear();
+            }
+        }
+    }
+
+    boolean checkReleaseWakeLock() {
+        if (mTriggeredUids.size() == 0 || mBlockedUids.size() == 0)
+            return false;
+
+        int uid;
+        for (int i = 0; i <  mTriggeredUids.size(); i++) {
+            uid = mTriggeredUids.get(i);
+            if (!mBlockedUids.contains(uid)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private void removeLocked(PendingIntent operation) {
         boolean didRemove = false;
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
@@ -1555,6 +1599,8 @@
         public final AlarmManager.AlarmClockInfo alarmClock;
         public final int userId;
         public PriorityClass priorityClass;
+        public int uid;
+        public int pid;
 
         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
                 long _interval, PendingIntent _op, WorkSource _ws,
@@ -1573,6 +1619,8 @@
             workSource = _ws;
             alarmClock = _info;
             userId = _userId;
+            uid = Binder.getCallingUid();
+            pid = Binder.getCallingPid();
         }
 
         public static String makeTag(PendingIntent pi, int type) {
@@ -1680,15 +1728,16 @@
                         mResultReceiver, mHandler);
 
                 // we have an active broadcast so stay awake.
-                if (mBroadcastRefCount == 0) {
+                if (mBroadcastRefCount == 0 || !mWakeLock.isHeld()) {
                     setWakelockWorkSource(alarm.operation, alarm.workSource,
                             alarm.type, alarm.tag, true);
                     mWakeLock.acquire();
                 }
                 final InFlight inflight = new InFlight(AlarmManagerService.this,
-                        alarm.operation, alarm.workSource, alarm.type, alarm.tag);
+                        alarm.operation, alarm.workSource, alarm.type, alarm.tag, alarm.uid);
                 mInFlight.add(inflight);
                 mBroadcastRefCount++;
+                mTriggeredUids.add(new Integer(alarm.uid));
 
                 final BroadcastStats bs = inflight.mBroadcastStats;
                 bs.count++;
@@ -1876,11 +1925,10 @@
                 mWakeLock.setWorkSource(new WorkSource(uid));
                 return;
             }
+            // Something went wrong; fall back to attributing the lock to the OS
+            mWakeLock.setWorkSource(null);
         } catch (Exception e) {
         }
-
-        // Something went wrong; fall back to attributing the lock to the OS
-        mWakeLock.setWorkSource(null);
     }
 
     private class AlarmHandler extends Handler {
@@ -2113,9 +2161,11 @@
         public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
                 String resultData, Bundle resultExtras) {
             synchronized (mLock) {
+                int uid = 0;
                 InFlight inflight = null;
                 for (int i=0; i<mInFlight.size(); i++) {
                     if (mInFlight.get(i).mPendingIntent == pi) {
+                        uid = mInFlight.get(i).mUid;
                         inflight = mInFlight.remove(i);
                         break;
                     }
@@ -2138,8 +2188,19 @@
                     mLog.w("No in-flight alarm for " + pi + " " + intent);
                 }
                 mBroadcastRefCount--;
+                mTriggeredUids.remove(new Integer(uid));
+
+                if (checkReleaseWakeLock()) {
+                    if (mWakeLock.isHeld()) {
+                        mWakeLock.release();
+                        if (localLOGV) Slog.v(TAG, "AM WakeLock Released Internally onSendFinish");
+                    }
+                }
+
                 if (mBroadcastRefCount == 0) {
-                    mWakeLock.release();
+                    if (mWakeLock.isHeld()) {
+                        mWakeLock.release();
+                    }
                     if (mInFlight.size() > 0) {
                         mLog.w("Finished all broadcasts with " + mInFlight.size()
                                 + " remaining inflights");
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a76615a..8da1973 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2007 The Android Open Source Project
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -155,6 +156,9 @@
     private static final int POWER_HINT_INTERACTION = 2;
     private static final int POWER_HINT_LOW_POWER = 5;
 
+    // Config value for NSRM
+    private static final int DPM_CONFIG_FEATURE_MASK_NSRM = 0x00000004;
+
     private final Context mContext;
     private final ServiceThread mHandlerThread;
     private final PowerManagerHandler mHandler;
@@ -425,6 +429,9 @@
     private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners
             = new ArrayList<PowerManagerInternal.LowPowerModeListener>();
 
+    //track the blocked uids.
+    private final ArrayList<Integer> mBlockedUids = new ArrayList<Integer>();
+
     private native void nativeInit();
 
     private static native void nativeAcquireSuspendBlocker(String name);
@@ -722,6 +729,15 @@
     private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
             WorkSource ws, String historyTag, int uid, int pid) {
         synchronized (mLock) {
+            if(mBlockedUids.contains(new Integer(uid)) && uid != Process.myUid()) {
+                //wakelock acquisition for blocked uid, do not acquire.
+                if (DEBUG_SPEW) {
+                    Slog.d(TAG, "uid is blocked not acquiring wakeLock flags=0x" +
+                            Integer.toHexString(flags) + " tag=" + tag + " uid=" + uid +
+                            " pid =" + pid);
+                }
+                return;
+            }
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "acquireWakeLockInternal: lock=" + Objects.hashCode(lock)
                         + ", flags=0x" + Integer.toHexString(flags)
@@ -848,13 +864,23 @@
             int callingUid) {
         synchronized (mLock) {
             int index = findWakeLockIndexLocked(lock);
+            int value = SystemProperties.getInt("persist.dpm.feature", 0);
+            boolean isNsrmEnabled = false;
+
+            if ((value & DPM_CONFIG_FEATURE_MASK_NSRM) == DPM_CONFIG_FEATURE_MASK_NSRM)
+                isNsrmEnabled = true;
+
             if (index < 0) {
                 if (DEBUG_SPEW) {
                     Slog.d(TAG, "updateWakeLockWorkSourceInternal: lock=" + Objects.hashCode(lock)
                             + " [not found], ws=" + ws);
                 }
+                if (!isNsrmEnabled) {
                 throw new IllegalArgumentException("Wake lock not active: " + lock
                         + " from uid " + callingUid);
+                } else {
+                    return;
+                }
             }
 
             WakeLock wakeLock = mWakeLocks.get(index);
@@ -873,6 +899,54 @@
         }
     }
 
+    /* updates the blocked uids, so if a wake lock is acquired for it
+     * can be released.
+     */
+    public void updateBlockedUids(int uid, boolean isBlocked) {
+        synchronized(mLock) {
+            if (DEBUG_SPEW) Slog.v(TAG, "updateBlockedUids: uid = "+uid +"isBlocked = "+isBlocked);
+            if(isBlocked) {
+                mBlockedUids.add(new Integer(uid));
+                for (int index = 0; index < mWakeLocks.size(); index++) {
+                    WakeLock wl = mWakeLocks.get(index);
+                    if(wl != null) {
+                        if(wl.mTag.startsWith("*sync*") && wl.mOwnerUid == Process.SYSTEM_UID) {
+                            releaseWakeLockInternal(wl.mLock, wl.mFlags);
+                            index--;
+                            if (DEBUG_SPEW) Slog.v(TAG, "Internally releasing the wakelock"
+                                    + "acquired by SyncManager");
+                            continue;
+                        }
+                        // release the wakelock for the blocked uid
+                        if (wl.mOwnerUid == uid || checkWorkSourceObjectId(uid, wl)) {
+                            releaseWakeLockInternal(wl.mLock, wl.mFlags);
+                            index--;
+                            if (DEBUG_SPEW) Slog.v(TAG, "Internally releasing it");
+                        }
+                    }
+                }
+            }
+            else {
+                mBlockedUids.remove(new Integer(uid));
+            }
+        }
+    }
+
+    private boolean checkWorkSourceObjectId(int uid, WakeLock wl) {
+        try {
+            for (int index = 0; index < wl.mWorkSource.size(); index++) {
+                if (uid == wl.mWorkSource.get(index)) {
+                    if (DEBUG_SPEW) Slog.v(TAG, "WS uid matched");
+                    return true;
+                }
+            }
+        }
+        catch (Exception e) {
+            return false;
+        }
+        return false;
+    }
+
     private int findWakeLockIndexLocked(IBinder lock) {
         final int count = mWakeLocks.size();
         for (int i = 0; i < count; i++) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 751ba42..c765154 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2006 The Android Open Source Project
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -99,6 +100,8 @@
 import com.android.server.wm.WindowManagerService;
 
 import dalvik.system.VMRuntime;
+import dalvik.system.PathClassLoader;
+import java.lang.reflect.Constructor;
 
 import java.io.File;
 import java.util.Timer;
@@ -152,6 +155,7 @@
     // TODO: remove all of these references by improving dependency resolution and boot phases
     private Installer mInstaller;
     private PowerManagerService mPowerManagerService;
+    private AlarmManagerService mAlarmManagerService;
     private ActivityManagerService mActivityManagerService;
     private DisplayManagerService mDisplayManagerService;
     private PackageManagerService mPackageManagerService;
@@ -462,7 +466,7 @@
             consumerIr = new ConsumerIrService(context);
             ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
 
-            mSystemServiceManager.startService(AlarmManagerService.class);
+            mAlarmManagerService = mSystemServiceManager.startService(AlarmManagerService.class);
             alarm = IAlarmManager.Stub.asInterface(
                     ServiceManager.getService(Context.ALARM_SERVICE));
 
@@ -695,6 +699,12 @@
                 } catch (Throwable e) {
                     reportWtf("starting Service Discovery Service", e);
                 }
+                try {
+                    Slog.i(TAG, "DPM Service");
+                    startDpmService(context, this);
+                } catch (Throwable e) {
+                    reportWtf("starting DpmService", e);
+                }
             }
 
             if (!disableNonCoreServices) {
@@ -1217,4 +1227,46 @@
         //Slog.d(TAG, "Starting service: " + intent);
         context.startServiceAsUser(intent, UserHandle.OWNER);
     }
+
+    private static final void startDpmService(Context context, SystemServer systemServer) {
+        try {
+            Object dpmObj = null;
+            int dpmFeature = SystemProperties.getInt("persist.dpm.feature", 0);
+            Slog.i(TAG, "DPM configuration set to " + dpmFeature);
+
+            if (dpmFeature > 0 && dpmFeature < 8) {
+                PathClassLoader dpmClassLoader =
+                    new PathClassLoader("/system/framework/com.qti.dpmframework.jar",
+                            ClassLoader.getSystemClassLoader());
+                Class dpmClass = dpmClassLoader.loadClass("com.qti.dpm.DpmService");
+                Constructor dpmConstructor = dpmClass.getConstructor(
+                        new Class[] {Context.class, SystemServer.class});
+                dpmObj = dpmConstructor.newInstance(context, systemServer);
+                try {
+                    if(dpmObj != null && (dpmObj instanceof IBinder)) {
+                        ServiceManager.addService("dpmservice", (IBinder)dpmObj);
+                        Slog.i(TAG, "Created DPM Service");
+                    }
+                } catch (Exception e) {
+                    Slog.i(TAG, "starting DPM Service", e);
+                }
+            }
+        } catch (Throwable e) {
+            Slog.i(TAG, "starting DPM Service", e);
+        }
+    }
+
+
+    public void updateBlockedUids(int uid, boolean isBlocked) {
+        try {
+            mAlarmManagerService.updateBlockedUids(uid, isBlocked);
+        } catch (NullPointerException e) {
+            Slog.w(TAG, "Could Not Update blocked Uids with alarmManager" + e);
+        }
+        try {
+            mPowerManagerService.updateBlockedUids(uid, isBlocked);
+        } catch (NullPointerException e) {
+            Slog.w(TAG, "Could Not Update blocked Uids with powerManager" + e);
+        }
+    }
 }