http://androidxref.com/8.0.0_r4
============================================================
/frameworks/base/core/java/android/provider/Settings.java
public static final String WIFI_SLEEP_POLICY = "wifi_sleep_policy";
public static final int WIFI_SLEEP_POLICY_DEFAULT = 0;
public static final int WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED = 1;
public static final int WIFI_SLEEP_POLICY_NEVER = 2;
============================================================
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiController.java
private int mSleepPolicy; // 當前休眠策略
private int mPluggedType; // 當前充電狀態 可選值如下
{
private static final int BATTERY_PLUGGED_NONE = 0; // 手機沒有充電
private static final int BATTERY_PLUGGED_AC = 1; // 註冊充電
private static final int BATTERY_PLUGGED_USB = 2; // 連接電腦USB充電
private static final int BATTERY_PLUGGED_WIRELESS= 4; // 無線充電
public static final int BATTERY_PLUGGED_ANY = 7;
}
/**
* Determines whether the Wi-Fi chipset should stay awake or be put to
* sleep. Looks at the setting for the sleep policy and the current
* conditions.
*
* @see #shouldDeviceStayAwake(int)
*/
private boolean shouldWifiStayAwake(int pluggedType) { //依據參數pluggedType和mSleepPolicy值 確定是否休眠
if (mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER) {
// Never sleep
return true;
} else if ((mSleepPolicy == Settings.Global.WIFI_SLEEP_POLICY_NEVER_WHILE_PLUGGED) && (pluggedType != 0)) {
// Never sleep while plugged, and we're plugged
return true;
} else {
// Default
return shouldDeviceStayAwake(pluggedType);
}
}
/**
* Observes changes to wifi sleep policy
*/
private void registerForWifiSleepPolicyChange(Handler handler) {
ContentObserver contentObserver = new ContentObserver(handler) {
@Override
public void onChange(boolean selfChange) {
readWifiSleepPolicy();
}
};
mFacade.registerContentObserver(mContext,Settings.Global.getUriFor(Settings.Global.WIFI_SLEEP_POLICY), false,
contentObserver);
}
private void readWifiSleepPolicy() {
mSleepPolicy = mFacade.getIntegerSetting(mContext,
Settings.Global.WIFI_SLEEP_POLICY,
Settings.Global.WIFI_SLEEP_POLICY_NEVER);
}
class DefaultState extends State {
@Override
public boolean processMessage(Message msg) {
switch (msg.what) {
case CMD_SCREEN_OFF: // 滅屏情況下
mScreenOff = true;
if (!shouldWifiStayAwake(mPluggedType)) {
//private static final long DEFAULT_IDLE_MS = 15 * 60 * 1000 // 15分鐘
// private static final String ACTION_DEVICE_IDLE ="com.android.server.WifiManager.action.DEVICE_IDLE";
//public static final String WIFI_IDLE_MS = "wifi_idle_ms";
// mIdleMillis = mFacade.getLongSetting(mContext,Settings.Global.WIFI_IDLE_MS, DEFAULT_IDLE_MS);
// Intent idleIntent = new Intent(ACTION_DEVICE_IDLE, null); private static final int IDLE_REQUEST = 0;
// private PendingIntentmIdleIntent = mFacade.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
// 【如果不保持連接,那麼設置mIdleMillis 15分鐘之後發送 ACTION_DEVICE_IDLE的廣播】
if (mNetworkInfo.getDetailedState() ==NetworkInfo.DetailedState.CONNECTED) {
if (DBG) Slog.d(TAG, "set idle timer: " + mIdleMillis + " ms");
mAlarmManager.set(AlarmManager.RTC_WAKEUP,System.currentTimeMillis() + mIdleMillis, mIdleIntent);
} else {
//需要使機器不保持連接 當前連接狀態不爲連接那麼就 直接使發送CMD_DEVICE_IDLE消息
sendMessage(CMD_DEVICE_IDLE);
}
}
break;
case CMD_BATTERY_CHANGED:
int pluggedType = msg.arg1;
// 如果當前滅屏
if (mScreenOff && shouldWifiStayAwake(mPluggedType)【CMD_BATTERY_CHANGED消息前記錄的PluggedType】
&&!shouldWifiStayAwake(pluggedType) 【CMD_BATTERY_CHANGED攜帶的PluggedType】 ) {
// 以上條件滿足 那麼就發送 mIdleIntent 廣播
long triggerTime = System.currentTimeMillis() + mIdleMillis;
if (DBG) Slog.d(TAG, "set idle timer for " + mIdleMillis + "ms");
mAlarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, mIdleIntent);
}
mPluggedType = pluggedType;
break;
case CMD_DEVICE_IDLE:
mDeviceIdle = true;
updateBatteryWorkSource();
break;
}
}
private final WorkSource mTmpWorkSource = new WorkSource();
private final WifiLockManager mWifiLockManager;
private void updateBatteryWorkSource() {
mTmpWorkSource.clear();
if (mDeviceIdle) {
mTmpWorkSource.add(mWifiLockManager.createMergedWorkSource());
}
mWifiStateMachine.updateBatteryWorkSource(mTmpWorkSource);
}
// 處理 ACTION_DEVICE_IDLE"com.android.server.WifiManager.action.DEVICE_IDLE"廣播的處理器
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_DEVICE_IDLE);
mContext.registerReceiver(
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_DEVICE_IDLE)) {
sendMessage(CMD_DEVICE_IDLE); // 發送消息 CMD_DEVICE_IDLE
}
...
}
}
============================================================
/frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiStateMachine.java
// Wakelock held during wifi start/stop and driver load/unload
private PowerManager.WakeLock mWakeLock; // 保持wifi連接的鎖Lock
public void updateBatteryWorkSource(WorkSource newSource) {
synchronized (mRunningWifiUids) {
try {
if (newSource != null) {
mRunningWifiUids.set(newSource);
}
if (mIsRunning) {
if (mReportedRunning) {
// If the work source has changed since last time, need
// to remove old work from battery stats.
if (mLastRunningWifiUids.diff(mRunningWifiUids)) {
mBatteryStats.noteWifiRunningChanged(mLastRunningWifiUids,mRunningWifiUids);
mLastRunningWifiUids.set(mRunningWifiUids);
}
} else {
// Now being started, report it.
mBatteryStats.noteWifiRunning(mRunningWifiUids);
mLastRunningWifiUids.set(mRunningWifiUids);
mReportedRunning = true;
}
} else {
if (mReportedRunning) {
// Last reported we were running, time to stop.
mBatteryStats.noteWifiStopped(mLastRunningWifiUids);
mLastRunningWifiUids.clear();
mReportedRunning = false;
}
}
mWakeLock.setWorkSource(newSource);
} catch (RemoteException ignore) {
}
}
}
================================================================
/frameworks/base/core/java/android/os/PowerManager.java
final IPowerManager mService;
public final class WakeLock {
private WorkSource mWorkSource;
public void setWorkSource(WorkSource ws) {
synchronized (mToken) {
if (ws != null && ws.size() == 0) {
ws = null;
}
final boolean changed;
if (ws == null) {
changed = mWorkSource != null;
mWorkSource = null;
} else if (mWorkSource == null) {
changed = true;
mWorkSource = new WorkSource(ws);
} else {
changed = mWorkSource.diff(ws);
if (changed) {
mWorkSource.set(ws);
}
}
if (changed && mHeld) {
try {
mService.updateWakeLockWorkSource(mToken, mWorkSource, mHistoryTag);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
}
================================================================
/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
@Override // Binder call
public void updateWakeLockWorkSource(IBinder lock, WorkSource ws, String historyTag) {
if (lock == null) {
throw new IllegalArgumentException("lock must not be null");
}
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
if (ws != null && ws.size() != 0) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.UPDATE_DEVICE_STATS, null);
} else {
ws = null;
}
final int callingUid = Binder.getCallingUid();
final long ident = Binder.clearCallingIdentity();
try {
updateWakeLockWorkSourceInternal(lock, ws, historyTag, callingUid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void updateWakeLockWorkSourceInternal(IBinder lock, WorkSource ws, String historyTag,int callingUid) {
synchronized (mLock) {
int index = findWakeLockIndexLocked(lock);
if (index < 0) {
throw new IllegalArgumentException("Wake lock not active: " + lock+ " from uid " + callingUid);
}
WakeLock wakeLock = mWakeLocks.get(index); // 獲得對應的鎖
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockWorkSourceInternal: lock=" + Objects.hashCode(lock)+ " [" + wakeLock.mTag + "], ws=" + ws);
}
if (!wakeLock.hasSameWorkSource(ws)) {
notifyWakeLockChangingLocked(wakeLock, wakeLock.mFlags, wakeLock.mTag,
wakeLock.mPackageName, wakeLock.mOwnerUid, wakeLock.mOwnerPid,ws, historyTag);
wakeLock.mHistoryTag = historyTag;
wakeLock.updateWorkSource(ws);
}
}
}
private void notifyWakeLockChangingLocked(WakeLock wakeLock, int flags, String tag,
String packageName, int uid, int pid, WorkSource ws, String historyTag) {
if (mSystemReady && wakeLock.mNotifiedAcquired) {
mNotifier.onWakeLockChanging(wakeLock.mFlags, wakeLock.mTag, wakeLock.mPackageName,
wakeLock.mOwnerUid, wakeLock.mOwnerPid, wakeLock.mWorkSource,
wakeLock.mHistoryTag, flags, tag, packageName, uid, pid, ws, historyTag);
notifyWakeLockLongFinishedLocked(wakeLock);
restartNofifyLongTimerLocked(wakeLock);
}
}
private void notifyWakeLockLongFinishedLocked(WakeLock wakeLock) { // 當前鎖完成使命
if (wakeLock.mNotifiedLong) {
wakeLock.mNotifiedLong = false;
mNotifier.onLongPartialWakeLockFinish(wakeLock.mTag, wakeLock.mOwnerUid,
wakeLock.mWorkSource, wakeLock.mHistoryTag);
}
}
================================================================
/frameworks/base/services/core/java/com/android/server/power/Notifier.java
public void onLongPartialWakeLockFinish(String tag, int ownerUid, WorkSource workSource,String historyTag) {
try {
if (workSource != null) {
final int N = workSource.size();
for (int i=0; i<N; i++) { // 通知一個Wakelock完成了使命
mBatteryStats.noteLongPartialWakelockFinish(tag, historyTag, workSource.get(i));
}
} else {
mBatteryStats.noteLongPartialWakelockFinish(tag, historyTag, ownerUid);
}
} catch (RemoteException ex) {
// Ignore
}
}
================================================================
/frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
final BatteryStatsImpl mStats;
public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
enforceCallingPermission();
synchronized (mStats) {
mStats.noteLongPartialWakelockFinish(name, historyName, uid);
}
}
================================================================
/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
// Event for reporting that a specific partial wake lock has been held for a long duration.
public static final int EVENT_LONG_WAKE_LOCK = 0x0014;
public static final int EVENT_FLAG_FINISH = 0x4000;
public static final int EVENT_LONG_WAKE_LOCK_FINISH =EVENT_LONG_WAKE_LOCK | EVENT_FLAG_FINISH;
final HistoryEventTracker mActiveEvents = new HistoryEventTracker();
public void noteLongPartialWakelockFinish(String name, String historyName, int uid) {
uid = mapUid(uid);
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
if (historyName == null) {
historyName = name;
}
if (!mActiveEvents.updateState(HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH, historyName, uid,0)) {
return;
}
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH,historyName, uid);
}
public final static class HistoryEventTracker {
// 用於保存需要鎖的那些線程id ,不需要鎖了 就從map中刪除
private final HashMap<String, SparseIntArray>[] mActiveEvents = (HashMap<String, SparseIntArray>[]) new HashMap[HistoryItem.EVENT_COUNT];
public boolean updateState(int code, String name, int uid, int poolIdx) {
if ((code&HistoryItem.EVENT_FLAG_START) != 0) { //起始標識符
int idx = code&HistoryItem.EVENT_TYPE_MASK;
HashMap<String, SparseIntArray> active = mActiveEvents[idx];
if (active == null) {
active = new HashMap<>();
mActiveEvents[idx] = active;
}
SparseIntArray uids = active.get(name);
if (uids == null) {
uids = new SparseIntArray();
active.put(name, uids);
}
if (uids.indexOfKey(uid) >= 0) {
// Already set, nothing to do!
return false;
}
uids.put(uid, poolIdx);
} else if ((code&HistoryItem.EVENT_FLAG_FINISH) != 0) { //關閉標識符
int idx = code&HistoryItem.EVENT_TYPE_MASK;
HashMap<String, SparseIntArray> active = mActiveEvents[idx];
if (active == null) {
// not currently active, nothing to do.
return false;
}
SparseIntArray uids = active.get(name);
if (uids == null) {
// not currently active, nothing to do.
return false;
}
idx = uids.indexOfKey(uid);
if (idx < 0) {
// not currently active, nothing to do.
return false;
}
uids.removeAt(idx); // 從Map中移除對應的進程線程id
if (uids.size() <= 0) {
active.remove(name);
}
}
return true;
}
final HistoryItem mHistoryCur = new HistoryItem();
public void addHistoryEventLocked(long elapsedRealtimeMs, long uptimeMs, int code,String name, int uid) {
mHistoryCur.eventCode = code;//【 HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH 】
mHistoryCur.eventTag = mHistoryCur.localEventTag;
mHistoryCur.eventTag.string = name;
mHistoryCur.eventTag.uid = uid;
addHistoryRecordLocked(elapsedRealtimeMs, uptimeMs);
}
void addHistoryRecordLocked(long elapsedRealtimeMs, long uptimeMs) {
if (mTrackRunningHistoryElapsedRealtime != 0) {
final long diffElapsed = elapsedRealtimeMs - mTrackRunningHistoryElapsedRealtime;
final long diffUptime = uptimeMs - mTrackRunningHistoryUptime;
if (diffUptime < (diffElapsed-20)) {
final long wakeElapsedTime = elapsedRealtimeMs - (diffElapsed - diffUptime);
mHistoryAddTmp.setTo(mHistoryLastWritten);
mHistoryAddTmp.wakelockTag = null;
mHistoryAddTmp.wakeReasonTag = null;
mHistoryAddTmp.eventCode = HistoryItem.EVENT_NONE;
mHistoryAddTmp.states &= ~HistoryItem.STATE_CPU_RUNNING_FLAG;
addHistoryRecordInnerLocked(wakeElapsedTime, uptimeMs, mHistoryAddTmp);
}
}
mHistoryCur.states |= HistoryItem.STATE_CPU_RUNNING_FLAG;
mTrackRunningHistoryElapsedRealtime = elapsedRealtimeMs;
mTrackRunningHistoryUptime = uptimeMs;
addHistoryRecordInnerLocked(elapsedRealtimeMs, uptimeMs, mHistoryCur);
}
//【 HistoryItem.EVENT_LONG_WAKE_LOCK_FINISH 】
void addHistoryRecordInnerLocked(long elapsedRealtimeMs, long uptimeMs, HistoryItem cur) {
private void addHistoryBufferLocked(long elapsedRealtimeMs, long uptimeMs, byte cmd,
HistoryItem cur) {
if (mIteratingHistory) {
throw new IllegalStateException("Can't do this while iterating history!");
}
mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
mHistoryLastLastWritten.setTo(mHistoryLastWritten);
mHistoryLastWritten.setTo(mHistoryBaseTime + elapsedRealtimeMs, cmd, cur);
mHistoryLastWritten.states &= mActiveHistoryStates;
mHistoryLastWritten.states2 &= mActiveHistoryStates2;
writeHistoryDelta(mHistoryBuffer, mHistoryLastWritten, mHistoryLastLastWritten);//【填充Parcel數據】
mLastHistoryElapsedRealtime = elapsedRealtimeMs;
cur.wakelockTag = null;
cur.wakeReasonTag = null;
cur.eventCode = HistoryItem.EVENT_NONE;
cur.eventTag = null;
if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
+ " now " + mHistoryBuffer.dataPosition()
+ " size is now " + mHistoryBuffer.dataSize());
}
}
public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
if (cur.wakelockTag != null || cur.wakeReasonTag != null) {
int wakeLockIndex;
int wakeReasonIndex;
if (cur.wakelockTag != null) {
wakeLockIndex = writeHistoryTag(cur.wakelockTag);
//DELTA: wakelock 刪除wakelock
if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakelockTag=#" + cur.wakelockTag.poolIdx + " " + cur.wakelockTag.uid + ":" + cur.wakelockTag.string);
} else {
wakeLockIndex = 0xffff;
}
if (cur.wakeReasonTag != null) {
wakeReasonIndex = writeHistoryTag(cur.wakeReasonTag);
if (DEBUG) Slog.i(TAG, "WRITE DELTA: wakeReasonTag=#" + cur.wakeReasonTag.poolIdx
+ " " + cur.wakeReasonTag.uid + ":" + cur.wakeReasonTag.string);
} else {
wakeReasonIndex = 0xffff;
}
dest.writeInt((wakeReasonIndex<<16) | wakeLockIndex); // 把要刪除鎖的索引寫到Parcel中
}
}
public final static class HistoryTag { // 每一個鎖 都有一個 HistoryTag
public String string;
public int uid;
public int poolIdx;
public void setTo(HistoryTag o) {
string = o.string;
uid = o.uid;
poolIdx = o.poolIdx;
}
public void setTo(String _string, int _uid) {
string = _string;
uid = _uid;
poolIdx = -1;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(string);
dest.writeInt(uid);
}
}
/frameworks/base/core/java/android/os/Environment.java
private static final File DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, "/data");
public static File getDataDirectory() {
return DIR_ANDROID_DATA;
}
/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system"); 【/data/system/ 】
systemDir.mkdirs();
mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
/frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
BatteryStatsService(File systemDir 【/data/system/ 】, Handler handler)
final BatteryStatsImpl mStats = new BatteryStatsImpl(systemDir, handler, mHandler, this);
/frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
// 感覺像把 HistoryEventTracker 裏面的 HashMap<String, SparseIntArray>[] mActiveEvents 對應的線程uid 進行鎖定
private final JournaledFile mFile; 【/data/system/batterystats.bin 】
mFile = new JournaledFile(new File(systemDir 【/data/system/ 】, "batterystats.bin"), new File(systemDir, "batterystats.bin.tmp"));
void writeLocked(boolean sync) { // 寫鎖?
if (mFile == null) {
Slog.w("BatteryStats", "writeLocked: no file associated with this instance");
return;
}
if (mShuttingDown) {
return;
}
Parcel out = Parcel.obtain();
writeSummaryToParcel(out, true);
mLastWriteTime = mClocks.elapsedRealtime();
if (mPendingWrite != null) {
mPendingWrite.recycle();
}
mPendingWrite = out;
if (sync) {
commitPendingDataToDisk(); // 寫數據到disk?
} else {
BackgroundThread.getHandler().post(new Runnable() {
@Override public void run() {
commitPendingDataToDisk();
}
});
}
}
public void commitPendingDataToDisk() {
final Parcel next;
synchronized (this) {
next = mPendingWrite;
mPendingWrite = null;
if (next == null) {
return;
}
}
mWriteLock.lock();
try { // 往一個文件中寫parcel? mFile = 【/data/system/batterystats.bin 】
FileOutputStream stream = new FileOutputStream(mFile.chooseForWrite());
stream.write(next【 Parcel 】.marshall());
stream.flush();
FileUtils.sync(stream);
stream.close();
mFile.commit();
} catch (IOException e) {
Slog.w("BatteryStats", "Error writing battery statistics", e);
mFile.rollback();
} finally {
next.recycle();
mWriteLock.unlock();
}
}
總結: 難道是把每一個設備鎖都封裝成一個Parcel,這些Parcel以一定方式寫入/data/system/batterystats.bin文件中
就能使得設備不進入完全休眠狀態,當要把鎖刪除也同樣把/data/system/batterystats.bin中對應的Parcel 刪除,已達到
釋放鎖的目的? No understand !!