diff options
Diffstat (limited to 'services')
34 files changed, 1717 insertions, 384 deletions
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index fde1490..c7c9d29 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -36,6 +36,7 @@ import android.hardware.TriggerEventListener; import android.hardware.display.DisplayManager; import android.net.INetworkPolicyManager; import android.net.Uri; +import android.os.BatteryStats; import android.os.Binder; import android.os.Environment; import android.os.FileUtils; @@ -54,9 +55,11 @@ import android.provider.Settings; import android.util.ArrayMap; import android.util.ArraySet; import android.util.KeyValueListParser; +import android.util.MutableLong; +import android.util.Pair; import android.util.Slog; +import android.util.SparseArray; import android.util.SparseBooleanArray; -import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.Xml; import android.view.Display; @@ -177,7 +180,13 @@ public class DeviceIdleController extends SystemService * List of end times for UIDs that are temporarily marked as being allowed to access * the network and acquire wakelocks. Times are in milliseconds. */ - private final SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray(); + private final SparseArray<Pair<MutableLong, String>> mTempWhitelistAppIdEndTimes + = new SparseArray<>(); + + /** + * Callback to the NetworkPolicyManagerService to tell it that the temp whitelist has changed. + */ + Runnable mNetworkPolicyTempWhitelistCallback; /** * Current app IDs of temporarily whitelist apps for high-priority messages. @@ -242,6 +251,8 @@ public class DeviceIdleController extends SystemService private static final String KEY_MIN_TIME_TO_ALARM = "min_time_to_alarm"; private static final String KEY_MAX_TEMP_APP_WHITELIST_DURATION = "max_temp_app_whitelist_duration"; + private static final String KEY_MMS_TEMP_APP_WHITELIST_DURATION = + "mms_temp_app_whitelist_duration"; /** * This is the time, after becoming inactive, at which we start looking at the @@ -339,6 +350,13 @@ public class DeviceIdleController extends SystemService */ public long MAX_TEMP_APP_WHITELIST_DURATION; + /** + * Amount of time we would like to whitelist an app that is receiving an MMS. + * @see Settings.Global#DEVICE_IDLE_CONSTANTS + * @see #KEY_MMS_TEMP_APP_WHITELIST_DURATION + */ + public long MMS_TEMP_APP_WHITELIST_DURATION; + private final ContentResolver mResolver; private final KeyValueListParser mParser = new KeyValueListParser(','); @@ -388,8 +406,10 @@ public class DeviceIdleController extends SystemService 2f); MIN_TIME_TO_ALARM = mParser.getLong(KEY_MIN_TIME_TO_ALARM, !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L); - MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong(KEY_MAX_TEMP_APP_WHITELIST_DURATION, - 5 * 60 * 1000L); + MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong( + KEY_MAX_TEMP_APP_WHITELIST_DURATION, 5 * 60 * 1000L); + MMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong( + KEY_MMS_TEMP_APP_WHITELIST_DURATION, 60 * 1000L); } } @@ -441,6 +461,10 @@ public class DeviceIdleController extends SystemService pw.print(" "); pw.print(KEY_MAX_TEMP_APP_WHITELIST_DURATION); pw.print("="); TimeUtils.formatDuration(MAX_TEMP_APP_WHITELIST_DURATION, pw); pw.println(); + + pw.print(" "); pw.print(KEY_MMS_TEMP_APP_WHITELIST_DURATION); pw.print("="); + TimeUtils.formatDuration(MMS_TEMP_APP_WHITELIST_DURATION, pw); + pw.println(); } } @@ -565,7 +589,7 @@ public class DeviceIdleController extends SystemService } @Override public void addPowerSaveTempWhitelistApp(String packageName, long duration, - int userId) throws RemoteException { + int userId, String reason) throws RemoteException { getContext().enforceCallingPermission( Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, "No permission to change device idle whitelist"); @@ -580,12 +604,19 @@ public class DeviceIdleController extends SystemService final long token = Binder.clearCallingIdentity(); try { DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(callingUid, - packageName, duration, userId); + packageName, duration, userId, true, reason); } finally { Binder.restoreCallingIdentity(token); } } + @Override public long addPowerSaveTempWhitelistAppForMms(String packageName, + int userId, String reason) throws RemoteException { + long duration = mConstants.MMS_TEMP_APP_WHITELIST_DURATION; + addPowerSaveTempWhitelistApp(packageName, duration, userId, reason); + return duration; + } + @Override public void exitIdle(String reason) { getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null); @@ -598,8 +629,13 @@ public class DeviceIdleController extends SystemService } public final class LocalService { - public void addPowerSaveTempWhitelistAppDirect(int appId, long duration) { - addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration); + public void addPowerSaveTempWhitelistAppDirect(int appId, long duration, boolean sync, + String reason) { + addPowerSaveTempWhitelistAppDirectInternal(0, appId, duration, sync, reason); + } + + public void setNetworkPolicyTempWhitelistCallback(Runnable callback) { + setNetworkPolicyTempWhitelistCallbackInternal(callback); } } @@ -777,11 +813,11 @@ public class DeviceIdleController extends SystemService * app an exemption to access network and acquire wakelocks. */ public void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName, - long duration, int userId) { + long duration, int userId, boolean sync, String reason) { try { int uid = getContext().getPackageManager().getPackageUid(packageName, userId); int appId = UserHandle.getAppId(uid); - addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration); + addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration, sync, reason); } catch (NameNotFoundException e) { } } @@ -791,8 +827,9 @@ public class DeviceIdleController extends SystemService * app an exemption to access network and acquire wakelocks. */ public void addPowerSaveTempWhitelistAppDirectInternal(int callingUid, int appId, - long duration) { + long duration, boolean sync, String reason) { final long timeNow = SystemClock.elapsedRealtime(); + Runnable networkPolicyTempWhitelistCallback = null; synchronized (this) { int callingAppId = UserHandle.getAppId(callingUid); if (callingAppId >= Process.FIRST_APPLICATION_UID) { @@ -802,19 +839,45 @@ public class DeviceIdleController extends SystemService } } duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION); - long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId); + Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(appId); + final boolean newEntry = entry == null; // Set the new end time - mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration); + if (newEntry) { + entry = new Pair<>(new MutableLong(0), reason); + mTempWhitelistAppIdEndTimes.put(appId, entry); + } + entry.first.value = timeNow + duration; if (DEBUG) { Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist"); } - if (currentEndTime == 0) { + if (newEntry) { // No pending timeout for the app id, post a delayed message + try { + mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_START, + reason, appId); + } catch (RemoteException e) { + } postTempActiveTimeoutMessage(appId, duration); updateTempWhitelistAppIdsLocked(); + if (mNetworkPolicyTempWhitelistCallback != null) { + if (!sync) { + mHandler.post(mNetworkPolicyTempWhitelistCallback); + } else { + networkPolicyTempWhitelistCallback = mNetworkPolicyTempWhitelistCallback; + } + } reportTempWhitelistChangedLocked(); } } + if (networkPolicyTempWhitelistCallback != null) { + networkPolicyTempWhitelistCallback.run(); + } + } + + public void setNetworkPolicyTempWhitelistCallbackInternal(Runnable callback) { + synchronized (this) { + mNetworkPolicyTempWhitelistCallback = callback; + } } private void postTempActiveTimeoutMessage(int uid, long delay) { @@ -825,21 +888,26 @@ public class DeviceIdleController extends SystemService void checkTempAppWhitelistTimeout(int uid) { final long timeNow = SystemClock.elapsedRealtime(); synchronized (this) { - long endTime = mTempWhitelistAppIdEndTimes.get(uid); - if (endTime == 0) { + Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.get(uid); + if (entry == null) { // Nothing to do return; } - if (timeNow >= endTime) { + if (timeNow >= entry.first.value) { mTempWhitelistAppIdEndTimes.delete(uid); if (DEBUG) { Slog.d(TAG, "Removing UID " + uid + " from temp whitelist"); } updateTempWhitelistAppIdsLocked(); reportTempWhitelistChangedLocked(); + try { + mBatteryStats.noteEvent(BatteryStats.HistoryItem.EVENT_TEMP_WHITELIST_FINISH, + entry.second, uid); + } catch (RemoteException e) { + } } else { // Need more time - postTempActiveTimeoutMessage(uid, endTime - timeNow); + postTempActiveTimeoutMessage(uid, entry.first.value - timeNow); } } } @@ -1101,7 +1169,7 @@ public class DeviceIdleController extends SystemService } void readConfigFileLocked() { - Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile()); + if (DEBUG) Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile()); mPowerSaveWhitelistUserApps.clear(); FileInputStream stream; try { @@ -1370,11 +1438,14 @@ public class DeviceIdleController extends SystemService while (i < args.length) { arg = args[i]; i++; - addPowerSaveTempWhitelistAppInternal(0, arg, 10000L, userId); + addPowerSaveTempWhitelistAppInternal(0, arg, 10000L, userId, true, + "shell"); + pw.println("Added: " + arg); } } finally { Binder.restoreCallingIdentity(token); } + return; } else if (arg.length() > 0 && arg.charAt(0) == '-'){ pw.println("Unknown option: " + arg); return; @@ -1421,8 +1492,10 @@ public class DeviceIdleController extends SystemService pw.print(" UID="); pw.print(mTempWhitelistAppIdEndTimes.keyAt(i)); pw.print(": "); - TimeUtils.formatDuration(mTempWhitelistAppIdEndTimes.valueAt(i), timeNow, pw); - pw.println(); + Pair<MutableLong, String> entry = mTempWhitelistAppIdEndTimes.valueAt(i); + TimeUtils.formatDuration(entry.first.value, timeNow, pw); + pw.print(" - "); + pw.println(entry.second); } } size = mTempWhitelistAppIdArray != null ? mTempWhitelistAppIdArray.length : 0; diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java index 41ce25d..5388f10 100644 --- a/services/core/java/com/android/server/DockObserver.java +++ b/services/core/java/com/android/server/DockObserver.java @@ -134,7 +134,8 @@ final class DockObserver extends SystemService { if (mAllowTheaterModeWakeFromDock || Settings.Global.getInt(getContext().getContentResolver(), Settings.Global.THEATER_MODE_ON, 0) == 0) { - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + mPowerManager.wakeUp(SystemClock.uptimeMillis(), + "android.server:DOCK"); } updateLocked(); } diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index bc61c3d..0e158a2 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -2602,8 +2602,15 @@ class MountService extends IMountService.Stub boolean foundPrimary = false; final int userId = UserHandle.getUserId(uid); - final boolean reportUnmounted = !mMountServiceInternal.hasExternalStorage( - uid, packageName); + final boolean reportUnmounted; + + final long identity = Binder.clearCallingIdentity(); + try { + reportUnmounted = !mMountServiceInternal.hasExternalStorage( + uid, packageName); + } finally { + Binder.restoreCallingIdentity(identity); + } synchronized (mLock) { for (int i = 0; i < mVolumes.size(); i++) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 5bfca10..3bf6fde 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -18,10 +18,7 @@ package com.android.server.am; import static android.Manifest.permission.INTERACT_ACROSS_USERS; import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL; -import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.START_TASKS_FROM_RECENTS; -import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; -import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; @@ -3516,8 +3513,8 @@ public final class ActivityManagerService extends ActivityManagerNative intent.setComponent(new ComponentName( ri.activityInfo.packageName, ri.activityInfo.name)); mStackSupervisor.startActivityLocked(null, intent, null, ri.activityInfo, - null, null, null, null, 0, 0, 0, null, 0, 0, 0, null, false, null, null, - null); + null, null, null, null, 0, 0, 0, null, 0, 0, 0, null, false, false, + null, null, null); } } } @@ -3803,13 +3800,14 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, - profilerInfo, null, null, options, userId, null, null); + profilerInfo, null, null, options, false, userId, null, null); } @Override public final int startActivityAsCaller(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, - int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) { + int startFlags, ProfilerInfo profilerInfo, Bundle options, boolean ignoreTargetSecurity, + int userId) { // This is very dangerous -- it allows you to perform a start activity (including // permission grants) as any app that may launch one of your own activities. So @@ -3843,6 +3841,16 @@ public final class ActivityManagerService extends ActivityManagerNative + sourceRecord.launchedFromUid); } } + if (ignoreTargetSecurity) { + if (intent.getComponent() == null) { + throw new SecurityException( + "Component must be specified with ignoreTargetSecurity"); + } + if (intent.getSelector() != null) { + throw new SecurityException( + "Selector not allowed with ignoreTargetSecurity"); + } + } targetUid = sourceRecord.launchedFromUid; targetPackage = sourceRecord.launchedFromPackage; } @@ -3855,7 +3863,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { int ret = mStackSupervisor.startActivityMayWait(null, targetUid, targetPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null, - null, null, options, userId, null, null); + null, null, options, ignoreTargetSecurity, userId, null, null); return ret; } catch (SecurityException e) { // XXX need to figure out how to propagate to original app. @@ -3884,7 +3892,7 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, profilerInfo, res, null, - options, userId, null, null); + options, false, userId, null, null); return res; } @@ -3898,7 +3906,7 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. int ret = mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, - null, null, config, options, userId, null, null); + null, null, config, options, false, userId, null, null); return ret; } @@ -3956,7 +3964,7 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. return mStackSupervisor.startActivityMayWait(null, callingUid, callingPackage, intent, resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo, null, - null, options, userId, null, null); + null, options, false, userId, null, null); } @Override @@ -4067,7 +4075,7 @@ public final class ActivityManagerService extends ActivityManagerNative int res = mStackSupervisor.startActivityLocked(r.app.thread, intent, r.resolvedType, aInfo, null, null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1, r.launchedFromUid, r.launchedFromPackage, - -1, r.launchedFromUid, 0, options, false, null, null, null); + -1, r.launchedFromUid, 0, options, false, false, null, null, null); Binder.restoreCallingIdentity(origId); r.finishing = wasFinishing; @@ -4125,7 +4133,7 @@ public final class ActivityManagerService extends ActivityManagerNative // TODO: Switch to user app stacks here. int ret = mStackSupervisor.startActivityMayWait(null, uid, callingPackage, intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, - null, null, null, options, userId, container, inTask); + null, null, null, options, false, userId, container, inTask); return ret; } @@ -6355,7 +6363,7 @@ public final class ActivityManagerService extends ActivityManagerNative } }, 0, null, null, - android.Manifest.permission.RECEIVE_BOOT_COMPLETED, + new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID, userId); } @@ -10801,6 +10809,8 @@ public final class ActivityManagerService extends ActivityManagerNative } // We are now ready to launch the assist activity. + IResultReceiver sendReceiver = null; + Bundle sendBundle = null; synchronized (this) { buildAssistBundleLocked(pae, extras); boolean exists = mPendingAssistExtras.remove(pae); @@ -10809,19 +10819,21 @@ public final class ActivityManagerService extends ActivityManagerNative // Timed out. return; } - if (pae.receiver != null) { + if ((sendReceiver=pae.receiver) != null) { // Caller wants result sent back to them. - Bundle topBundle = new Bundle(); - topBundle.putBundle("data", pae.extras); - topBundle.putParcelable("structure", pae.structure); - topBundle.putParcelable("content", pae.content); - try { - pae.receiver.send(0, topBundle); - } catch (RemoteException e) { - } - return; + sendBundle = new Bundle(); + sendBundle.putBundle("data", pae.extras); + sendBundle.putParcelable("structure", pae.structure); + sendBundle.putParcelable("content", pae.content); } } + if (sendReceiver != null) { + try { + sendReceiver.send(0, sendBundle); + } catch (RemoteException e) { + } + return; + } long ident = Binder.clearCallingIdentity(); try { @@ -11773,7 +11785,7 @@ public final class ActivityManagerService extends ActivityManagerNative throws RemoteException { } }, 0, null, null, - INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE, + new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } catch (Throwable t) { Slog.wtf(TAG, "Failed sending first user broadcasts", t); @@ -16327,7 +16339,7 @@ public final class ActivityManagerService extends ActivityManagerNative private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, - Bundle resultExtras, String requiredPermission, int appOp, Bundle options, + Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = new Intent(intent); @@ -16580,9 +16592,9 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, msg); throw new SecurityException(msg); } - if (requiredPermission != null) { + if (requiredPermissions != null && requiredPermissions.length > 0) { Slog.w(TAG, "Can't broadcast sticky intent " + intent - + " and enforce permission " + requiredPermission); + + " and enforce permissions " + Arrays.toString(requiredPermissions)); return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION; } if (intent.getComponent() != null) { @@ -16690,7 +16702,7 @@ public final class ActivityManagerService extends ActivityManagerNative // components to be launched. final BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, - callerPackage, callingPid, callingUid, resolvedType, requiredPermission, + callerPackage, callingPid, callingUid, resolvedType, requiredPermissions, appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r); @@ -16780,7 +16792,7 @@ public final class ActivityManagerService extends ActivityManagerNative BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, - requiredPermission, appOp, brOptions, receivers, resultTo, resultCode, + requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r @@ -16829,7 +16841,7 @@ public final class ActivityManagerService extends ActivityManagerNative public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, - String requiredPermission, int appOp, Bundle options, + String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) { enforceNotIsolatedCaller("broadcastIntent"); synchronized(this) { @@ -16842,13 +16854,14 @@ public final class ActivityManagerService extends ActivityManagerNative int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, - requiredPermission, appOp, null, serialized, sticky, + requiredPermissions, appOp, null, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; } } + int broadcastIntentInPackage(String packageName, int uid, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, @@ -16858,9 +16871,12 @@ public final class ActivityManagerService extends ActivityManagerNative intent = verifyBroadcastLocked(intent); final long origId = Binder.clearCallingIdentity(); + String[] requiredPermissions = requiredPermission == null ? null + : new String[] {requiredPermission}; int res = broadcastIntentLocked(null, packageName, intent, resolvedType, - resultTo, resultCode, resultData, resultExtras, requiredPermission, - AppOpsManager.OP_NONE, options, serialized, sticky, -1, uid, userId); + resultTo, resultCode, resultData, resultExtras, + requiredPermissions, AppOpsManager.OP_NONE, options, serialized, + sticky, -1, uid, userId); Binder.restoreCallingIdentity(origId); return res; } @@ -19795,7 +19811,7 @@ public final class ActivityManagerService extends ActivityManagerNative int sendingUser) throws RemoteException { } }, 0, null, null, - INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE, + new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } } @@ -19857,8 +19873,9 @@ public final class ActivityManagerService extends ActivityManagerNative intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, - android.Manifest.permission.MANAGE_USERS, AppOpsManager.OP_NONE, - null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + new String[] {android.Manifest.permission.MANAGE_USERS}, + AppOpsManager.OP_NONE, null, false, false, MY_PID, Process.SYSTEM_UID, + UserHandle.USER_ALL); } } finally { Binder.restoreCallingIdentity(ident); @@ -20041,8 +20058,9 @@ public final class ActivityManagerService extends ActivityManagerNative intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, - android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE, - null, true, false, MY_PID, Process.SYSTEM_UID, userId); + new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, + AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID, + userId); } } } @@ -20180,7 +20198,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Kick things off. broadcastIntentLocked(null, null, stoppingIntent, null, stoppingReceiver, 0, null, null, - INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE, + new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } finally { Binder.restoreCallingIdentity(ident); @@ -20519,7 +20537,7 @@ public final class ActivityManagerService extends ActivityManagerNative } return mStackSupervisor.startActivityMayWait(appThread, -1, callingPackage, intent, resolvedType, null, null, null, null, 0, 0, null, null, - null, options, callingUser, null, tr); + null, options, false, callingUser, null, tr); } @Override diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 470bbb0..e57e3ff 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -3117,7 +3117,7 @@ final class ActivityStack { int res = mStackSupervisor.startActivityLocked(srec.app.thread, destIntent, null, aInfo, null, null, parent.appToken, null, 0, -1, parent.launchedFromUid, parent.launchedFromPackage, - -1, parent.launchedFromUid, 0, null, true, null, null, null); + -1, parent.launchedFromUid, 0, null, false, true, null, null, null); foundParentInTask = res == ActivityManager.START_SUCCESS; } catch (RemoteException e) { foundParentInTask = false; diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index c12aff6..05c58d7 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -911,7 +911,8 @@ public final class ActivityStackSupervisor implements DisplayListener { null /* voiceSession */, null /* voiceInteractor */, null /* resultTo */, null /* resultWho */, 0 /* requestCode */, 0 /* callingPid */, 0 /* callingUid */, null /* callingPackage */, 0 /* realCallingPid */, 0 /* realCallingUid */, - 0 /* startFlags */, null /* options */, false /* componentSpecified */, + 0 /* startFlags */, null /* options */, false /* ignoreTargetSecurity */, + false /* componentSpecified */, null /* outActivity */, null /* container */, null /* inTask */); if (inResumeTopActivity) { // If we are in resume section already, home activity will be initialized, but not @@ -926,7 +927,8 @@ public final class ActivityStackSupervisor implements DisplayListener { IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, WaitResult outResult, Configuration config, - Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) { + Bundle options, boolean ignoreTargetSecurity, int userId, + IActivityContainer iContainer, TaskRecord inTask) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -1043,7 +1045,7 @@ public final class ActivityStackSupervisor implements DisplayListener { int res = startActivityLocked(caller, intent, resolvedType, aInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode, callingPid, callingUid, callingPackage, - realCallingPid, realCallingUid, startFlags, options, + realCallingPid, realCallingUid, startFlags, options, ignoreTargetSecurity, componentSpecified, null, container, inTask); Binder.restoreCallingIdentity(origId); @@ -1159,7 +1161,7 @@ public final class ActivityStackSupervisor implements DisplayListener { int res = startActivityLocked(caller, intent, resolvedTypes[i], aInfo, null, null, resultTo, null, -1, callingPid, callingUid, callingPackage, callingPid, callingUid, - 0, theseOptions, componentSpecified, outActivity, null, null); + 0, theseOptions, false, componentSpecified, outActivity, null, null); if (res < 0) { return res; } @@ -1400,8 +1402,8 @@ public final class ActivityStackSupervisor implements DisplayListener { IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, String callingPackage, int realCallingPid, int realCallingUid, int startFlags, Bundle options, - boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container, - TaskRecord inTask) { + boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity, + ActivityContainer container, TaskRecord inTask) { int err = ActivityManager.START_SUCCESS; ProcessRecord callerApp = null; @@ -1546,7 +1548,7 @@ public final class ActivityStackSupervisor implements DisplayListener { if (startAnyPerm != PERMISSION_GRANTED) { final int componentRestriction = getComponentRestrictionForCallingPackage( - aInfo, callingPackage, callingPid, callingUid); + aInfo, callingPackage, callingPid, callingUid, ignoreTargetSecurity); final int actionRestriction = getActionRestrictionForCallingPackage( intent.getAction(), callingPackage, callingPid, callingUid); @@ -1675,13 +1677,13 @@ public final class ActivityStackSupervisor implements DisplayListener { } private int getComponentRestrictionForCallingPackage(ActivityInfo activityInfo, - String callingPackage, int callingPid, int callingUid) { + String callingPackage, int callingPid, int callingUid, boolean ignoreTargetSecurity) { if (activityInfo.permission == null) { return ACTIVITY_RESTRICTION_NONE; } - if (mService.checkComponentPermission(activityInfo.permission, callingPid, callingUid, - activityInfo.applicationInfo.uid, activityInfo.exported) + if (!ignoreTargetSecurity && mService.checkComponentPermission(activityInfo.permission, + callingPid, callingUid, activityInfo.applicationInfo.uid, activityInfo.exported) == PackageManager.PERMISSION_DENIED) { return ACTIVITY_RESTRICTION_PERMISSION; } @@ -1693,7 +1695,9 @@ public final class ActivityStackSupervisor implements DisplayListener { if (mService.mAppOpsService.noteOperation(opCode, callingUid, callingPackage) != AppOpsManager.MODE_ALLOWED) { - return ACTIVITY_RESTRICTION_APPOP; + if (!ignoreTargetSecurity) { + return ACTIVITY_RESTRICTION_APPOP; + } } return ACTIVITY_RESTRICTION_NONE; @@ -4296,7 +4300,7 @@ public final class ActivityStackSupervisor implements DisplayListener { intent.addFlags(FORCE_NEW_TASK_FLAGS); return startActivityMayWait(null, -1, null, intent, mimeType, null, null, null, null, - 0, 0, null, null, null, null, userId, this, null); + 0, 0, null, null, null, null, false, userId, this, null); } @Override diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 070813b..4b0b924 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -101,8 +101,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub mUpdateFlags = 0; } updateExternalStats((String)msg.obj, updateFlags); - synchronized (this) { - synchronized (mStats) { + + // other parts of the system could be calling into us + // from mStats in order to report of changes. We must grab the mStats + // lock before grabbing our own or we'll end up in a deadlock. + synchronized (mStats) { + synchronized (this) { final int numUidsToRemove = mUidsToRemove.size(); for (int i = 0; i < numUidsToRemove; i++) { mStats.removeIsolatedUidLocked(mUidsToRemove.get(i)); @@ -489,6 +493,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub } } + public void noteWakeUp(String reason, int reasonUid) { + enforceCallingPermission(); + synchronized (mStats) { + mStats.noteWakeUpLocked(reason, reasonUid); + } + } + public void noteInteractive(boolean interactive) { enforceCallingPermission(); synchronized (mStats) { diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 30aa411..91d97ef 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -175,7 +175,7 @@ public final class BroadcastQueue { DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController; if (dic != null) { dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1), - msg.arg2); + msg.arg2, true, (String)msg.obj); } } break; } @@ -493,59 +493,74 @@ public final class BroadcastQueue { } } } - if (!skip) { - int perm = mService.checkComponentPermission(r.requiredPermission, - filter.receiverList.pid, filter.receiverList.uid, -1, true); - if (perm != PackageManager.PERMISSION_GRANTED) { - Slog.w(TAG, "Permission Denial: receiving " - + r.intent.toString() - + " to " + filter.receiverList.app - + " (pid=" + filter.receiverList.pid - + ", uid=" + filter.receiverList.uid + ")" - + " requires " + r.requiredPermission - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - } - int appOp = AppOpsManager.OP_NONE; - if (r.requiredPermission != null) { - appOp = AppOpsManager.permissionToOpCode(r.requiredPermission); - if (appOp != AppOpsManager.OP_NONE - && mService.mAppOpsService.noteOperation(appOp, - filter.receiverList.uid, filter.packageName) - != AppOpsManager.MODE_ALLOWED) { - Slog.w(TAG, "Appop Denial: receiving " + if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) { + for (int i = 0; i < r.requiredPermissions.length; i++) { + String requiredPermission = r.requiredPermissions[i]; + int perm = mService.checkComponentPermission(requiredPermission, + filter.receiverList.pid, filter.receiverList.uid, -1, true); + if (perm != PackageManager.PERMISSION_GRANTED) { + Slog.w(TAG, "Permission Denial: receiving " + r.intent.toString() + " to " + filter.receiverList.app + " (pid=" + filter.receiverList.pid + ", uid=" + filter.receiverList.uid + ")" - + " requires appop " + AppOpsManager.permissionToOp( - r.requiredPermission) + + " requires " + requiredPermission + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")"); skip = true; + break; } - } - if (!skip && r.appOp != appOp && r.appOp != AppOpsManager.OP_NONE - && mService.mAppOpsService.noteOperation(r.appOp, - filter.receiverList.uid, filter.packageName) - != AppOpsManager.MODE_ALLOWED) { + int appOp = AppOpsManager.permissionToOpCode(requiredPermission); + if (appOp != r.appOp + && mService.mAppOpsService.noteOperation(appOp, + filter.receiverList.uid, filter.packageName) + != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: receiving " + r.intent.toString() + " to " + filter.receiverList.app + " (pid=" + filter.receiverList.pid + ", uid=" + filter.receiverList.uid + ")" + " requires appop " + AppOpsManager.permissionToOp( - r.requiredPermission) + requiredPermission) + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")"); skip = true; + break; + } } } + if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) { + int perm = mService.checkComponentPermission(null, + filter.receiverList.pid, filter.receiverList.uid, -1, true); + if (perm != PackageManager.PERMISSION_GRANTED) { + Slog.w(TAG, "Permission Denial: security check failed when receiving " + + r.intent.toString() + + " to " + filter.receiverList.app + + " (pid=" + filter.receiverList.pid + + ", uid=" + filter.receiverList.uid + ")" + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + } + } + if (!skip && r.appOp != AppOpsManager.OP_NONE + && mService.mAppOpsService.noteOperation(r.appOp, + filter.receiverList.uid, filter.packageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent.toString() + + " to " + filter.receiverList.app + + " (pid=" + filter.receiverList.pid + + ", uid=" + filter.receiverList.uid + ")" + + " requires appop " + AppOpsManager.opToName(r.appOp) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + } - if (!skip) { - skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, - r.callingPid, r.resolvedType, filter.receiverList.uid); + if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, + r.callingPid, r.resolvedType, filter.receiverList.uid)) { + return; } if (filter.receiverList.app == null || filter.receiverList.app.crashing) { @@ -597,7 +612,7 @@ public final class BroadcastQueue { } } - final void scheduleTempWhitelistLocked(int uid, long duration) { + final void scheduleTempWhitelistLocked(int uid, long duration, BroadcastRecord r) { if (duration > Integer.MAX_VALUE) { duration = Integer.MAX_VALUE; } @@ -607,7 +622,19 @@ public final class BroadcastQueue { // not that big a deal, however, because the main purpose here is to allow apps // to hold wake locks, and they will be able to acquire their wake lock immediately // it just won't be enabled until we get through this work. - mHandler.obtainMessage(SCHEDULE_TEMP_WHITELIST_MSG, uid, (int)duration).sendToTarget(); + StringBuilder b = new StringBuilder(); + b.append("broadcast:"); + UserHandle.formatUid(b, r.callingUid); + b.append(":"); + if (r.intent.getAction() != null) { + b.append(r.intent.getAction()); + } else if (r.intent.getComponent() != null) { + b.append(r.intent.getComponent().flattenToShortString()); + } else if (r.intent.getData() != null) { + b.append(r.intent.getData()); + } + mHandler.obtainMessage(SCHEDULE_TEMP_WHITELIST_MSG, uid, (int)duration, b.toString()) + .sendToTarget(); } final void processNextBroadcast(boolean fromMsg) { @@ -807,7 +834,7 @@ public final class BroadcastQueue { } else { if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { scheduleTempWhitelistLocked(filter.owningUid, - brOptions.getTemporaryAppWhitelistDuration()); + brOptions.getTemporaryAppWhitelistDuration(), r); } } return; @@ -860,51 +887,53 @@ public final class BroadcastQueue { } } if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID && - r.requiredPermission != null) { - try { - perm = AppGlobals.getPackageManager(). - checkPermission(r.requiredPermission, - info.activityInfo.applicationInfo.packageName, - UserHandle.getUserId(info.activityInfo.applicationInfo.uid)); - } catch (RemoteException e) { - perm = PackageManager.PERMISSION_DENIED; - } - if (perm != PackageManager.PERMISSION_GRANTED) { - Slog.w(TAG, "Permission Denial: receiving " - + r.intent + " to " - + component.flattenToShortString() - + " requires " + r.requiredPermission - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; - } - } - int appOp = AppOpsManager.OP_NONE; - if (!skip && r.requiredPermission != null) { - appOp = AppOpsManager.permissionToOpCode(r.requiredPermission); - if (appOp != AppOpsManager.OP_NONE - && mService.mAppOpsService.noteOperation(appOp, - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) - != AppOpsManager.MODE_ALLOWED) { - Slog.w(TAG, "Appop Denial: receiving " - + r.intent + " to " - + component.flattenToShortString() - + " requires appop " + AppOpsManager.permissionToOp( - r.requiredPermission) - + " due to sender " + r.callerPackage - + " (uid " + r.callingUid + ")"); - skip = true; + r.requiredPermissions != null && r.requiredPermissions.length > 0) { + for (int i = 0; i < r.requiredPermissions.length; i++) { + String requiredPermission = r.requiredPermissions[i]; + try { + perm = AppGlobals.getPackageManager(). + checkPermission(requiredPermission, + info.activityInfo.applicationInfo.packageName, + UserHandle + .getUserId(info.activityInfo.applicationInfo.uid)); + } catch (RemoteException e) { + perm = PackageManager.PERMISSION_DENIED; + } + if (perm != PackageManager.PERMISSION_GRANTED) { + Slog.w(TAG, "Permission Denial: receiving " + + r.intent + " to " + + component.flattenToShortString() + + " requires " + requiredPermission + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + break; + } + int appOp = AppOpsManager.permissionToOpCode(requiredPermission); + if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp + && mService.mAppOpsService.noteOperation(appOp, + info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) + != AppOpsManager.MODE_ALLOWED) { + Slog.w(TAG, "Appop Denial: receiving " + + r.intent + " to " + + component.flattenToShortString() + + " requires appop " + AppOpsManager.permissionToOp( + requiredPermission) + + " due to sender " + r.callerPackage + + " (uid " + r.callingUid + ")"); + skip = true; + break; + } } } - if (!skip && r.appOp != appOp && r.appOp != AppOpsManager.OP_NONE + if (!skip && r.appOp != AppOpsManager.OP_NONE && mService.mAppOpsService.noteOperation(r.appOp, - info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) - != AppOpsManager.MODE_ALLOWED) { + info.activityInfo.applicationInfo.uid, info.activityInfo.packageName) + != AppOpsManager.MODE_ALLOWED) { Slog.w(TAG, "Appop Denial: receiving " + r.intent + " to " + component.flattenToShortString() - + " requires appop " + AppOpsManager.permissionToOp( - r.requiredPermission) + + " requires appop " + AppOpsManager.opToName(r.appOp) + " due to sender " + r.callerPackage + " (uid " + r.callingUid + ")"); skip = true; @@ -988,7 +1017,7 @@ public final class BroadcastQueue { if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { scheduleTempWhitelistLocked(receiverUid, - brOptions.getTemporaryAppWhitelistDuration()); + brOptions.getTemporaryAppWhitelistDuration(), r); } // Broadcast is being executed, its package can't be stopped. diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index b943222..a7e6471 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -32,6 +32,7 @@ import android.util.PrintWriterPrinter; import android.util.TimeUtils; import java.io.PrintWriter; +import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Set; @@ -51,7 +52,7 @@ final class BroadcastRecord extends Binder { final boolean initialSticky; // initial broadcast from register to sticky? final int userId; // user id this broadcast was for final String resolvedType; // the resolved data type - final String requiredPermission; // a permission the caller has required + final String[] requiredPermissions; // permissions the caller has required final int appOp; // an app op that is associated with this broadcast final BroadcastOptions options; // BroadcastOptions supplied by caller final List receivers; // contains BroadcastFilter and ResolveInfo @@ -103,9 +104,11 @@ final class BroadcastRecord extends Binder { pw.print(callerApp != null ? callerApp.toShortString() : "null"); pw.print(" pid="); pw.print(callingPid); pw.print(" uid="); pw.println(callingUid); - if (requiredPermission != null || appOp != AppOpsManager.OP_NONE) { - pw.print(prefix); pw.print("requiredPermission="); pw.print(requiredPermission); - pw.print(" appOp="); pw.println(appOp); + if ((requiredPermissions != null && requiredPermissions.length > 0) + || appOp != AppOpsManager.OP_NONE) { + pw.print(prefix); pw.print("requiredPermissions="); + pw.print(Arrays.toString(requiredPermissions)); + pw.print(" appOp="); pw.println(appOp); } if (options != null) { pw.print(prefix); pw.print("options="); pw.println(options.toBundle()); @@ -184,7 +187,7 @@ final class BroadcastRecord extends Binder { BroadcastRecord(BroadcastQueue _queue, Intent _intent, ProcessRecord _callerApp, String _callerPackage, - int _callingPid, int _callingUid, String _resolvedType, String _requiredPermission, + int _callingPid, int _callingUid, String _resolvedType, String[] _requiredPermissions, int _appOp, BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, int _resultCode, String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky, boolean _initialSticky, @@ -197,7 +200,7 @@ final class BroadcastRecord extends Binder { callingPid = _callingPid; callingUid = _callingUid; resolvedType = _resolvedType; - requiredPermission = _requiredPermission; + requiredPermissions = _requiredPermissions; appOp = _appOp; options = _options; receivers = _receivers; diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java index 458928f..8813a61 100644 --- a/services/core/java/com/android/server/dreams/DreamManagerService.java +++ b/services/core/java/com/android/server/dreams/DreamManagerService.java @@ -648,7 +648,8 @@ public final class DreamManagerService extends SystemService { if (mCurrentDreamName != null && mCurrentDreamCanDoze && !mCurrentDreamName.equals(getDozeComponent())) { // May have updated the doze component, wake up - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + mPowerManager.wakeUp(SystemClock.uptimeMillis(), + "android.server.dreams:SYSPROP"); } } } diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java index 4d8d105..8871e64 100644 --- a/services/core/java/com/android/server/fingerprint/FingerprintService.java +++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java @@ -86,6 +86,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe private static final int FINGERPRINT_ACQUIRED_GOOD = 0; Handler mHandler = new Handler() { + @Override public void handleMessage(android.os.Message msg) { switch (msg.what) { case MSG_USER_SWITCHING: @@ -274,7 +275,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe Slog.w(TAG, "enroll: no fingeprintd!"); return; } - stopPendingOperations(); + stopPendingOperations(true); mEnrollClient = new ClientMonitor(token, receiver, groupId, restricted); final int timeout = (int) (ENROLLMENT_TIMEOUT_MS / MS_PER_SEC); try { @@ -315,17 +316,23 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe return 0; } - private void stopPendingOperations() { + private void stopPendingOperations(boolean initiatedByClient) { if (mEnrollClient != null) { - stopEnrollment(mEnrollClient.token, true); + stopEnrollment(mEnrollClient.token, initiatedByClient); } if (mAuthClient != null) { - stopAuthentication(mAuthClient.token, true); + stopAuthentication(mAuthClient.token, initiatedByClient); } // mRemoveClient is allowed to continue } - void stopEnrollment(IBinder token, boolean notify) { + /** + * Stop enrollment in progress and inform client if they initiated it. + * + * @param token token for client + * @param initiatedByClient if this call is the result of client action (e.g. calling cancel) + */ + void stopEnrollment(IBinder token, boolean initiatedByClient) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopEnrollment: no fingeprintd!"); @@ -333,15 +340,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } final ClientMonitor client = mEnrollClient; if (client == null || client.token != token) return; - try { - int result = daemon.cancelEnrollment(); - if (result != 0) { - Slog.w(TAG, "startEnrollCancel failed, result = " + result); + if (initiatedByClient) { + try { + int result = daemon.cancelEnrollment(); + if (result != 0) { + Slog.w(TAG, "startEnrollCancel failed, result = " + result); + } + } catch (RemoteException e) { + Slog.e(TAG, "stopEnrollment failed", e); } - } catch (RemoteException e) { - Slog.e(TAG, "stopEnrollment failed", e); - } - if (notify) { client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); } removeClient(mEnrollClient); @@ -354,7 +361,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe Slog.w(TAG, "startAuthentication: no fingeprintd!"); return; } - stopPendingOperations(); + stopPendingOperations(true); mAuthClient = new ClientMonitor(token, receiver, groupId, restricted); if (inLockoutMode()) { Slog.v(TAG, "In lockout mode; disallowing authentication"); @@ -374,7 +381,13 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } } - void stopAuthentication(IBinder token, boolean notify) { + /** + * Stop authentication in progress and inform client if they initiated it. + * + * @param token token for client + * @param initiatedByClient if this call is the result of client action (e.g. calling cancel) + */ + void stopAuthentication(IBinder token, boolean initiatedByClient) { IFingerprintDaemon daemon = getFingerprintDaemon(); if (daemon == null) { Slog.w(TAG, "stopAuthentication: no fingeprintd!"); @@ -382,15 +395,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe } final ClientMonitor client = mAuthClient; if (client == null || client.token != token) return; - try { - int result = daemon.cancelAuthentication(); - if (result != 0) { - Slog.w(TAG, "stopAuthentication failed, result=" + result); + if (initiatedByClient) { + try { + int result = daemon.cancelAuthentication(); + if (result != 0) { + Slog.w(TAG, "stopAuthentication failed, result=" + result); + } + } catch (RemoteException e) { + Slog.e(TAG, "stopAuthentication failed", e); } - } catch (RemoteException e) { - Slog.e(TAG, "stopAuthentication failed", e); - } - if (notify) { client.sendError(FingerprintManager.FINGERPRINT_ERROR_CANCELED); } removeClient(mAuthClient); @@ -486,12 +499,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe receiver = null; } + @Override public void binderDied() { token = null; removeClient(this); receiver = null; } + @Override protected void finalize() throws Throwable { try { if (token != null) { @@ -565,7 +580,8 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe // For fingerprint devices that support touch-to-wake, this will ensure the device // wakes up and turns the screen on when fingerprint is authenticated. if (mIsKeyguard && authenticated) { - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + mPowerManager.wakeUp(SystemClock.uptimeMillis(), + "android.server.fingerprint:AUTH"); } return result; } diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index c37f619..cfc5f7d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -1969,7 +1969,7 @@ public final class HdmiControlService extends SystemService { void wakeUp() { assertRunOnServiceThread(); mWakeUpMessageReceived = true; - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.hdmi:WAKE"); // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets // the intent, the sequence will continue at onWakeUp(). } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index f8f00ef..395aa27 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -147,6 +147,7 @@ import android.util.SparseIntArray; import android.util.TrustedTime; import android.util.Xml; +import com.android.server.DeviceIdleController; import com.android.server.EventLogTags; import libcore.io.IoUtils; @@ -462,9 +463,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // listen for changes to power save whitelist final IntentFilter whitelistFilter = new IntentFilter( PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED); - whitelistFilter.addAction(PowerManager.ACTION_POWER_SAVE_TEMP_WHITELIST_CHANGED); mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler); + DeviceIdleController.LocalService deviceIdleService + = LocalServices.getService(DeviceIdleController.LocalService.class); + deviceIdleService.setNetworkPolicyTempWhitelistCallback(mTempPowerSaveChangedCallback); + // watch for network interfaces to be claimed final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION); mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); @@ -512,7 +516,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } - private IUidObserver mUidObserver = new IUidObserver.Stub() { + final private IUidObserver mUidObserver = new IUidObserver.Stub() { @Override public void onUidStateChanged(int uid, int procState) throws RemoteException { synchronized (mRulesLock) { updateUidStateLocked(uid, procState); @@ -526,24 +530,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }; - private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected synchronized (mRulesLock) { - if (PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED.equals(intent.getAction())) { - updatePowerSaveWhitelistLocked(); - updateRulesForGlobalChangeLocked(false); - } else { - updatePowerSaveTempWhitelistLocked(); - updateRulesForTempWhitelistChangeLocked(); - purgePowerSaveTempWhitelistLocked(); - } + updatePowerSaveWhitelistLocked(); + updateRulesForGlobalChangeLocked(false); } } }; - private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { + final private Runnable mTempPowerSaveChangedCallback = new Runnable() { + @Override + public void run() { + synchronized (mRulesLock) { + updatePowerSaveTempWhitelistLocked(); + updateRulesForTempWhitelistChangeLocked(); + purgePowerSaveTempWhitelistLocked(); + } + } + }; + + final private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // screen-related broadcasts are protected by system, no need @@ -552,7 +561,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }; - private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mPackageReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and PACKAGE_ADDED is protected @@ -572,7 +581,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }; - private BroadcastReceiver mUidRemovedReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mUidRemovedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and UID_REMOVED is protected @@ -590,7 +599,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } }; - private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and USER_ADDED and USER_REMOVED @@ -619,7 +628,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Receiver that watches for {@link INetworkStatsService} updates, which we * use to check against {@link NetworkPolicy#warningBytes}. */ - private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mStatsReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and verified @@ -637,7 +646,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Receiver that watches for {@link Notification} control of * {@link #mRestrictBackground}. */ - private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mAllowReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and verified MANAGE_NETWORK_POLICY @@ -651,7 +660,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Receiver that watches for {@link Notification} control of * {@link NetworkPolicy#lastWarningSnooze}. */ - private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mSnoozeWarningReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and verified MANAGE_NETWORK_POLICY @@ -665,7 +674,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Receiver that watches for {@link WifiConfiguration} to be changed. */ - private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mWifiConfigReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and verified CONNECTIVITY_INTERNAL @@ -692,7 +701,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { * Receiver that watches {@link WifiInfo} state changes to infer metered * state. Ignores hints when policy is user-defined. */ - private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() { + final private BroadcastReceiver mWifiStateReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and verified CONNECTIVITY_INTERNAL @@ -732,7 +741,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** * Observer that watches for {@link INetworkManagementService} alerts. */ - private INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() { + final private INetworkManagementEventObserver mAlertObserver + = new BaseNetworkObserver() { @Override public void limitReached(String limitName, String iface) { // only someone like NMS should be calling us @@ -1985,6 +1995,10 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // state changed, push updated rules mUidState.put(uid, uidState); updateRulesForUidStateChangeLocked(uid, oldUidState, uidState); + if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState) + != isProcStateAllowedWhileIdle(uidState)) { + updateRulesForDeviceIdleLocked(); + } } } @@ -1996,6 +2010,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { if (oldUidState != ActivityManager.PROCESS_STATE_CACHED_EMPTY) { updateRulesForUidStateChangeLocked(uid, oldUidState, ActivityManager.PROCESS_STATE_CACHED_EMPTY); + if (mDeviceIdleMode) { + updateRulesForDeviceIdleLocked(); + } } } } @@ -2033,13 +2050,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + static boolean isProcStateAllowedWhileIdle(int procState) { + return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; + } + void updateRulesForDeviceIdleLocked() { if (mDeviceIdleMode) { // sync the whitelists before enable dozable chain. We don't care about the rules if // we are disabling the chain. SparseIntArray uidRules = new SparseIntArray(); final List<UserInfo> users = mUserManager.getUsers(); - for (UserInfo user : users) { + for (int ui = users.size() - 1; ui >= 0; ui--) { + UserInfo user = users.get(ui); for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) { int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); int uid = UserHandle.getUid(user.id, appId); @@ -2051,6 +2073,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { uidRules.put(uid, FIREWALL_RULE_ALLOW); } } + for (int i = mUidState.size() - 1; i >= 0; i--) { + if (isProcStateAllowedWhileIdle(mUidState.valueAt(i))) { + uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW); + } + } setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules); } enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode); diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index b23b856..7a6895f 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1837,7 +1837,7 @@ public class NotificationManagerService extends SystemService { void dumpImpl(PrintWriter pw, DumpFilter filter) { pw.print("Current Notification Manager state"); - if (filter != null) { + if (filter.filtered) { pw.print(" (filtered to "); pw.print(filter); pw.print(")"); } pw.println(':'); @@ -1865,7 +1865,7 @@ public class NotificationManagerService extends SystemService { for (int i=0; i<N; i++) { final NotificationRecord nr = mNotificationList.get(i); if (filter != null && !filter.matches(nr.sbn)) continue; - nr.dump(pw, " ", getContext()); + nr.dump(pw, " ", getContext(), filter.redact); } pw.println(" "); } @@ -1948,7 +1948,7 @@ public class NotificationManagerService extends SystemService { pw.println(" " + entry.getKey() + " -> " + r.getKey()); if (mNotificationsByKey.get(r.getKey()) != r) { pw.println("!!!!!!LEAK: Record not found in mNotificationsByKey."); - r.dump(pw, " ", getContext()); + r.dump(pw, " ", getContext(), filter.redact); } } @@ -3499,46 +3499,59 @@ public class NotificationManagerService extends SystemService { } public static final class DumpFilter { + public boolean filtered = false; public String pkgFilter; public boolean zen; public long since; public boolean stats; - private boolean all; + public boolean redact = true; public static DumpFilter parseFromArguments(String[] args) { - if (args != null && args.length == 2 && "p".equals(args[0]) - && args[1] != null && !args[1].trim().isEmpty()) { - final DumpFilter filter = new DumpFilter(); - filter.pkgFilter = args[1].trim().toLowerCase(); - return filter; - } - if (args != null && args.length == 1 && "zen".equals(args[0])) { - final DumpFilter filter = new DumpFilter(); - filter.zen = true; - filter.all = true; - return filter; - } - if (args != null && args.length >= 1 && "--stats".equals(args[0])) { - final DumpFilter filter = new DumpFilter(); - filter.stats = true; - filter.since = args.length == 2 ? Long.valueOf(args[1]) : 0; - filter.all = true; - return filter; + final DumpFilter filter = new DumpFilter(); + for (int ai = 0; ai < args.length; ai++) { + final String a = args[ai]; + if ("--noredact".equals(a) || "--reveal".equals(a)) { + filter.redact = false; + } else if ("p".equals(a) || "pkg".equals(a) || "--package".equals(a)) { + if (ai < args.length-1) { + ai++; + filter.pkgFilter = args[ai].trim().toLowerCase(); + if (filter.pkgFilter.isEmpty()) { + filter.pkgFilter = null; + } else { + filter.filtered = true; + } + } + } else if ("--zen".equals(a) || "zen".equals(a)) { + filter.filtered = true; + filter.zen = true; + } else if ("--stats".equals(a)) { + filter.stats = true; + if (ai < args.length-1) { + ai++; + filter.since = Long.valueOf(args[ai]); + } else { + filter.since = 0; + } + } } - return null; + return filter; } public boolean matches(StatusBarNotification sbn) { - return all ? true : sbn != null + if (!filtered) return true; + return zen ? true : sbn != null && (matches(sbn.getPackageName()) || matches(sbn.getOpPkg())); } public boolean matches(ComponentName component) { - return all ? true : component != null && matches(component.getPackageName()); + if (!filtered) return true; + return zen ? true : component != null && matches(component.getPackageName()); } public boolean matches(String pkg) { - return all ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); + if (!filtered) return true; + return zen ? true : pkg != null && pkg.toLowerCase().contains(pkgFilter); } @Override diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index b7aea9d..f37702c 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -114,7 +114,7 @@ public final class NotificationRecord { /** @deprecated Use {@link #getUser()} instead. */ public int getUserId() { return sbn.getUserId(); } - void dump(PrintWriter pw, String prefix, Context baseContext) { + void dump(PrintWriter pw, String prefix, Context baseContext, boolean redact) { final Notification notification = sbn.getNotification(); final Icon icon = notification.getSmallIcon(); String iconStr = String.valueOf(icon); @@ -164,7 +164,7 @@ public final class NotificationRecord { pw.println("null"); } else { pw.print(val.getClass().getSimpleName()); - if (val instanceof CharSequence || val instanceof String) { + if (redact && (val instanceof CharSequence || val instanceof String)) { // redact contents from bugreports } else if (val instanceof Bitmap) { pw.print(String.format(" (%dx%d)", @@ -172,7 +172,14 @@ public final class NotificationRecord { ((Bitmap) val).getHeight())); } else if (val.getClass().isArray()) { final int N = Array.getLength(val); - pw.println(" (" + N + ")"); + pw.print(" (" + N + ")"); + if (!redact) { + for (int j=0; j<N; j++) { + pw.println(); + pw.print(String.format("%s [%d] %s", + prefix, j, String.valueOf(Array.get(val, j)))); + } + } } else { pw.print(" (" + String.valueOf(val) + ")"); } diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index e3c6037..b76db41 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -29,7 +29,6 @@ import android.content.pm.ProviderInfo; import android.content.pm.ResolveInfo; import android.net.Uri; import android.os.Build; -import android.os.Debug; import android.os.UserHandle; import android.provider.CalendarContract; import android.provider.ContactsContract; @@ -73,6 +72,7 @@ final class DefaultPermissionGrantPolicy { static { CONTACTS_PERMISSIONS.add(Manifest.permission.READ_CONTACTS); CONTACTS_PERMISSIONS.add(Manifest.permission.WRITE_CONTACTS); + CONTACTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS); } private static final Set<String> LOCATION_PERMISSIONS = new ArraySet<>(); @@ -118,16 +118,6 @@ final class DefaultPermissionGrantPolicy { STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } - private static final Set<String> ACCOUNTS_PERMISSIONS = new ArraySet<>(); - static { - //ACCOUNTS_PERMISSIONS.add(Manifest.permission.GET_ACCOUNTS); - } - - private static final Set<String> SETTINGS_PERMISSIONS = new ArraySet<>(); - static { - SETTINGS_PERMISSIONS.add(Manifest.permission.WRITE_SETTINGS); - } - private final PackageManagerService mService; private PackagesProvider mImePackagesProvider; @@ -161,7 +151,7 @@ final class DefaultPermissionGrantPolicy { mDialerAppPackagesProvider = provider; } - public void setSyncAdapterPackagesProviderrLPw(SyncAdapterPackagesProvider provider) { + public void setSyncAdapterPackagesProviderLPw(SyncAdapterPackagesProvider provider) { mSyncAdapterPackagesProvider = provider; } @@ -256,7 +246,7 @@ final class DefaultPermissionGrantPolicy { // SetupWizard Intent setupIntent = new Intent(Intent.ACTION_MAIN); - setupIntent.addCategory(Intent.CATEGORY_HOME); + setupIntent.addCategory(Intent.CATEGORY_SETUP_WIZARD); PackageParser.Package setupPackage = getDefaultSystemHandlerActivityPackageLPr( setupIntent, userId); if (setupPackage != null @@ -358,7 +348,6 @@ final class DefaultPermissionGrantPolicy { && doesPackageSupportRuntimePermissions(calendarPackage)) { grantRuntimePermissionsLPw(calendarPackage, CALENDAR_PERMISSIONS, userId); grantRuntimePermissionsLPw(calendarPackage, CONTACTS_PERMISSIONS, userId); - grantRuntimePermissionsLPw(calendarPackage, ACCOUNTS_PERMISSIONS, userId); } // Calendar provider @@ -368,14 +357,12 @@ final class DefaultPermissionGrantPolicy { grantRuntimePermissionsLPw(calendarProviderPackage, CONTACTS_PERMISSIONS, userId); grantRuntimePermissionsLPw(calendarProviderPackage, CALENDAR_PERMISSIONS, true, userId); - grantRuntimePermissionsLPw(calendarProviderPackage, ACCOUNTS_PERMISSIONS, userId); grantRuntimePermissionsLPw(calendarProviderPackage, STORAGE_PERMISSIONS, userId); } // Calendar provider sync adapters List<PackageParser.Package> calendarSyncAdapters = getHeadlessSyncAdapterPackagesLPr( - calendarSyncAdapterPackages, - userId); + calendarSyncAdapterPackages, userId); final int calendarSyncAdapterCount = calendarSyncAdapters.size(); for (int i = 0; i < calendarSyncAdapterCount; i++) { PackageParser.Package calendarSyncAdapter = calendarSyncAdapters.get(i); @@ -393,13 +380,11 @@ final class DefaultPermissionGrantPolicy { && doesPackageSupportRuntimePermissions(contactsPackage)) { grantRuntimePermissionsLPw(contactsPackage, CONTACTS_PERMISSIONS, userId); grantRuntimePermissionsLPw(contactsPackage, PHONE_PERMISSIONS, userId); - grantRuntimePermissionsLPw(contactsPackage, ACCOUNTS_PERMISSIONS, userId); } // Contacts provider sync adapters List<PackageParser.Package> contactsSyncAdapters = getHeadlessSyncAdapterPackagesLPr( - contactsSyncAdapterPackages, - userId); + contactsSyncAdapterPackages, userId); final int contactsSyncAdapterCount = contactsSyncAdapters.size(); for (int i = 0; i < contactsSyncAdapterCount; i++) { PackageParser.Package contactsSyncAdapter = contactsSyncAdapters.get(i); @@ -416,7 +401,6 @@ final class DefaultPermissionGrantPolicy { true, userId); grantRuntimePermissionsLPw(contactsProviderPackage, PHONE_PERMISSIONS, true, userId); - grantRuntimePermissionsLPw(contactsProviderPackage, ACCOUNTS_PERMISSIONS, userId); grantRuntimePermissionsLPw(contactsProviderPackage, STORAGE_PERMISSIONS, userId); } @@ -427,7 +411,7 @@ final class DefaultPermissionGrantPolicy { getDefaultSystemHandlerActivityPackageLPr(deviceProvisionIntent, userId); if (deviceProvisionPackage != null && doesPackageSupportRuntimePermissions(deviceProvisionPackage)) { - grantRuntimePermissionsLPw(deviceProvisionPackage, ACCOUNTS_PERMISSIONS, userId); + grantRuntimePermissionsLPw(deviceProvisionPackage, CONTACTS_PERMISSIONS, userId); } // Maps @@ -628,10 +612,12 @@ final class DefaultPermissionGrantPolicy { List<ResolveInfo> handlers = mService.mActivities.queryIntent(intent, intent.resolveType(mService.mContext.getContentResolver()), PackageManager.GET_DISABLED_COMPONENTS, userId); + if (handlers == null) { + return null; + } final int handlerCount = handlers.size(); for (int i = 0; i < handlerCount; i++) { ResolveInfo handler = handlers.get(i); - // TODO: This is a temporary hack to figure out the setup app. PackageParser.Package handlerPackage = getSystemPackageLPr( handler.activityInfo.packageName); if (handlerPackage != null) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index ec40b74..f041d50 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -800,12 +800,9 @@ public class PackageManagerService extends IPackageManager.Stub { } private static boolean hasValidDomains(ActivityIntentInfo filter) { - boolean hasHTTPorHTTPS = filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || - filter.hasDataScheme(IntentFilter.SCHEME_HTTPS); - if (!hasHTTPorHTTPS) { - return false; - } - return true; + return filter.hasCategory(Intent.CATEGORY_BROWSABLE) + && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || + filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)); } private IntentFilterVerifier mIntentFilterVerifier; @@ -4434,9 +4431,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized(mPackages) { CrossProfileDomainInfo xpDomainInfo = getCrossProfileDomainPreferredLpr( intent, resolvedType, 0, sourceUserId, parent.id); - return xpDomainInfo != null - && xpDomainInfo.bestDomainVerificationStatus != - INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + return xpDomainInfo != null; } } return false; @@ -4593,6 +4588,11 @@ public class PackageManagerService extends IPackageManager.Stub { result.bestDomainVerificationStatus); } } + // Don't consider matches with status NEVER across profiles. + if (result != null && result.bestDomainVerificationStatus + == INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { + return null; + } return result; } @@ -4730,8 +4730,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else { // Browser/generic handling case. If there's a default browser, go straight // to that (but only if there is no other higher-priority match). - final String defaultBrowserPackageName = getDefaultBrowserPackageName( - UserHandle.myUserId()); + final String defaultBrowserPackageName = getDefaultBrowserPackageName(userId); int maxMatchPrio = 0; ResolveInfo defaultBrowserMatch = null; final int numCandidates = matchAllList.size(); @@ -9944,7 +9943,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (packageName != null) { result |= updateIntentVerificationStatus(packageName, PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS, - UserHandle.myUserId()); + userId); mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowserLPr( packageName, userId); } @@ -10640,6 +10639,12 @@ public class PackageManagerService extends IPackageManager.Stub { final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite, receivers, verificationState); + // Apps installed for "all" users use the device owner to verify the app + UserHandle verifierUser = getUser(); + if (verifierUser == UserHandle.ALL) { + verifierUser = UserHandle.OWNER; + } + /* * If any sufficient verifiers were listed in the package * manifest, attempt to ask them. @@ -10655,8 +10660,7 @@ public class PackageManagerService extends IPackageManager.Stub { final Intent sufficientIntent = new Intent(verification); sufficientIntent.setComponent(verifierComponent); - - mContext.sendBroadcastAsUser(sufficientIntent, getUser()); + mContext.sendBroadcastAsUser(sufficientIntent, verifierUser); } } } @@ -10671,7 +10675,7 @@ public class PackageManagerService extends IPackageManager.Stub { * target BroadcastReceivers have run. */ verification.setComponent(requiredVerifierComponent); - mContext.sendOrderedBroadcastAsUser(verification, getUser(), + mContext.sendOrderedBroadcastAsUser(verification, verifierUser, android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, new BroadcastReceiver() { @Override @@ -15100,8 +15104,9 @@ public class PackageManagerService extends IPackageManager.Stub { } if (filters != null && filters.size() > 0) { for (IntentFilter filter : filters) { - if (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || - filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)) { + if (filter.hasCategory(Intent.CATEGORY_BROWSABLE) + && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || + filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) { result.addAll(filter.getHostsList()); } } @@ -16433,7 +16438,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void setSyncAdapterPackagesprovider(SyncAdapterPackagesProvider provider) { synchronized (mPackages) { - mDefaultPermissionPolicy.setSyncAdapterPackagesProviderrLPw(provider); + mDefaultPermissionPolicy.setSyncAdapterPackagesProviderLPw(provider); } } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index 4faf75a..bbdfe31 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -238,6 +238,7 @@ abstract class PackageSettingBase extends SettingBase { installStatus = base.installStatus; keySetData = base.keySetData; verificationInfo = base.verificationInfo; + installerPackageName = base.installerPackageName; } private PackageUserState modifyUserState(int userId) { diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 9e41f70..13e075c 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -126,6 +126,7 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -753,7 +754,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { if (shouldEnableWakeGestureLp()) { performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); - wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture); + wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture, + "android.policy:GESTURE"); } } } @@ -1874,21 +1876,33 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (permission != null) { if (permission == android.Manifest.permission.SYSTEM_ALERT_WINDOW) { final int callingUid = Binder.getCallingUid(); - // check if this is a system uid first before bothering with - // obtaining package name + // system processes will be automatically allowed privilege to draw if (callingUid == Process.SYSTEM_UID) { return WindowManagerGlobal.ADD_OKAY; } + // check if user has enabled this operation. SecurityException will be thrown if + // this app has not been allowed by the user final int mode = mAppOpsManager.checkOp(outAppOp[0], callingUid, attrs.packageName); - if (mode == AppOpsManager.MODE_DEFAULT) { - if (mContext.checkCallingPermission(permission) != - PackageManager.PERMISSION_GRANTED) { + switch (mode) { + case AppOpsManager.MODE_ALLOWED: + case AppOpsManager.MODE_IGNORED: + // although we return ADD_OKAY for MODE_IGNORED, the added window will + // actually be hidden in WindowManagerService + return WindowManagerGlobal.ADD_OKAY; + case AppOpsManager.MODE_ERRORED: return WindowManagerGlobal.ADD_PERMISSION_DENIED; - } + default: + // in the default mode, we will make a decision here based on + // checkCallingPermission() + if (mContext.checkCallingPermission(permission) != + PackageManager.PERMISSION_GRANTED) { + return WindowManagerGlobal.ADD_PERMISSION_DENIED; + } else { + return WindowManagerGlobal.ADD_OKAY; + } } - return WindowManagerGlobal.ADD_OKAY; } if (mContext.checkCallingOrSelfPermission(permission) @@ -4691,7 +4705,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation(true); if (lidOpen) { - wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch); + wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch, + "android.policy:LID"); } else if (!mLidControlsSleep) { mPowerManager.userActivity(SystemClock.uptimeMillis(), false); } @@ -4713,7 +4728,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); } - wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens); + wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens, + "android.policy:CAMERA_COVER"); startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); } mCameraLensCoverState = lensCoverState; @@ -4892,7 +4908,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (isValidGlobalKey(keyCode) && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { if (isWakeKey) { - wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey); + wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY"); } return result; } @@ -5123,7 +5139,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (isWakeKey) { - wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey); + wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY"); } return result; @@ -5184,7 +5200,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) { if ((policyFlags & FLAG_WAKE) != 0) { - if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion)) { + if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion, + "android.policy:MOTION")) { return 0; } } @@ -5197,7 +5214,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // there will be no dream to intercept the touch and wake into ambient. The device should // wake up in this case. if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) { - wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming); + wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming, + "android.policy:MOTION"); } return 0; @@ -5493,10 +5511,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private void wakeUpFromPowerKey(long eventTime) { - wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey); + wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER"); } - private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode) { + private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) { final boolean theaterModeEnabled = isTheaterModeEnabled(); if (!wakeInTheaterMode && theaterModeEnabled) { return false; @@ -5507,7 +5525,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Global.THEATER_MODE_ON, 0); } - mPowerManager.wakeUp(wakeTime); + mPowerManager.wakeUp(wakeTime, reason); return true; } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index d21c6d2..c5ad7fe 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -472,6 +472,26 @@ final class Notifier { } /** + * Called when the screen has turned on. + */ + public void onWakeUp(String reason, int reasonUid, String opPackageName, int opUid) { + if (DEBUG) { + Slog.d(TAG, "onWakeUp: event=" + reason + ", reasonUid=" + reasonUid + + " opPackageName=" + opPackageName + " opUid=" + opUid); + } + + try { + mBatteryStats.noteWakeUp(reason, reasonUid); + if (opPackageName != null) { + mAppOps.noteOperation(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName); + } + } catch (RemoteException ex) { + // Ignore + } + + } + + /** * Called when wireless charging has started so as to provide user feedback. */ public void onWirelessChargingStarted() { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 3f59755..88476ce 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -830,7 +830,18 @@ public final class PowerManagerService extends SystemService private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) { if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0 && isScreenLock(wakeLock)) { - wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), uid); + String opPackageName; + int opUid; + if (wakeLock.mWorkSource != null && wakeLock.mWorkSource.getName(0) != null) { + opPackageName = wakeLock.mWorkSource.getName(0); + opUid = wakeLock.mWorkSource.get(0); + } else { + opPackageName = wakeLock.mPackageName; + opUid = wakeLock.mWorkSource != null ? wakeLock.mWorkSource.get(0) + : wakeLock.mOwnerUid; + } + wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid, + opPackageName, opUid); } } @@ -1042,17 +1053,19 @@ public final class PowerManagerService extends SystemService return false; } - private void wakeUpInternal(long eventTime, int uid) { + private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName, + int opUid) { synchronized (mLock) { - if (wakeUpNoUpdateLocked(eventTime, uid)) { + if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) { updatePowerStateLocked(); } } } - private boolean wakeUpNoUpdateLocked(long eventTime, int uid) { + private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid, + String opPackageName, int opUid) { if (DEBUG_SPEW) { - Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid); + Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid); } if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE @@ -1064,21 +1077,22 @@ public final class PowerManagerService extends SystemService try { switch (mWakefulness) { case WAKEFULNESS_ASLEEP: - Slog.i(TAG, "Waking up from sleep (uid " + uid +")..."); + Slog.i(TAG, "Waking up from sleep (uid " + reasonUid +")..."); break; case WAKEFULNESS_DREAMING: - Slog.i(TAG, "Waking up from dream (uid " + uid +")..."); + Slog.i(TAG, "Waking up from dream (uid " + reasonUid +")..."); break; case WAKEFULNESS_DOZING: - Slog.i(TAG, "Waking up from dozing (uid " + uid +")..."); + Slog.i(TAG, "Waking up from dozing (uid " + reasonUid +")..."); break; } mLastWakeTime = eventTime; setWakefulnessLocked(WAKEFULNESS_AWAKE, 0); + mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid); userActivityNoUpdateLocked( - eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid); + eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } @@ -1334,7 +1348,8 @@ public final class PowerManagerService extends SystemService final long now = SystemClock.uptimeMillis(); if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType, dockedOnWirelessCharger)) { - wakeUpNoUpdateLocked(now, Process.SYSTEM_UID); + wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID, + mContext.getOpPackageName(), Process.SYSTEM_UID); } userActivityNoUpdateLocked( now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID); @@ -1788,7 +1803,8 @@ public final class PowerManagerService extends SystemService PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID); updatePowerStateLocked(); } else { - wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID); + wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), "android.server.power:DREAM", + Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID); updatePowerStateLocked(); } } else if (wakefulness == WAKEFULNESS_DOZING) { @@ -3136,7 +3152,7 @@ public final class PowerManagerService extends SystemService } @Override // Binder call - public void wakeUp(long eventTime) { + public void wakeUp(long eventTime, String reason, String opPackageName) { if (eventTime > SystemClock.uptimeMillis()) { throw new IllegalArgumentException("event time must not be in the future"); } @@ -3147,7 +3163,7 @@ public final class PowerManagerService extends SystemService final int uid = Binder.getCallingUid(); final long ident = Binder.clearCallingIdentity(); try { - wakeUpInternal(eventTime, uid); + wakeUpInternal(eventTime, reason, uid, opPackageName, uid); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index ec566bc..c776e8f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2543,8 +2543,10 @@ public class WindowManagerService extends IWindowManager.Stub win.attach(); mWindowMap.put(client.asBinder(), win); if (win.mAppOp != AppOpsManager.OP_NONE) { - if (mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage()) - != AppOpsManager.MODE_ALLOWED) { + int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), + win.getOwningPackage()); + if ((startOpResult != AppOpsManager.MODE_ALLOWED) && + (startOpResult != AppOpsManager.MODE_DEFAULT)) { win.setAppOpVisibilityLw(false); } } @@ -2728,10 +2730,10 @@ public class WindowManagerService extends IWindowManager.Stub wasVisible = win.isWinVisibleLw(); if (wasVisible) { - int transit = WindowManagerPolicy.TRANSIT_EXIT; - if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { - transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; - } + final int transit = (!startingWindow) + ? WindowManagerPolicy.TRANSIT_EXIT + : WindowManagerPolicy.TRANSIT_PREVIEW_DONE; + // Try starting an animation. if (win.mWinAnimator.applyAnimationLocked(transit, false)) { win.mExiting = true; @@ -2743,12 +2745,13 @@ public class WindowManagerService extends IWindowManager.Stub } } final AppWindowToken appToken = win.mAppToken; + final boolean isAnimating = win.mWinAnimator.isAnimating(); // The starting window is the last window in this app token and it isn't animating. // Allow it to be removed now as there is no additional window or animation that will // trigger its removal. final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null - && appToken.allAppWindows.size() == 1 && !win.mWinAnimator.isAnimating(); - if (!lastWinStartingNotAnimating && (win.mExiting || win.mWinAnimator.isAnimating())) { + && appToken.allAppWindows.size() == 1 && !isAnimating; + if (!lastWinStartingNotAnimating && (win.mExiting || isAnimating)) { // The exit animation is running... wait for it! win.mExiting = true; win.mRemoveOnExit = true; @@ -2899,7 +2902,8 @@ public class WindowManagerService extends IWindowManager.Stub if (win.mAppOp != AppOpsManager.OP_NONE) { final int mode = mAppOps.checkOpNoThrow(win.mAppOp, win.getOwningUid(), win.getOwningPackage()); - win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED); + win.setAppOpVisibilityLw(mode == AppOpsManager.MODE_ALLOWED || + mode == AppOpsManager.MODE_DEFAULT); } } } @@ -4524,7 +4528,10 @@ public class WindowManagerService extends IWindowManager.Stub } wtoken.willBeHidden = false; - if (wtoken.hidden == visible) { + // Allow for state changes and animation to be applied if token is transitioning + // visibility state or the token was marked as hidden and is exiting before we had a chance + // to play the transition animation. + if (wtoken.hidden == visible || (wtoken.hidden && wtoken.mIsExiting)) { boolean changed = false; if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden @@ -10307,7 +10314,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_VISIBILITY || DEBUG_POWER) { Slog.v(TAG, "Turning screen on after layout!"); } - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.wm:TURN_ON"); } mTurnOnScreen = false; } diff --git a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java index ffd1568..757f1c6 100644 --- a/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java +++ b/services/tests/servicestests/src/com/android/server/BroadcastInterceptingContext.java @@ -139,6 +139,11 @@ public class BroadcastInterceptingContext extends ContextWrapper { } @Override + public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) { + sendBroadcast(intent); + } + + @Override public void sendBroadcastAsUser(Intent intent, UserHandle user) { sendBroadcast(intent); } diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index c49a5f9..b0a14c8 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -1177,7 +1177,11 @@ public class UsageStatsService extends SystemService implements @Override public void whitelistAppTemporarily(String packageName, long duration, int userId) throws RemoteException { - mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId); + StringBuilder reason = new StringBuilder(32); + reason.append("from:"); + UserHandle.formatUid(reason, Binder.getCallingUid()); + mDeviceIdleController.addPowerSaveTempWhitelistApp(packageName, duration, userId, + reason.toString()); } @Override diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java index 638783d..31763e7 100644 --- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java +++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java @@ -35,6 +35,7 @@ import android.util.Slog; import com.android.internal.alsa.AlsaCardsParser; import com.android.internal.alsa.AlsaDevicesParser; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.audio.AudioService; import libcore.io.IoUtils; @@ -502,14 +503,14 @@ public final class UsbAlsaManager { // // Logging // - public void dump(FileDescriptor fd, PrintWriter pw) { - pw.println(" USB Audio Devices:"); + public void dump(IndentingPrintWriter pw) { + pw.println("USB Audio Devices:"); for (UsbDevice device : mAudioDevices.keySet()) { - pw.println(" " + device.getDeviceName() + ": " + mAudioDevices.get(device)); + pw.println(" " + device.getDeviceName() + ": " + mAudioDevices.get(device)); } - pw.println(" USB MIDI Devices:"); + pw.println("USB MIDI Devices:"); for (UsbDevice device : mMidiDevices.keySet()) { - pw.println(" " + device.getDeviceName() + ": " + mMidiDevices.get(device)); + pw.println(" " + device.getDeviceName() + ": " + mMidiDevices.get(device)); } } diff --git a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java index 9a04e8b..ae17fde 100644 --- a/services/usb/java/com/android/server/usb/UsbDebuggingManager.java +++ b/services/usb/java/com/android/server/usb/UsbDebuggingManager.java @@ -38,6 +38,7 @@ import android.util.Base64; import android.util.Slog; import com.android.internal.R; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.FgThread; import java.io.File; @@ -451,17 +452,17 @@ public class UsbDebuggingManager { mHandler.sendEmptyMessage(UsbDebuggingHandler.MESSAGE_ADB_CLEAR); } - public void dump(FileDescriptor fd, PrintWriter pw) { - pw.println(" USB Debugging State:"); - pw.println(" Connected to adbd: " + (mThread != null)); - pw.println(" Last key received: " + mFingerprints); - pw.println(" User keys:"); + public void dump(IndentingPrintWriter pw) { + pw.println("USB Debugging State:"); + pw.println(" Connected to adbd: " + (mThread != null)); + pw.println(" Last key received: " + mFingerprints); + pw.println(" User keys:"); try { pw.println(FileUtils.readTextFile(new File("/data/misc/adb/adb_keys"), 0, null)); } catch (IOException e) { pw.println("IOException: " + e); } - pw.println(" System keys:"); + pw.println(" System keys:"); try { pw.println(FileUtils.readTextFile(new File("/adb_keys"), 0, null)); } catch (IOException e) { diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 81b4857..653cbd8 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -45,6 +45,7 @@ import android.util.Pair; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.FgThread; import java.io.File; @@ -807,17 +808,17 @@ public class UsbDeviceManager { UsbManager.USB_FUNCTION_ADB); } - public void dump(FileDescriptor fd, PrintWriter pw) { - pw.println(" USB Device State:"); - pw.println(" mCurrentFunctions: " + mCurrentFunctions); - pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied); - pw.println(" mConnected: " + mConnected); - pw.println(" mConfigured: " + mConfigured); - pw.println(" mCurrentAccessory: " + mCurrentAccessory); + public void dump(IndentingPrintWriter pw) { + pw.println("USB Device State:"); + pw.println(" mCurrentFunctions: " + mCurrentFunctions); + pw.println(" mCurrentFunctionsApplied: " + mCurrentFunctionsApplied); + pw.println(" mConnected: " + mConnected); + pw.println(" mConfigured: " + mConfigured); + pw.println(" mCurrentAccessory: " + mCurrentAccessory); try { - pw.println(" Kernel state: " + pw.println(" Kernel state: " + FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim()); - pw.println(" Kernel function list: " + pw.println(" Kernel function list: " + FileUtils.readTextFile(new File(FUNCTIONS_PATH), 0, null).trim()); } catch (IOException e) { pw.println("IOException: " + e); @@ -908,12 +909,12 @@ public class UsbDeviceManager { } } - public void dump(FileDescriptor fd, PrintWriter pw) { + public void dump(IndentingPrintWriter pw) { if (mHandler != null) { - mHandler.dump(fd, pw); + mHandler.dump(pw); } if (mDebuggingManager != null) { - mDebuggingManager.dump(fd, pw); + mDebuggingManager.dump(pw); } } diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index f5f2b07..6300a9a 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -27,6 +27,7 @@ import android.os.ParcelFileDescriptor; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -283,11 +284,11 @@ public class UsbHostManager { } } - public void dump(FileDescriptor fd, PrintWriter pw) { + public void dump(IndentingPrintWriter pw) { synchronized (mLock) { - pw.println(" USB Host State:"); + pw.println("USB Host State:"); for (String name : mDevices.keySet()) { - pw.println(" " + name + ": " + mDevices.get(name)); + pw.println(" " + name + ": " + mDevices.get(name)); } } } diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java new file mode 100644 index 0000000..52abcfe --- /dev/null +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -0,0 +1,753 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.usb; + +import com.android.internal.util.IndentingPrintWriter; +import com.android.server.FgThread; + +import android.content.Context; +import android.content.Intent; +import android.hardware.usb.UsbManager; +import android.hardware.usb.UsbPort; +import android.hardware.usb.UsbPortStatus; +import android.os.Handler; +import android.os.Message; +import android.os.UEventObserver; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.Log; +import android.util.Slog; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import libcore.io.IoUtils; + +/** + * Allows trusted components to control the properties of physical USB ports + * via the "/sys/class/dual_role_usb" kernel interface. + * <p> + * Note: This interface may not be supported on all chipsets since the USB drivers + * must be changed to publish this information through the module. At the moment + * we only need this for devices with USB Type C ports to allow the System UI to + * control USB charging and data direction. On devices that do not support this + * interface the list of ports may incorrectly appear to be empty + * (but we don't care today). + * </p> + */ +public class UsbPortManager { + private static final String TAG = "UsbPortManager"; + + private static final int MSG_UPDATE_PORTS = 1; + + // UEvent path to watch. + private static final String UEVENT_FILTER = "SUBSYSTEM=dual_role_usb"; + + // SysFS directory that contains USB ports as subdirectories. + private static final String SYSFS_CLASS = "/sys/class/dual_role_usb"; + + // SysFS file that contains a USB port's supported modes. (read-only) + // Contents: "", "ufp", "dfp", or "ufp dfp". + private static final String SYSFS_PORT_SUPPORTED_MODES = "supported_modes"; + + // SysFS file that contains a USB port's current mode. (read-write if configurable) + // Contents: "", "ufp", or "dfp". + private static final String SYSFS_PORT_MODE = "mode"; + + // SysFS file that contains a USB port's current power role. (read-write if configurable) + // Contents: "", "source", or "sink". + private static final String SYSFS_PORT_POWER_ROLE = "power_role"; + + // SysFS file that contains a USB port's current data role. (read-write if configurable) + // Contents: "", "host", or "device". + private static final String SYSFS_PORT_DATA_ROLE = "data_role"; + + // Port modes: upstream facing port or downstream facing port. + private static final String PORT_MODE_DFP = "dfp"; + private static final String PORT_MODE_UFP = "ufp"; + + // Port power roles: source or sink. + private static final String PORT_POWER_ROLE_SOURCE = "source"; + private static final String PORT_POWER_ROLE_SINK = "sink"; + + // Port data roles: host or device. + private static final String PORT_DATA_ROLE_HOST = "host"; + private static final String PORT_DATA_ROLE_DEVICE = "device"; + + // All non-trivial role combinations. + private static final int COMBO_SOURCE_HOST = + UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST); + private static final int COMBO_SOURCE_DEVICE = + UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_DEVICE); + private static final int COMBO_SINK_HOST = + UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_HOST); + private static final int COMBO_SINK_DEVICE = + UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE); + + // The system context. + private final Context mContext; + + // True if we have kernel support. + private final boolean mHaveKernelSupport; + + // Mutex for all mutable shared state. + private final Object mLock = new Object(); + + // List of all ports, indexed by id. + // Ports may temporarily have different dispositions as they are added or removed + // but the class invariant is that this list will only contain ports with DISPOSITION_READY + // except while updatePortsLocked() is in progress. + private final ArrayMap<String, PortInfo> mPorts = new ArrayMap<String, PortInfo>(); + + // List of all simulated ports, indexed by id. + private final ArrayMap<String, SimulatedPortInfo> mSimulatedPorts = + new ArrayMap<String, SimulatedPortInfo>(); + + public UsbPortManager(Context context) { + mContext = context; + mHaveKernelSupport = new File(SYSFS_CLASS).exists(); + } + + public void systemReady() { + mUEventObserver.startObserving(UEVENT_FILTER); + scheduleUpdatePorts(); + } + + public UsbPort[] getPorts() { + synchronized (mLock) { + final int count = mPorts.size(); + final UsbPort[] result = new UsbPort[count]; + for (int i = 0; i < count; i++) { + result[i] = mPorts.valueAt(i).mUsbPort; + } + return result; + } + } + + public UsbPortStatus getPortStatus(String portId) { + synchronized (mLock) { + final PortInfo portInfo = mPorts.get(portId); + return portInfo != null ? portInfo.mUsbPortStatus : null; + } + } + + public void setPortRoles(String portId, int newPowerRole, int newDataRole, + IndentingPrintWriter pw) { + synchronized (mLock) { + final PortInfo portInfo = mPorts.get(portId); + if (portInfo == null) { + if (pw != null) { + pw.println("No such USB port: " + portId); + } + return; + } + + // Check whether the new role is actually supported. + if (!portInfo.mUsbPortStatus.isRoleCombinationSupported(newPowerRole, newDataRole)) { + logAndPrint(Log.ERROR, pw, "Attempted to set USB port into unsupported " + + "role combination: portId=" + portId + + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole) + + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole)); + return; + } + + // Check whether anything actually changed. + final int currentDataRole = portInfo.mUsbPortStatus.getCurrentDataRole(); + final int currentPowerRole = portInfo.mUsbPortStatus.getCurrentPowerRole(); + if (currentDataRole == newDataRole && currentPowerRole == newPowerRole) { + if (pw != null) { + pw.println("No change."); + } + return; + } + + // Determine whether we need to change the mode in order to accomplish this goal. + // We prefer not to do this since it's more likely to fail. + // + // Note: Arguably it might be worth allowing the client to influence this policy + // decision so that we could show more powerful developer facing UI but let's + // see how far we can get without having to do that. + final boolean canChangeMode = portInfo.mCanChangeMode; + final boolean canChangePowerRole = portInfo.mCanChangePowerRole; + final boolean canChangeDataRole = portInfo.mCanChangeDataRole; + final int currentMode = portInfo.mUsbPortStatus.getCurrentMode(); + final int newMode; + if ((!canChangePowerRole && currentPowerRole != newPowerRole) + || (!canChangeDataRole && currentDataRole != newDataRole)) { + if (canChangeMode && newPowerRole == UsbPort.POWER_ROLE_SOURCE + && newDataRole == UsbPort.DATA_ROLE_HOST) { + newMode = UsbPort.MODE_DFP; + } else if (canChangeMode && newPowerRole == UsbPort.POWER_ROLE_SINK + && newDataRole == UsbPort.DATA_ROLE_DEVICE) { + newMode = UsbPort.MODE_UFP; + } else { + logAndPrint(Log.ERROR, pw, "Found mismatch in supported USB role combinations " + + "while attempting to change role: " + portInfo + + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole) + + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole)); + return; + } + } else { + newMode = currentMode; + } + + // Make it happen. + logAndPrint(Log.INFO, pw, "Setting USB port mode and role: portId=" + portId + + ", currentMode=" + UsbPort.modeToString(currentMode) + + ", currentPowerRole=" + UsbPort.powerRoleToString(currentPowerRole) + + ", currentDataRole=" + UsbPort.dataRoleToString(currentDataRole) + + ", newMode=" + UsbPort.modeToString(newMode) + + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole) + + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole)); + + SimulatedPortInfo sim = mSimulatedPorts.get(portId); + if (sim != null) { + // Change simulated state. + sim.mCurrentMode = newMode; + sim.mCurrentPowerRole = newPowerRole; + sim.mCurrentDataRole = newDataRole; + } else if (mHaveKernelSupport) { + // Change actual state. + final File portDir = new File(SYSFS_CLASS, portId); + if (!portDir.exists()) { + logAndPrint(Log.ERROR, pw, "USB port not found: portId=" + portId); + return; + } + + if (currentMode != newMode) { + // Changing the mode will have the side-effect of also changing + // the power and data roles but it might take some time to apply + // and the renegotiation might fail. Due to limitations of the USB + // hardware, we have no way of knowing whether it will work apriori + // which is why we would prefer to set the power and data roles + // directly instead. + if (!writeFile(portDir, SYSFS_PORT_MODE, + newMode == UsbPort.MODE_DFP ? PORT_MODE_DFP : PORT_MODE_UFP)) { + logAndPrint(Log.ERROR, pw, "Failed to set the USB port mode: " + + "portId=" + portId + + ", newMode=" + UsbPort.modeToString(newMode)); + return; + } + } else { + // Change power and data role independently as needed. + if (currentPowerRole != newPowerRole) { + if (!writeFile(portDir, SYSFS_PORT_POWER_ROLE, + newPowerRole == UsbPort.POWER_ROLE_SOURCE + ? PORT_POWER_ROLE_SOURCE : PORT_POWER_ROLE_SINK)) { + logAndPrint(Log.ERROR, pw, "Failed to set the USB port power role: " + + "portId=" + portId + + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)); + return; + } + } + if (currentDataRole != newDataRole) { + if (!writeFile(portDir, SYSFS_PORT_DATA_ROLE, + newDataRole == UsbPort.DATA_ROLE_HOST + ? PORT_DATA_ROLE_HOST : PORT_DATA_ROLE_DEVICE)) { + logAndPrint(Log.ERROR, pw, "Failed to set the USB port data role: " + + "portId=" + portId + + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole)); + return; + } + } + } + } + updatePortsLocked(pw); + } + } + + public void addSimulatedPort(String portId, int supportedModes, IndentingPrintWriter pw) { + synchronized (mLock) { + if (mSimulatedPorts.containsKey(portId)) { + pw.println("Port with same name already exists. Please remove it first."); + return; + } + + pw.println("Adding simulated port: portId=" + portId + + ", supportedModes=" + UsbPort.modeToString(supportedModes)); + mSimulatedPorts.put(portId, + new SimulatedPortInfo(portId, supportedModes)); + updatePortsLocked(pw); + } + } + + public void connectSimulatedPort(String portId, int mode, boolean canChangeMode, + int powerRole, boolean canChangePowerRole, + int dataRole, boolean canChangeDataRole, IndentingPrintWriter pw) { + synchronized (mLock) { + final SimulatedPortInfo portInfo = mSimulatedPorts.get(portId); + if (portInfo == null) { + pw.println("Cannot connect simulated port which does not exist."); + return; + } + + if (mode == 0 || powerRole == 0 || dataRole == 0) { + pw.println("Cannot connect simulated port in null mode, " + + "power role, or data role."); + return; + } + + if ((portInfo.mSupportedModes & mode) == 0) { + pw.println("Simulated port does not support mode: " + UsbPort.modeToString(mode)); + return; + } + + pw.println("Connecting simulated port: portId=" + portId + + ", mode=" + UsbPort.modeToString(mode) + + ", canChangeMode=" + canChangeMode + + ", powerRole=" + UsbPort.powerRoleToString(powerRole) + + ", canChangePowerRole=" + canChangePowerRole + + ", dataRole=" + UsbPort.dataRoleToString(dataRole) + + ", canChangeDataRole=" + canChangeDataRole); + portInfo.mCurrentMode = mode; + portInfo.mCanChangeMode = canChangeMode; + portInfo.mCurrentPowerRole = powerRole; + portInfo.mCanChangePowerRole = canChangePowerRole; + portInfo.mCurrentDataRole = dataRole; + portInfo.mCanChangeDataRole = canChangeDataRole; + updatePortsLocked(pw); + } + } + + public void disconnectSimulatedPort(String portId, IndentingPrintWriter pw) { + synchronized (mLock) { + final SimulatedPortInfo portInfo = mSimulatedPorts.get(portId); + if (portInfo == null) { + pw.println("Cannot disconnect simulated port which does not exist."); + return; + } + + pw.println("Disconnecting simulated port: portId=" + portId); + portInfo.mCurrentMode = 0; + portInfo.mCanChangeMode = false; + portInfo.mCurrentPowerRole = 0; + portInfo.mCanChangePowerRole = false; + portInfo.mCurrentDataRole = 0; + portInfo.mCanChangeDataRole = false; + updatePortsLocked(pw); + } + } + + public void removeSimulatedPort(String portId, IndentingPrintWriter pw) { + synchronized (mLock) { + final int index = mSimulatedPorts.indexOfKey(portId); + if (index < 0) { + pw.println("Cannot remove simulated port which does not exist."); + return; + } + + pw.println("Disconnecting simulated port: portId=" + portId); + mSimulatedPorts.removeAt(index); + updatePortsLocked(pw); + } + } + + public void resetSimulation(IndentingPrintWriter pw) { + synchronized (mLock) { + pw.println("Removing all simulated ports and ending simulation."); + if (!mSimulatedPorts.isEmpty()) { + mSimulatedPorts.clear(); + updatePortsLocked(pw); + } + } + } + + public void dump(IndentingPrintWriter pw) { + synchronized (mLock) { + pw.print("USB Port State:"); + if (!mSimulatedPorts.isEmpty()) { + pw.print(" (simulation active; end with 'dumpsys usb reset')"); + } + pw.println(); + + if (mPorts.isEmpty()) { + pw.println(" <no ports>"); + } else { + for (PortInfo portInfo : mPorts.values()) { + pw.println(" " + portInfo.mUsbPort.getId() + ": " + portInfo); + } + } + } + } + + private void updatePortsLocked(IndentingPrintWriter pw) { + // Assume all ports are gone unless informed otherwise. + // Kind of pessimistic but simple. + for (int i = mPorts.size(); i-- > 0; ) { + mPorts.valueAt(i).mDisposition = PortInfo.DISPOSITION_REMOVED; + } + + // Enumerate all extant ports. + if (!mSimulatedPorts.isEmpty()) { + final int count = mSimulatedPorts.size(); + for (int i = 0; i < count; i++) { + final SimulatedPortInfo portInfo = mSimulatedPorts.valueAt(i); + addOrUpdatePortLocked(portInfo.mPortId, portInfo.mSupportedModes, + portInfo.mCurrentMode, portInfo.mCanChangeMode, + portInfo.mCurrentPowerRole, portInfo.mCanChangePowerRole, + portInfo.mCurrentDataRole, portInfo.mCanChangeDataRole, pw); + } + } else if (mHaveKernelSupport) { + final File[] portDirs = new File(SYSFS_CLASS).listFiles(); + if (portDirs != null) { + for (File portDir : portDirs) { + if (!portDir.isDirectory()) { + continue; + } + + // Parse the sysfs file contents. + final String portId = portDir.getName(); + final int supportedModes = readSupportedModes(portDir); + final int currentMode = readCurrentMode(portDir); + final boolean canChangeMode = canChangeMode(portDir); + final int currentPowerRole = readCurrentPowerRole(portDir); + final boolean canChangePowerRole = canChangePowerRole(portDir); + final int currentDataRole = readCurrentDataRole(portDir); + final boolean canChangeDataRole = canChangeDataRole(portDir); + addOrUpdatePortLocked(portId, supportedModes, + currentMode, canChangeMode, + currentPowerRole, canChangePowerRole, + currentDataRole, canChangeDataRole, pw); + } + } + } + + // Process the updates. + // Once finished, the list of ports will only contain ports in DISPOSITION_READY. + for (int i = mPorts.size(); i-- > 0; ) { + final PortInfo portInfo = mPorts.valueAt(i); + switch (portInfo.mDisposition) { + case PortInfo.DISPOSITION_ADDED: + handlePortAddedLocked(portInfo, pw); + portInfo.mDisposition = PortInfo.DISPOSITION_READY; + break; + case PortInfo.DISPOSITION_CHANGED: + handlePortChangedLocked(portInfo, pw); + portInfo.mDisposition = PortInfo.DISPOSITION_READY; + break; + case PortInfo.DISPOSITION_REMOVED: + mPorts.removeAt(i); + portInfo.mUsbPortStatus = null; // must do this early + handlePortRemovedLocked(portInfo, pw); + break; + } + } + } + + // Must only be called by updatePortsLocked. + private void addOrUpdatePortLocked(String portId, int supportedModes, + int currentMode, boolean canChangeMode, + int currentPowerRole, boolean canChangePowerRole, + int currentDataRole, boolean canChangeDataRole, + IndentingPrintWriter pw) { + // Only allow mode switch capability for dual role ports. + // Validate that the current mode matches the supported modes we expect. + if (supportedModes != UsbPort.MODE_DUAL) { + canChangeMode = false; + if (currentMode != 0 && currentMode != supportedModes) { + logAndPrint(Log.WARN, pw, "Ignoring inconsistent current mode from USB " + + "port driver: supportedModes=" + UsbPort.modeToString(supportedModes) + + ", currentMode=" + UsbPort.modeToString(currentMode)); + currentMode = 0; + } + } + + // Determine the supported role combinations. + // Note that the policy is designed to prefer setting the power and data + // role independently rather than changing the mode. + int supportedRoleCombinations = UsbPort.combineRolesAsBit( + currentPowerRole, currentDataRole); + if (currentMode != 0 && currentPowerRole != 0 && currentDataRole != 0) { + if (canChangePowerRole && canChangeDataRole) { + // Can change both power and data role independently. + // Assume all combinations are possible. + supportedRoleCombinations |= + COMBO_SOURCE_HOST | COMBO_SOURCE_DEVICE + | COMBO_SINK_HOST | COMBO_SINK_DEVICE; + } else if (canChangePowerRole) { + // Can only change power role. + // Assume data role must remain at its current value. + supportedRoleCombinations |= UsbPort.combineRolesAsBit( + UsbPort.POWER_ROLE_SOURCE, currentDataRole); + supportedRoleCombinations |= UsbPort.combineRolesAsBit( + UsbPort.POWER_ROLE_SINK, currentDataRole); + } else if (canChangeDataRole) { + // Can only change data role. + // Assume power role must remain at its current value. + supportedRoleCombinations |= UsbPort.combineRolesAsBit( + currentPowerRole, UsbPort.DATA_ROLE_HOST); + supportedRoleCombinations |= UsbPort.combineRolesAsBit( + currentPowerRole, UsbPort.DATA_ROLE_DEVICE); + } else if (canChangeMode) { + // Can only change the mode. + // Assume both standard UFP and DFP configurations will become available + // when this happens. + supportedRoleCombinations |= COMBO_SOURCE_HOST | COMBO_SINK_DEVICE; + } + } + + // Update the port data structures. + PortInfo portInfo = mPorts.get(portId); + if (portInfo == null) { + portInfo = new PortInfo(portId, supportedModes); + portInfo.setStatus(currentMode, canChangeMode, + currentPowerRole, canChangePowerRole, + currentDataRole, canChangeDataRole, + supportedRoleCombinations); + mPorts.put(portId, portInfo); + } else { + // Sanity check that ports aren't changing definition out from under us. + if (supportedModes != portInfo.mUsbPort.getSupportedModes()) { + logAndPrint(Log.WARN, pw, "Ignoring inconsistent list of supported modes from " + + "USB port driver (should be immutable): " + + "previous=" + UsbPort.modeToString( + portInfo.mUsbPort.getSupportedModes()) + + ", current=" + UsbPort.modeToString(supportedModes)); + } + + if (portInfo.setStatus(currentMode, canChangeMode, + currentPowerRole, canChangePowerRole, + currentDataRole, canChangeDataRole, + supportedRoleCombinations)) { + portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED; + } else { + portInfo.mDisposition = PortInfo.DISPOSITION_READY; + } + } + } + + private void handlePortAddedLocked(PortInfo portInfo, IndentingPrintWriter pw) { + logAndPrint(Log.INFO, pw, "USB port added: " + portInfo); + sendPortChangedBroadcastLocked(portInfo); + } + + private void handlePortChangedLocked(PortInfo portInfo, IndentingPrintWriter pw) { + logAndPrint(Log.INFO, pw, "USB port changed: " + portInfo); + sendPortChangedBroadcastLocked(portInfo); + } + + private void handlePortRemovedLocked(PortInfo portInfo, IndentingPrintWriter pw) { + logAndPrint(Log.INFO, pw, "USB port removed: " + portInfo); + sendPortChangedBroadcastLocked(portInfo); + } + + private void sendPortChangedBroadcastLocked(PortInfo portInfo) { + final Intent intent = new Intent(UsbManager.ACTION_USB_PORT_CHANGED); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + intent.putExtra(UsbManager.EXTRA_PORT, portInfo.mUsbPort); + intent.putExtra(UsbManager.EXTRA_PORT_STATUS, portInfo.mUsbPortStatus); + + // Guard against possible reentrance by posting the broadcast from the handler + // instead of from within the critical section. + mHandler.post(new Runnable() { + @Override + public void run() { + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } + }); + } + + private void scheduleUpdatePorts() { + if (!mHandler.hasMessages(MSG_UPDATE_PORTS)) { + mHandler.sendEmptyMessage(MSG_UPDATE_PORTS); + } + } + + private static int readSupportedModes(File portDir) { + int modes = 0; + final String contents = readFile(portDir, SYSFS_PORT_SUPPORTED_MODES); + if (contents != null) { + if (contents.contains(PORT_MODE_DFP)) { + modes |= UsbPort.MODE_DFP; + } + if (contents.contains(PORT_MODE_UFP)) { + modes |= UsbPort.MODE_UFP; + } + } + return modes; + } + + private static int readCurrentMode(File portDir) { + final String contents = readFile(portDir, SYSFS_PORT_MODE); + if (contents != null) { + if (contents.equals(PORT_MODE_DFP)) { + return UsbPort.MODE_DFP; + } + if (contents.equals(PORT_MODE_UFP)) { + return UsbPort.MODE_UFP; + } + } + return 0; + } + + private static int readCurrentPowerRole(File portDir) { + final String contents = readFile(portDir, SYSFS_PORT_POWER_ROLE); + if (contents != null) { + if (contents.equals(PORT_POWER_ROLE_SOURCE)) { + return UsbPort.POWER_ROLE_SOURCE; + } + if (contents.equals(PORT_POWER_ROLE_SINK)) { + return UsbPort.POWER_ROLE_SINK; + } + } + return 0; + } + + private static int readCurrentDataRole(File portDir) { + final String contents = readFile(portDir, SYSFS_PORT_DATA_ROLE); + if (contents != null) { + if (contents.equals(PORT_DATA_ROLE_HOST)) { + return UsbPort.DATA_ROLE_HOST; + } + if (contents.equals(PORT_DATA_ROLE_DEVICE)) { + return UsbPort.DATA_ROLE_DEVICE; + } + } + return 0; + } + + private static boolean canChangeMode(File portDir) { + return new File(portDir, SYSFS_PORT_MODE).canWrite(); + } + + private static boolean canChangePowerRole(File portDir) { + return new File(portDir, SYSFS_PORT_POWER_ROLE).canWrite(); + } + + private static boolean canChangeDataRole(File portDir) { + return new File(portDir, SYSFS_PORT_DATA_ROLE).canWrite(); + } + + private static String readFile(File dir, String filename) { + final File file = new File(dir, filename); + try { + return IoUtils.readFileAsString(file.getAbsolutePath()).trim(); + } catch (IOException ex) { + return null; + } + } + + private static boolean writeFile(File dir, String filename, String contents) { + final File file = new File(dir, filename); + try { + try (FileWriter writer = new FileWriter(file)) { + writer.write(contents); + } + return true; + } catch (IOException ex) { + return false; + } + } + + private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) { + Slog.println(priority, TAG, msg); + if (pw != null) { + pw.println(msg); + } + } + + private final Handler mHandler = new Handler(FgThread.get().getLooper()) { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_UPDATE_PORTS: { + synchronized (mLock) { + updatePortsLocked(null); + } + break; + } + } + } + }; + + private final UEventObserver mUEventObserver = new UEventObserver() { + @Override + public void onUEvent(UEvent event) { + scheduleUpdatePorts(); + } + }; + + /** + * Describes a USB port. + */ + private static final class PortInfo { + public static final int DISPOSITION_ADDED = 0; + public static final int DISPOSITION_CHANGED = 1; + public static final int DISPOSITION_READY = 2; + public static final int DISPOSITION_REMOVED = 3; + + public final UsbPort mUsbPort; + public UsbPortStatus mUsbPortStatus; + public boolean mCanChangeMode; + public boolean mCanChangePowerRole; + public boolean mCanChangeDataRole; + public int mDisposition; // default initialized to 0 which means added + + public PortInfo(String portId, int supportedModes) { + mUsbPort = new UsbPort(portId, supportedModes); + } + + public boolean setStatus(int currentMode, boolean canChangeMode, + int currentPowerRole, boolean canChangePowerRole, + int currentDataRole, boolean canChangeDataRole, + int supportedRoleCombinations) { + mCanChangeMode = canChangeMode; + mCanChangePowerRole = canChangePowerRole; + mCanChangeDataRole = canChangeDataRole; + if (mUsbPortStatus == null + || mUsbPortStatus.getCurrentMode() != currentMode + || mUsbPortStatus.getCurrentPowerRole() != currentPowerRole + || mUsbPortStatus.getCurrentDataRole() != currentDataRole + || mUsbPortStatus.getSupportedRoleCombinations() + != supportedRoleCombinations) { + mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole, + supportedRoleCombinations); + return true; + } + return false; + } + + @Override + public String toString() { + return "port=" + mUsbPort + ", status=" + mUsbPortStatus + + ", canChangeMode=" + mCanChangeMode + + ", canChangePowerRole=" + mCanChangePowerRole + + ", canChangeDataRole=" + mCanChangeDataRole; + } + } + + /** + * Describes a simulated USB port. + * Roughly mirrors the information we would ordinarily get from the kernel. + */ + private static final class SimulatedPortInfo { + public final String mPortId; + public final int mSupportedModes; + public int mCurrentMode; + public boolean mCanChangeMode; + public int mCurrentPowerRole; + public boolean mCanChangePowerRole; + public int mCurrentDataRole; + public boolean mCanChangeDataRole; + + public SimulatedPortInfo(String portId, int supportedModes) { + mPortId = portId; + mSupportedModes = supportedModes; + } + } +} diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java index c8b4226..f93a2ef 100644 --- a/services/usb/java/com/android/server/usb/UsbService.java +++ b/services/usb/java/com/android/server/usb/UsbService.java @@ -27,6 +27,9 @@ import android.hardware.usb.IUsbManager; import android.hardware.usb.UsbAccessory; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; +import android.hardware.usb.UsbPort; +import android.hardware.usb.UsbPortStatus; +import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.UserHandle; @@ -36,6 +39,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Preconditions; import com.android.server.SystemService; import java.io.File; @@ -78,6 +82,7 @@ public class UsbService extends IUsbManager.Stub { private UsbDeviceManager mDeviceManager; private UsbHostManager mHostManager; + private UsbPortManager mPortManager; private final UsbAlsaManager mAlsaManager; private final Object mLock = new Object(); @@ -110,6 +115,9 @@ public class UsbService extends IUsbManager.Stub { if (new File("/sys/class/android_usb").exists()) { mDeviceManager = new UsbDeviceManager(context, mAlsaManager); } + if (mHostManager != null || mDeviceManager != null) { + mPortManager = new UsbPortManager(context); + } setCurrentUser(UserHandle.USER_OWNER); @@ -160,6 +168,9 @@ public class UsbService extends IUsbManager.Stub { if (mHostManager != null) { mHostManager.systemReady(); } + if (mPortManager != null) { + mPortManager.systemReady(); + } } public void bootCompleted() { @@ -346,29 +357,258 @@ public class UsbService extends IUsbManager.Stub { } @Override - public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); - final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + public UsbPort[] getPorts() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); - pw.println("USB Manager State:"); - if (mDeviceManager != null) { - mDeviceManager.dump(fd, pw); + final long ident = Binder.clearCallingIdentity(); + try { + return mPortManager != null ? mPortManager.getPorts() : null; + } finally { + Binder.restoreCallingIdentity(ident); } - if (mHostManager != null) { - mHostManager.dump(fd, pw); + } + + @Override + public UsbPortStatus getPortStatus(String portId) { + Preconditions.checkNotNull(portId, "portId must not be null"); + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + + final long ident = Binder.clearCallingIdentity(); + try { + return mPortManager != null ? mPortManager.getPortStatus(portId) : null; + } finally { + Binder.restoreCallingIdentity(ident); } - mAlsaManager.dump(fd, pw); + } - synchronized (mLock) { - for (int i = 0; i < mSettingsByUser.size(); i++) { - final int userId = mSettingsByUser.keyAt(i); - final UsbSettingsManager settings = mSettingsByUser.valueAt(i); + @Override + public void setPortRoles(String portId, int powerRole, int dataRole) { + Preconditions.checkNotNull(portId, "portId must not be null"); + UsbPort.checkRoles(powerRole, dataRole); + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + + final long ident = Binder.clearCallingIdentity(); + try { + if (mPortManager != null) { + mPortManager.setPortRoles(portId, powerRole, dataRole, null); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + @Override + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); + + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + final long ident = Binder.clearCallingIdentity(); + try { + if (args == null || args.length == 0 || "-a".equals(args[0])) { + pw.println("USB Manager State:"); pw.increaseIndent(); - pw.println("Settings for user " + userId + ":"); - settings.dump(fd, pw); - pw.decreaseIndent(); + if (mDeviceManager != null) { + mDeviceManager.dump(pw); + } + if (mHostManager != null) { + mHostManager.dump(pw); + } + if (mPortManager != null) { + mPortManager.dump(pw); + } + mAlsaManager.dump(pw); + + synchronized (mLock) { + for (int i = 0; i < mSettingsByUser.size(); i++) { + final int userId = mSettingsByUser.keyAt(i); + final UsbSettingsManager settings = mSettingsByUser.valueAt(i); + pw.println("Settings for user " + userId + ":"); + pw.increaseIndent(); + settings.dump(pw); + pw.decreaseIndent(); + } + } + } else if (args.length == 4 && "set-port-roles".equals(args[0])) { + final String portId = args[1]; + final int powerRole; + switch (args[2]) { + case "source": + powerRole = UsbPort.POWER_ROLE_SOURCE; + break; + case "sink": + powerRole = UsbPort.POWER_ROLE_SINK; + break; + case "no-power": + powerRole = 0; + break; + default: + pw.println("Invalid power role: " + args[2]); + return; + } + final int dataRole; + switch (args[3]) { + case "host": + dataRole = UsbPort.DATA_ROLE_HOST; + break; + case "device": + dataRole = UsbPort.DATA_ROLE_DEVICE; + break; + case "no-data": + dataRole = 0; + break; + default: + pw.println("Invalid data role: " + args[3]); + return; + } + if (mPortManager != null) { + mPortManager.setPortRoles(portId, powerRole, dataRole, pw); + // Note: It might take some time for the side-effects of this operation + // to be fully applied by the kernel since the driver may need to + // renegotiate the USB port mode. If this proves to be an issue + // during debugging, it might be worth adding a sleep here before + // dumping the new state. + pw.println(); + mPortManager.dump(pw); + } + } else if (args.length == 3 && "add-port".equals(args[0])) { + final String portId = args[1]; + final int supportedModes; + switch (args[2]) { + case "ufp": + supportedModes = UsbPort.MODE_UFP; + break; + case "dfp": + supportedModes = UsbPort.MODE_DFP; + break; + case "dual": + supportedModes = UsbPort.MODE_DUAL; + break; + case "none": + supportedModes = 0; + break; + default: + pw.println("Invalid mode: " + args[2]); + return; + } + if (mPortManager != null) { + mPortManager.addSimulatedPort(portId, supportedModes, pw); + pw.println(); + mPortManager.dump(pw); + } + } else if (args.length == 5 && "connect-port".equals(args[0])) { + final String portId = args[1]; + final int mode; + final boolean canChangeMode = args[2].endsWith("?"); + switch (canChangeMode ? removeLastChar(args[2]) : args[2]) { + case "ufp": + mode = UsbPort.MODE_UFP; + break; + case "dfp": + mode = UsbPort.MODE_DFP; + break; + default: + pw.println("Invalid mode: " + args[2]); + return; + } + final int powerRole; + final boolean canChangePowerRole = args[3].endsWith("?"); + switch (canChangePowerRole ? removeLastChar(args[3]) : args[3]) { + case "source": + powerRole = UsbPort.POWER_ROLE_SOURCE; + break; + case "sink": + powerRole = UsbPort.POWER_ROLE_SINK; + break; + default: + pw.println("Invalid power role: " + args[3]); + return; + } + final int dataRole; + final boolean canChangeDataRole = args[4].endsWith("?"); + switch (canChangeDataRole ? removeLastChar(args[4]) : args[4]) { + case "host": + dataRole = UsbPort.DATA_ROLE_HOST; + break; + case "device": + dataRole = UsbPort.DATA_ROLE_DEVICE; + break; + default: + pw.println("Invalid data role: " + args[4]); + return; + } + if (mPortManager != null) { + mPortManager.connectSimulatedPort(portId, mode, canChangeMode, + powerRole, canChangePowerRole, dataRole, canChangeDataRole, pw); + pw.println(); + mPortManager.dump(pw); + } + } else if (args.length == 2 && "disconnect-port".equals(args[0])) { + final String portId = args[1]; + if (mPortManager != null) { + mPortManager.disconnectSimulatedPort(portId, pw); + pw.println(); + mPortManager.dump(pw); + } + } else if (args.length == 2 && "remove-port".equals(args[0])) { + final String portId = args[1]; + if (mPortManager != null) { + mPortManager.removeSimulatedPort(portId, pw); + pw.println(); + mPortManager.dump(pw); + } + } else if (args.length == 1 && "reset".equals(args[0])) { + if (mPortManager != null) { + mPortManager.resetSimulation(pw); + pw.println(); + mPortManager.dump(pw); + } + } else if (args.length == 1 && "ports".equals(args[0])) { + if (mPortManager != null) { + mPortManager.dump(pw); + } + } else { + pw.println("Dump current USB state or issue command:"); + pw.println(" ports"); + pw.println(" set-port-roles <id> <source|sink|no-power> <host|device|no-data>"); + pw.println(" add-port <id> <ufp|dfp|dual|none>"); + pw.println(" connect-port <id> <ufp|dfp><?> <source|sink><?> <host|device><?>"); + pw.println(" (add ? suffix if mode, power role, or data role can be changed)"); + pw.println(" disconnect-port <id>"); + pw.println(" remove-port <id>"); + pw.println(" reset"); + pw.println(); + pw.println("Example USB type C port role switch:"); + pw.println(" dumpsys usb set-port-roles \"default\" source device"); + pw.println(); + pw.println("Example USB type C port simulation with full capabilities:"); + pw.println(" dumpsys usb add-port \"matrix\" dual"); + pw.println(" dumpsys usb connect-port \"matrix\" ufp? sink? device?"); + pw.println(" dumpsys usb ports"); + pw.println(" dumpsys usb disconnect-port \"matrix\""); + pw.println(" dumpsys usb remove-port \"matrix\""); + pw.println(" dumpsys usb reset"); + pw.println(); + pw.println("Example USB type C port where only power role can be changed:"); + pw.println(" dumpsys usb add-port \"matrix\" dual"); + pw.println(" dumpsys usb connect-port \"matrix\" dfp source? host"); + pw.println(" dumpsys usb reset"); + pw.println(); + pw.println("Example USB OTG port where id pin determines function:"); + pw.println(" dumpsys usb add-port \"matrix\" dual"); + pw.println(" dumpsys usb connect-port \"matrix\" dfp source host"); + pw.println(" dumpsys usb reset"); + pw.println(); + pw.println("Example USB device-only port:"); + pw.println(" dumpsys usb add-port \"matrix\" ufp"); + pw.println(" dumpsys usb connect-port \"matrix\" ufp sink device"); + pw.println(" dumpsys usb reset"); } + } finally { + Binder.restoreCallingIdentity(ident); } - pw.decreaseIndent(); + } + + private static final String removeLastChar(String value) { + return value.substring(0, value.length() - 1); } } diff --git a/services/usb/java/com/android/server/usb/UsbSettingsManager.java b/services/usb/java/com/android/server/usb/UsbSettingsManager.java index 2331a8b..2cf42f0 100644 --- a/services/usb/java/com/android/server/usb/UsbSettingsManager.java +++ b/services/usb/java/com/android/server/usb/UsbSettingsManager.java @@ -44,6 +44,7 @@ import android.util.Xml; import com.android.internal.content.PackageMonitor; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import org.xmlpull.v1.XmlPullParser; @@ -1193,35 +1194,35 @@ class UsbSettingsManager { } } - public void dump(FileDescriptor fd, PrintWriter pw) { + public void dump(IndentingPrintWriter pw) { synchronized (mLock) { - pw.println(" Device permissions:"); + pw.println("Device permissions:"); for (String deviceName : mDevicePermissionMap.keySet()) { - pw.print(" " + deviceName + ": "); + pw.print(" " + deviceName + ": "); SparseBooleanArray uidList = mDevicePermissionMap.get(deviceName); int count = uidList.size(); for (int i = 0; i < count; i++) { pw.print(Integer.toString(uidList.keyAt(i)) + " "); } - pw.println(""); + pw.println(); } - pw.println(" Accessory permissions:"); + pw.println("Accessory permissions:"); for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) { - pw.print(" " + accessory + ": "); + pw.print(" " + accessory + ": "); SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); int count = uidList.size(); for (int i = 0; i < count; i++) { pw.print(Integer.toString(uidList.keyAt(i)) + " "); } - pw.println(""); + pw.println(); } - pw.println(" Device preferences:"); + pw.println("Device preferences:"); for (DeviceFilter filter : mDevicePreferenceMap.keySet()) { - pw.println(" " + filter + ": " + mDevicePreferenceMap.get(filter)); + pw.println(" " + filter + ": " + mDevicePreferenceMap.get(filter)); } - pw.println(" Accessory preferences:"); + pw.println("Accessory preferences:"); for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) { - pw.println(" " + filter + ": " + mAccessoryPreferenceMap.get(filter)); + pw.println(" " + filter + ": " + mAccessoryPreferenceMap.get(filter)); } } } diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index 36478da..42f879c 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -578,6 +578,44 @@ public class VoiceInteractionManagerService extends SystemService { } } + @Override + public void setDisabledShowContext(int flags) { + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, "setDisabledShowContext without running voice interaction service"); + return; + } + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); + final long caller = Binder.clearCallingIdentity(); + try { + mImpl.setDisabledShowContextLocked(callingPid, callingUid, flags); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + + } + + @Override + public int getDisabledShowContext() { + synchronized (this) { + if (mImpl == null) { + Slog.w(TAG, "getDisabledShowContext without running voice interaction service"); + return 0; + } + final int callingPid = Binder.getCallingPid(); + final int callingUid = Binder.getCallingUid(); + final long caller = Binder.clearCallingIdentity(); + try { + return mImpl.getDisabledShowContextLocked(callingPid, callingUid); + } finally { + Binder.restoreCallingIdentity(caller); + } + } + + } + //----------------- Model management APIs --------------------------------// @Override diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java index e5faf4d..7409f99 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java @@ -65,6 +65,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne IVoiceInteractionService mService; VoiceInteractionSessionConnection mActiveSession; + int mDisabledShowContext; final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override @@ -146,7 +147,7 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName, mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler); } - return mActiveSession.showLocked(args, flags, showCallback); + return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback); } public boolean hideSessionLocked() { @@ -222,6 +223,24 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne mActiveSession = null; } + public void setDisabledShowContextLocked(int callingPid, int callingUid, int flags) { + int activeUid = mInfo.getServiceInfo().applicationInfo.uid; + if (callingUid != activeUid) { + throw new SecurityException("Calling uid " + callingUid + + " does not match active uid " + activeUid); + } + mDisabledShowContext = flags; + } + + public int getDisabledShowContextLocked(int callingPid, int callingUid) { + int activeUid = mInfo.getServiceInfo().applicationInfo.uid; + if (callingUid != activeUid) { + throw new SecurityException("Calling uid " + callingUid + + " does not match active uid " + activeUid); + } + return mDisabledShowContext; + } + public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) { if (!mValid) { pw.print(" NOT VALID: "); @@ -235,6 +254,10 @@ class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConne pw.print(" mComponent="); pw.println(mComponent.flattenToShortString()); pw.print(" Session service="); pw.println(mInfo.getSessionService()); pw.print(" Settings activity="); pw.println(mInfo.getSettingsActivity()); + if (mDisabledShowContext != 0) { + pw.print(" mDisabledShowContext="); + pw.println(Integer.toHexString(mDisabledShowContext)); + } pw.print(" mBound="); pw.print(mBound); pw.print(" mService="); pw.println(mService); if (mActiveSession != null) { pw.println(" Active session:"); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index bd043ac..dfdd639 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -183,7 +183,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { } } - public boolean showLocked(Bundle args, int flags, + public boolean showLocked(Bundle args, int flags, int disabledContext, IVoiceInteractionSessionShowCallback showCallback) { if (mBound) { if (!mFullyBound) { @@ -200,15 +200,17 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { } boolean structureEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0 - && isScreenCaptureAllowed; + && isScreenCaptureAllowed + && (disabledContext&VoiceInteractionSession.SHOW_WITH_ASSIST) == 0; boolean screenshotEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(), Settings.Secure.ASSIST_SCREENSHOT_ENABLED, 1, mUser) != 0 - && isScreenCaptureAllowed; + && isScreenCaptureAllowed + && (disabledContext&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0; mShowArgs = args; mShowFlags = flags; mHaveAssistData = false; boolean needDisclosure = false; - if ((flags& VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) { + if ((flags&VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) { if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid, mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED && structureEnabled) { @@ -226,7 +228,7 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mAssistData = null; } mHaveScreenshot = false; - if ((flags& VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) { + if ((flags&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) { if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid, mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED && screenshotEnabled) { |