diff options
Diffstat (limited to 'services')
12 files changed, 768 insertions, 544 deletions
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index baa5016..f8611e4 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -44,6 +44,7 @@ import android.os.storage.IMountService; import android.os.storage.IMountServiceListener; import android.os.storage.IMountShutdownObserver; import android.os.storage.IObbActionListener; +import android.os.storage.OnObbStateChangeListener; import android.os.storage.StorageResultCode; import android.security.MessageDigest; import android.util.Slog; @@ -53,7 +54,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -163,25 +163,25 @@ class MountService extends IMountService.Stub final private Map<String, ObbState> mObbPathToStateMap = new HashMap<String, ObbState>(); class ObbState implements IBinder.DeathRecipient { - public ObbState(String filename, IObbActionListener token, int callerUid) + public ObbState(String filename, int callerUid, IObbActionListener token, int nonce) throws RemoteException { this.filename = filename; - this.token = token; this.callerUid = callerUid; - mounted = false; + this.token = token; + this.nonce = nonce; } // OBB source filename - final String filename; - - // Token of remote Binder caller - final IObbActionListener token; + String filename; // Binder.callingUid() final public int callerUid; - // Whether this is mounted currently. - boolean mounted; + // Token of remote Binder caller + final IObbActionListener token; + + // Identifier to pass back to the token + final int nonce; public IBinder getBinder() { return token.asBinder(); @@ -210,8 +210,6 @@ class MountService extends IMountService.Stub sb.append(token.toString()); sb.append(",callerUid="); sb.append(callerUid); - sb.append(",mounted="); - sb.append(mounted); sb.append('}'); return sb.toString(); } @@ -225,6 +223,7 @@ class MountService extends IMountService.Stub private static final int OBB_MCS_BOUND = 2; private static final int OBB_MCS_UNBIND = 3; private static final int OBB_MCS_RECONNECT = 4; + private static final int OBB_FLUSH_MOUNT_STATE = 5; /* * Default Container Service information @@ -508,38 +507,19 @@ class MountService extends IMountService.Stub if (!mEmulateExternalStorage) { if (Environment.MEDIA_UNMOUNTED.equals(state)) { mPms.updateExternalMediaStatus(false, false); + + /* + * Some OBBs might have been unmounted when this volume was + * unmounted, so send a message to the handler to let it know to + * remove those from the list of mounted OBBS. + */ + mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_FLUSH_MOUNT_STATE, + path)); } else if (Environment.MEDIA_MOUNTED.equals(state)) { mPms.updateExternalMediaStatus(true, false); } } - // Remove all OBB mappings and listeners from this path - synchronized (mObbMounts) { - final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); - - final Iterator<Entry<String, ObbState>> i = mObbPathToStateMap.entrySet().iterator(); - while (i.hasNext()) { - final Entry<String, ObbState> obbEntry = i.next(); - - // If this entry's source file is in the volume path that got - // unmounted, remove it because it's no longer valid. - if (obbEntry.getKey().startsWith(path)) { - obbStatesToRemove.add(obbEntry.getValue()); - } - } - - for (final ObbState obbState : obbStatesToRemove) { - removeObbState(obbState); - - try { - obbState.token.onObbResult(obbState.filename, Environment.MEDIA_UNMOUNTED); - } catch (RemoteException e) { - Slog.i(TAG, "Couldn't send unmount notification for OBB: " - + obbState.filename); - } - } - } - String oldState = mLegacyState; mLegacyState = state; @@ -1547,6 +1527,10 @@ class MountService extends IMountService.Stub } public String getMountedObbPath(String filename) { + if (filename == null) { + throw new IllegalArgumentException("filename cannot be null"); + } + waitForReady(); warnOnNotMounted(); @@ -1569,164 +1553,98 @@ class MountService extends IMountService.Stub } public boolean isObbMounted(String filename) { + if (filename == null) { + throw new IllegalArgumentException("filename cannot be null"); + } + synchronized (mObbMounts) { - final ObbState obbState = mObbPathToStateMap.get(filename); - if (obbState != null) { - synchronized (obbState) { - return obbState.mounted; - } - } + return mObbPathToStateMap.containsKey(filename); } - return false; } - public void mountObb(String filename, String key, IObbActionListener token) + public void mountObb(String filename, String key, IObbActionListener token, int nonce) throws RemoteException { - waitForReady(); - warnOnNotMounted(); - if (filename == null) { throw new IllegalArgumentException("filename cannot be null"); - } else if (token == null) { - throw new IllegalArgumentException("token cannot be null"); } - final ObbState obbState; - - synchronized (mObbMounts) { - if (isObbMounted(filename)) { - try { - token.onObbResult(filename, Environment.MEDIA_MOUNTED); - } catch (RemoteException e) { - Slog.d(TAG, "Could not send unmount notification for: " + filename); - } - return; - } - - final int callerUid = Binder.getCallingUid(); - obbState = new ObbState(filename, token, callerUid); - addObbState(obbState); - } - - String hashedKey = null; - if (key != null) { - final MessageDigest md; - try { - md = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - Slog.e(TAG, "Could not load MD5 algorithm", e); - try { - token.onObbResult(filename, Environment.MEDIA_UNMOUNTED); - } catch (RemoteException e1) { - Slog.d(TAG, "Could not send unmount notification for: " + filename); - } - return; - } - - hashedKey = HexDump.toHexString(md.digest(key.getBytes())); + if (token == null) { + throw new IllegalArgumentException("token cannot be null"); } - ObbAction action = new MountObbAction(obbState, hashedKey); + final int callerUid = Binder.getCallingUid(); + final ObbState obbState = new ObbState(filename, callerUid, token, nonce); + final ObbAction action = new MountObbAction(obbState, key); mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); if (DEBUG_OBB) Slog.i(TAG, "Send to OBB handler: " + action.toString()); } - public void unmountObb(String filename, boolean force, IObbActionListener token) { + public void unmountObb(String filename, boolean force, IObbActionListener token, int nonce) + throws RemoteException { if (filename == null) { throw new IllegalArgumentException("filename cannot be null"); - } else if (token == null) { - throw new IllegalArgumentException("token cannot be null"); } - final ObbState obbState; - - synchronized (mObbMounts) { - if (!isObbMounted(filename)) { - try { - token.onObbResult(filename, Environment.MEDIA_UNMOUNTED); - } catch (RemoteException e) { - Slog.d(TAG, "Could not send unmount notification for: " + filename); - } - return; - } - - obbState = mObbPathToStateMap.get(filename); - - if (Binder.getCallingUid() != obbState.callerUid) { - throw new SecurityException("caller UID does not match original mount caller UID"); - } else if (!token.asBinder().equals(obbState.getBinder())) { - throw new SecurityException("caller does not match original mount caller"); - } - } - - ObbAction action = new UnmountObbAction(obbState, force); + final int callerUid = Binder.getCallingUid(); + final ObbState obbState = new ObbState(filename, callerUid, token, nonce); + final ObbAction action = new UnmountObbAction(obbState, force); mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action)); if (DEBUG_OBB) Slog.i(TAG, "Send to OBB handler: " + action.toString()); } - private void addObbState(ObbState obbState) throws RemoteException { - synchronized (mObbMounts) { - final IBinder binder = obbState.getBinder(); - List<ObbState> obbStates = mObbMounts.get(binder); - final boolean unique; - - if (obbStates == null) { - obbStates = new ArrayList<ObbState>(); - mObbMounts.put(binder, obbStates); - unique = true; - } else { - unique = obbStates.contains(obbState); - } - - if (unique) { - obbStates.add(obbState); - try { - obbState.link(); - } catch (RemoteException e) { - /* - * The binder died before we could link it, so clean up our - * state and return failure. - */ - obbStates.remove(obbState); - if (obbStates.isEmpty()) { - mObbMounts.remove(binder); - } + private void addObbStateLocked(ObbState obbState) throws RemoteException { + final IBinder binder = obbState.getBinder(); + List<ObbState> obbStates = mObbMounts.get(binder); - // Rethrow the error so mountObb can get it - throw e; + if (obbStates == null) { + obbStates = new ArrayList<ObbState>(); + mObbMounts.put(binder, obbStates); + } else { + for (final ObbState o : obbStates) { + if (o.filename.equals(obbState.filename)) { + throw new IllegalStateException("Attempt to add ObbState twice. " + + "This indicates an error in the MountService logic."); } } - - mObbPathToStateMap.put(obbState.filename, obbState); } - } - private void removeObbState(ObbState obbState) { - synchronized (mObbMounts) { - final IBinder binder = obbState.getBinder(); - final List<ObbState> obbStates = mObbMounts.get(binder); - if (obbStates != null) { - if (obbStates.remove(obbState)) { - obbState.unlink(); - } - if (obbStates.isEmpty()) { - mObbMounts.remove(binder); - } + obbStates.add(obbState); + try { + obbState.link(); + } catch (RemoteException e) { + /* + * The binder died before we could link it, so clean up our state + * and return failure. + */ + obbStates.remove(obbState); + if (obbStates.isEmpty()) { + mObbMounts.remove(binder); } - mObbPathToStateMap.remove(obbState.filename); + // Rethrow the error so mountObb can get it + throw e; } + + mObbPathToStateMap.put(obbState.filename, obbState); } - private void replaceObbState(ObbState oldObbState, ObbState newObbState) throws RemoteException { - synchronized (mObbMounts) { - removeObbState(oldObbState); - addObbState(newObbState); + private void removeObbStateLocked(ObbState obbState) { + final IBinder binder = obbState.getBinder(); + final List<ObbState> obbStates = mObbMounts.get(binder); + if (obbStates != null) { + if (obbStates.remove(obbState)) { + obbState.unlink(); + } + if (obbStates.isEmpty()) { + mObbMounts.remove(binder); + } } + + mObbPathToStateMap.remove(obbState.filename); } private class ObbActionHandler extends Handler { @@ -1825,6 +1743,47 @@ class MountService extends IMountService.Stub } break; } + case OBB_FLUSH_MOUNT_STATE: { + final String path = (String) msg.obj; + + if (DEBUG_OBB) + Slog.i(TAG, "Flushing all OBB state for path " + path); + + synchronized (mObbMounts) { + final List<ObbState> obbStatesToRemove = new LinkedList<ObbState>(); + + final Iterator<Entry<String, ObbState>> i = + mObbPathToStateMap.entrySet().iterator(); + while (i.hasNext()) { + final Entry<String, ObbState> obbEntry = i.next(); + + /* + * If this entry's source file is in the volume path + * that got unmounted, remove it because it's no + * longer valid. + */ + if (obbEntry.getKey().startsWith(path)) { + obbStatesToRemove.add(obbEntry.getValue()); + } + } + + for (final ObbState obbState : obbStatesToRemove) { + if (DEBUG_OBB) + Slog.i(TAG, "Removing state for " + obbState.filename); + + removeObbStateLocked(obbState); + + try { + obbState.token.onObbResult(obbState.filename, obbState.nonce, + OnObbStateChangeListener.UNMOUNTED); + } catch (RemoteException e) { + Slog.i(TAG, "Couldn't send unmount notification for OBB: " + + obbState.filename); + } + } + } + break; + } } } @@ -1903,9 +1862,13 @@ class MountService extends IMountService.Stub return obbInfo; } - protected void sendNewStatusOrIgnore(String filename, String status) { + protected void sendNewStatusOrIgnore(int status) { + if (mObbState == null || mObbState.token == null) { + return; + } + try { - mObbState.token.onObbResult(filename, status); + mObbState.token.onObbResult(mObbState.filename, mObbState.nonce, status); } catch (RemoteException e) { Slog.w(TAG, "MountServiceListener went away while calling onObbStateChanged"); } @@ -1921,89 +1884,80 @@ class MountService extends IMountService.Stub } public void handleExecute() throws IOException, RemoteException { + waitForReady(); + warnOnNotMounted(); + final ObbInfo obbInfo = getObbInfo(); + if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) { + Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename + + " which is owned by " + obbInfo.packageName); + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); + return; + } + + final boolean isMounted; + synchronized (mObbMounts) { + isMounted = mObbPathToStateMap.containsKey(obbInfo.filename); + } + if (isMounted) { + Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename); + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED); + return; + } + /* - * If someone tried to trick us with some weird characters, rectify - * it here. + * The filename passed in might not be the canonical name, so just + * set the filename to the canonicalized version. */ - if (!mObbState.filename.equals(obbInfo.filename)) { - if (DEBUG_OBB) - Slog.i(TAG, "OBB filename " + mObbState.filename + " is actually " - + obbInfo.filename); - - synchronized (mObbMounts) { - /* - * If the real filename is already mounted, discard this - * state and notify the caller that the OBB is already - * mounted. - */ - if (isObbMounted(obbInfo.filename)) { - if (DEBUG_OBB) - Slog.i(TAG, "OBB already mounted as " + obbInfo.filename); - - removeObbState(mObbState); - sendNewStatusOrIgnore(obbInfo.filename, Environment.MEDIA_MOUNTED); - return; - } + mObbState.filename = obbInfo.filename; - /* - * It's not already mounted, so we have to replace the state - * with the state containing the actual filename. - */ - ObbState newObbState = new ObbState(obbInfo.filename, mObbState.token, - mObbState.callerUid); - replaceObbState(mObbState, newObbState); - mObbState = newObbState; + final String hashedKey; + if (mKey == null) { + hashedKey = "none"; + } else { + final MessageDigest md; + try { + md = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + Slog.e(TAG, "Could not load MD5 algorithm", e); + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); + return; } - } - if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mObbState.callerUid)) { - throw new IllegalArgumentException("Caller package does not match OBB file"); + hashedKey = HexDump.toHexString(md.digest(mKey.getBytes())); } - boolean mounted = false; - int rc; - synchronized (mObbState) { - if (mObbState.mounted) { - sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED); - return; + int rc = StorageResultCode.OperationSucceeded; + String cmd = String.format("obb mount %s %s %d", mObbState.filename, hashedKey, + mObbState.callerUid); + try { + mConnector.doCommand(cmd); + } catch (NativeDaemonConnectorException e) { + int code = e.getCode(); + if (code != VoldResponseCode.OpFailedStorageBusy) { + rc = StorageResultCode.OperationFailedInternalError; } + } - rc = StorageResultCode.OperationSucceeded; - String cmd = String.format("obb mount %s %s %d", mObbState.filename, - mKey != null ? mKey : "none", - mObbState.callerUid); - try { - mConnector.doCommand(cmd); - } catch (NativeDaemonConnectorException e) { - int code = e.getCode(); - if (code != VoldResponseCode.OpFailedStorageBusy) { - rc = StorageResultCode.OperationFailedInternalError; - } - } + if (rc == StorageResultCode.OperationSucceeded) { + if (DEBUG_OBB) + Slog.d(TAG, "Successfully mounted OBB " + mObbState.filename); - if (rc == StorageResultCode.OperationSucceeded) { - mObbState.mounted = mounted = true; + synchronized (mObbMounts) { + addObbStateLocked(mObbState); } - } - if (mounted) { - sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED); + sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED); } else { Slog.e(TAG, "Couldn't mount OBB file: " + rc); - // We didn't succeed, so remove this from the mount-set. - removeObbState(mObbState); - - sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED); + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT); } } public void handleError() { - removeObbState(mObbState); - - sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_BAD_REMOVAL); + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); } @Override @@ -2016,6 +1970,8 @@ class MountService extends IMountService.Stub sb.append(mObbState.callerUid); sb.append(",token="); sb.append(mObbState.token != null ? mObbState.token.toString() : "NULL"); + sb.append(",binder="); + sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); sb.append('}'); return sb.toString(); } @@ -2030,68 +1986,61 @@ class MountService extends IMountService.Stub } public void handleExecute() throws IOException { + waitForReady(); + warnOnNotMounted(); + final ObbInfo obbInfo = getObbInfo(); - /* - * If someone tried to trick us with some weird characters, rectify - * it here. - */ + final ObbState obbState; synchronized (mObbMounts) { - if (!isObbMounted(obbInfo.filename)) { - removeObbState(mObbState); - sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED); - return; - } + obbState = mObbPathToStateMap.get(obbInfo.filename); + } - if (!mObbState.filename.equals(obbInfo.filename)) { - removeObbState(mObbState); - mObbState = mObbPathToStateMap.get(obbInfo.filename); - } + if (obbState == null) { + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED); + return; } - boolean unmounted = false; - synchronized (mObbState) { - if (!mObbState.mounted) { - sendNewStatusOrIgnore(obbInfo.filename, Environment.MEDIA_UNMOUNTED); - return; - } + if (obbState.callerUid != mObbState.callerUid) { + Slog.w(TAG, "Permission denied attempting to unmount OBB " + obbInfo.filename + + " (owned by " + obbInfo.packageName + ")"); + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED); + return; + } - int rc = StorageResultCode.OperationSucceeded; - String cmd = String.format("obb unmount %s%s", mObbState.filename, - (mForceUnmount ? " force" : "")); - try { - mConnector.doCommand(cmd); - } catch (NativeDaemonConnectorException e) { - int code = e.getCode(); - if (code == VoldResponseCode.OpFailedStorageBusy) { - rc = StorageResultCode.OperationFailedStorageBusy; - } else if (code == VoldResponseCode.OpFailedStorageNotFound) { - // If it's not mounted then we've already won. - rc = StorageResultCode.OperationSucceeded; - } else { - rc = StorageResultCode.OperationFailedInternalError; - } - } + mObbState.filename = obbInfo.filename; - if (rc == StorageResultCode.OperationSucceeded) { - mObbState.mounted = false; - unmounted = true; + int rc = StorageResultCode.OperationSucceeded; + String cmd = String.format("obb unmount %s%s", mObbState.filename, + (mForceUnmount ? " force" : "")); + try { + mConnector.doCommand(cmd); + } catch (NativeDaemonConnectorException e) { + int code = e.getCode(); + if (code == VoldResponseCode.OpFailedStorageBusy) { + rc = StorageResultCode.OperationFailedStorageBusy; + } else if (code == VoldResponseCode.OpFailedStorageNotFound) { + // If it's not mounted then we've already won. + rc = StorageResultCode.OperationSucceeded; + } else { + rc = StorageResultCode.OperationFailedInternalError; } } - if (unmounted) { - removeObbState(mObbState); + if (rc == StorageResultCode.OperationSucceeded) { + synchronized (mObbMounts) { + removeObbStateLocked(obbState); + } - sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_UNMOUNTED); + sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED); } else { - sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_MOUNTED); + Slog.w(TAG, "Could not mount OBB: " + mObbState.filename); + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT); } } public void handleError() { - removeObbState(mObbState); - - sendNewStatusOrIgnore(mObbState.filename, Environment.MEDIA_BAD_REMOVAL); + sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL); } @Override @@ -2107,7 +2056,7 @@ class MountService extends IMountService.Stub sb.append(",token="); sb.append(mObbState.token != null ? mObbState.token.toString() : "null"); sb.append(",binder="); - sb.append(mObbState.getBinder().toString()); + sb.append(mObbState.token != null ? mObbState.getBinder().toString() : "null"); sb.append('}'); return sb.toString(); } @@ -2122,16 +2071,27 @@ class MountService extends IMountService.Stub return; } - pw.println(" mObbMounts:"); - synchronized (mObbMounts) { - final Collection<List<ObbState>> obbStateLists = mObbMounts.values(); + pw.println(" mObbMounts:"); - for (final List<ObbState> obbStates : obbStateLists) { + final Iterator<Entry<IBinder, List<ObbState>>> binders = mObbMounts.entrySet().iterator(); + while (binders.hasNext()) { + Entry<IBinder, List<ObbState>> e = binders.next(); + pw.print(" Key="); pw.println(e.getKey().toString()); + final List<ObbState> obbStates = e.getValue(); for (final ObbState obbState : obbStates) { - pw.print(" "); pw.println(obbState.toString()); + pw.print(" "); pw.println(obbState.toString()); } } + + pw.println(""); + pw.println(" mObbPathToStateMap:"); + final Iterator<Entry<String, ObbState>> maps = mObbPathToStateMap.entrySet().iterator(); + while (maps.hasNext()) { + final Entry<String, ObbState> e = maps.next(); + pw.print(" "); pw.print(e.getKey()); + pw.print(" -> "); pw.println(e.getValue().toString()); + } } } } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 5afabbd..15eaa9e 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -741,10 +741,6 @@ public class NotificationManagerService extends INotificationManager.Stub throw new IllegalArgumentException("contentView required: pkg=" + pkg + " id=" + id + " notification=" + notification); } - if (notification.contentIntent == null) { - throw new IllegalArgumentException("contentIntent required: pkg=" + pkg - + " id=" + id + " notification=" + notification); - } } synchronized (mNotificationList) { diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index a3d5961..608ffe1 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -7208,6 +7208,8 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); pw.print(" installStatus="); pw.print(ps.installStatus); pw.print(" enabled="); pw.println(ps.enabled); + pw.print(" versionCode="); pw.print(ps.versionCode); + pw.print(" versionName="); pw.println(ps.pkg.mVersionName); if (ps.disabledComponents.size() > 0) { pw.println(" disabledComponents:"); for (String s : ps.disabledComponents) { diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 9d9ad26..36298d1 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -141,9 +141,7 @@ class PowerManagerService extends IPowerManager.Stub // used for noChangeLights in setPowerState() private static final int LIGHTS_MASK = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT; - static final boolean ANIMATE_SCREEN_LIGHTS = true; - static final boolean ANIMATE_BUTTON_LIGHTS = false; - static final boolean ANIMATE_KEYBOARD_LIGHTS = false; + boolean mAnimateScreenLights = true; static final int ANIM_STEPS = 60/4; // Slower animation for autobrightness changes @@ -201,15 +199,12 @@ class PowerManagerService extends IPowerManager.Stub private UnsynchronizedWakeLock mPreventScreenOnPartialLock; private UnsynchronizedWakeLock mProximityPartialLock; private HandlerThread mHandlerThread; + private HandlerThread mScreenOffThread; + private Handler mScreenOffHandler; private Handler mHandler; private final TimeoutTask mTimeoutTask = new TimeoutTask(); - private final LightAnimator mLightAnimator = new LightAnimator(); private final BrightnessState mScreenBrightness = new BrightnessState(SCREEN_BRIGHT_BIT); - private final BrightnessState mKeyboardBrightness - = new BrightnessState(KEYBOARD_BRIGHT_BIT); - private final BrightnessState mButtonBrightness - = new BrightnessState(BUTTON_BRIGHT_BIT); private boolean mStillNeedSleepNotification; private boolean mIsPowered = false; private IActivityManager mActivityService; @@ -261,6 +256,7 @@ class PowerManagerService extends IPowerManager.Stub private native void nativeInit(); private native void nativeSetPowerState(boolean screenOn, boolean screenBright); + private native void nativeStartSurfaceFlingerAnimation(); /* static PrintStream mLog; @@ -485,6 +481,35 @@ class PowerManagerService extends IPowerManager.Stub mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD); mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION); + nativeInit(); + synchronized (mLocks) { + updateNativePowerStateLocked(); + } + + mInitComplete = false; + mScreenOffThread = new HandlerThread("PowerManagerService.mScreenOffThread") { + @Override + protected void onLooperPrepared() { + mScreenOffHandler = new Handler(); + synchronized (mScreenOffThread) { + mInitComplete = true; + mScreenOffThread.notifyAll(); + } + } + }; + mScreenOffThread.start(); + + synchronized (mScreenOffThread) { + while (!mInitComplete) { + try { + mScreenOffThread.wait(); + } catch (InterruptedException e) { + // Ignore + } + } + } + + mInitComplete = false; mHandlerThread = new HandlerThread("PowerManagerService") { @Override protected void onLooperPrepared() { @@ -531,6 +556,9 @@ class PowerManagerService extends IPowerManager.Stub Resources resources = mContext.getResources(); + mAnimateScreenLights = resources.getBoolean( + com.android.internal.R.bool.config_animateScreenLights); + mUnplugTurnsOnScreen = resources.getBoolean( com.android.internal.R.bool.config_unplugTurnsOnScreen); @@ -1093,8 +1121,6 @@ class PowerManagerService extends IPowerManager.Stub pw.println(" mUseSoftwareAutoBrightness=" + mUseSoftwareAutoBrightness); pw.println(" mAutoBrightessEnabled=" + mAutoBrightessEnabled); mScreenBrightness.dump(pw, " mScreenBrightness: "); - mKeyboardBrightness.dump(pw, " mKeyboardBrightness: "); - mButtonBrightness.dump(pw, " mButtonBrightness: "); int N = mLocks.size(); pw.println(); @@ -1724,7 +1750,8 @@ class PowerManagerService extends IPowerManager.Stub // I don't think we need to check the current state here because all of these // Power.setScreenState and sendNotificationLocked can both handle being // called multiple times in the same state. -joeo - EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, reason, mTotalTouchDownTime, mTouchCycles); + EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 0, reason, mTotalTouchDownTime, + mTouchCycles); mLastTouchDown = 0; int err = setScreenStateLocked(false); if (err == 0) { @@ -1754,145 +1781,95 @@ class PowerManagerService extends IPowerManager.Stub int onMask = 0; int preferredBrightness = getPreferredBrightness(); - boolean startAnimation = false; if ((difference & KEYBOARD_BRIGHT_BIT) != 0) { - if (ANIMATE_KEYBOARD_LIGHTS) { - if ((newState & KEYBOARD_BRIGHT_BIT) == 0) { - mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_OFF, - ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS, - Power.BRIGHTNESS_ON); - } else { - mKeyboardBrightness.setTargetLocked(Power.BRIGHTNESS_ON, - ANIM_STEPS, INITIAL_KEYBOARD_BRIGHTNESS, - Power.BRIGHTNESS_OFF); - } - startAnimation = true; + if ((newState & KEYBOARD_BRIGHT_BIT) == 0) { + offMask |= KEYBOARD_BRIGHT_BIT; } else { - if ((newState & KEYBOARD_BRIGHT_BIT) == 0) { - offMask |= KEYBOARD_BRIGHT_BIT; - } else { - onMask |= KEYBOARD_BRIGHT_BIT; - } + onMask |= KEYBOARD_BRIGHT_BIT; } } if ((difference & BUTTON_BRIGHT_BIT) != 0) { - if (ANIMATE_BUTTON_LIGHTS) { - if ((newState & BUTTON_BRIGHT_BIT) == 0) { - mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_OFF, - ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS, - Power.BRIGHTNESS_ON); - } else { - mButtonBrightness.setTargetLocked(Power.BRIGHTNESS_ON, - ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS, - Power.BRIGHTNESS_OFF); - } - startAnimation = true; + if ((newState & BUTTON_BRIGHT_BIT) == 0) { + offMask |= BUTTON_BRIGHT_BIT; } else { - if ((newState & BUTTON_BRIGHT_BIT) == 0) { - offMask |= BUTTON_BRIGHT_BIT; - } else { - onMask |= BUTTON_BRIGHT_BIT; - } + onMask |= BUTTON_BRIGHT_BIT; } } if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) { - if (ANIMATE_SCREEN_LIGHTS) { - int nominalCurrentValue = -1; - // If there was an actual difference in the light state, then - // figure out the "ideal" current value based on the previous - // state. Otherwise, this is a change due to the brightness - // override, so we want to animate from whatever the current - // value is. - if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) { - switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) { - case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT: - nominalCurrentValue = preferredBrightness; - break; - case SCREEN_ON_BIT: - nominalCurrentValue = Power.BRIGHTNESS_DIM; - break; - case 0: - nominalCurrentValue = Power.BRIGHTNESS_OFF; - break; - case SCREEN_BRIGHT_BIT: - default: - // not possible - nominalCurrentValue = (int)mScreenBrightness.curValue; - break; - } + int nominalCurrentValue = -1; + // If there was an actual difference in the light state, then + // figure out the "ideal" current value based on the previous + // state. Otherwise, this is a change due to the brightness + // override, so we want to animate from whatever the current + // value is. + if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) { + switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) { + case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT: + nominalCurrentValue = preferredBrightness; + break; + case SCREEN_ON_BIT: + nominalCurrentValue = Power.BRIGHTNESS_DIM; + break; + case 0: + nominalCurrentValue = Power.BRIGHTNESS_OFF; + break; + case SCREEN_BRIGHT_BIT: + default: + // not possible + nominalCurrentValue = (int)mScreenBrightness.curValue; + break; } - int brightness = preferredBrightness; - int steps = ANIM_STEPS; - if ((newState & SCREEN_BRIGHT_BIT) == 0) { - // dim or turn off backlight, depending on if the screen is on - // the scale is because the brightness ramp isn't linear and this biases - // it so the later parts take longer. - final float scale = 1.5f; - float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness); - if (ratio > 1.0f) ratio = 1.0f; - if ((newState & SCREEN_ON_BIT) == 0) { - if ((oldState & SCREEN_BRIGHT_BIT) != 0) { - // was bright - steps = ANIM_STEPS; - } else { - // was dim - steps = (int)(ANIM_STEPS*ratio*scale); - } - brightness = Power.BRIGHTNESS_OFF; + } + int brightness = preferredBrightness; + int steps = ANIM_STEPS; + if ((newState & SCREEN_BRIGHT_BIT) == 0) { + // dim or turn off backlight, depending on if the screen is on + // the scale is because the brightness ramp isn't linear and this biases + // it so the later parts take longer. + final float scale = 1.5f; + float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness); + if (ratio > 1.0f) ratio = 1.0f; + if ((newState & SCREEN_ON_BIT) == 0) { + if ((oldState & SCREEN_BRIGHT_BIT) != 0) { + // was bright + steps = ANIM_STEPS; } else { - if ((oldState & SCREEN_ON_BIT) != 0) { - // was bright - steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale); - } else { - // was dim - steps = (int)(ANIM_STEPS*ratio); - } - if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { - // If the "stay on while plugged in" option is - // turned on, then the screen will often not - // automatically turn off while plugged in. To - // still have a sense of when it is inactive, we - // will then count going dim as turning off. - mScreenOffTime = SystemClock.elapsedRealtime(); - } - brightness = Power.BRIGHTNESS_DIM; + // was dim + steps = (int)(ANIM_STEPS*ratio*scale); } - } - long identity = Binder.clearCallingIdentity(); - try { - mBatteryStats.noteScreenBrightness(brightness); - } catch (RemoteException e) { - // Nothing interesting to do. - } finally { - Binder.restoreCallingIdentity(identity); - } - if (mScreenBrightness.setTargetLocked(brightness, - steps, INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue)) { - startAnimation = true; - } - } else { - if ((newState & SCREEN_BRIGHT_BIT) == 0) { - // dim or turn off backlight, depending on if the screen is on - if ((newState & SCREEN_ON_BIT) == 0) { - offMask |= SCREEN_BRIGHT_BIT; + brightness = Power.BRIGHTNESS_OFF; + } else { + if ((oldState & SCREEN_ON_BIT) != 0) { + // was bright + steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale); } else { - dimMask |= SCREEN_BRIGHT_BIT; + // was dim + steps = (int)(ANIM_STEPS*ratio); } - } else { - onMask |= SCREEN_BRIGHT_BIT; + if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { + // If the "stay on while plugged in" option is + // turned on, then the screen will often not + // automatically turn off while plugged in. To + // still have a sense of when it is inactive, we + // will then count going dim as turning off. + mScreenOffTime = SystemClock.elapsedRealtime(); + } + brightness = Power.BRIGHTNESS_DIM; } } - } - - if (startAnimation) { - if (mSpew) { - Slog.i(TAG, "Scheduling light animator!"); + long identity = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteScreenBrightness(brightness); + } catch (RemoteException e) { + // Nothing interesting to do. + } finally { + Binder.restoreCallingIdentity(identity); } - mHandler.removeCallbacks(mLightAnimator); - mHandler.post(mLightAnimator); + mScreenBrightness.setTargetLocked(brightness, steps, + INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); } if (offMask != 0) { @@ -1934,7 +1911,7 @@ class PowerManagerService extends IPowerManager.Stub } } - class BrightnessState { + class BrightnessState implements Runnable { final int mask; boolean initialized; @@ -1954,13 +1931,13 @@ class PowerManagerService extends IPowerManager.Stub + " delta=" + delta); } - boolean setTargetLocked(int target, int stepsToTarget, int initialValue, + void setTargetLocked(int target, int stepsToTarget, int initialValue, int nominalCurrentValue) { if (!initialized) { initialized = true; curValue = (float)initialValue; } else if (targetValue == target) { - return false; + return; } targetValue = target; delta = (targetValue - @@ -1974,7 +1951,12 @@ class PowerManagerService extends IPowerManager.Stub + noticeMe); } animating = true; - return true; + + if (mSpew) { + Slog.i(TAG, "scheduling light animator"); + } + mScreenOffHandler.removeCallbacks(this); + mScreenOffHandler.post(this); } boolean stepLocked() { @@ -2000,32 +1982,50 @@ class PowerManagerService extends IPowerManager.Stub more = false; } } - //Slog.i(TAG, "Animating brightess " + curIntValue + ": " + mask); + if (mSpew) Slog.d(TAG, "Animating curIntValue=" + curIntValue + ": " + mask); setLightBrightness(mask, curIntValue); + finishAnimation(more, curIntValue); + return more; + } + + void jumpToTarget() { + if (mSpew) Slog.d(TAG, "jumpToTarget targetValue=" + targetValue + ": " + mask); + setLightBrightness(mask, targetValue); + final int tv = targetValue; + curValue = tv; + targetValue = -1; + finishAnimation(false, tv); + } + + private void finishAnimation(boolean more, int curIntValue) { animating = more; if (!more) { if (mask == SCREEN_BRIGHT_BIT && curIntValue == Power.BRIGHTNESS_OFF) { screenOffFinishedAnimatingLocked(mScreenOffReason); } } - return more; } - } - private class LightAnimator implements Runnable { public void run() { - synchronized (mLocks) { - long now = SystemClock.uptimeMillis(); - boolean more = mScreenBrightness.stepLocked(); - if (mKeyboardBrightness.stepLocked()) { - more = true; + if (mAnimateScreenLights) { + synchronized (mLocks) { + long now = SystemClock.uptimeMillis(); + boolean more = mScreenBrightness.stepLocked(); + if (more) { + mScreenOffHandler.postAtTime(this, now+(1000/60)); + } } - if (mButtonBrightness.stepLocked()) { - more = true; + } else { + boolean animate; + boolean jump; + synchronized (mLocks) { + jump = animating; // we haven't already run this animation + animate = jump && targetValue == Power.BRIGHTNESS_OFF; // we're turning off } - if (more) { - mHandler.postAtTime(mLightAnimator, now+(1000/60)); + if (animate) { + nativeStartSurfaceFlingerAnimation(); } + mScreenBrightness.jumpToTarget(); } } } @@ -2343,49 +2343,15 @@ class PowerManagerService extends IPowerManager.Stub Slog.d(TAG, "keyboardValue " + keyboardValue); } - boolean startAnimation = false; if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) { - if (ANIMATE_SCREEN_LIGHTS) { - if (mScreenBrightness.setTargetLocked(lcdValue, - AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS, - (int)mScreenBrightness.curValue)) { - startAnimation = true; - } - } else { - int brightnessMode = (mAutoBrightessEnabled - ? LightsService.BRIGHTNESS_MODE_SENSOR - : LightsService.BRIGHTNESS_MODE_USER); - mLcdLight.setBrightness(lcdValue, brightnessMode); - } + mScreenBrightness.setTargetLocked(lcdValue, AUTOBRIGHTNESS_ANIM_STEPS, + INITIAL_SCREEN_BRIGHTNESS, (int)mScreenBrightness.curValue); } if (mButtonBrightnessOverride < 0) { - if (ANIMATE_BUTTON_LIGHTS) { - if (mButtonBrightness.setTargetLocked(buttonValue, - AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS, - (int)mButtonBrightness.curValue)) { - startAnimation = true; - } - } else { - mButtonLight.setBrightness(buttonValue); - } + mButtonLight.setBrightness(buttonValue); } if (mButtonBrightnessOverride < 0 || !mKeyboardVisible) { - if (ANIMATE_KEYBOARD_LIGHTS) { - if (mKeyboardBrightness.setTargetLocked(keyboardValue, - AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS, - (int)mKeyboardBrightness.curValue)) { - startAnimation = true; - } - } else { - mKeyboardLight.setBrightness(keyboardValue); - } - } - if (startAnimation) { - if (mDebugLightSensor) { - Slog.i(TAG, "lightSensorChangedLocked scheduling light animator"); - } - mHandler.removeCallbacks(mLightAnimator); - mHandler.post(mLightAnimator); + mKeyboardLight.setBrightness(keyboardValue); } } } @@ -2754,6 +2720,7 @@ class PowerManagerService extends IPowerManager.Stub } } + // for watchdog public void monitor() { synchronized (mLocks) { } } @@ -2773,34 +2740,23 @@ class PowerManagerService extends IPowerManager.Stub public void setBacklightBrightness(int brightness) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); // Don't let applications turn the screen all the way off - brightness = Math.max(brightness, Power.BRIGHTNESS_DIM); - mLcdLight.setBrightness(brightness); - mKeyboardLight.setBrightness(mKeyboardVisible ? brightness : 0); - mButtonLight.setBrightness(brightness); - long identity = Binder.clearCallingIdentity(); - try { - mBatteryStats.noteScreenBrightness(brightness); - } catch (RemoteException e) { - Slog.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e); - } finally { - Binder.restoreCallingIdentity(identity); - } + synchronized (mLocks) { + brightness = Math.max(brightness, Power.BRIGHTNESS_DIM); + mLcdLight.setBrightness(brightness); + mKeyboardLight.setBrightness(mKeyboardVisible ? brightness : 0); + mButtonLight.setBrightness(brightness); + long identity = Binder.clearCallingIdentity(); + try { + mBatteryStats.noteScreenBrightness(brightness); + } catch (RemoteException e) { + Slog.w(TAG, "RemoteException calling noteScreenBrightness on BatteryStatsService", e); + } finally { + Binder.restoreCallingIdentity(identity); + } - // update our animation state - if (ANIMATE_SCREEN_LIGHTS) { - mScreenBrightness.curValue = brightness; - mScreenBrightness.animating = false; - mScreenBrightness.targetValue = -1; - } - if (ANIMATE_KEYBOARD_LIGHTS) { - mKeyboardBrightness.curValue = brightness; - mKeyboardBrightness.animating = false; - mKeyboardBrightness.targetValue = -1; - } - if (ANIMATE_BUTTON_LIGHTS) { - mButtonBrightness.curValue = brightness; - mButtonBrightness.animating = false; - mButtonBrightness.targetValue = -1; + // update our animation state + mScreenBrightness.targetValue = brightness; + mScreenBrightness.jumpToTarget(); } } diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java index b1baec5..66e0214 100644 --- a/services/java/com/android/server/StatusBarManagerService.java +++ b/services/java/com/android/server/StatusBarManagerService.java @@ -72,6 +72,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub // We usually call it lights out mode, but double negatives are annoying boolean mLightsOn = true; + boolean mMenuVisible = false; + private class DisableRecord implements IBinder.DeathRecipient { String pkg; int what; @@ -246,6 +248,32 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } + /** + * Hide or show the on-screen Menu key. Only call this from the window manager, typically in + * response to a window with FLAG_NEEDS_MENU_KEY set. + */ + public void setMenuKeyVisible(final boolean visible) { + enforceStatusBar(); + + if (SPEW) Slog.d(TAG, (visible?"showing":"hiding") + " MENU key"); + + synchronized(mLock) { + if (mMenuVisible != visible) { + mMenuVisible = visible; + mHandler.post(new Runnable() { + public void run() { + if (mBar != null) { + try { + mBar.setMenuKeyVisible(visible); + } catch (RemoteException ex) { + } + } + } + }); + } + } + } + /** * This is used for the automatic version of lights-out mode. Only call this from * the window manager. @@ -317,7 +345,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub // ================================================================================ public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList, List<IBinder> notificationKeys, List<StatusBarNotification> notifications, - boolean lightsOn[]) { + boolean switches[]) { enforceStatusBarService(); Slog.i(TAG, "registerStatusBar bar=" + bar); @@ -332,7 +360,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub } } synchronized (mLock) { - lightsOn[0] = mLightsOn; + switches[0] = mLightsOn; + switches[1] = mMenuVisible; } } diff --git a/services/jni/Android.mk b/services/jni/Android.mk index 459551d..d10f54f 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -24,7 +24,8 @@ LOCAL_SHARED_LIBRARIES := \ libnativehelper \ libsystem_server \ libutils \ - libui + libui \ + libsurfaceflinger_client LOCAL_STATIC_LIBRARIES := libusbhost diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index e15e8d8..599163b 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -842,31 +842,35 @@ void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when, flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; } - const int32_t WM_ACTION_PASS_TO_USER = 1; - const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2; - const int32_t WM_ACTION_GO_TO_SLEEP = 4; + // Policy: + // - Ignore untrusted events and pass them along. + // - Ask the window manager what to do with normal events and trusted injected events. + // - For normal events wake and brighten the screen if currently off or dim. + if ((policyFlags & POLICY_FLAG_TRUSTED)) { + const int32_t WM_ACTION_PASS_TO_USER = 1; + const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2; + const int32_t WM_ACTION_GO_TO_SLEEP = 4; + + bool isScreenOn = this->isScreenOn(); + bool isScreenBright = this->isScreenBright(); - bool isScreenOn = this->isScreenOn(); - bool isScreenBright = this->isScreenBright(); - - JNIEnv* env = jniEnv(); - jint wmActions = env->CallIntMethod(mCallbacksObj, - gCallbacksClassInfo.interceptKeyBeforeQueueing, - when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn); - if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { - wmActions = 0; - } - - if (policyFlags & POLICY_FLAG_TRUSTED) { - if (! isScreenOn) { - // Key presses and releases wake the device. - policyFlags |= POLICY_FLAG_WOKE_HERE; - flags |= AKEY_EVENT_FLAG_WOKE_HERE; + JNIEnv* env = jniEnv(); + jint wmActions = env->CallIntMethod(mCallbacksObj, + gCallbacksClassInfo.interceptKeyBeforeQueueing, + when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn); + if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { + wmActions = 0; } - if (! isScreenBright) { - // Key presses and releases brighten the screen if dimmed. - policyFlags |= POLICY_FLAG_BRIGHT_HERE; + if (!(flags & POLICY_FLAG_INJECTED)) { + if (!isScreenOn) { + policyFlags |= POLICY_FLAG_WOKE_HERE; + flags |= AKEY_EVENT_FLAG_WOKE_HERE; + } + + if (!isScreenBright) { + policyFlags |= POLICY_FLAG_BRIGHT_HERE; + } } if (wmActions & WM_ACTION_GO_TO_SLEEP) { @@ -876,9 +880,11 @@ void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when, if (wmActions & WM_ACTION_POKE_USER_ACTIVITY) { android_server_PowerManagerService_userActivity(when, POWER_MANAGER_BUTTON_EVENT); } - } - if (wmActions & WM_ACTION_PASS_TO_USER) { + if (wmActions & WM_ACTION_PASS_TO_USER) { + policyFlags |= POLICY_FLAG_PASS_TO_USER; + } + } else { policyFlags |= POLICY_FLAG_PASS_TO_USER; } } @@ -888,33 +894,47 @@ void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags); #endif - if (isScreenOn()) { - // Only dispatch events when the device is awake. - // Do not wake the device. - policyFlags |= POLICY_FLAG_PASS_TO_USER; - - if ((policyFlags & POLICY_FLAG_TRUSTED) && !isScreenBright()) { - // Brighten the screen if dimmed. - policyFlags |= POLICY_FLAG_BRIGHT_HERE; + // Policy: + // - Ignore untrusted events and pass them along. + // - No special filtering for injected events required at this time. + // - Filter normal events based on screen state. + // - For normal events brighten (but do not wake) the screen if currently dim. + if ((policyFlags & POLICY_FLAG_TRUSTED) && !(policyFlags & POLICY_FLAG_INJECTED)) { + if (isScreenOn()) { + policyFlags |= POLICY_FLAG_PASS_TO_USER; + + if (!isScreenBright()) { + policyFlags |= POLICY_FLAG_BRIGHT_HERE; + } } + } else { + policyFlags |= POLICY_FLAG_PASS_TO_USER; } } bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel, const KeyEvent* keyEvent, uint32_t policyFlags) { - JNIEnv* env = jniEnv(); + // Policy: + // - Ignore untrusted events and pass them along. + // - Filter normal events and trusted injected events through the window manager policy to + // handle the HOME key and the like. + if (policyFlags & POLICY_FLAG_TRUSTED) { + JNIEnv* env = jniEnv(); + + // Note: inputChannel may be null. + jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel); + jboolean consumed = env->CallBooleanMethod(mCallbacksObj, + gCallbacksClassInfo.interceptKeyBeforeDispatching, + inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(), + keyEvent->getKeyCode(), keyEvent->getMetaState(), + keyEvent->getRepeatCount(), policyFlags); + bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching"); - // Note: inputChannel may be null. - jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel); - jboolean consumed = env->CallBooleanMethod(mCallbacksObj, - gCallbacksClassInfo.interceptKeyBeforeDispatching, - inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(), - keyEvent->getKeyCode(), keyEvent->getMetaState(), - keyEvent->getRepeatCount(), policyFlags); - bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching"); - - env->DeleteLocalRef(inputChannelObj); - return consumed && ! error; + env->DeleteLocalRef(inputChannelObj); + return consumed && ! error; + } else { + return false; + } } void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) { diff --git a/services/jni/com_android_server_PowerManagerService.cpp b/services/jni/com_android_server_PowerManagerService.cpp index 146c177..2ec20bd 100644 --- a/services/jni/com_android_server_PowerManagerService.cpp +++ b/services/jni/com_android_server_PowerManagerService.cpp @@ -20,9 +20,14 @@ #include "JNIHelp.h" #include "jni.h" + #include <limits.h> + #include <android_runtime/AndroidRuntime.h> #include <utils/Timers.h> +#include <surfaceflinger/ISurfaceComposer.h> +#include <surfaceflinger/SurfaceComposerClient.h> + #include "com_android_server_PowerManagerService.h" namespace android { @@ -119,6 +124,12 @@ static void android_server_PowerManagerService_nativeSetPowerState(JNIEnv* env, gScreenBright = screenBright; } +static void android_server_PowerManagerService_nativeStartSurfaceFlingerAnimation(JNIEnv* env, + jobject obj) { + sp<ISurfaceComposer> s(ComposerService::getComposerService()); + s->turnElectronBeamOff(0); +} + // ---------------------------------------------------------------------------- static JNINativeMethod gPowerManagerServiceMethods[] = { @@ -127,6 +138,8 @@ static JNINativeMethod gPowerManagerServiceMethods[] = { (void*) android_server_PowerManagerService_nativeInit }, { "nativeSetPowerState", "(ZZ)V", (void*) android_server_PowerManagerService_nativeSetPowerState }, + { "nativeStartSurfaceFlingerAnimation", "()V", + (void*) android_server_PowerManagerService_nativeStartSurfaceFlingerAnimation }, }; #define FIND_CLASS(var, className) \ diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp index 1d09f84..fe9a5ab 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp @@ -359,7 +359,7 @@ status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const DisplayHardwareBase::DisplayHardwareBase(const sp<SurfaceFlinger>& flinger, uint32_t displayIndex) - : mCanDraw(true) + : mCanDraw(true), mScreenAcquired(true) { mDisplayEventThread = new DisplayEventThread(flinger); if (mDisplayEventThread->initCheck() != NO_ERROR) { @@ -374,18 +374,21 @@ DisplayHardwareBase::~DisplayHardwareBase() mDisplayEventThread->requestExitAndWait(); } +void DisplayHardwareBase::setCanDraw(bool canDraw) +{ + mCanDraw = canDraw; +} bool DisplayHardwareBase::canDraw() const { - return mCanDraw; + return mCanDraw && mScreenAcquired; } void DisplayHardwareBase::releaseScreen() const { status_t err = mDisplayEventThread->releaseScreen(); if (err >= 0) { - //LOGD("screen given-up"); - mCanDraw = false; + mScreenAcquired = false; } } @@ -393,9 +396,14 @@ void DisplayHardwareBase::acquireScreen() const { status_t err = mDisplayEventThread->acquireScreen(); if (err >= 0) { - //LOGD("screen returned"); mCanDraw = true; + mScreenAcquired = true; } } +bool DisplayHardwareBase::isScreenAcquired() const +{ + return mScreenAcquired; +} + }; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h index 8369bb8..fa6a0c4 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h @@ -40,7 +40,11 @@ public: // console managment void releaseScreen() const; void acquireScreen() const; + bool isScreenAcquired() const; + bool canDraw() const; + void setCanDraw(bool canDraw); + private: class DisplayEventThreadBase : public Thread { @@ -89,6 +93,7 @@ private: sp<DisplayEventThreadBase> mDisplayEventThread; mutable int mCanDraw; + mutable int mScreenAcquired; }; }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e6bdfd1..97365aa 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -430,14 +430,14 @@ void SurfaceFlinger::handleConsoleEvents() hw.acquireScreen(); } - if (mDeferReleaseConsole && hw.canDraw()) { + if (mDeferReleaseConsole && hw.isScreenAcquired()) { // We got the release signal before the acquire signal mDeferReleaseConsole = false; hw.releaseScreen(); } if (what & eConsoleReleased) { - if (hw.canDraw()) { + if (hw.isScreenAcquired()) { hw.releaseScreen(); } else { mDeferReleaseConsole = true; @@ -1558,6 +1558,7 @@ status_t SurfaceFlinger::onTransact( case FREEZE_DISPLAY: case UNFREEZE_DISPLAY: case BOOT_FINISHED: + case TURN_ELECTRON_BEAM_OFF: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); @@ -1651,6 +1652,231 @@ status_t SurfaceFlinger::onTransact( return err; } + +// --------------------------------------------------------------------------- + +status_t SurfaceFlinger::turnElectronBeamOffImplLocked() +{ + status_t result = PERMISSION_DENIED; + + if (!GLExtensions::getInstance().haveFramebufferObject()) + return INVALID_OPERATION; + + // get screen geometry + const int dpy = 0; + const DisplayHardware& hw(graphicPlane(dpy).displayHardware()); + if (!hw.canDraw()) { + // we're already off + return NO_ERROR; + } + + const uint32_t hw_w = hw.getWidth(); + const uint32_t hw_h = hw.getHeight(); + const Region screenBounds(hw.bounds()); + GLfloat u = 1; + GLfloat v = 1; + + // make sure to clear all GL error flags + while ( glGetError() != GL_NO_ERROR ) ; + + // create a FBO + GLuint name, tname; + glGenTextures(1, &tname); + glBindTexture(GL_TEXTURE_2D, tname); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + if (glGetError() != GL_NO_ERROR) { + GLint tw = (2 << (31 - clz(hw_w))); + GLint th = (2 << (31 - clz(hw_h))); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + u = GLfloat(hw_w) / tw; + v = GLfloat(hw_h) / th; + } + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); + + GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + if (status == GL_FRAMEBUFFER_COMPLETE_OES) { + // redraw the screen entirely... + glClearColor(0,0,0,1); + glClear(GL_COLOR_BUFFER_BIT); + const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); + const size_t count = layers.size(); + for (size_t i=0 ; i<count ; ++i) { + const sp<LayerBase>& layer(layers[i]); + layer->drawForSreenShot(); + } + // back to main framebuffer + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + glDisable(GL_SCISSOR_TEST); + + GLfloat vtx[8]; + const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} }; + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tname); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, vtx); + + class s_curve_interpolator { + const float nbFrames, s, v; + public: + s_curve_interpolator(int nbFrames, float s) + : nbFrames(1.0f / (nbFrames-1)), s(s), + v(1.0f + expf(-s + 0.5f*s)) { + } + float operator()(int f) { + const float x = f * nbFrames; + return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f; + } + }; + + class v_stretch { + const GLfloat hw_w, hw_h; + public: + v_stretch(uint32_t hw_w, uint32_t hw_h) + : hw_w(hw_w), hw_h(hw_h) { + } + void operator()(GLfloat* vtx, float v) { + const GLfloat w = hw_w + (hw_w * v); + const GLfloat h = hw_h - (hw_h * v); + const GLfloat x = (hw_w - w) * 0.5f; + const GLfloat y = (hw_h - h) * 0.5f; + vtx[0] = x; vtx[1] = y; + vtx[2] = x; vtx[3] = y + h; + vtx[4] = x + w; vtx[5] = y + h; + vtx[6] = x + w; vtx[7] = y; + } + }; + + class h_stretch { + const GLfloat hw_w, hw_h; + public: + h_stretch(uint32_t hw_w, uint32_t hw_h) + : hw_w(hw_w), hw_h(hw_h) { + } + void operator()(GLfloat* vtx, float v) { + const GLfloat w = hw_w - (hw_w * v); + const GLfloat h = 1.0f; + const GLfloat x = (hw_w - w) * 0.5f; + const GLfloat y = (hw_h - h) * 0.5f; + vtx[0] = x; vtx[1] = y; + vtx[2] = x; vtx[3] = y + h; + vtx[4] = x + w; vtx[5] = y + h; + vtx[6] = x + w; vtx[7] = y; + } + }; + + // the full animation is 24 frames + const int nbFrames = 12; + + v_stretch vverts(hw_w, hw_h); + s_curve_interpolator itr(nbFrames, 7.5f); + s_curve_interpolator itg(nbFrames, 8.0f); + s_curve_interpolator itb(nbFrames, 8.5f); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + for (int i=0 ; i<nbFrames ; i++) { + float x, y, w, h; + const float vr = itr(i); + const float vg = itg(i); + const float vb = itb(i); + + // clear screen + glColorMask(1,1,1,1); + glClear(GL_COLOR_BUFFER_BIT); + glEnable(GL_TEXTURE_2D); + + // draw the red plane + vverts(vtx, vr); + glColorMask(1,0,0,1); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // draw the green plane + vverts(vtx, vg); + glColorMask(0,1,0,1); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // draw the blue plane + vverts(vtx, vb); + glColorMask(0,0,1,1); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // draw the white highlight (we use the last vertices) + glDisable(GL_TEXTURE_2D); + glColorMask(1,1,1,1); + glColor4f(vg, vg, vg, 1); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + hw.flip(screenBounds); + } + + h_stretch hverts(hw_w, hw_h); + glDisable(GL_BLEND); + glDisable(GL_TEXTURE_2D); + glColorMask(1,1,1,1); + for (int i=0 ; i<nbFrames ; i++) { + const float v = itg(i); + hverts(vtx, v); + glClear(GL_COLOR_BUFFER_BIT); + glColor4f(1-v, 1-v, 1-v, 1); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + hw.flip(screenBounds); + } + + glColorMask(1,1,1,1); + glEnable(GL_SCISSOR_TEST); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + result = NO_ERROR; + } else { + // release FBO resources + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + result = BAD_VALUE; + } + + glDeleteFramebuffersOES(1, &name); + glDeleteTextures(1, &tname); + + if (result == NO_ERROR) { + DisplayHardware& hw(graphicPlane(dpy).editDisplayHardware()); + hw.setCanDraw(false); + } + + return result; +} + +status_t SurfaceFlinger::turnElectronBeamOff(int32_t mode) +{ + if (!GLExtensions::getInstance().haveFramebufferObject()) + return INVALID_OPERATION; + + class MessageTurnElectronBeamOff : public MessageBase { + SurfaceFlinger* flinger; + status_t result; + public: + MessageTurnElectronBeamOff(SurfaceFlinger* flinger) + : flinger(flinger), result(PERMISSION_DENIED) { + } + status_t getResult() const { + return result; + } + virtual bool handler() { + Mutex::Autolock _l(flinger->mStateLock); + result = flinger->turnElectronBeamOffImplLocked(); + return true; + } + }; + + sp<MessageBase> msg = new MessageTurnElectronBeamOff(this); + status_t res = postMessageSync(msg); + if (res == NO_ERROR) { + res = static_cast<MessageTurnElectronBeamOff*>( msg.get() )->getResult(); + } + return res; +} + // --------------------------------------------------------------------------- status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, @@ -2115,6 +2341,10 @@ const DisplayHardware& GraphicPlane::displayHardware() const { return *mHw; } +DisplayHardware& GraphicPlane::editDisplayHardware() { + return *mHw; +} + const Transform& GraphicPlane::transform() const { return mGlobalTransform; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 732e57e..3470d87 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -141,6 +141,7 @@ public: int getHeight() const; const DisplayHardware& displayHardware() const; + DisplayHardware& editDisplayHardware(); const Transform& transform() const; EGLDisplay getEGLDisplay() const; @@ -200,6 +201,7 @@ public: PixelFormat* format, uint32_t reqWidth, uint32_t reqHeight); + virtual status_t turnElectronBeamOff(int32_t mode); void screenReleased(DisplayID dpy); void screenAcquired(DisplayID dpy); @@ -326,6 +328,8 @@ private: uint32_t* width, uint32_t* height, PixelFormat* format, uint32_t reqWidth = 0, uint32_t reqHeight = 0); + status_t turnElectronBeamOffImplLocked(); + friend class FreezeLock; sp<FreezeLock> getFreezeLock() const; inline void incFreezeCount() { |