blob: 3fa2087f91bf651c53a7d59f60b0f421dbe742c9 [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
19import com.android.internal.app.IBatteryStats;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080020import com.android.server.am.BatteryStatsService;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070021
22import android.app.ActivityManagerNative;
23import android.app.IActivityManager;
24import android.content.BroadcastReceiver;
25import android.content.ContentQueryMap;
26import android.content.ContentResolver;
27import android.content.Context;
28import android.content.Intent;
29import android.content.IntentFilter;
30import android.content.pm.PackageManager;
31import android.database.Cursor;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080032import android.os.BatteryStats;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070033import android.os.Binder;
34import android.os.Handler;
35import android.os.HandlerThread;
36import android.os.IBinder;
37import android.os.IPowerManager;
38import android.os.LocalPowerManager;
39import android.os.Power;
40import android.os.PowerManager;
41import android.os.Process;
42import android.os.RemoteException;
43import android.os.SystemClock;
44import android.provider.Settings.SettingNotFoundException;
45import android.provider.Settings;
46import android.util.EventLog;
47import android.util.Log;
48import android.view.WindowManagerPolicy;
49import static android.provider.Settings.System.DIM_SCREEN;
50import static android.provider.Settings.System.SCREEN_BRIGHTNESS;
51import static android.provider.Settings.System.SCREEN_OFF_TIMEOUT;
52import static android.provider.Settings.System.STAY_ON_WHILE_PLUGGED_IN;
53
54import java.io.FileDescriptor;
55import java.io.PrintWriter;
56import java.util.ArrayList;
57import java.util.HashMap;
58import java.util.Observable;
59import java.util.Observer;
60
61class PowerManagerService extends IPowerManager.Stub implements LocalPowerManager, Watchdog.Monitor {
62
63 private static final String TAG = "PowerManagerService";
64 static final String PARTIAL_NAME = "PowerManagerService";
65
66 private static final boolean LOG_PARTIAL_WL = false;
67
68 // Indicates whether touch-down cycles should be logged as part of the
69 // LOG_POWER_SCREEN_STATE log events
70 private static final boolean LOG_TOUCH_DOWNS = true;
71
72 private static final int LOCK_MASK = PowerManager.PARTIAL_WAKE_LOCK
73 | PowerManager.SCREEN_DIM_WAKE_LOCK
74 | PowerManager.SCREEN_BRIGHT_WAKE_LOCK
75 | PowerManager.FULL_WAKE_LOCK;
76
77 // time since last state: time since last event:
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080078 // The short keylight delay comes from Gservices; this is the default.
79 private static final int SHORT_KEYLIGHT_DELAY_DEFAULT = 6000; // t+6 sec
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070080 private static final int MEDIUM_KEYLIGHT_DELAY = 15000; // t+15 sec
81 private static final int LONG_KEYLIGHT_DELAY = 6000; // t+6 sec
82 private static final int LONG_DIM_TIME = 7000; // t+N-5 sec
83
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -080084 // Cached Gservices settings; see updateGservicesValues()
85 private int mShortKeylightDelay = SHORT_KEYLIGHT_DELAY_DEFAULT;
86
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070087 // flags for setPowerState
88 private static final int SCREEN_ON_BIT = 0x00000001;
89 private static final int SCREEN_BRIGHT_BIT = 0x00000002;
90 private static final int BUTTON_BRIGHT_BIT = 0x00000004;
91 private static final int KEYBOARD_BRIGHT_BIT = 0x00000008;
92 private static final int BATTERY_LOW_BIT = 0x00000010;
93
94 // values for setPowerState
95
96 // SCREEN_OFF == everything off
97 private static final int SCREEN_OFF = 0x00000000;
98
99 // SCREEN_DIM == screen on, screen backlight dim
100 private static final int SCREEN_DIM = SCREEN_ON_BIT;
101
102 // SCREEN_BRIGHT == screen on, screen backlight bright
103 private static final int SCREEN_BRIGHT = SCREEN_ON_BIT | SCREEN_BRIGHT_BIT;
104
105 // SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright
106 private static final int SCREEN_BUTTON_BRIGHT = SCREEN_BRIGHT | BUTTON_BRIGHT_BIT;
107
108 // SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlights bright
109 private static final int ALL_BRIGHT = SCREEN_BUTTON_BRIGHT | KEYBOARD_BRIGHT_BIT;
110
111 // used for noChangeLights in setPowerState()
112 private static final int LIGHTS_MASK = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT;
113
114 static final boolean ANIMATE_SCREEN_LIGHTS = true;
115 static final boolean ANIMATE_BUTTON_LIGHTS = false;
116 static final boolean ANIMATE_KEYBOARD_LIGHTS = false;
117
118 static final int ANIM_STEPS = 60/4;
119
120 // These magic numbers are the initial state of the LEDs at boot. Ideally
121 // we should read them from the driver, but our current hardware returns 0
122 // for the initial value. Oops!
123 static final int INITIAL_SCREEN_BRIGHTNESS = 255;
124 static final int INITIAL_BUTTON_BRIGHTNESS = Power.BRIGHTNESS_OFF;
125 static final int INITIAL_KEYBOARD_BRIGHTNESS = Power.BRIGHTNESS_OFF;
126
127 static final int LOG_POWER_SLEEP_REQUESTED = 2724;
128 static final int LOG_POWER_SCREEN_BROADCAST_SEND = 2725;
129 static final int LOG_POWER_SCREEN_BROADCAST_DONE = 2726;
130 static final int LOG_POWER_SCREEN_BROADCAST_STOP = 2727;
131 static final int LOG_POWER_SCREEN_STATE = 2728;
132 static final int LOG_POWER_PARTIAL_WAKE_STATE = 2729;
133
134 private final int MY_UID;
135
136 private boolean mDoneBooting = false;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800137 private int mStayOnConditions = 0;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700138 private int mNotificationQueue = -1;
139 private int mNotificationWhy;
140 private int mPartialCount = 0;
141 private int mPowerState;
142 private boolean mOffBecauseOfUser;
143 private int mUserState;
144 private boolean mKeyboardVisible = false;
145 private boolean mUserActivityAllowed = true;
146 private int mTotalDelaySetting;
147 private int mKeylightDelay;
148 private int mDimDelay;
149 private int mScreenOffDelay;
150 private int mWakeLockState;
151 private long mLastEventTime = 0;
152 private long mScreenOffTime;
153 private volatile WindowManagerPolicy mPolicy;
154 private final LockList mLocks = new LockList();
155 private Intent mScreenOffIntent;
156 private Intent mScreenOnIntent;
157 private Context mContext;
158 private UnsynchronizedWakeLock mBroadcastWakeLock;
159 private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;
160 private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;
161 private HandlerThread mHandlerThread;
162 private Handler mHandler;
163 private TimeoutTask mTimeoutTask = new TimeoutTask();
164 private LightAnimator mLightAnimator = new LightAnimator();
165 private final BrightnessState mScreenBrightness
166 = new BrightnessState(Power.SCREEN_LIGHT);
167 private final BrightnessState mKeyboardBrightness
168 = new BrightnessState(Power.KEYBOARD_LIGHT);
169 private final BrightnessState mButtonBrightness
170 = new BrightnessState(Power.BUTTON_LIGHT);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700171 private boolean mIsPowered = false;
172 private IActivityManager mActivityService;
173 private IBatteryStats mBatteryStats;
174 private BatteryService mBatteryService;
175 private boolean mDimScreen = true;
176 private long mNextTimeout;
177 private volatile int mPokey = 0;
178 private volatile boolean mPokeAwakeOnSet = false;
179 private volatile boolean mInitComplete = false;
180 private HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();
181 private long mScreenOnTime;
182 private long mScreenOnStartTime;
183
184 // Used when logging number and duration of touch-down cycles
185 private long mTotalTouchDownTime;
186 private long mLastTouchDown;
187 private int mTouchCycles;
188
189 // could be either static or controllable at runtime
190 private static final boolean mSpew = false;
191
192 /*
193 static PrintStream mLog;
194 static {
195 try {
196 mLog = new PrintStream("/data/power.log");
197 }
198 catch (FileNotFoundException e) {
199 android.util.Log.e(TAG, "Life is hard", e);
200 }
201 }
202 static class Log {
203 static void d(String tag, String s) {
204 mLog.println(s);
205 android.util.Log.d(tag, s);
206 }
207 static void i(String tag, String s) {
208 mLog.println(s);
209 android.util.Log.i(tag, s);
210 }
211 static void w(String tag, String s) {
212 mLog.println(s);
213 android.util.Log.w(tag, s);
214 }
215 static void e(String tag, String s) {
216 mLog.println(s);
217 android.util.Log.e(tag, s);
218 }
219 }
220 */
221
222 /**
223 * This class works around a deadlock between the lock in PowerManager.WakeLock
224 * and our synchronizing on mLocks. PowerManager.WakeLock synchronizes on its
225 * mToken object so it can be accessed from any thread, but it calls into here
226 * with its lock held. This class is essentially a reimplementation of
227 * PowerManager.WakeLock, but without that extra synchronized block, because we'll
228 * only call it with our own locks held.
229 */
230 private class UnsynchronizedWakeLock {
231 int mFlags;
232 String mTag;
233 IBinder mToken;
234 int mCount = 0;
235 boolean mRefCounted;
236
237 UnsynchronizedWakeLock(int flags, String tag, boolean refCounted) {
238 mFlags = flags;
239 mTag = tag;
240 mToken = new Binder();
241 mRefCounted = refCounted;
242 }
243
244 public void acquire() {
245 if (!mRefCounted || mCount++ == 0) {
246 PowerManagerService.this.acquireWakeLockLocked(mFlags, mToken, mTag);
247 }
248 }
249
250 public void release() {
251 if (!mRefCounted || --mCount == 0) {
252 PowerManagerService.this.releaseWakeLockLocked(mToken, false);
253 }
254 if (mCount < 0) {
255 throw new RuntimeException("WakeLock under-locked " + mTag);
256 }
257 }
258
259 public String toString() {
260 return "UnsynchronizedWakeLock(mFlags=0x" + Integer.toHexString(mFlags)
261 + " mCount=" + mCount + ")";
262 }
263 }
264
265 private final class BatteryReceiver extends BroadcastReceiver {
266 @Override
267 public void onReceive(Context context, Intent intent) {
268 synchronized (mLocks) {
269 boolean wasPowered = mIsPowered;
270 mIsPowered = mBatteryService.isPowered();
271
272 if (mIsPowered != wasPowered) {
273 // update mStayOnWhilePluggedIn wake lock
274 updateWakeLockLocked();
275
276 // treat plugging and unplugging the devices as a user activity.
277 // users find it disconcerting when they unplug the device
278 // and it shuts off right away.
279 // temporarily set mUserActivityAllowed to true so this will work
280 // even when the keyguard is on.
281 synchronized (mLocks) {
282 boolean savedActivityAllowed = mUserActivityAllowed;
283 mUserActivityAllowed = true;
284 userActivity(SystemClock.uptimeMillis(), false);
285 mUserActivityAllowed = savedActivityAllowed;
286 }
287 }
288 }
289 }
290 }
291
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800292 /**
293 * Set the setting that determines whether the device stays on when plugged in.
294 * The argument is a bit string, with each bit specifying a power source that,
295 * when the device is connected to that source, causes the device to stay on.
296 * See {@link android.os.BatteryManager} for the list of power sources that
297 * can be specified. Current values include {@link android.os.BatteryManager#BATTERY_PLUGGED_AC}
298 * and {@link android.os.BatteryManager#BATTERY_PLUGGED_USB}
299 * @param val an {@code int} containing the bits that specify which power sources
300 * should cause the device to stay on.
301 */
302 public void setStayOnSetting(int val) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700303 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WRITE_SETTINGS, null);
304 Settings.System.putInt(mContext.getContentResolver(),
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800305 Settings.System.STAY_ON_WHILE_PLUGGED_IN, val);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700306 }
307
308 private class SettingsObserver implements Observer {
309 private int getInt(String name) {
310 return mSettings.getValues(name).getAsInteger(Settings.System.VALUE);
311 }
312
313 public void update(Observable o, Object arg) {
314 synchronized (mLocks) {
315 // STAY_ON_WHILE_PLUGGED_IN
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800316 mStayOnConditions = getInt(STAY_ON_WHILE_PLUGGED_IN);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700317 updateWakeLockLocked();
318
319 // SCREEN_OFF_TIMEOUT
320 mTotalDelaySetting = getInt(SCREEN_OFF_TIMEOUT);
321
322 // DIM_SCREEN
323 //mDimScreen = getInt(DIM_SCREEN) != 0;
324
325 // recalculate everything
326 setScreenOffTimeoutsLocked();
327 }
328 }
329 }
330
331 PowerManagerService()
332 {
333 // Hack to get our uid... should have a func for this.
334 long token = Binder.clearCallingIdentity();
335 MY_UID = Binder.getCallingUid();
336 Binder.restoreCallingIdentity(token);
337
338 // XXX remove this when the kernel doesn't timeout wake locks
339 Power.setLastUserActivityTimeout(7*24*3600*1000); // one week
340
341 // assume nothing is on yet
342 mUserState = mPowerState = 0;
343
344 // Add ourself to the Watchdog monitors.
345 Watchdog.getInstance().addMonitor(this);
346 mScreenOnStartTime = SystemClock.elapsedRealtime();
347 }
348
349 private ContentQueryMap mSettings;
350
351 void init(Context context, IActivityManager activity, BatteryService battery) {
352 mContext = context;
353 mActivityService = activity;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800354 mBatteryStats = BatteryStatsService.getService();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700355 mBatteryService = battery;
356
357 mHandlerThread = new HandlerThread("PowerManagerService") {
358 @Override
359 protected void onLooperPrepared() {
360 super.onLooperPrepared();
361 initInThread();
362 }
363 };
364 mHandlerThread.start();
365
366 synchronized (mHandlerThread) {
367 while (!mInitComplete) {
368 try {
369 mHandlerThread.wait();
370 } catch (InterruptedException e) {
371 // Ignore
372 }
373 }
374 }
375 }
376
377 void initInThread() {
378 mHandler = new Handler();
379
380 mBroadcastWakeLock = new UnsynchronizedWakeLock(
381 PowerManager.PARTIAL_WAKE_LOCK, "sleep_notification", true);
382 mStayOnWhilePluggedInScreenDimLock = new UnsynchronizedWakeLock(
383 PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);
384 mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(
385 PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false);
386
387 mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
388 mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
389 mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
390 mScreenOffIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
391
392 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800393 Cursor settingsCursor = resolver.query(Settings.System.CONTENT_URI, null,
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700394 "(" + Settings.System.NAME + "=?) or ("
395 + Settings.System.NAME + "=?) or ("
396 + Settings.System.NAME + "=?)",
397 new String[]{STAY_ON_WHILE_PLUGGED_IN, SCREEN_OFF_TIMEOUT, DIM_SCREEN},
398 null);
399 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mHandler);
400 SettingsObserver settingsObserver = new SettingsObserver();
401 mSettings.addObserver(settingsObserver);
402
403 // pretend that the settings changed so we will get their initial state
404 settingsObserver.update(mSettings, null);
405
406 // register for the battery changed notifications
407 IntentFilter filter = new IntentFilter();
408 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
409 mContext.registerReceiver(new BatteryReceiver(), filter);
410
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800411 // Listen for Gservices changes
412 IntentFilter gservicesChangedFilter =
413 new IntentFilter(Settings.Gservices.CHANGED_ACTION);
414 mContext.registerReceiver(new GservicesChangedReceiver(), gservicesChangedFilter);
415 // And explicitly do the initial update of our cached settings
416 updateGservicesValues();
417
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700418 // turn everything on
419 setPowerState(ALL_BRIGHT);
420
421 synchronized (mHandlerThread) {
422 mInitComplete = true;
423 mHandlerThread.notifyAll();
424 }
425 }
426
427 private class WakeLock implements IBinder.DeathRecipient
428 {
429 WakeLock(int f, IBinder b, String t, int u) {
430 super();
431 flags = f;
432 binder = b;
433 tag = t;
434 uid = u == MY_UID ? Process.SYSTEM_UID : u;
435 if (u != MY_UID || (
436 !"KEEP_SCREEN_ON_FLAG".equals(tag)
437 && !"KeyInputQueue".equals(tag))) {
438 monitorType = (f & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK
439 ? BatteryStats.WAKE_TYPE_PARTIAL
440 : BatteryStats.WAKE_TYPE_FULL;
441 } else {
442 monitorType = -1;
443 }
444 try {
445 b.linkToDeath(this, 0);
446 } catch (RemoteException e) {
447 binderDied();
448 }
449 }
450 public void binderDied() {
451 synchronized (mLocks) {
452 releaseWakeLockLocked(this.binder, true);
453 }
454 }
455 final int flags;
456 final IBinder binder;
457 final String tag;
458 final int uid;
459 final int monitorType;
460 boolean activated = true;
461 int minState;
462 }
463
464 private void updateWakeLockLocked() {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800465 if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700466 // keep the device on if we're plugged in and mStayOnWhilePluggedIn is set.
467 mStayOnWhilePluggedInScreenDimLock.acquire();
468 mStayOnWhilePluggedInPartialLock.acquire();
469 } else {
470 mStayOnWhilePluggedInScreenDimLock.release();
471 mStayOnWhilePluggedInPartialLock.release();
472 }
473 }
474
475 private boolean isScreenLock(int flags)
476 {
477 int n = flags & LOCK_MASK;
478 return n == PowerManager.FULL_WAKE_LOCK
479 || n == PowerManager.SCREEN_BRIGHT_WAKE_LOCK
480 || n == PowerManager.SCREEN_DIM_WAKE_LOCK;
481 }
482
483 public void acquireWakeLock(int flags, IBinder lock, String tag) {
484 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
485 synchronized (mLocks) {
486 acquireWakeLockLocked(flags, lock, tag);
487 }
488 }
489
490 public void acquireWakeLockLocked(int flags, IBinder lock, String tag) {
491 int acquireUid = -1;
492 String acquireName = null;
493 int acquireType = -1;
494
495 if (mSpew) {
496 Log.d(TAG, "acquireWakeLock flags=0x" + Integer.toHexString(flags) + " tag=" + tag);
497 }
498
499 int index = mLocks.getIndex(lock);
500 WakeLock wl;
501 boolean newlock;
502 if (index < 0) {
503 wl = new WakeLock(flags, lock, tag, Binder.getCallingUid());
504 switch (wl.flags & LOCK_MASK)
505 {
506 case PowerManager.FULL_WAKE_LOCK:
507 wl.minState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
508 break;
509 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
510 wl.minState = SCREEN_BRIGHT;
511 break;
512 case PowerManager.SCREEN_DIM_WAKE_LOCK:
513 wl.minState = SCREEN_DIM;
514 break;
515 case PowerManager.PARTIAL_WAKE_LOCK:
516 break;
517 default:
518 // just log and bail. we're in the server, so don't
519 // throw an exception.
520 Log.e(TAG, "bad wakelock type for lock '" + tag + "' "
521 + " flags=" + flags);
522 return;
523 }
524 mLocks.addLock(wl);
525 newlock = true;
526 } else {
527 wl = mLocks.get(index);
528 newlock = false;
529 }
530 if (isScreenLock(flags)) {
531 // if this causes a wakeup, we reactivate all of the locks and
532 // set it to whatever they want. otherwise, we modulate that
533 // by the current state so we never turn it more on than
534 // it already is.
535 if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
536 reactivateWakeLocksLocked();
537 if (mSpew) {
538 Log.d(TAG, "wakeup here mUserState=0x" + Integer.toHexString(mUserState)
539 + " mLocks.gatherState()=0x"
540 + Integer.toHexString(mLocks.gatherState())
541 + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
542 }
543 mWakeLockState = mLocks.gatherState();
544 } else {
545 if (mSpew) {
546 Log.d(TAG, "here mUserState=0x" + Integer.toHexString(mUserState)
547 + " mLocks.gatherState()=0x"
548 + Integer.toHexString(mLocks.gatherState())
549 + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
550 }
551 mWakeLockState = (mUserState | mWakeLockState) & mLocks.gatherState();
552 }
553 setPowerState(mWakeLockState | mUserState);
554 }
555 else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
556 if (newlock) {
557 mPartialCount++;
558 if (mPartialCount == 1) {
559 if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 1, tag);
560 }
561 }
562 Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
563 }
564 if (newlock) {
565 acquireUid = wl.uid;
566 acquireName = wl.tag;
567 acquireType = wl.monitorType;
568 }
569
570 if (acquireType >= 0) {
571 try {
572 long origId = Binder.clearCallingIdentity();
573 mBatteryStats.noteStartWakelock(acquireUid, acquireName, acquireType);
574 Binder.restoreCallingIdentity(origId);
575 } catch (RemoteException e) {
576 // Ignore
577 }
578 }
579 }
580
581 public void releaseWakeLock(IBinder lock) {
582 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
583
584 synchronized (mLocks) {
585 releaseWakeLockLocked(lock, false);
586 }
587 }
588
589 private void releaseWakeLockLocked(IBinder lock, boolean death) {
590 int releaseUid;
591 String releaseName;
592 int releaseType;
593
594 WakeLock wl = mLocks.removeLock(lock);
595 if (wl == null) {
596 return;
597 }
598
599 if (mSpew) {
600 Log.d(TAG, "releaseWakeLock flags=0x"
601 + Integer.toHexString(wl.flags) + " tag=" + wl.tag);
602 }
603
604 if (isScreenLock(wl.flags)) {
605 mWakeLockState = mLocks.gatherState();
606 // goes in the middle to reduce flicker
607 if ((wl.flags & PowerManager.ON_AFTER_RELEASE) != 0) {
608 userActivity(SystemClock.uptimeMillis(), false);
609 }
610 setPowerState(mWakeLockState | mUserState);
611 }
612 else if ((wl.flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
613 mPartialCount--;
614 if (mPartialCount == 0) {
615 if (LOG_PARTIAL_WL) EventLog.writeEvent(LOG_POWER_PARTIAL_WAKE_STATE, 0, wl.tag);
616 Power.releaseWakeLock(PARTIAL_NAME);
617 }
618 }
619 // Unlink the lock from the binder.
620 wl.binder.unlinkToDeath(wl, 0);
621 releaseUid = wl.uid;
622 releaseName = wl.tag;
623 releaseType = wl.monitorType;
624
625 if (releaseType >= 0) {
626 try {
627 long origId = Binder.clearCallingIdentity();
628 mBatteryStats.noteStopWakelock(releaseUid, releaseName, releaseType);
629 Binder.restoreCallingIdentity(origId);
630 } catch (RemoteException e) {
631 // Ignore
632 }
633 }
634 }
635
636 private void reactivateWakeLocksLocked()
637 {
638 int N = mLocks.size();
639 for (int i=0; i<N; i++) {
640 WakeLock wl = mLocks.get(i);
641 if (isScreenLock(wl.flags)) {
642 mLocks.get(i).activated = true;
643 }
644 }
645 }
646
647 private class PokeLock implements IBinder.DeathRecipient
648 {
649 PokeLock(int p, IBinder b, String t) {
650 super();
651 this.pokey = p;
652 this.binder = b;
653 this.tag = t;
654 try {
655 b.linkToDeath(this, 0);
656 } catch (RemoteException e) {
657 binderDied();
658 }
659 }
660 public void binderDied() {
661 setPokeLock(0, this.binder, this.tag);
662 }
663 int pokey;
664 IBinder binder;
665 String tag;
666 boolean awakeOnSet;
667 }
668
669 public void setPokeLock(int pokey, IBinder token, String tag) {
670 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
671 if (token == null) {
672 Log.e(TAG, "setPokeLock got null token for tag='" + tag + "'");
673 return;
674 }
675
676 if ((pokey & POKE_LOCK_TIMEOUT_MASK) == POKE_LOCK_TIMEOUT_MASK) {
677 throw new IllegalArgumentException("setPokeLock can't have both POKE_LOCK_SHORT_TIMEOUT"
678 + " and POKE_LOCK_MEDIUM_TIMEOUT");
679 }
680
681 synchronized (mLocks) {
682 if (pokey != 0) {
683 PokeLock p = mPokeLocks.get(token);
684 int oldPokey = 0;
685 if (p != null) {
686 oldPokey = p.pokey;
687 p.pokey = pokey;
688 } else {
689 p = new PokeLock(pokey, token, tag);
690 mPokeLocks.put(token, p);
691 }
692 int oldTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
693 int newTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
694 if (((mPowerState & SCREEN_ON_BIT) == 0) && (oldTimeout != newTimeout)) {
695 p.awakeOnSet = true;
696 }
697 } else {
698 mPokeLocks.remove(token);
699 }
700
701 int oldPokey = mPokey;
702 int cumulative = 0;
703 boolean oldAwakeOnSet = mPokeAwakeOnSet;
704 boolean awakeOnSet = false;
705 for (PokeLock p: mPokeLocks.values()) {
706 cumulative |= p.pokey;
707 if (p.awakeOnSet) {
708 awakeOnSet = true;
709 }
710 }
711 mPokey = cumulative;
712 mPokeAwakeOnSet = awakeOnSet;
713
714 int oldCumulativeTimeout = oldPokey & POKE_LOCK_TIMEOUT_MASK;
715 int newCumulativeTimeout = pokey & POKE_LOCK_TIMEOUT_MASK;
716
717 if (oldCumulativeTimeout != newCumulativeTimeout) {
718 setScreenOffTimeoutsLocked();
719 // reset the countdown timer, but use the existing nextState so it doesn't
720 // change anything
721 setTimeoutLocked(SystemClock.uptimeMillis(), mTimeoutTask.nextState);
722 }
723 }
724 }
725
726 private static String lockType(int type)
727 {
728 switch (type)
729 {
730 case PowerManager.FULL_WAKE_LOCK:
731 return "FULL_WAKE_LOCK ";
732 case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
733 return "SCREEN_BRIGHT_WAKE_LOCK";
734 case PowerManager.SCREEN_DIM_WAKE_LOCK:
735 return "SCREEN_DIM_WAKE_LOCK ";
736 case PowerManager.PARTIAL_WAKE_LOCK:
737 return "PARTIAL_WAKE_LOCK ";
738 default:
739 return "??? ";
740 }
741 }
742
743 private static String dumpPowerState(int state) {
744 return (((state & KEYBOARD_BRIGHT_BIT) != 0)
745 ? "KEYBOARD_BRIGHT_BIT " : "")
746 + (((state & SCREEN_BRIGHT_BIT) != 0)
747 ? "SCREEN_BRIGHT_BIT " : "")
748 + (((state & SCREEN_ON_BIT) != 0)
749 ? "SCREEN_ON_BIT " : "")
750 + (((state & BATTERY_LOW_BIT) != 0)
751 ? "BATTERY_LOW_BIT " : "");
752 }
753
754 @Override
755 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
756 if (mContext.checkCallingPermission(android.Manifest.permission.DUMP)
757 != PackageManager.PERMISSION_GRANTED) {
758 pw.println("Permission Denial: can't dump PowerManager from from pid="
759 + Binder.getCallingPid()
760 + ", uid=" + Binder.getCallingUid());
761 return;
762 }
763
764 long now = SystemClock.uptimeMillis();
765
766 pw.println("Power Manager State:");
767 pw.println(" mIsPowered=" + mIsPowered
768 + " mPowerState=" + mPowerState
769 + " mScreenOffTime=" + (SystemClock.elapsedRealtime()-mScreenOffTime)
770 + " ms");
771 pw.println(" mPartialCount=" + mPartialCount);
772 pw.println(" mWakeLockState=" + dumpPowerState(mWakeLockState));
773 pw.println(" mUserState=" + dumpPowerState(mUserState));
774 pw.println(" mPowerState=" + dumpPowerState(mPowerState));
775 pw.println(" mLocks.gather=" + dumpPowerState(mLocks.gatherState()));
776 pw.println(" mNextTimeout=" + mNextTimeout + " now=" + now
777 + " " + ((mNextTimeout-now)/1000) + "s from now");
778 pw.println(" mDimScreen=" + mDimScreen
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800779 + " mStayOnConditions=" + mStayOnConditions);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700780 pw.println(" mOffBecauseOfUser=" + mOffBecauseOfUser
781 + " mUserState=" + mUserState);
782 pw.println(" mNotificationQueue=" + mNotificationQueue
783 + " mNotificationWhy=" + mNotificationWhy);
784 pw.println(" mPokey=" + mPokey + " mPokeAwakeonSet=" + mPokeAwakeOnSet);
785 pw.println(" mKeyboardVisible=" + mKeyboardVisible
786 + " mUserActivityAllowed=" + mUserActivityAllowed);
787 pw.println(" mKeylightDelay=" + mKeylightDelay + " mDimDelay=" + mDimDelay
788 + " mScreenOffDelay=" + mScreenOffDelay);
789 pw.println(" mTotalDelaySetting=" + mTotalDelaySetting);
790 pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
791 pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
792 pw.println(" mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
793 mScreenBrightness.dump(pw, " mScreenBrightness: ");
794 mKeyboardBrightness.dump(pw, " mKeyboardBrightness: ");
795 mButtonBrightness.dump(pw, " mButtonBrightness: ");
796
797 int N = mLocks.size();
798 pw.println();
799 pw.println("mLocks.size=" + N + ":");
800 for (int i=0; i<N; i++) {
801 WakeLock wl = mLocks.get(i);
802 String type = lockType(wl.flags & LOCK_MASK);
803 String acquireCausesWakeup = "";
804 if ((wl.flags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0) {
805 acquireCausesWakeup = "ACQUIRE_CAUSES_WAKEUP ";
806 }
807 String activated = "";
808 if (wl.activated) {
809 activated = " activated";
810 }
811 pw.println(" " + type + " '" + wl.tag + "'" + acquireCausesWakeup
812 + activated + " (minState=" + wl.minState + ")");
813 }
814
815 pw.println();
816 pw.println("mPokeLocks.size=" + mPokeLocks.size() + ":");
817 for (PokeLock p: mPokeLocks.values()) {
818 pw.println(" poke lock '" + p.tag + "':"
819 + ((p.pokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0
820 ? " POKE_LOCK_IGNORE_CHEEK_EVENTS" : "")
821 + ((p.pokey & POKE_LOCK_SHORT_TIMEOUT) != 0
822 ? " POKE_LOCK_SHORT_TIMEOUT" : "")
823 + ((p.pokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0
824 ? " POKE_LOCK_MEDIUM_TIMEOUT" : ""));
825 }
826
827 pw.println();
828 }
829
830 private void setTimeoutLocked(long now, int nextState)
831 {
832 if (mDoneBooting) {
833 mHandler.removeCallbacks(mTimeoutTask);
834 mTimeoutTask.nextState = nextState;
835 long when = now;
836 switch (nextState)
837 {
838 case SCREEN_BRIGHT:
839 when += mKeylightDelay;
840 break;
841 case SCREEN_DIM:
842 if (mDimDelay >= 0) {
843 when += mDimDelay;
844 break;
845 } else {
846 Log.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim");
847 }
848 case SCREEN_OFF:
849 synchronized (mLocks) {
850 when += mScreenOffDelay;
851 }
852 break;
853 }
854 if (mSpew) {
855 Log.d(TAG, "setTimeoutLocked now=" + now + " nextState=" + nextState
856 + " when=" + when);
857 }
858 mHandler.postAtTime(mTimeoutTask, when);
859 mNextTimeout = when; // for debugging
860 }
861 }
862
863 private void cancelTimerLocked()
864 {
865 mHandler.removeCallbacks(mTimeoutTask);
866 mTimeoutTask.nextState = -1;
867 }
868
869 private class TimeoutTask implements Runnable
870 {
871 int nextState; // access should be synchronized on mLocks
872 public void run()
873 {
874 synchronized (mLocks) {
875 if (mSpew) {
876 Log.d(TAG, "user activity timeout timed out nextState=" + this.nextState);
877 }
878
879 if (nextState == -1) {
880 return;
881 }
882
883 mUserState = this.nextState;
884 setPowerState(this.nextState | mWakeLockState);
885
886 long now = SystemClock.uptimeMillis();
887
888 switch (this.nextState)
889 {
890 case SCREEN_BRIGHT:
891 if (mDimDelay >= 0) {
892 setTimeoutLocked(now, SCREEN_DIM);
893 break;
894 }
895 case SCREEN_DIM:
896 setTimeoutLocked(now, SCREEN_OFF);
897 break;
898 }
899 }
900 }
901 }
902
903 private void sendNotificationLocked(boolean on, int why)
904 {
905
906 if (!on) {
907 mNotificationWhy = why;
908 }
909
910 int value = on ? 1 : 0;
911 if (mNotificationQueue == -1) {
912 // empty
913 // Acquire the broadcast wake lock before changing the power
914 // state. It will be release after the broadcast is sent.
915 mBroadcastWakeLock.acquire();
916 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_SEND, mBroadcastWakeLock.mCount);
917 mNotificationQueue = value;
918 mHandler.post(mNotificationTask);
919 } else if (mNotificationQueue != value) {
920 // it's a pair, so cancel it
921 mNotificationQueue = -1;
922 mHandler.removeCallbacks(mNotificationTask);
923 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 1, mBroadcastWakeLock.mCount);
924 mBroadcastWakeLock.release();
925 } else {
926 // else, same so do nothing -- maybe we should warn?
927 Log.w(TAG, "Duplicate notification: on=" + on + " why=" + why);
928 }
929 }
930
931 private Runnable mNotificationTask = new Runnable()
932 {
933 public void run()
934 {
935 int value;
936 int why;
937 WindowManagerPolicy policy;
938 synchronized (mLocks) {
939 policy = getPolicyLocked();
940 value = mNotificationQueue;
941 why = mNotificationWhy;
942 mNotificationQueue = -1;
943 }
944 if (value == 1) {
945 mScreenOnStart = SystemClock.uptimeMillis();
946
947 policy.screenTurnedOn();
948 try {
949 ActivityManagerNative.getDefault().wakingUp();
950 } catch (RemoteException e) {
951 // ignore it
952 }
953
954 if (mSpew) {
955 Log.d(TAG, "mBroadcastWakeLock=" + mBroadcastWakeLock);
956 }
957 if (mContext != null) {
958 mContext.sendOrderedBroadcast(mScreenOnIntent, null,
959 mScreenOnBroadcastDone, mHandler, 0, null, null);
960 } else {
961 synchronized (mLocks) {
962 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 2,
963 mBroadcastWakeLock.mCount);
964 mBroadcastWakeLock.release();
965 }
966 }
967 }
968 else if (value == 0) {
969 mScreenOffStart = SystemClock.uptimeMillis();
970
971 policy.screenTurnedOff(why);
972 try {
973 ActivityManagerNative.getDefault().goingToSleep();
974 } catch (RemoteException e) {
975 // ignore it.
976 }
977
978 if (mContext != null) {
979 mContext.sendOrderedBroadcast(mScreenOffIntent, null,
980 mScreenOffBroadcastDone, mHandler, 0, null, null);
981 } else {
982 synchronized (mLocks) {
983 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 3,
984 mBroadcastWakeLock.mCount);
985 mBroadcastWakeLock.release();
986 }
987 }
988 }
989 else {
990 synchronized (mLocks) {
991 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 4,
992 mBroadcastWakeLock.mCount);
993 mBroadcastWakeLock.release();
994 }
995 }
996 }
997 };
998
999 long mScreenOnStart;
1000 private BroadcastReceiver mScreenOnBroadcastDone = new BroadcastReceiver() {
1001 public void onReceive(Context context, Intent intent) {
1002 synchronized (mLocks) {
1003 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 1,
1004 SystemClock.uptimeMillis() - mScreenOnStart, mBroadcastWakeLock.mCount);
1005 mBroadcastWakeLock.release();
1006 }
1007 }
1008 };
1009
1010 long mScreenOffStart;
1011 private BroadcastReceiver mScreenOffBroadcastDone = new BroadcastReceiver() {
1012 public void onReceive(Context context, Intent intent) {
1013 synchronized (mLocks) {
1014 EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_DONE, 0,
1015 SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount);
1016 mBroadcastWakeLock.release();
1017 }
1018 }
1019 };
1020
1021 void logPointerUpEvent() {
1022 if (LOG_TOUCH_DOWNS) {
1023 mTotalTouchDownTime += SystemClock.elapsedRealtime() - mLastTouchDown;
1024 mLastTouchDown = 0;
1025 }
1026 }
1027
1028 void logPointerDownEvent() {
1029 if (LOG_TOUCH_DOWNS) {
1030 // If we are not already timing a down/up sequence
1031 if (mLastTouchDown == 0) {
1032 mLastTouchDown = SystemClock.elapsedRealtime();
1033 mTouchCycles++;
1034 }
1035 }
1036 }
1037
1038 private void setPowerState(int state)
1039 {
1040 setPowerState(state, false, false);
1041 }
1042
1043 private void setPowerState(int newState, boolean noChangeLights, boolean becauseOfUser)
1044 {
1045 synchronized (mLocks) {
1046 int err;
1047
1048 if (mSpew) {
1049 Log.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState)
1050 + " newState=0x" + Integer.toHexString(newState)
1051 + " noChangeLights=" + noChangeLights);
1052 }
1053
1054 if (noChangeLights) {
1055 newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK);
1056 }
1057
1058 if (batteryIsLow()) {
1059 newState |= BATTERY_LOW_BIT;
1060 } else {
1061 newState &= ~BATTERY_LOW_BIT;
1062 }
1063 if (newState == mPowerState) {
1064 return;
1065 }
1066
1067 if (!mDoneBooting) {
1068 newState |= ALL_BRIGHT;
1069 }
1070
1071 boolean oldScreenOn = (mPowerState & SCREEN_ON_BIT) != 0;
1072 boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0;
1073
1074 if (mSpew) {
1075 Log.d(TAG, "setPowerState: mPowerState=" + mPowerState
1076 + " newState=" + newState + " noChangeLights=" + noChangeLights);
1077 Log.d(TAG, " oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0)
1078 + " newKeyboardBright=" + ((newState & KEYBOARD_BRIGHT_BIT) != 0));
1079 Log.d(TAG, " oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0)
1080 + " newScreenBright=" + ((newState & SCREEN_BRIGHT_BIT) != 0));
1081 Log.d(TAG, " oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0)
1082 + " newButtonBright=" + ((newState & BUTTON_BRIGHT_BIT) != 0));
1083 Log.d(TAG, " oldScreenOn=" + oldScreenOn
1084 + " newScreenOn=" + newScreenOn);
1085 Log.d(TAG, " oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0)
1086 + " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0));
1087 }
1088
1089 if (mPowerState != newState) {
1090 err = updateLightsLocked(newState, becauseOfUser);
1091 if (err != 0) {
1092 return;
1093 }
1094 mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK);
1095 }
1096
1097 if (oldScreenOn != newScreenOn) {
1098 if (newScreenOn) {
1099 err = Power.setScreenState(true);
1100 mScreenOnStartTime = SystemClock.elapsedRealtime();
1101 mLastTouchDown = 0;
1102 mTotalTouchDownTime = 0;
1103 mTouchCycles = 0;
1104 EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 1, becauseOfUser ? 1 : 0,
1105 mTotalTouchDownTime, mTouchCycles);
1106 if (err == 0) {
1107 mPowerState |= SCREEN_ON_BIT;
1108 sendNotificationLocked(true, -1);
1109 }
1110 } else {
1111 mScreenOffTime = SystemClock.elapsedRealtime();
1112 if (!mScreenBrightness.animating) {
1113 err = turnScreenOffLocked(becauseOfUser);
1114 } else {
1115 mOffBecauseOfUser = becauseOfUser;
1116 err = 0;
1117 mLastTouchDown = 0;
1118 }
1119 }
1120 }
1121 }
1122 }
1123
1124 private int turnScreenOffLocked(boolean becauseOfUser) {
1125 if ((mPowerState&SCREEN_ON_BIT) != 0) {
1126 EventLog.writeEvent(LOG_POWER_SCREEN_STATE, 0, becauseOfUser ? 1 : 0,
1127 mTotalTouchDownTime, mTouchCycles);
1128 mLastTouchDown = 0;
1129 int err = Power.setScreenState(false);
1130 mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime;
1131 mScreenOnStartTime = 0;
1132 if (err == 0) {
1133 mPowerState &= ~SCREEN_ON_BIT;
1134 int why = becauseOfUser
1135 ? WindowManagerPolicy.OFF_BECAUSE_OF_USER
1136 : WindowManagerPolicy.OFF_BECAUSE_OF_TIMEOUT;
1137 sendNotificationLocked(false, why);
1138 }
1139 return err;
1140 }
1141 return 0;
1142 }
1143
1144 private boolean batteryIsLow() {
1145 return (!mIsPowered &&
1146 mBatteryService.getBatteryLevel() <= Power.LOW_BATTERY_THRESHOLD);
1147 }
1148
1149 private int updateLightsLocked(int newState, boolean becauseOfUser) {
1150 int oldState = mPowerState;
1151 int difference = newState ^ oldState;
1152 if (difference == 0) {
1153 return 0;
1154 }
1155
1156 int offMask = 0;
1157 int dimMask = 0;
1158 int onMask = 0;
1159
1160 int preferredBrightness = getPreferredBrightness();
1161 boolean startAnimation = false;
1162
1163 if ((difference & KEYBOARD_BRIGHT_BIT) != 0) {
1164 if (ANIMATE_KEYBOARD_LIGHTS) {
1165 if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
1166 mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
1167 ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS);
1168 } else {
1169 mKeyboardBrightness.setTargetLocked(preferredBrightness,
1170 ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS);
1171 }
1172 startAnimation = true;
1173 } else {
1174 if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {
1175 offMask |= Power.KEYBOARD_LIGHT;
1176 } else {
1177 onMask |= Power.KEYBOARD_LIGHT;
1178 }
1179 }
1180 }
1181
1182 if ((difference & BUTTON_BRIGHT_BIT) != 0) {
1183 if (ANIMATE_BUTTON_LIGHTS) {
1184 if ((newState & BUTTON_BRIGHT_BIT) == 0) {
1185 mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
1186 ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS);
1187 } else {
1188 mButtonBrightness.setTargetLocked(preferredBrightness,
1189 ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS);
1190 }
1191 startAnimation = true;
1192 } else {
1193 if ((newState & BUTTON_BRIGHT_BIT) == 0) {
1194 offMask |= Power.BUTTON_LIGHT;
1195 } else {
1196 onMask |= Power.BUTTON_LIGHT;
1197 }
1198 }
1199 }
1200
1201 if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {
1202 if (ANIMATE_SCREEN_LIGHTS) {
1203 if ((newState & SCREEN_BRIGHT_BIT) == 0) {
1204 // dim or turn off backlight, depending on if the screen is on
1205 // the scale is because the brightness ramp isn't linear and this biases
1206 // it so the later parts take longer.
1207 final float scale = 1.5f;
1208 float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness);
1209 if (ratio > 1.0f) ratio = 1.0f;
1210 if ((newState & SCREEN_ON_BIT) == 0) {
1211 int steps;
1212 if ((oldState & SCREEN_BRIGHT_BIT) != 0) {
1213 // was bright
1214 steps = ANIM_STEPS;
1215 } else {
1216 // was dim
1217 steps = (int)(ANIM_STEPS*ratio*scale);
1218 }
1219 mScreenBrightness.setTargetLocked(Power.BRIGHTNESS_OFF,
1220 steps, INITIAL_SCREEN_BRIGHTNESS);
1221 } else {
1222 int steps;
1223 if ((oldState & SCREEN_ON_BIT) != 0) {
1224 // was bright
1225 steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale);
1226 } else {
1227 // was dim
1228 steps = (int)(ANIM_STEPS*ratio);
1229 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001230 if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001231 // If the "stay on while plugged in" option is
1232 // turned on, then the screen will often not
1233 // automatically turn off while plugged in. To
1234 // still have a sense of when it is inactive, we
1235 // will then count going dim as turning off.
1236 mScreenOffTime = SystemClock.elapsedRealtime();
1237 }
1238 mScreenBrightness.setTargetLocked(Power.BRIGHTNESS_DIM,
1239 steps, INITIAL_SCREEN_BRIGHTNESS);
1240 }
1241 } else {
1242 mScreenBrightness.setTargetLocked(preferredBrightness,
1243 ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS);
1244 }
1245 startAnimation = true;
1246 } else {
1247 if ((newState & SCREEN_BRIGHT_BIT) == 0) {
1248 // dim or turn off backlight, depending on if the screen is on
1249 if ((newState & SCREEN_ON_BIT) == 0) {
1250 offMask |= Power.SCREEN_LIGHT;
1251 } else {
1252 dimMask |= Power.SCREEN_LIGHT;
1253 }
1254 } else {
1255 onMask |= Power.SCREEN_LIGHT;
1256 }
1257 }
1258 }
1259
1260 if (startAnimation) {
1261 if (mSpew) {
1262 Log.i(TAG, "Scheduling light animator!");
1263 }
1264 mHandler.removeCallbacks(mLightAnimator);
1265 mHandler.post(mLightAnimator);
1266 }
1267
1268 int err = 0;
1269 if (offMask != 0) {
1270 //Log.i(TAG, "Setting brightess off: " + offMask);
1271 err |= Power.setLightBrightness(offMask, Power.BRIGHTNESS_OFF);
1272 }
1273 if (dimMask != 0) {
1274 int brightness = Power.BRIGHTNESS_DIM;
1275 if ((newState & BATTERY_LOW_BIT) != 0 &&
1276 brightness > Power.BRIGHTNESS_LOW_BATTERY) {
1277 brightness = Power.BRIGHTNESS_LOW_BATTERY;
1278 }
1279 //Log.i(TAG, "Setting brightess dim " + brightness + ": " + offMask);
1280 err |= Power.setLightBrightness(dimMask, brightness);
1281 }
1282 if (onMask != 0) {
1283 int brightness = getPreferredBrightness();
1284 if ((newState & BATTERY_LOW_BIT) != 0 &&
1285 brightness > Power.BRIGHTNESS_LOW_BATTERY) {
1286 brightness = Power.BRIGHTNESS_LOW_BATTERY;
1287 }
1288 //Log.i(TAG, "Setting brightess on " + brightness + ": " + onMask);
1289 err |= Power.setLightBrightness(onMask, brightness);
1290 }
1291
1292 return err;
1293 }
1294
1295 class BrightnessState {
1296 final int mask;
1297
1298 boolean initialized;
1299 int targetValue;
1300 float curValue;
1301 float delta;
1302 boolean animating;
1303
1304 BrightnessState(int m) {
1305 mask = m;
1306 }
1307
1308 public void dump(PrintWriter pw, String prefix) {
1309 pw.println(prefix + "animating=" + animating
1310 + " targetValue=" + targetValue
1311 + " curValue=" + curValue
1312 + " delta=" + delta);
1313 }
1314
1315 void setTargetLocked(int target, int stepsToTarget, int initialValue) {
1316 if (!initialized) {
1317 initialized = true;
1318 curValue = (float)initialValue;
1319 }
1320 targetValue = target;
1321 delta = (targetValue-curValue) / stepsToTarget;
1322 if (mSpew) {
1323 Log.i(TAG, "Setting target " + mask + ": cur=" + curValue
1324 + " target=" + targetValue + " delta=" + delta);
1325 }
1326 animating = true;
1327 }
1328
1329 boolean stepLocked() {
1330 if (!animating) return false;
1331 if (false && mSpew) {
1332 Log.i(TAG, "Step target " + mask + ": cur=" + curValue
1333 + " target=" + targetValue + " delta=" + delta);
1334 }
1335 curValue += delta;
1336 int curIntValue = (int)curValue;
1337 boolean more = true;
1338 if (delta == 0) {
1339 more = false;
1340 } else if (delta > 0) {
1341 if (curIntValue >= targetValue) {
1342 curValue = curIntValue = targetValue;
1343 more = false;
1344 }
1345 } else {
1346 if (curIntValue <= targetValue) {
1347 curValue = curIntValue = targetValue;
1348 more = false;
1349 }
1350 }
1351 //Log.i(TAG, "Animating brightess " + curIntValue + ": " + mask);
1352 Power.setLightBrightness(mask, curIntValue);
1353 animating = more;
1354 if (!more) {
1355 if (mask == Power.SCREEN_LIGHT && curIntValue == Power.BRIGHTNESS_OFF) {
1356 turnScreenOffLocked(mOffBecauseOfUser);
1357 }
1358 }
1359 return more;
1360 }
1361 }
1362
1363 private class LightAnimator implements Runnable {
1364 public void run() {
1365 synchronized (mLocks) {
1366 long now = SystemClock.uptimeMillis();
1367 boolean more = mScreenBrightness.stepLocked();
1368 if (mKeyboardBrightness.stepLocked()) {
1369 more = true;
1370 }
1371 if (mButtonBrightness.stepLocked()) {
1372 more = true;
1373 }
1374 if (more) {
1375 mHandler.postAtTime(mLightAnimator, now+(1000/60));
1376 }
1377 }
1378 }
1379 }
1380
1381 private int getPreferredBrightness() {
1382 try {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001383 final int brightness = Settings.System.getInt(mContext.getContentResolver(),
1384 SCREEN_BRIGHTNESS);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001385 // Don't let applications turn the screen all the way off
1386 return Math.max(brightness, Power.BRIGHTNESS_DIM);
1387 } catch (SettingNotFoundException snfe) {
1388 return Power.BRIGHTNESS_ON;
1389 }
1390 }
1391
1392 boolean screenIsOn() {
1393 synchronized (mLocks) {
1394 return (mPowerState & SCREEN_ON_BIT) != 0;
1395 }
1396 }
1397
1398 boolean screenIsBright() {
1399 synchronized (mLocks) {
1400 return (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT;
1401 }
1402 }
1403
1404 public void userActivityWithForce(long time, boolean noChangeLights, boolean force) {
1405 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
1406 userActivity(time, noChangeLights, OTHER_EVENT, force);
1407 }
1408
1409 public void userActivity(long time, boolean noChangeLights) {
1410 userActivity(time, noChangeLights, OTHER_EVENT, false);
1411 }
1412
1413 public void userActivity(long time, boolean noChangeLights, int eventType) {
1414 userActivity(time, noChangeLights, eventType, false);
1415 }
1416
1417 public void userActivity(long time, boolean noChangeLights, int eventType, boolean force) {
1418 //mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
1419
1420 if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
1421 && !((eventType == OTHER_EVENT) || (eventType == BUTTON_EVENT))) {
1422 if (false) {
1423 Log.d(TAG, "dropping mPokey=0x" + Integer.toHexString(mPokey));
1424 }
1425 return;
1426 }
1427
1428 if (false) {
1429 if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) {
1430 Log.d(TAG, "userActivity !!!");//, new RuntimeException());
1431 } else {
1432 Log.d(TAG, "mPokey=0x" + Integer.toHexString(mPokey));
1433 }
1434 }
1435
1436 synchronized (mLocks) {
1437 if (mSpew) {
1438 Log.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time
1439 + " mUserActivityAllowed=" + mUserActivityAllowed
1440 + " mUserState=0x" + Integer.toHexString(mUserState)
1441 + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState));
1442 }
1443 if (mLastEventTime <= time || force) {
1444 mLastEventTime = time;
1445 if (mUserActivityAllowed || force) {
1446 // Only turn on button backlights if a button was pressed.
1447 if (eventType == BUTTON_EVENT) {
1448 mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);
1449 } else {
1450 // don't clear button/keyboard backlights when the screen is touched.
1451 mUserState |= SCREEN_BRIGHT;
1452 }
1453
1454 reactivateWakeLocksLocked();
1455 mWakeLockState = mLocks.gatherState();
1456 setPowerState(mUserState | mWakeLockState, noChangeLights, true);
1457 setTimeoutLocked(time, SCREEN_BRIGHT);
1458 }
1459 }
1460 }
1461 }
1462
1463 /**
1464 * The user requested that we go to sleep (probably with the power button).
1465 * This overrides all wake locks that are held.
1466 */
1467 public void goToSleep(long time)
1468 {
1469 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
1470 synchronized (mLocks) {
1471 goToSleepLocked(time);
1472 }
1473 }
1474
1475 /**
1476 * Returns the time the screen has been on since boot, in millis.
1477 * @return screen on time
1478 */
1479 public long getScreenOnTime() {
1480 synchronized (mLocks) {
1481 if (mScreenOnStartTime == 0) {
1482 return mScreenOnTime;
1483 } else {
1484 return SystemClock.elapsedRealtime() - mScreenOnStartTime + mScreenOnTime;
1485 }
1486 }
1487 }
1488
1489 private void goToSleepLocked(long time) {
1490
1491 if (mLastEventTime <= time) {
1492 mLastEventTime = time;
1493 // cancel all of the wake locks
1494 mWakeLockState = SCREEN_OFF;
1495 int N = mLocks.size();
1496 int numCleared = 0;
1497 for (int i=0; i<N; i++) {
1498 WakeLock wl = mLocks.get(i);
1499 if (isScreenLock(wl.flags)) {
1500 mLocks.get(i).activated = false;
1501 numCleared++;
1502 }
1503 }
1504 EventLog.writeEvent(LOG_POWER_SLEEP_REQUESTED, numCleared);
1505 mUserState = SCREEN_OFF;
1506 setPowerState(SCREEN_OFF, false, true);
1507 cancelTimerLocked();
1508 }
1509 }
1510
1511 public long timeSinceScreenOn() {
1512 synchronized (mLocks) {
1513 if ((mPowerState & SCREEN_ON_BIT) != 0) {
1514 return 0;
1515 }
1516 return SystemClock.elapsedRealtime() - mScreenOffTime;
1517 }
1518 }
1519
1520 public void setKeyboardVisibility(boolean visible) {
1521 mKeyboardVisible = visible;
1522 }
1523
1524 /**
1525 * When the keyguard is up, it manages the power state, and userActivity doesn't do anything.
1526 */
1527 public void enableUserActivity(boolean enabled) {
1528 synchronized (mLocks) {
1529 mUserActivityAllowed = enabled;
1530 mLastEventTime = SystemClock.uptimeMillis(); // we might need to pass this in
1531 }
1532 }
1533
1534 /** Sets the screen off timeouts:
1535 * mKeylightDelay
1536 * mDimDelay
1537 * mScreenOffDelay
1538 * */
1539 private void setScreenOffTimeoutsLocked() {
1540 if ((mPokey & POKE_LOCK_SHORT_TIMEOUT) != 0) {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001541 mKeylightDelay = mShortKeylightDelay; // Configurable via Gservices
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001542 mDimDelay = -1;
1543 mScreenOffDelay = 0;
1544 } else if ((mPokey & POKE_LOCK_MEDIUM_TIMEOUT) != 0) {
1545 mKeylightDelay = MEDIUM_KEYLIGHT_DELAY;
1546 mDimDelay = -1;
1547 mScreenOffDelay = 0;
1548 } else {
1549 int totalDelay = mTotalDelaySetting;
1550 mKeylightDelay = LONG_KEYLIGHT_DELAY;
1551 if (totalDelay < 0) {
1552 mScreenOffDelay = Integer.MAX_VALUE;
1553 } else if (mKeylightDelay < totalDelay) {
1554 // subtract the time that the keylight delay. This will give us the
1555 // remainder of the time that we need to sleep to get the accurate
1556 // screen off timeout.
1557 mScreenOffDelay = totalDelay - mKeylightDelay;
1558 } else {
1559 mScreenOffDelay = 0;
1560 }
1561 if (mDimScreen && totalDelay >= (LONG_KEYLIGHT_DELAY + LONG_DIM_TIME)) {
1562 mDimDelay = mScreenOffDelay - LONG_DIM_TIME;
1563 mScreenOffDelay = LONG_DIM_TIME;
1564 } else {
1565 mDimDelay = -1;
1566 }
1567 }
1568 if (mSpew) {
1569 Log.d(TAG, "setScreenOffTimeouts mKeylightDelay=" + mKeylightDelay
1570 + " mDimDelay=" + mDimDelay + " mScreenOffDelay=" + mScreenOffDelay
1571 + " mDimScreen=" + mDimScreen);
1572 }
1573 }
1574
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001575 /**
1576 * Refreshes cached Gservices settings. Called once on startup, and
1577 * on subsequent Settings.Gservices.CHANGED_ACTION broadcasts (see
1578 * GservicesChangedReceiver).
1579 */
1580 private void updateGservicesValues() {
1581 mShortKeylightDelay = Settings.Gservices.getInt(
1582 mContext.getContentResolver(),
1583 Settings.Gservices.SHORT_KEYLIGHT_DELAY_MS,
1584 SHORT_KEYLIGHT_DELAY_DEFAULT);
1585 // Log.i(TAG, "updateGservicesValues(): mShortKeylightDelay now " + mShortKeylightDelay);
1586 }
1587
1588 /**
1589 * Receiver for the Gservices.CHANGED_ACTION broadcast intent,
1590 * which tells us we need to refresh our cached Gservices settings.
1591 */
1592 private class GservicesChangedReceiver extends BroadcastReceiver {
1593 @Override
1594 public void onReceive(Context context, Intent intent) {
1595 // Log.i(TAG, "GservicesChangedReceiver.onReceive(): " + intent);
1596 updateGservicesValues();
1597 }
1598 }
1599
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001600 private class LockList extends ArrayList<WakeLock>
1601 {
1602 void addLock(WakeLock wl)
1603 {
1604 int index = getIndex(wl.binder);
1605 if (index < 0) {
1606 this.add(wl);
1607 }
1608 }
1609
1610 WakeLock removeLock(IBinder binder)
1611 {
1612 int index = getIndex(binder);
1613 if (index >= 0) {
1614 return this.remove(index);
1615 } else {
1616 return null;
1617 }
1618 }
1619
1620 int getIndex(IBinder binder)
1621 {
1622 int N = this.size();
1623 for (int i=0; i<N; i++) {
1624 if (this.get(i).binder == binder) {
1625 return i;
1626 }
1627 }
1628 return -1;
1629 }
1630
1631 int gatherState()
1632 {
1633 int result = 0;
1634 int N = this.size();
1635 for (int i=0; i<N; i++) {
1636 WakeLock wl = this.get(i);
1637 if (wl.activated) {
1638 if (isScreenLock(wl.flags)) {
1639 result |= wl.minState;
1640 }
1641 }
1642 }
1643 return result;
1644 }
1645 }
1646
1647 void setPolicy(WindowManagerPolicy p) {
1648 synchronized (mLocks) {
1649 mPolicy = p;
1650 mLocks.notifyAll();
1651 }
1652 }
1653
1654 WindowManagerPolicy getPolicyLocked() {
1655 while (mPolicy == null || !mDoneBooting) {
1656 try {
1657 mLocks.wait();
1658 } catch (InterruptedException e) {
1659 // Ignore
1660 }
1661 }
1662 return mPolicy;
1663 }
1664
1665 void systemReady() {
1666 synchronized (mLocks) {
1667 Log.d(TAG, "system ready!");
1668 mDoneBooting = true;
1669 userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
1670 updateWakeLockLocked();
1671 mLocks.notifyAll();
1672 }
1673 }
1674
1675 public void monitor() {
1676 synchronized (mLocks) { }
1677 }
1678}