diff options
27 files changed, 970 insertions, 94 deletions
diff --git a/api/current.xml b/api/current.xml index e570ac9..8b6f4dc 100644 --- a/api/current.xml +++ b/api/current.xml @@ -85983,6 +85983,8 @@ > <parameter name="uid" type="int"> </parameter> +<parameter name="ws" type="android.os.WorkSource"> +</parameter> </method> <method name="onDisable" return="void" @@ -86112,6 +86114,8 @@ > <parameter name="uid" type="int"> </parameter> +<parameter name="ws" type="android.os.WorkSource"> +</parameter> </method> <method name="onRequiresCell" return="boolean" @@ -86173,6 +86177,8 @@ > <parameter name="minTime" type="long"> </parameter> +<parameter name="ws" type="android.os.WorkSource"> +</parameter> </method> <method name="onSupportsAltitude" return="boolean" @@ -103293,6 +103299,19 @@ <parameter name="refCounted" type="boolean"> </parameter> </method> +<method name="setWorkSource" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="ws" type="android.os.WorkSource"> +</parameter> +</method> </class> </package> <package name="android.opengl" @@ -130104,6 +130123,19 @@ <parameter name="value" type="boolean"> </parameter> </method> +<method name="setWorkSource" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="ws" type="android.os.WorkSource"> +</parameter> +</method> </class> <class name="Process" extends="java.lang.Object" @@ -131252,6 +131284,134 @@ </parameter> </method> </class> +<class name="WorkSource" + extends="java.lang.Object" + abstract="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<implements name="android.os.Parcelable"> +</implements> +<constructor name="WorkSource" + type="android.os.WorkSource" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</constructor> +<constructor name="WorkSource" + type="android.os.WorkSource" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="orig" type="android.os.WorkSource"> +</parameter> +</constructor> +<method name="add" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="other" type="android.os.WorkSource"> +</parameter> +</method> +<method name="clear" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="describeContents" + return="int" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +</method> +<method name="diff" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="other" type="android.os.WorkSource"> +</parameter> +</method> +<method name="remove" + return="boolean" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="other" type="android.os.WorkSource"> +</parameter> +</method> +<method name="set" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="other" type="android.os.WorkSource"> +</parameter> +</method> +<method name="writeToParcel" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="dest" type="android.os.Parcel"> +</parameter> +<parameter name="flags" type="int"> +</parameter> +</method> +<field name="CREATOR" + type="android.os.Parcelable.Creator" + transient="false" + volatile="false" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +</class> </package> <package name="android.os.storage" > diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java index d3ec3d9..e1d6619 100644 --- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java +++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java @@ -64,7 +64,7 @@ public class PowerCommand extends Svc.Command { = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE)); try { IBinder lock = new Binder(); - pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power"); + pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power", null); pm.setStayOnSetting(val); pm.releaseWakeLock(lock, 0); } diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java index d0b67cc..3e44fcf 100644 --- a/core/java/android/content/SyncManager.java +++ b/core/java/android/content/SyncManager.java @@ -45,6 +45,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.WorkSource; import android.provider.Settings; import android.text.format.DateUtils; import android.text.format.Time; @@ -126,8 +127,8 @@ public class SyncManager implements OnAccountsUpdateListener { private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000; - private static final String SYNC_WAKE_LOCK = "SyncManagerSyncWakeLock"; - private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarmWakeLock"; + private static final String SYNC_WAKE_LOCK = "*sync*"; + private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarm"; private Context mContext; @@ -1695,6 +1696,7 @@ public class SyncManager implements OnAccountsUpdateListener { Log.v(TAG, "runStateIdle: setting mActiveSyncContext to " + mActiveSyncContext); } mSyncStorageEngine.setActiveSync(mActiveSyncContext); + mSyncWakeLock.setWorkSource(new WorkSource(syncAdapterInfo.uid)); if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo)) { Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo); mActiveSyncContext.close(); diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index f5b1e57..f182a7a 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -404,6 +404,7 @@ public abstract class BatteryStats implements Parcelable { public static final byte CMD_UPDATE = 0; public static final byte CMD_START = 1; + public static final byte CMD_OVERFLOW = 2; public byte cmd; @@ -1703,6 +1704,8 @@ public abstract class BatteryStats implements Parcelable { pw.print(" "); if (rec.cmd == HistoryItem.CMD_START) { pw.println(" START"); + } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) { + pw.println(" *OVERFLOW*"); } else { if (rec.batteryLevel < 10) pw.print("00"); else if (rec.batteryLevel < 100) pw.print("0"); diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 01cc408..0067e94 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -17,10 +17,13 @@ package android.os; +import android.os.WorkSource; + /** @hide */ interface IPowerManager { - void acquireWakeLock(int flags, IBinder lock, String tag); + void acquireWakeLock(int flags, IBinder lock, String tag, in WorkSource ws); + void updateWakeLockWorkSource(IBinder lock, in WorkSource ws); void goToSleep(long time); void goToSleepWithReason(long time, int reason); void releaseWakeLock(IBinder lock, int flags); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index f4ca8bc..3876a3e 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -209,6 +209,7 @@ public class PowerManager int mCount = 0; boolean mRefCounted = true; boolean mHeld = false; + WorkSource mWorkSource; WakeLock(int flags, String tag) { @@ -247,7 +248,7 @@ public class PowerManager synchronized (mToken) { if (!mRefCounted || mCount++ == 0) { try { - mService.acquireWakeLock(mFlags, mToken, mTag); + mService.acquireWakeLock(mFlags, mToken, mTag, mWorkSource); } catch (RemoteException e) { } mHeld = true; @@ -313,6 +314,32 @@ public class PowerManager } } + public void setWorkSource(WorkSource ws) { + synchronized (mToken) { + if (ws != null && ws.size() == 0) { + ws = null; + } + boolean changed = true; + if (ws == null) { + mWorkSource = null; + } else if (mWorkSource == null) { + changed = mWorkSource != null; + mWorkSource = new WorkSource(ws); + } else { + changed = mWorkSource.diff(ws); + if (changed) { + mWorkSource.set(ws); + } + } + if (changed && mHeld) { + try { + mService.updateWakeLockWorkSource(mToken, mWorkSource); + } catch (RemoteException e) { + } + } + } + } + public String toString() { synchronized (mToken) { return "WakeLock{" diff --git a/core/java/android/os/WorkSource.aidl b/core/java/android/os/WorkSource.aidl new file mode 100644 index 0000000..1e7fabc --- /dev/null +++ b/core/java/android/os/WorkSource.aidl @@ -0,0 +1,18 @@ +/* Copyright 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 android.os; + +parcelable WorkSource; diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java new file mode 100644 index 0000000..bba1984 --- /dev/null +++ b/core/java/android/os/WorkSource.java @@ -0,0 +1,311 @@ +package android.os; + +/** + * Describes the source of some work that may be done by someone else. + * Currently the public representation of what a work source is is not + * defined; this is an opaque container. + */ +public class WorkSource implements Parcelable { + int mNum; + int[] mUids; + + /** + * Internal statics to avoid object allocations in some operations. + * The WorkSource object itself is not thread safe, but we need to + * hold sTmpWorkSource lock while working with these statics. + */ + static final WorkSource sTmpWorkSource = new WorkSource(0); + /** + * For returning newbie work from a modification operation. + */ + static WorkSource sNewbWork; + /** + * For returning gone work form a modification operation. + */ + static WorkSource sGoneWork; + + /** + * Create an empty work source. + */ + public WorkSource() { + mNum = 0; + } + + /** + * Create a new WorkSource that is a copy of an existing one. + * If <var>orig</var> is null, an empty WorkSource is created. + */ + public WorkSource(WorkSource orig) { + if (orig == null) { + mNum = 0; + return; + } + mNum = orig.mNum; + if (orig.mUids != null) { + mUids = orig.mUids.clone(); + } else { + mUids = null; + } + } + + /** @hide */ + public WorkSource(int uid) { + mNum = 1; + mUids = new int[] { uid, 0 }; + } + + WorkSource(Parcel in) { + mNum = in.readInt(); + mUids = in.createIntArray(); + } + + /** @hide */ + public int size() { + return mNum; + } + + /** @hide */ + public int get(int index) { + return mUids[index]; + } + + /** + * Clear this WorkSource to be empty. + */ + public void clear() { + mNum = 0; + } + + /** + * Compare this WorkSource with another. + * @param other The WorkSource to compare against. + * @return If there is a difference, true is returned. + */ + public boolean diff(WorkSource other) { + int N = mNum; + if (N != other.mNum) { + return true; + } + final int[] uids1 = mUids; + final int[] uids2 = other.mUids; + for (int i=0; i<N; i++) { + if (uids1[i] != uids2[i]) { + return true; + } + } + return false; + } + + /** + * Replace the current contents of this work source with the given + * work source. If <var>other</var> is null, the current work source + * will be made empty. + */ + public void set(WorkSource other) { + if (other == null) { + mNum = 0; + return; + } + mNum = other.mNum; + if (other.mUids != null) { + if (mUids != null && mUids.length >= mNum) { + System.arraycopy(other.mUids, 0, mUids, 0, mNum); + } else { + mUids = other.mUids.clone(); + } + } else { + mUids = null; + } + } + + /** @hide */ + public void set(int uid) { + mNum = 1; + if (mUids == null) mUids = new int[2]; + mUids[0] = uid; + } + + /** @hide */ + public WorkSource[] setReturningDiffs(WorkSource other) { + synchronized (sTmpWorkSource) { + sNewbWork = null; + sGoneWork = null; + updateLocked(other, true, true); + if (sNewbWork != null || sGoneWork != null) { + WorkSource[] diffs = new WorkSource[2]; + diffs[0] = sNewbWork; + diffs[1] = sGoneWork; + return diffs; + } + return null; + } + } + + /** + * Merge the contents of <var>other</var> WorkSource in to this one. + * + * @param other The other WorkSource whose contents are to be merged. + * @return Returns true if any new sources were added. + */ + public boolean add(WorkSource other) { + synchronized (sTmpWorkSource) { + return updateLocked(other, false, false); + } + } + + /** @hide */ + public WorkSource addReturningNewbs(WorkSource other) { + synchronized (sTmpWorkSource) { + sNewbWork = null; + updateLocked(other, false, true); + return sNewbWork; + } + } + + /** @hide */ + public boolean add(int uid) { + synchronized (sTmpWorkSource) { + sTmpWorkSource.mUids[0] = uid; + return updateLocked(sTmpWorkSource, false, false); + } + } + + /** @hide */ + public WorkSource addReturningNewbs(int uid) { + synchronized (sTmpWorkSource) { + sNewbWork = null; + sTmpWorkSource.mUids[0] = uid; + updateLocked(sTmpWorkSource, false, true); + return sNewbWork; + } + } + + public boolean remove(WorkSource other) { + int N1 = mNum; + final int[] uids1 = mUids; + final int N2 = other.mNum; + final int[] uids2 = other.mUids; + boolean changed = false; + int i1 = 0; + for (int i2=0; i2<N2 && i1<N1; i2++) { + if (uids2[i2] == uids1[i1]) { + N1--; + if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1-1, N1-i1); + } + while (i1 < N1 && uids2[i2] > uids1[i1]) { + i1++; + } + } + + mNum = N1; + + return changed; + } + + private boolean updateLocked(WorkSource other, boolean set, boolean returnNewbs) { + int N1 = mNum; + int[] uids1 = mUids; + final int N2 = other.mNum; + final int[] uids2 = other.mUids; + boolean changed = false; + int i1 = 0; + for (int i2=0; i2<N2; i2++) { + if (i1 >= N1 || uids2[i2] < uids1[i1]) { + // Need to insert a new uid. + changed = true; + if (uids1 == null) { + uids1 = new int[4]; + uids1[0] = uids2[i2]; + } else if (i1 >= uids1.length) { + int[] newuids = new int[(uids1.length*3)/2]; + if (i1 > 0) System.arraycopy(uids1, 0, newuids, 0, i1); + if (i1 < N1) System.arraycopy(uids1, i1, newuids, i1+1, N1-i1); + uids1 = newuids; + uids1[i1] = uids2[i2]; + } else { + if (i1 < N1) System.arraycopy(uids1, i1, uids1, i1+1, N1-i1); + uids1[i1] = uids2[i2]; + } + if (returnNewbs) { + if (sNewbWork == null) { + sNewbWork = new WorkSource(uids2[i2]); + } else { + sNewbWork.addLocked(uids2[i2]); + } + } + N1++; + i1++; + } else { + if (!set) { + // Skip uids that already exist or are not in 'other'. + do { + i1++; + } while (i1 < N1 && uids2[i2] >= uids1[i1]); + } else { + // Remove any uids that don't exist in 'other'. + int start = i1; + while (i1 < N1 && uids2[i2] > uids1[i1]) { + if (sGoneWork == null) { + sGoneWork = new WorkSource(uids1[i1]); + } else { + sGoneWork.addLocked(uids1[i1]); + } + i1++; + } + if (start < i1) { + System.arraycopy(uids1, i1, uids1, start, i1-start); + N1 -= i1-start; + i1 = start; + } + // If there is a matching uid, skip it. + if (i1 < N1 && uids2[i1] == uids1[i1]) { + i1++; + } + } + } + } + + mNum = N1; + mUids = uids1; + + return changed; + } + + private void addLocked(int uid) { + if (mUids == null) { + mUids = new int[4]; + mUids[0] = uid; + mNum = 1; + return; + } + if (mNum >= mUids.length) { + int[] newuids = new int[(mNum*3)/2]; + System.arraycopy(mUids, 0, newuids, 0, mNum); + mUids = newuids; + } + + mUids[mNum] = uid; + mNum++; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mNum); + dest.writeIntArray(mUids); + } + + public static final Parcelable.Creator<WorkSource> CREATOR + = new Parcelable.Creator<WorkSource>() { + public WorkSource createFromParcel(Parcel in) { + return new WorkSource(in); + } + public WorkSource[] newArray(int size) { + return new WorkSource[size]; + } + }; +} diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index 1620778..bd87a0d 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -18,6 +18,7 @@ package com.android.internal.app; import com.android.internal.os.BatteryStatsImpl; +import android.os.WorkSource; import android.telephony.SignalStrength; interface IBatteryStats { @@ -33,6 +34,9 @@ interface IBatteryStats { SensorService.cpp */ void noteStopSensor(int uid, int sensor); + void noteStartWakelockFromSource(in WorkSource ws, int pid, String name, int type); + void noteStopWakelockFromSource(in WorkSource ws, int pid, String name, int type); + void noteStartGps(int uid); void noteStopGps(int uid); void noteScreenOn(); @@ -57,6 +61,12 @@ interface IBatteryStats { void noteScanWifiLockReleased(int uid); void noteWifiMulticastEnabled(int uid); void noteWifiMulticastDisabled(int uid); + void noteFullWifiLockAcquiredFromSource(in WorkSource ws); + void noteFullWifiLockReleasedFromSource(in WorkSource ws); + void noteScanWifiLockAcquiredFromSource(in WorkSource ws); + void noteScanWifiLockReleasedFromSource(in WorkSource ws); + void noteWifiMulticastEnabledFromSource(in WorkSource ws); + void noteWifiMulticastDisabledFromSource(in WorkSource ws); void setBatteryState(int status, int health, int plugType, int level, int temp, int volt); long getAwakeTimeBattery(); long getAwakeTimePlugged(); diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index b9f0c61..4943531 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -29,6 +29,7 @@ import android.os.ParcelFormatException; import android.os.Parcelable; import android.os.Process; import android.os.SystemClock; +import android.os.WorkSource; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; @@ -68,12 +69,12 @@ public final class BatteryStatsImpl extends BatteryStats { private static final int VERSION = 50; // Maximum number of items we will record in the history. - private static final int MAX_HISTORY_ITEMS = 1000; + private static final int MAX_HISTORY_ITEMS = 2000; // The maximum number of names wakelocks we will keep track of // per uid; once the limit is reached, we batch the remaining wakelocks // in to one common name. - private static final int MAX_WAKELOCKS_PER_UID = 20; + private static final int MAX_WAKELOCKS_PER_UID = 30; private static final String BATCHED_WAKELOCK_NAME = "*overflow*"; @@ -1173,7 +1174,7 @@ public final class BatteryStatsImpl extends BatteryStats { // If the current time is basically the same as the last time, // just collapse into one record. if (mHistoryEnd != null && mHistoryEnd.cmd == HistoryItem.CMD_UPDATE - && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+100)) { + && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+500)) { // If the current is the same as the one before, then we no // longer need the entry. if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE @@ -1189,6 +1190,10 @@ public final class BatteryStatsImpl extends BatteryStats { return; } + if (mNumHistoryItems == MAX_HISTORY_ITEMS) { + addHistoryRecordLocked(curTime, HistoryItem.CMD_OVERFLOW); + } + if (mNumHistoryItems >= MAX_HISTORY_ITEMS) { // Once we've reached the maximum number of items, we only // record changes to the battery level. @@ -1329,6 +1334,20 @@ public final class BatteryStatsImpl extends BatteryStats { } } + public void noteStartWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) { + int N = ws.size(); + for (int i=0; i<N; i++) { + noteStartWakeLocked(ws.get(i), pid, name, type); + } + } + + public void noteStopWakeFromSourceLocked(WorkSource ws, int pid, String name, int type) { + int N = ws.size(); + for (int i=0; i<N; i++) { + noteStopWakeLocked(ws.get(i), pid, name, type); + } + } + public int startAddingCpuLocked() { mHandler.removeMessages(MSG_UPDATE_WAKELOCKS); @@ -1949,6 +1968,48 @@ public final class BatteryStatsImpl extends BatteryStats { getUidStatsLocked(uid).noteWifiMulticastDisabledLocked(); } + public void noteFullWifiLockAcquiredFromSourceLocked(WorkSource ws) { + int N = ws.size(); + for (int i=0; i<N; i++) { + noteFullWifiLockAcquiredLocked(ws.get(i)); + } + } + + public void noteFullWifiLockReleasedFromSourceLocked(WorkSource ws) { + int N = ws.size(); + for (int i=0; i<N; i++) { + noteFullWifiLockReleasedLocked(ws.get(i)); + } + } + + public void noteScanWifiLockAcquiredFromSourceLocked(WorkSource ws) { + int N = ws.size(); + for (int i=0; i<N; i++) { + noteScanWifiLockAcquiredLocked(ws.get(i)); + } + } + + public void noteScanWifiLockReleasedFromSourceLocked(WorkSource ws) { + int N = ws.size(); + for (int i=0; i<N; i++) { + noteScanWifiLockReleasedLocked(ws.get(i)); + } + } + + public void noteWifiMulticastEnabledFromSourceLocked(WorkSource ws) { + int N = ws.size(); + for (int i=0; i<N; i++) { + noteWifiMulticastEnabledLocked(ws.get(i)); + } + } + + public void noteWifiMulticastDisabledFromSourceLocked(WorkSource ws) { + int N = ws.size(); + for (int i=0; i<N; i++) { + noteWifiMulticastDisabledLocked(ws.get(i)); + } + } + @Override public long getScreenOnTime(long batteryRealtime, int which) { return mScreenOnTimer.getTotalTimeLocked(batteryRealtime, which); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a9e4971..9b9b4be 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -930,7 +930,7 @@ <permission android:name="android.permission.UPDATE_DEVICE_STATS" android:label="@string/permlab_batteryStats" android:description="@string/permdesc_batteryStats" - android:protectionLevel="signature" /> + android:protectionLevel="signatureOrSystem" /> <!-- Allows an application to open windows that are for use by parts of the system user interface. Not for use by third party apps. --> diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl index 2b9782a..ecf6789 100644 --- a/location/java/android/location/ILocationProvider.aidl +++ b/location/java/android/location/ILocationProvider.aidl @@ -20,6 +20,7 @@ import android.location.Criteria; import android.location.Location; import android.net.NetworkInfo; import android.os.Bundle; +import android.os.WorkSource; /** * Binder interface for services that implement location providers. @@ -43,7 +44,7 @@ interface ILocationProvider { long getStatusUpdateTime(); String getInternalState(); void enableLocationTracking(boolean enable); - void setMinTime(long minTime); + void setMinTime(long minTime, in WorkSource ws); void updateNetworkState(int state, in NetworkInfo info); void updateLocation(in Location location); boolean sendExtraCommand(String command, inout Bundle extras); diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java index cf939de..95b4425 100644 --- a/location/java/android/location/provider/LocationProvider.java +++ b/location/java/android/location/provider/LocationProvider.java @@ -26,6 +26,7 @@ import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.WorkSource; import android.util.Log; /** @@ -106,8 +107,8 @@ public abstract class LocationProvider { LocationProvider.this.onEnableLocationTracking(enable); } - public void setMinTime(long minTime) { - LocationProvider.this.onSetMinTime(minTime); + public void setMinTime(long minTime, WorkSource ws) { + LocationProvider.this.onSetMinTime(minTime, ws); } public void updateNetworkState(int state, NetworkInfo info) { @@ -123,11 +124,11 @@ public abstract class LocationProvider { } public void addListener(int uid) { - LocationProvider.this.onAddListener(uid); + LocationProvider.this.onAddListener(uid, new WorkSource(uid)); } public void removeListener(int uid) { - LocationProvider.this.onRemoveListener(uid); + LocationProvider.this.onRemoveListener(uid, new WorkSource(uid)); } }; @@ -303,8 +304,9 @@ public abstract class LocationProvider { * the frequency of updates to match the requested frequency. * * @param minTime the smallest minTime value over all listeners for this provider. + * @param ws the source this work is coming from. */ - public abstract void onSetMinTime(long minTime); + public abstract void onSetMinTime(long minTime, WorkSource ws); /** * Updates the network state for the given provider. This function must @@ -340,14 +342,16 @@ public abstract class LocationProvider { * Notifies the location provider when a new client is listening for locations. * * @param uid user ID of the new client. + * @param ws a WorkSource representation of the client. */ - public abstract void onAddListener(int uid); + public abstract void onAddListener(int uid, WorkSource ws); /** * Notifies the location provider when a client is no longer listening for locations. * * @param uid user ID of the client no longer listening. + * @param ws a WorkSource representation of the client. */ - public abstract void onRemoveListener(int uid); + public abstract void onRemoveListener(int uid, WorkSource ws); } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index e454c08..aa87f29 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -54,6 +54,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; +import android.os.WorkSource; import android.provider.Settings; import android.util.EventLog; import android.util.Slog; @@ -504,7 +505,7 @@ class BackupManagerService extends IBackupManager.Stub { parseLeftoverJournals(); // Power management - mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup"); + mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"); // Start the backup passes going setBackupEnabled(areEnabled); @@ -1363,6 +1364,7 @@ class BackupManagerService extends IBackupManager.Stub { ? IApplicationThread.BACKUP_MODE_FULL : IApplicationThread.BACKUP_MODE_INCREMENTAL; try { + mWakelock.setWorkSource(new WorkSource(request.appInfo.uid)); agent = bindToAgentSynchronous(request.appInfo, mode); if (agent != null) { int result = processOneBackup(request, agent, transport); @@ -1378,6 +1380,8 @@ class BackupManagerService extends IBackupManager.Stub { } } + mWakelock.setWorkSource(null); + return BackupConstants.TRANSPORT_OK; } diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index a38970f..f3ce8ba 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -52,6 +52,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; +import android.os.WorkSource; import android.provider.Settings; import android.util.Log; import android.util.Slog; @@ -157,6 +158,12 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider = new HashMap<String,ArrayList<UpdateRecord>>(); + /** + * Temporary filled in when computing min time for a provider. Access is + * protected by global lock mLock. + */ + private final WorkSource mTmpWorkSource = new WorkSource(); + // Proximity listeners private Receiver mProximityReceiver = null; private ILocationListener mProximityListener = null; @@ -912,7 +919,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (enabled) { p.enable(); if (listeners > 0) { - p.setMinTime(getMinTimeLocked(provider)); + p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource); p.enableLocationTracking(true); } } else { @@ -924,9 +931,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run private long getMinTimeLocked(String provider) { long minTime = Long.MAX_VALUE; ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider); + mTmpWorkSource.clear(); if (records != null) { for (int i=records.size()-1; i>=0; i--) { - minTime = Math.min(minTime, records.get(i).mMinTime); + UpdateRecord ur = records.get(i); + long curTime = ur.mMinTime; + if (curTime < minTime) { + minTime = curTime; + } + } + long inclTime = (minTime*3)/2; + for (int i=records.size()-1; i>=0; i--) { + UpdateRecord ur = records.get(i); + if (ur.mMinTime <= inclTime) { + mTmpWorkSource.add(ur.mUid); + } } } return minTime; @@ -1124,7 +1143,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run boolean isProviderEnabled = isAllowedBySettingsLocked(provider); if (isProviderEnabled) { long minTimeForProvider = getMinTimeLocked(provider); - p.setMinTime(minTimeForProvider); + p.setMinTime(minTimeForProvider, mTmpWorkSource); // try requesting single shot if singleShot is true, and fall back to // regular location tracking if requestSingleShotFix() is not supported if (!singleShot || !p.requestSingleShotFix()) { @@ -1222,7 +1241,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run LocationProviderInterface p = mProvidersByName.get(provider); if (p != null) { if (hasOtherListener) { - p.setMinTime(getMinTimeLocked(provider)); + p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource); } else { p.enableLocationTracking(false); } diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 16f3f10..af8d7d4 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -50,6 +50,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.WorkSource; import android.provider.Settings.SettingNotFoundException; import android.provider.Settings; import android.util.EventLog; @@ -310,7 +311,7 @@ class PowerManagerService extends IPowerManager.Stub long ident = Binder.clearCallingIdentity(); try { PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken, - MY_UID, MY_PID, mTag); + MY_UID, MY_PID, mTag, null); mHeld = true; } finally { Binder.restoreCallingIdentity(ident); @@ -607,6 +608,7 @@ class PowerManagerService extends IPowerManager.Stub final int uid; final int pid; final int monitorType; + WorkSource ws; boolean activated = true; int minState; } @@ -630,35 +632,74 @@ class PowerManagerService extends IPowerManager.Stub || n == PowerManager.SCREEN_DIM_WAKE_LOCK; } - public void acquireWakeLock(int flags, IBinder lock, String tag) { + void enforceWakeSourcePermission(int uid, int pid) { + if (uid == Process.myUid()) { + return; + } + mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, + pid, uid, null); + } + + public void acquireWakeLock(int flags, IBinder lock, String tag, WorkSource ws) { int uid = Binder.getCallingUid(); int pid = Binder.getCallingPid(); if (uid != Process.myUid()) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); } + if (ws != null) { + enforceWakeSourcePermission(uid, pid); + } long ident = Binder.clearCallingIdentity(); try { synchronized (mLocks) { - acquireWakeLockLocked(flags, lock, uid, pid, tag); + acquireWakeLockLocked(flags, lock, uid, pid, tag, ws); } } finally { Binder.restoreCallingIdentity(ident); } } - public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag) { - int acquireUid = -1; - int acquirePid = -1; - String acquireName = null; - int acquireType = -1; + void noteStartWakeLocked(WakeLock wl, WorkSource ws) { + try { + if (ws != null) { + mBatteryStats.noteStartWakelockFromSource(ws, wl.pid, wl.tag, + wl.monitorType); + } else { + mBatteryStats.noteStartWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType); + } + } catch (RemoteException e) { + // Ignore + } + } + void noteStopWakeLocked(WakeLock wl, WorkSource ws) { + try { + if (ws != null) { + mBatteryStats.noteStopWakelockFromSource(ws, wl.pid, wl.tag, + wl.monitorType); + } else { + mBatteryStats.noteStopWakelock(wl.uid, wl.pid, wl.tag, wl.monitorType); + } + } catch (RemoteException e) { + // Ignore + } + } + + public void acquireWakeLockLocked(int flags, IBinder lock, int uid, int pid, String tag, + WorkSource ws) { if (mSpew) { Slog.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag); } + if (ws != null && ws.size() == 0) { + ws = null; + } + int index = mLocks.getIndex(lock); WakeLock wl; boolean newlock; + boolean diffsource; + WorkSource oldsource; if (index < 0) { wl = new WakeLock(flags, lock, tag, uid, pid); switch (wl.flags & LOCK_MASK) @@ -687,10 +728,31 @@ class PowerManagerService extends IPowerManager.Stub return; } mLocks.addLock(wl); + if (ws != null) { + wl.ws = new WorkSource(ws); + } newlock = true; + diffsource = false; + oldsource = null; } else { wl = mLocks.get(index); newlock = false; + oldsource = wl.ws; + if (oldsource != null) { + if (ws == null) { + wl.ws = null; + diffsource = true; + } else { + diffsource = oldsource.diff(ws); + } + } else if (ws != null) { + diffsource = true; + } else { + diffsource = false; + } + if (diffsource) { + wl.ws = new WorkSource(ws); + } } if (isScreenLock(flags)) { // if this causes a wakeup, we reactivate all of the locks and @@ -731,19 +793,41 @@ class PowerManagerService extends IPowerManager.Stub enableProximityLockLocked(); } } - if (newlock) { - acquireUid = wl.uid; - acquirePid = wl.pid; - acquireName = wl.tag; - acquireType = wl.monitorType; + + if (diffsource) { + // If the lock sources have changed, need to first release the + // old ones. + noteStopWakeLocked(wl, oldsource); + } + if (newlock || diffsource) { + noteStartWakeLocked(wl, ws); } + } - if (acquireType >= 0) { - try { - mBatteryStats.noteStartWakelock(acquireUid, acquirePid, acquireName, acquireType); - } catch (RemoteException e) { - // Ignore + public void updateWakeLockWorkSource(IBinder lock, WorkSource ws) { + int uid = Binder.getCallingUid(); + int pid = Binder.getCallingPid(); + if (ws != null && ws.size() == 0) { + ws = null; + } + if (ws != null) { + enforceWakeSourcePermission(uid, pid); + } + long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLocks) { + int index = mLocks.getIndex(lock); + if (index < 0) { + throw new IllegalArgumentException("Wake lock not active"); + } + WakeLock wl = mLocks.get(index); + WorkSource oldsource = wl.ws; + wl.ws = ws != null ? new WorkSource(ws) : null; + noteStopWakeLocked(wl, oldsource); + noteStartWakeLocked(wl, ws); } + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -759,11 +843,6 @@ class PowerManagerService extends IPowerManager.Stub } private void releaseWakeLockLocked(IBinder lock, int flags, boolean death) { - int releaseUid; - int releasePid; - String releaseName; - int releaseType; - WakeLock wl = mLocks.removeLock(lock); if (wl == null) { return; @@ -804,17 +883,11 @@ class PowerManagerService extends IPowerManager.Stub } // Unlink the lock from the binder. wl.binder.unlinkToDeath(wl, 0); - releaseUid = wl.uid; - releasePid = wl.pid; - releaseName = wl.tag; - releaseType = wl.monitorType; - if (releaseType >= 0) { + if (wl.monitorType >= 0) { long origId = Binder.clearCallingIdentity(); try { - mBatteryStats.noteStopWakelock(releaseUid, releasePid, releaseName, releaseType); - } catch (RemoteException e) { - // Ignore + noteStopWakeLocked(wl, wl.ws); } finally { Binder.restoreCallingIdentity(origId); } diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java index 2e7e3e1..f0b5955 100755 --- a/services/java/com/android/server/VibratorService.java +++ b/services/java/com/android/server/VibratorService.java @@ -29,6 +29,7 @@ import android.os.RemoteException; import android.os.IBinder; import android.os.Binder; import android.os.SystemClock; +import android.os.WorkSource; import android.util.Slog; import java.util.LinkedList; @@ -39,6 +40,7 @@ public class VibratorService extends IVibratorService.Stub { private final LinkedList<Vibration> mVibrations; private Vibration mCurrentVibration; + private final WorkSource mTmpWorkSource = new WorkSource(); private class Vibration implements IBinder.DeathRecipient { private final IBinder mToken; @@ -46,22 +48,24 @@ public class VibratorService extends IVibratorService.Stub { private final long mStartTime; private final long[] mPattern; private final int mRepeat; + private final int mUid; - Vibration(IBinder token, long millis) { - this(token, millis, null, 0); + Vibration(IBinder token, long millis, int uid) { + this(token, millis, null, 0, uid); } - Vibration(IBinder token, long[] pattern, int repeat) { - this(token, 0, pattern, repeat); + Vibration(IBinder token, long[] pattern, int repeat, int uid) { + this(token, 0, pattern, repeat, uid); } private Vibration(IBinder token, long millis, long[] pattern, - int repeat) { + int repeat, int uid) { mToken = token; mTimeout = millis; mStartTime = SystemClock.uptimeMillis(); mPattern = pattern; mRepeat = repeat; + mUid = uid; } public void binderDied() { @@ -98,7 +102,7 @@ public class VibratorService extends IVibratorService.Stub { mContext = context; PowerManager pm = (PowerManager)context.getSystemService( Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*"); mWakeLock.setReferenceCounted(true); mVibrations = new LinkedList<Vibration>(); @@ -113,6 +117,7 @@ public class VibratorService extends IVibratorService.Stub { != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires VIBRATE permission"); } + int uid = Binder.getCallingUid(); // We're running in the system server so we cannot crash. Check for a // timeout of 0 or negative. This will ensure that a vibration has // either a timeout of > 0 or a non-null pattern. @@ -122,7 +127,7 @@ public class VibratorService extends IVibratorService.Stub { // longer than milliseconds. return; } - Vibration vib = new Vibration(token, milliseconds); + Vibration vib = new Vibration(token, milliseconds, uid); synchronized (mVibrations) { removeVibrationLocked(token); doCancelVibrateLocked(); @@ -146,6 +151,7 @@ public class VibratorService extends IVibratorService.Stub { != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires VIBRATE permission"); } + int uid = Binder.getCallingUid(); // so wakelock calls will succeed long identity = Binder.clearCallingIdentity(); try { @@ -165,7 +171,7 @@ public class VibratorService extends IVibratorService.Stub { return; } - Vibration vib = new Vibration(token, pattern, repeat); + Vibration vib = new Vibration(token, pattern, repeat, uid); try { token.linkToDeath(vib, 0); } catch (RemoteException e) { @@ -280,6 +286,8 @@ public class VibratorService extends IVibratorService.Stub { VibrateThread(Vibration vib) { mVibration = vib; + mTmpWorkSource.set(vib.mUid); + mWakeLock.setWorkSource(mTmpWorkSource); mWakeLock.acquire(); } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index 0eca082..f11c0f7 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -63,6 +63,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.WorkSource; import android.provider.Settings; import android.util.Slog; import android.text.TextUtils; @@ -2036,8 +2037,8 @@ public class WifiService extends IWifiManager.Stub { } private class WifiLock extends DeathRecipient { - WifiLock(int lockMode, String tag, IBinder binder) { - super(lockMode, tag, binder); + WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) { + super(lockMode, tag, binder, ws); } public void binderDied() { @@ -2111,7 +2112,15 @@ public class WifiService extends IWifiManager.Stub { } } - public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) { + void enforceWakeSourcePermission(int uid, int pid) { + if (uid == Process.myUid()) { + return; + } + mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS, + pid, uid, null); + } + + public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY && @@ -2120,34 +2129,68 @@ public class WifiService extends IWifiManager.Stub { if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode); return false; } - WifiLock wifiLock = new WifiLock(lockMode, tag, binder); + if (ws != null) { + enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid()); + } + if (ws != null && ws.size() == 0) { + ws = null; + } + if (ws == null) { + ws = new WorkSource(Binder.getCallingUid()); + } + WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws); synchronized (mLocks) { return acquireWifiLockLocked(wifiLock); } } + private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException { + switch(wifiLock.mMode) { + case WifiManager.WIFI_MODE_FULL: + mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource); + break; + case WifiManager.WIFI_MODE_FULL_HIGH_PERF: + /* Treat high power as a full lock for battery stats */ + mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource); + break; + case WifiManager.WIFI_MODE_SCAN_ONLY: + mBatteryStats.noteScanWifiLockAcquiredFromSource(wifiLock.mWorkSource); + break; + } + } + + private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException { + switch(wifiLock.mMode) { + case WifiManager.WIFI_MODE_FULL: + mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource); + break; + case WifiManager.WIFI_MODE_FULL_HIGH_PERF: + /* Treat high power as a full lock for battery stats */ + mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource); + break; + case WifiManager.WIFI_MODE_SCAN_ONLY: + mBatteryStats.noteScanWifiLockReleasedFromSource(wifiLock.mWorkSource); + break; + } + } + private boolean acquireWifiLockLocked(WifiLock wifiLock) { Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock); mLocks.addLock(wifiLock); - int uid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); try { + noteAcquireWifiLock(wifiLock); switch(wifiLock.mMode) { case WifiManager.WIFI_MODE_FULL: ++mFullLocksAcquired; - mBatteryStats.noteFullWifiLockAcquired(uid); break; case WifiManager.WIFI_MODE_FULL_HIGH_PERF: ++mFullHighPerfLocksAcquired; - /* Treat high power as a full lock for battery stats */ - mBatteryStats.noteFullWifiLockAcquired(uid); break; - case WifiManager.WIFI_MODE_SCAN_ONLY: ++mScanLocksAcquired; - mBatteryStats.noteScanWifiLockAcquired(uid); break; } } catch (RemoteException e) { @@ -2159,6 +2202,33 @@ public class WifiService extends IWifiManager.Stub { return true; } + public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) { + int uid = Binder.getCallingUid(); + int pid = Binder.getCallingPid(); + if (ws != null && ws.size() == 0) { + ws = null; + } + if (ws != null) { + enforceWakeSourcePermission(uid, pid); + } + long ident = Binder.clearCallingIdentity(); + try { + synchronized (mLocks) { + int index = mLocks.findLockByBinder(lock); + if (index < 0) { + throw new IllegalArgumentException("Wifi lock not active"); + } + WifiLock wl = mLocks.mList.get(index); + noteReleaseWifiLock(wl); + wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid); + noteAcquireWifiLock(wl); + } + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); + } + } + public boolean releaseWifiLock(IBinder lock) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null); synchronized (mLocks) { @@ -2176,21 +2246,18 @@ public class WifiService extends IWifiManager.Stub { hadLock = (wifiLock != null); if (hadLock) { - int uid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); try { + noteAcquireWifiLock(wifiLock); switch(wifiLock.mMode) { case WifiManager.WIFI_MODE_FULL: ++mFullLocksReleased; - mBatteryStats.noteFullWifiLockReleased(uid); break; case WifiManager.WIFI_MODE_FULL_HIGH_PERF: ++mFullHighPerfLocksReleased; - mBatteryStats.noteFullWifiLockReleased(uid); break; case WifiManager.WIFI_MODE_SCAN_ONLY: ++mScanLocksReleased; - mBatteryStats.noteScanWifiLockReleased(uid); break; } } catch (RemoteException e) { @@ -2208,12 +2275,14 @@ public class WifiService extends IWifiManager.Stub { String mTag; int mMode; IBinder mBinder; + WorkSource mWorkSource; - DeathRecipient(int mode, String tag, IBinder binder) { + DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) { super(); mTag = tag; mMode = mode; mBinder = binder; + mWorkSource = ws; try { mBinder.linkToDeath(this, 0); } catch (RemoteException e) { @@ -2228,7 +2297,7 @@ public class WifiService extends IWifiManager.Stub { private class Multicaster extends DeathRecipient { Multicaster(String tag, IBinder binder) { - super(Binder.getCallingUid(), tag, binder); + super(Binder.getCallingUid(), tag, binder, null); } public void binderDied() { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 3046464..cb4def5 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -5988,12 +5988,18 @@ public final class ActivityManagerService extends ActivityManagerNative finisher = new IIntentReceiver.Stub() { public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, - boolean sticky) - throws RemoteException { - synchronized (ActivityManagerService.this) { - mDidUpdate = true; - } - systemReady(goingCallback); + boolean sticky) { + // The raw IIntentReceiver interface is called + // with the AM lock held, so redispatch to + // execute our code without the lock. + mHandler.post(new Runnable() { + public void run() { + synchronized (ActivityManagerService.this) { + mDidUpdate = true; + } + systemReady(goingCallback); + } + }); } }; } diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java index 7314e04..bb40967 100644 --- a/services/java/com/android/server/am/BatteryStatsService.java +++ b/services/java/com/android/server/am/BatteryStatsService.java @@ -23,6 +23,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.Process; import android.os.ServiceManager; +import android.os.WorkSource; import android.telephony.SignalStrength; import android.util.Slog; @@ -107,6 +108,20 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } } + public void noteStartWakelockFromSource(WorkSource ws, int pid, String name, int type) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteStartWakeFromSourceLocked(ws, pid, name, type); + } + } + + public void noteStopWakelockFromSource(WorkSource ws, int pid, String name, int type) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteStopWakeFromSourceLocked(ws, pid, name, type); + } + } + public void noteStartSensor(int uid, int sensor) { enforceCallingPermission(); synchronized (mStats) { @@ -317,6 +332,48 @@ public final class BatteryStatsService extends IBatteryStats.Stub { } } + public void noteFullWifiLockAcquiredFromSource(WorkSource ws) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteFullWifiLockAcquiredFromSourceLocked(ws); + } + } + + public void noteFullWifiLockReleasedFromSource(WorkSource ws) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteFullWifiLockReleasedFromSourceLocked(ws); + } + } + + public void noteScanWifiLockAcquiredFromSource(WorkSource ws) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteScanWifiLockAcquiredFromSourceLocked(ws); + } + } + + public void noteScanWifiLockReleasedFromSource(WorkSource ws) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteScanWifiLockReleasedFromSourceLocked(ws); + } + } + + public void noteWifiMulticastEnabledFromSource(WorkSource ws) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteWifiMulticastEnabledFromSourceLocked(ws); + } + } + + public void noteWifiMulticastDisabledFromSource(WorkSource ws) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteWifiMulticastDisabledFromSourceLocked(ws); + } + } + public boolean isOnBattery() { return mStats.isOnBattery(); } diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index c1165c7..3bf6ee4 100755 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -44,6 +44,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.WorkSource; import android.provider.Settings; import android.util.Log; import android.util.SparseIntArray; @@ -736,7 +737,7 @@ public class GpsLocationProvider implements LocationProviderInterface { startNavigating(true); } - public void setMinTime(long minTime) { + public void setMinTime(long minTime, WorkSource ws) { if (DEBUG) Log.d(TAG, "setMinTime " + minTime); if (minTime >= 0) { @@ -779,7 +780,7 @@ public class GpsLocationProvider implements LocationProviderInterface { public void addListener(int uid) { synchronized (mWakeLock) { mPendingListenerMessages++; - mWakeLock.acquire(); + mWakeLock.acquire(); Message m = Message.obtain(mHandler, ADD_LISTENER); m.arg1 = uid; mHandler.sendMessage(m); diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java index 084ab81..858a582 100644 --- a/services/java/com/android/server/location/LocationProviderInterface.java +++ b/services/java/com/android/server/location/LocationProviderInterface.java @@ -20,6 +20,7 @@ import android.location.Criteria; import android.location.Location; import android.net.NetworkInfo; import android.os.Bundle; +import android.os.WorkSource; /** * Location Manager's interface for location providers. @@ -47,7 +48,7 @@ public interface LocationProviderInterface { /* returns false if single shot is not supported */ boolean requestSingleShotFix(); String getInternalState(); - void setMinTime(long minTime); + void setMinTime(long minTime, WorkSource ws); void updateNetworkState(int state, NetworkInfo info); void updateLocation(Location location); boolean sendExtraCommand(String command, Bundle extras); diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java index 24d7737..7dc9920 100644 --- a/services/java/com/android/server/location/LocationProviderProxy.java +++ b/services/java/com/android/server/location/LocationProviderProxy.java @@ -29,6 +29,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemClock; +import android.os.WorkSource; import android.util.Log; import com.android.internal.location.DummyLocationProvider; @@ -52,6 +53,7 @@ public class LocationProviderProxy implements LocationProviderInterface { private boolean mLocationTracking = false; private boolean mEnabled = false; private long mMinTime = -1; + private WorkSource mMinTimeSource = new WorkSource(); private int mNetworkState; private NetworkInfo mNetworkInfo; @@ -122,7 +124,7 @@ public class LocationProviderProxy implements LocationProviderInterface { provider.enableLocationTracking(true); } if (mMinTime >= 0) { - provider.setMinTime(mMinTime); + provider.setMinTime(mMinTime, mMinTimeSource); } if (mNetworkInfo != null) { provider.updateNetworkState(mNetworkState, mNetworkInfo); @@ -318,6 +320,7 @@ public class LocationProviderProxy implements LocationProviderInterface { mLocationTracking = enable; if (!enable) { mMinTime = -1; + mMinTimeSource.clear(); } ILocationProvider provider; synchronized (mServiceConnection) { @@ -339,15 +342,16 @@ public class LocationProviderProxy implements LocationProviderInterface { return mMinTime; } - public void setMinTime(long minTime) { - mMinTime = minTime; + public void setMinTime(long minTime, WorkSource ws) { + mMinTime = minTime; + mMinTimeSource.set(ws); ILocationProvider provider; synchronized (mServiceConnection) { provider = mProvider; } if (provider != null) { try { - provider.setMinTime(minTime); + provider.setMinTime(minTime, ws); } catch (RemoteException e) { } } diff --git a/services/java/com/android/server/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java index 01b34b7..09d799f 100644 --- a/services/java/com/android/server/location/MockProvider.java +++ b/services/java/com/android/server/location/MockProvider.java @@ -23,6 +23,7 @@ import android.location.LocationProvider; import android.net.NetworkInfo; import android.os.Bundle; import android.os.RemoteException; +import android.os.WorkSource; import android.util.Log; import android.util.PrintWriterPrinter; @@ -201,7 +202,7 @@ public class MockProvider implements LocationProviderInterface { return false; } - public void setMinTime(long minTime) { + public void setMinTime(long minTime, WorkSource ws) { } public void updateNetworkState(int state, NetworkInfo info) { diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java index 7fc93f8..ea0d1b0 100644 --- a/services/java/com/android/server/location/PassiveProvider.java +++ b/services/java/com/android/server/location/PassiveProvider.java @@ -24,6 +24,7 @@ import android.location.LocationProvider; import android.net.NetworkInfo; import android.os.Bundle; import android.os.RemoteException; +import android.os.WorkSource; import android.util.Log; /** @@ -123,7 +124,7 @@ public class PassiveProvider implements LocationProviderInterface { return false; } - public void setMinTime(long minTime) { + public void setMinTime(long minTime, WorkSource ws) { } public void updateNetworkState(int state, NetworkInfo info) { diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 6e0bc9d..0ee559e 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -21,6 +21,8 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.ScanResult; import android.net.DhcpInfo; +import android.os.WorkSource; + /** * Interface that allows controlling and querying Wi-Fi connectivity. * @@ -66,7 +68,9 @@ interface IWifiManager DhcpInfo getDhcpInfo(); - boolean acquireWifiLock(IBinder lock, int lockType, String tag); + boolean acquireWifiLock(IBinder lock, int lockType, String tag, in WorkSource ws); + + void updateWifiLockWorkSource(IBinder lock, in WorkSource ws); boolean releaseWifiLock(IBinder lock); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 9d21521..dd162f2 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -23,6 +23,7 @@ import android.os.Binder; import android.os.IBinder; import android.os.Handler; import android.os.RemoteException; +import android.os.WorkSource; import java.util.List; @@ -872,6 +873,7 @@ public class WifiManager { int mLockType; private boolean mRefCounted; private boolean mHeld; + private WorkSource mWorkSource; private WifiLock(int lockType, String tag) { mTag = tag; @@ -897,7 +899,7 @@ public class WifiManager { synchronized (mBinder) { if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) { try { - mService.acquireWifiLock(mBinder, mLockType, mTag); + mService.acquireWifiLock(mBinder, mLockType, mTag, mWorkSource); synchronized (WifiManager.this) { if (mActiveLockCount >= MAX_ACTIVE_LOCKS) { mService.releaseWifiLock(mBinder); @@ -969,6 +971,32 @@ public class WifiManager { } } + public void setWorkSource(WorkSource ws) { + synchronized (mBinder) { + if (ws != null && ws.size() == 0) { + ws = null; + } + boolean changed = true; + if (ws == null) { + mWorkSource = null; + } else if (mWorkSource == null) { + changed = mWorkSource != null; + mWorkSource = new WorkSource(ws); + } else { + changed = mWorkSource.diff(ws); + if (changed) { + mWorkSource.set(ws); + } + } + if (changed && mHeld) { + try { + mService.updateWifiLockWorkSource(mBinder, mWorkSource); + } catch (RemoteException e) { + } + } + } + } + public String toString() { String s1, s2, s3; synchronized (mBinder) { |