From cfb30af1182efed17a61a1c6848d5e1bc9060f1d Mon Sep 17 00:00:00 2001 From: Filip Pavlis Date: Wed, 6 Feb 2019 12:32:57 +0000 Subject: [PATCH 001/349] Restrict access to View's hierarchy listener. The private field should not be used directly. There is a setter for it called setOnHierarchyChangeListener that allows to provide listener implementation. The callback should not be called outside of ViewGroup as ViewGroup also calls onViewAdded / onViewRemoved. In case the reference to the callback is really needed, the developer can override the setter. Bug: b/123768704 Test: N/A Change-Id: Idfc9c656d496b4e3e2c134a1d5e2c95f15099f51 --- core/java/android/view/ViewGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d2b40f75a6a8..94af0f375968 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -142,7 +142,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * This field should be made private, so it is hidden from the SDK. * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768704) protected OnHierarchyChangeListener mOnHierarchyChangeListener; // The view contained within this ViewGroup that has or contains focus. -- GitLab From d590b1a719f0dbb992812dc064fff332e3de276f Mon Sep 17 00:00:00 2001 From: Filip Pavlis Date: Wed, 6 Feb 2019 13:47:19 +0000 Subject: [PATCH 002/349] Restrict FLAG_SUPPORT_STATIC_TRANSFORMATIONS usage There is a proper setter for it already called setStaticTransformationsEnabled. There is not a strong motivation for a getter as this is only used to instruct the class to invoke getChildStaticTransformation when a child is drawn. And any class setting this flag to true is supposed to override that getter. Also I was not able to find any reasonable public usages of the flag. Bug: b/123769647 Test: N/A Change-Id: I14ea7d560a5318cc372ac84dc5a1daad626e4f7e --- core/java/android/view/ViewGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d2b40f75a6a8..7e7384e8f868 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -314,7 +314,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769647) protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800; // UNUSED FLAG VALUE: 0x1000; -- GitLab From b04f2a8ec4736f859c00b1b43ccedf6279666e30 Mon Sep 17 00:00:00 2001 From: Filip Pavlis Date: Wed, 6 Feb 2019 14:15:49 +0000 Subject: [PATCH 003/349] Restrict access to FLAG_USE_CHILD_DRAWING_ORDER. There is already a setter called setChildrenDrawingOrderEnabled and getter called isChildrenDrawingOrderEnabled. Bug: b/123769377 Test: N/A Change-Id: Ia342129610fc332475163dc5245fc533ae5e21b2 --- core/java/android/view/ViewGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d2b40f75a6a8..b5058ec5c31e 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -300,7 +300,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769377) protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400; /** -- GitLab From c010f01052e6b30210835c595f40b8b527128aab Mon Sep 17 00:00:00 2001 From: Filip Pavlis Date: Wed, 6 Feb 2019 14:33:29 +0000 Subject: [PATCH 004/349] Restrict accesss to FLAG_DISALLOW_INTERCEPT The flag is very internal and optimally it should be set indirectly via requestDisallowInterceptTouchEvent method. Bug: b/123983692 Test: N/A Change-Id: I49e08c0b96e7e80353a223917cadf547aae3c797 --- core/java/android/view/ViewGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d2b40f75a6a8..2e9f61f9e595 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -368,7 +368,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * When set, this ViewGroup should not intercept touch events. * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123983692) protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000; /** -- GitLab From 0e63fcbeed6ac2b98f1a200796f1582da0c32bcd Mon Sep 17 00:00:00 2001 From: Filip Pavlis Date: Wed, 6 Feb 2019 14:46:37 +0000 Subject: [PATCH 005/349] Restrict access to mGroupFlags. We can safely restrict the access because there are no flags that could be publicly accessed. Please see the overview below. Private flags: FLAG_CLIP_TO_PADDING FLAG_RUN_ANIMATION FLAG_PADDING_NOT_NULL FLAG_NOTIFY_ANIMATION_LISTENER FLAG_ANIMATION_CACHE FLAG_ALWAYS_DRAWN_WITH_CACHE FLAG_CHILDREN_DRAWN_WITH_CACHE FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE FLAG_MASK_FOCUSABILITY FLAG_ADD_STATES_FROM_CHILDREN FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE FLAG_MASK_FOCUSABILITY FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED FLAG_SHOW_CONTEXT_MENU_WITH_COORDS DESCENDANT_FOCUSABILITY_FLAGS Package private flags: FLAG_CLIP_CHILDREN FLAG_INVALIDATE_REQUIRED FLAG_ANIMATION_DONE FLAG_OPTIMIZE_INVALIDATE FLAG_CLEAR_TRANSFORMATION FLAG_IS_TRANSITION_GROUP FLAG_IS_TRANSITION_GROUP_SET FLAG_TOUCHSCREEN_BLOCKS_FOCUS Public but not related to mGroupFlags FOCUS_BEFORE_DESCENDANTS FOCUS_AFTER_DESCENDANTS FOCUS_BLOCK_DESCENDANTS Protected that are going to be restricted FLAG_SUPPORT_STATIC_TRANSFORMATIONS - ag/6278964 FLAG_USE_CHILD_DRAWING_ORDER - ag/6278967 FLAG_DISALLOW_INTERCEPT - ag/6278968 Bug: b/123769411 Test: N/A Change-Id: I7137c09f1274b5e65b45163e88ed914b1288a0eb --- core/java/android/view/ViewGroup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index d2b40f75a6a8..fe8ad3be0227 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -239,7 +239,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL, name = "PADDING_NOT_NULL") }, formatToHexString = true) - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769411) protected int mGroupFlags; /** -- GitLab From 1c88bcee5c834f2dfd40b7a862c0ec80074e7e47 Mon Sep 17 00:00:00 2001 From: Qasid Ahmad Sadiq Date: Mon, 11 Feb 2019 18:05:25 -0800 Subject: [PATCH 006/349] AccessibilityRequestPreparer shouldn't crash if the view is released before the preparer is added or removed. AccessibilityRequestPreparer holds onto a weak reference of the view. When it is added or removed, AccessibilityManager uses the views accessibilityId to maintain the lists of requestPreparers. But, it is completely possible, that a view is released before requestPreparer is removed, or even added, and that will cause bad things. Instead, store the id on the preparer also. Change-Id: I5d489c061cd8039d066a81f4a927c1d8185d4f06 Fix: 123047944 Test: CtsAccessibilityServiceTestCases --- .../android/view/accessibility/AccessibilityManager.java | 4 ++-- .../view/accessibility/AccessibilityRequestPreparer.java | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index 06207a9290d7..0f0d3c9b0356 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -848,7 +848,7 @@ public final class AccessibilityManager { if (mRequestPreparerLists == null) { mRequestPreparerLists = new SparseArray<>(1); } - int id = preparer.getView().getAccessibilityViewId(); + int id = preparer.getAccessibilityViewId(); List requestPreparerList = mRequestPreparerLists.get(id); if (requestPreparerList == null) { requestPreparerList = new ArrayList<>(1); @@ -864,7 +864,7 @@ public final class AccessibilityManager { if (mRequestPreparerLists == null) { return; } - int viewId = preparer.getView().getAccessibilityViewId(); + int viewId = preparer.getAccessibilityViewId(); List requestPreparerList = mRequestPreparerLists.get(viewId); if (requestPreparerList != null) { requestPreparerList.remove(preparer); diff --git a/core/java/android/view/accessibility/AccessibilityRequestPreparer.java b/core/java/android/view/accessibility/AccessibilityRequestPreparer.java index 4dcb18766347..8108d37a8814 100644 --- a/core/java/android/view/accessibility/AccessibilityRequestPreparer.java +++ b/core/java/android/view/accessibility/AccessibilityRequestPreparer.java @@ -51,6 +51,7 @@ public abstract class AccessibilityRequestPreparer { public @interface RequestTypes {} private final WeakReference mViewRef; + private final int mAccessibilityViewId; private final int mRequestTypes; /** @@ -68,6 +69,7 @@ public abstract class AccessibilityRequestPreparer { throw new IllegalStateException("View must be attached to a window"); } mViewRef = new WeakReference<>(view); + mAccessibilityViewId = view.getAccessibilityViewId(); mRequestTypes = requestTypes; view.addOnAttachStateChangeListener(new ViewAttachStateListener()); } @@ -118,4 +120,8 @@ public abstract class AccessibilityRequestPreparer { v.removeOnAttachStateChangeListener(this); } } + + int getAccessibilityViewId() { + return mAccessibilityViewId; + } } -- GitLab From 0fc2da03fe61a4105ffadd2e09f1accc9b790b5a Mon Sep 17 00:00:00 2001 From: Ray Essick Date: Thu, 28 Feb 2019 09:26:19 -0800 Subject: [PATCH 007/349] Allow app-level updates to video/audio timers Relax permission checking so that an app can self-report that it is playing video. This helps as more video playback moves to app space rather than a system service. Bug: 123732427 Test: play videos, dumpsys batterystats --- .../android/server/am/BatteryStatsService.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 4d5cb8cb4473..f86ba278138c 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -754,7 +754,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStartAudio(int uid) { - enforceCallingPermission(); + enforceSelfOrCallingPermission(uid); synchronized (mStats) { mStats.noteAudioOnLocked(uid); StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null, @@ -763,7 +763,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStopAudio(int uid) { - enforceCallingPermission(); + enforceSelfOrCallingPermission(uid); synchronized (mStats) { mStats.noteAudioOffLocked(uid); StatsLog.write_non_chained(StatsLog.AUDIO_STATE_CHANGED, uid, null, @@ -772,7 +772,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStartVideo(int uid) { - enforceCallingPermission(); + enforceSelfOrCallingPermission(uid); synchronized (mStats) { mStats.noteVideoOnLocked(uid); StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, null, @@ -781,7 +781,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void noteStopVideo(int uid) { - enforceCallingPermission(); + enforceSelfOrCallingPermission(uid); synchronized (mStats) { mStats.noteVideoOffLocked(uid); StatsLog.write_non_chained(StatsLog.MEDIA_CODEC_STATE_CHANGED, uid, @@ -1182,6 +1182,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub Binder.getCallingPid(), Binder.getCallingUid(), null); } + private void enforceSelfOrCallingPermission(int uid) { + if (Binder.getCallingUid() == uid) { + return; + } + enforceCallingPermission(); + } + final class WakeupReasonThread extends Thread { private static final int MAX_REASON_SIZE = 512; private CharsetDecoder mDecoder; -- GitLab From 47a6760c760d47a382578e3e0f92b2f9edcc7867 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 7 Feb 2019 14:13:13 -0800 Subject: [PATCH 008/349] Remove ConnectivityManager and its usages from NetworkStatsService. NSS needed it for getting VpnInfo[], NetworkState[] and activeLinkProperties which it used to query via ConnectivityManager. For VpnInfo[], this was racy as NSS may ignore intermediate changes to a VPN's underlying networks. See http://b/123961098 for more context. It may also lead to deadlocks b/w ConnectivityService and NetworkStatsService. See http://b/126245192 for more info. This change will ensure that NSS is never contending on any of ConnectivityService locks. This change also is cherry-picking cleanup made to NSS in http://aosp/628368. Bug: 123961098 Bug: 126245192 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: Ia687845888434c8ddd24bdf44b4c70dfe80e03f5 Merged-In: I57e117bb4e9efe491b19d6b5a479f2d58d1c58e6 --- .../android/net/IConnectivityManager.aidl | 2 - .../android/net/INetworkStatsService.aidl | 8 +- .../android/server/ConnectivityService.java | 22 +++-- .../server/net/NetworkStatsService.java | 53 +++++------- .../java/com/android/server/SystemServer.java | 1 - .../server/ConnectivityServiceTest.java | 63 ++++++++++++--- .../server/net/NetworkStatsServiceTest.java | 81 +++++++++---------- 7 files changed, 137 insertions(+), 93 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index ce95b60dd2db..83c862f75372 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -120,8 +120,6 @@ interface IConnectivityManager LegacyVpnInfo getLegacyVpnInfo(int userId); - VpnInfo[] getAllVpnInfo(); - boolean updateLockdownVpn(); boolean isAlwaysOnVpnPackageSupported(int userId, String packageName); boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown); diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 8e6f27238846..148b25dfa86f 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -19,11 +19,13 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.Network; +import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; +import com.android.internal.net.VpnInfo; /** {@hide} */ interface INetworkStatsService { @@ -58,7 +60,11 @@ interface INetworkStatsService { void incrementOperationCount(int uid, int tag, int operationCount); /** Force update of ifaces. */ - void forceUpdateIfaces(in Network[] defaultNetworks); + void forceUpdateIfaces( + in Network[] defaultNetworks, + in VpnInfo[] vpnArray, + in NetworkState[] networkStates, + in String activeIface); /** Force update of statistics. */ void forceUpdate(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1c66c5a77151..17cece1a2245 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3743,12 +3743,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Return the information of all ongoing VPNs. This method is used by NetworkStatsService - * and not available in ConnectivityManager. + * Return the information of all ongoing VPNs. + * + *

This method is used to update NetworkStatsService. + * + *

Must be called on the handler thread. */ - @Override - public VpnInfo[] getAllVpnInfo() { - enforceConnectivityInternalPermission(); + private VpnInfo[] getAllVpnInfo() { + ensureRunningOnConnectivityServiceThread(); synchronized (mVpns) { if (mLockdownEnabled) { return new VpnInfo[0]; @@ -5816,6 +5818,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * Must be called on the handler thread. */ private Network[] getDefaultNetworks() { + ensureRunningOnConnectivityServiceThread(); ArrayList defaultNetworks = new ArrayList<>(); NetworkAgentInfo defaultNetwork = getDefaultNetwork(); for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { @@ -5831,8 +5834,15 @@ public class ConnectivityService extends IConnectivityManager.Stub * properties tracked by NetworkStatsService on an active iface has changed. */ private void notifyIfacesChangedForNetworkStats() { + ensureRunningOnConnectivityServiceThread(); + String activeIface = null; + LinkProperties activeLinkProperties = getActiveLinkProperties(); + if (activeLinkProperties != null) { + activeIface = activeLinkProperties.getInterfaceName(); + } try { - mStatsService.forceUpdateIfaces(getDefaultNetworks()); + mStatsService.forceUpdateIfaces( + getDefaultNetworks(), getAllVpnInfo(), getAllNetworkState(), activeIface); } catch (Exception ignored) { } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 17ab29d74790..2fef560afdcd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -82,7 +82,6 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -161,9 +160,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Perform polling and persist all (FLAG_PERSIST_ALL). private static final int MSG_PERFORM_POLL = 1; - private static final int MSG_UPDATE_IFACES = 2; // Perform polling, persist network, and register the global alert again. - private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 3; + private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -196,8 +194,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final boolean mUseBpfTrafficStats; - private IConnectivityManager mConnManager; - @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; @@ -259,6 +255,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final ArrayMap mActiveUidIfaces = new ArrayMap<>(); /** Current default active iface. */ + @GuardedBy("mStatsLock") private String mActiveIface; /** Set of any ifaces associated with mobile networks since boot. */ @@ -269,6 +266,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Set containing info about active VPNs and their underlying networks. */ + @GuardedBy("mStatsLock") + private VpnInfo[] mVpnInfos = new VpnInfo[0]; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -371,10 +372,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerCallback = callback; } - public void bindConnectivityManager(IConnectivityManager connManager) { - mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); - } - public void systemReady() { mSystemReady = true; @@ -853,13 +850,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void forceUpdateIfaces(Network[] defaultNetworks) { + public void forceUpdateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks); + updateIfaces(defaultNetworks, vpnArray, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1077,11 +1078,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private void updateIfaces(Network[] defaultNetworks) { + private void updateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - updateIfacesLocked(defaultNetworks); + mVpnInfos = vpnArray; + mActiveIface = activeIface; + updateIfacesLocked(defaultNetworks, networkStates); } finally { mWakeLock.release(); } @@ -1095,7 +1102,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks) { + private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1107,18 +1114,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // will be persisted during next alarm poll event. performPollLocked(FLAG_PERSIST_NETWORK); - final NetworkState[] states; - final LinkProperties activeLink; - try { - states = mConnManager.getAllNetworkState(); - activeLink = mConnManager.getActiveLinkProperties(); - } catch (RemoteException e) { - // ignored; service lives in system_server - return; - } - - mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null; - // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); @@ -1230,7 +1225,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - VpnInfo[] vpnArray = mConnManager.getAllVpnInfo(); + VpnInfo[] vpnArray = mVpnInfos; Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); @@ -1689,10 +1684,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mService.performPoll(FLAG_PERSIST_ALL); return true; } - case MSG_UPDATE_IFACES: { - mService.updateIfaces(null); - return true; - } case MSG_PERFORM_POLL_REGISTER_ALERT: { mService.performPoll(FLAG_PERSIST_NETWORK); mService.registerGlobalAlert(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ae971f45525e..8613fcb5ddc0 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1190,7 +1190,6 @@ public final class SystemServer { ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); - networkStats.bindConnectivityManager(connectivity); networkPolicy.bindConnectivityManager(connectivity); } catch (Throwable e) { reportWtf("starting Connectivity Service", e); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0dcb21ab8386..e6a889b1c27f 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -109,6 +109,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; import android.net.NetworkRequest; import android.net.NetworkSpecifier; +import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.StringNetworkSpecifier; @@ -137,6 +138,7 @@ import android.util.ArraySet; import android.util.Log; import com.android.internal.net.VpnConfig; +import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; @@ -3813,48 +3815,91 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - Network[] onlyCell = new Network[]{mCellNetworkAgent.getNetwork()}; - Network[] onlyWifi = new Network[]{mWiFiNetworkAgent.getNetwork()}; + Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()}; + Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()}; + + LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName(MOBILE_IFNAME); + LinkProperties wifiLp = new LinkProperties(); + wifiLp.setInterfaceName(WIFI_IFNAME); // Simple connection should have updated ifaces mCellNetworkAgent.connect(false); + mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Default network switch should update ifaces. mWiFiNetworkAgent.connect(false); + mWiFiNetworkAgent.sendLinkProperties(wifiLp); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyWifi); + assertEquals(wifiLp, mService.getActiveLinkProperties()); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyWifi), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(WIFI_IFNAME)); reset(mStatsService); // Disconnect should update ifaces. mWiFiNetworkAgent.disconnect(); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Metered change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Captive portal change shouldn't update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); waitForIdle(); - verify(mStatsService, never()).forceUpdateIfaces(onlyCell); + verify(mStatsService, never()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Roaming change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index e371abcb2645..7cf1dc460bea 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -70,7 +70,6 @@ import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.Intent; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsSession; import android.net.LinkProperties; @@ -163,7 +162,6 @@ public class NetworkStatsServiceTest { private @Mock INetworkManagementService mNetManager; private @Mock NetworkStatsSettings mSettings; - private @Mock IConnectivityManager mConnManager; private @Mock IBinder mBinder; private @Mock AlarmManager mAlarmManager; private HandlerThread mHandlerThread; @@ -205,7 +203,6 @@ public class NetworkStatsServiceTest { Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService); mHandler = new Handler(mHandlerThread.getLooper(), callback); mService.setHandler(mHandler, callback); - mService.bindConnectivityManager(mConnManager); mElapsedRealtime = 0L; @@ -237,7 +234,6 @@ public class NetworkStatsServiceTest { mNetManager = null; mSettings = null; - mConnManager = null; mSession.close(); mService = null; @@ -248,12 +244,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -292,12 +288,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -366,12 +362,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // modify some number on wifi, and trigger poll event @@ -408,12 +404,12 @@ public class NetworkStatsServiceTest { public void testUidStatsAcrossNetworks() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some traffic on first network @@ -440,7 +436,7 @@ public class NetworkStatsServiceTest { // disappearing, to verify we don't count backwards. incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_2)); + states = new NetworkState[] {buildMobile3gState(IMSI_2)}; expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) @@ -449,7 +445,7 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); forcePollAndWaitForIdle(); @@ -484,12 +480,12 @@ public class NetworkStatsServiceTest { public void testUidRemovedIsMoved() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some traffic @@ -543,12 +539,12 @@ public class NetworkStatsServiceTest { public void testUid3g4gCombinedByTemplate() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some traffic @@ -569,14 +565,14 @@ public class NetworkStatsServiceTest { // now switch over to 4g network incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - expectNetworkState(buildMobile4gState(TEST_IFACE2)); + states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); forcePollAndWaitForIdle(); @@ -601,12 +597,12 @@ public class NetworkStatsServiceTest { public void testSummaryForAllUid() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some traffic for two apps @@ -660,12 +656,12 @@ public class NetworkStatsServiceTest { public void testDetailedUidStats() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); NetworkStats.Entry entry1 = new NetworkStats.Entry( TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L); @@ -703,13 +699,13 @@ public class NetworkStatsServiceTest { stackedProp.setInterfaceName(stackedIface); final NetworkState wifiState = buildWifiState(); wifiState.linkProperties.addStackedLink(stackedProp); - expectNetworkState(wifiState); + NetworkState[] states = new NetworkState[] {wifiState}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); NetworkStats.Entry uidStats = new NetworkStats.Entry( TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); @@ -748,12 +744,12 @@ public class NetworkStatsServiceTest { public void testForegroundBackground() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some initial traffic @@ -806,12 +802,12 @@ public class NetworkStatsServiceTest { public void testMetered() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState(true /* isMetered */)); + NetworkState[] states = new NetworkState[] {buildWifiState(true /* isMetered */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some initial traffic @@ -846,12 +842,13 @@ public class NetworkStatsServiceTest { public void testRoaming() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */)); + NetworkState[] states = + new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // Create some traffic @@ -885,12 +882,12 @@ public class NetworkStatsServiceTest { public void testTethering() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some tethering traffic @@ -928,12 +925,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -1081,11 +1078,11 @@ public class NetworkStatsServiceTest { expectBandwidthControlCheck(); } - private void expectNetworkState(NetworkState... state) throws Exception { - when(mConnManager.getAllNetworkState()).thenReturn(state); - - final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null; - when(mConnManager.getActiveLinkProperties()).thenReturn(linkProp); + private String getActiveIface(NetworkState... states) throws Exception { + if (states == null || states.length == 0 || states[0].linkProperties == null) { + return null; + } + return states[0].linkProperties.getInterfaceName(); } private void expectNetworkStatsSummary(NetworkStats summary) throws Exception { @@ -1094,8 +1091,6 @@ public class NetworkStatsServiceTest { private void expectNetworkStatsSummary(NetworkStats summary, NetworkStats tetherStats) throws Exception { - when(mConnManager.getAllVpnInfo()).thenReturn(new VpnInfo[0]); - expectNetworkStatsTethering(STATS_PER_IFACE, tetherStats); expectNetworkStatsSummaryDev(summary.clone()); expectNetworkStatsSummaryXt(summary.clone()); -- GitLab From 62b68341e8c9cb7a57da99413f5d3d52373e85e0 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Mon, 11 Mar 2019 13:28:02 -0700 Subject: [PATCH 009/349] Compile all files in res/xml as xml AAPT(1) compiled all files in res/xml as xml. Continue to do the same to prevent regressions. Bug: 122321161 Test: manual Change-Id: I99c80da6d304c13ce911cd5258fd561f3c9e91b4 --- tools/aapt2/cmd/Compile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 42dc74c6db55..2ec1ab31a58c 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -678,7 +678,7 @@ int Compile(IAaptContext* context, io::IFileCollection* inputs, IArchiveWriter* } else if (const ResourceType* type = ParseResourceType(path_data.resource_dir)) { if (*type != ResourceType::kRaw) { - if (path_data.extension == "xml") { + if (*type == ResourceType::kXml || path_data.extension == "xml") { compile_func = &CompileXml; } else if ((!options.no_png_crunch && path_data.extension == "png") || path_data.extension == "9.png") { -- GitLab From 3319d02012f4cf63a8448fcf147a0944de19b604 Mon Sep 17 00:00:00 2001 From: Louis Chang Date: Tue, 12 Mar 2019 11:53:14 +0800 Subject: [PATCH 010/349] Fix activities cannot be resumed when non-secure keyguard shown Activities were unable to show on secondary displays with FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD flag because the AOD was showing on default display. Bug: 128248976 Test: atest KeyguardTests Test: atest ActivityManagerMultiDisplayTests Change-Id: Ifcbc06106c306aca897d280f84d19fb7fb8a6582 --- .../java/com/android/server/wm/KeyguardController.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java index 8c8b05f1307a..ad93c6335532 100644 --- a/services/core/java/com/android/server/wm/KeyguardController.java +++ b/services/core/java/com/android/server/wm/KeyguardController.java @@ -95,13 +95,15 @@ class KeyguardController { } /** - * @return {@code true} if 1) Keyguard is showing, not going away, and not being occluded on the - * given display, or 2) AOD is showing, {@code false} otherwise. + * @return {@code true} for default display when AOD is showing. Otherwise, same as + * {@link #isKeyguardOrAodShowing(int)} * TODO(b/125198167): Replace isKeyguardOrAodShowing() by this logic. */ boolean isKeyguardUnoccludedOrAodShowing(int displayId) { - return (mKeyguardShowing && !mKeyguardGoingAway && !isDisplayOccluded(displayId)) - || mAodShowing; + if (displayId == DEFAULT_DISPLAY && mAodShowing) { + return true; + } + return isKeyguardOrAodShowing(displayId); } /** -- GitLab From 309ba00310e594ae830e25ec797c065b1bda672f Mon Sep 17 00:00:00 2001 From: Varun Shah Date: Fri, 8 Mar 2019 23:02:40 -0800 Subject: [PATCH 011/349] Remove deprecated USM#registerAppUsageLimitObserver. Removes deprecated API registerAppUsageLimitObserver in UsageStatsManager. Bug: 126917290 Test: n/a Change-Id: I21fb0a1ab47a1222af4e0052cd2b5fb0eb2ee9a8 --- .../android/app/usage/UsageStatsManager.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index e47ec22310aa..bdd356dbf532 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -738,23 +738,6 @@ public final class UsageStatsManager { } } - /** - * @deprecated use - * {@link #registerAppUsageLimitObserver(int, String[], Duration, Duration, PendingIntent)}. - * - * @removed - * @hide - */ - @Deprecated - @UnsupportedAppUsage - // STOPSHIP b/126917290: remove this method once b/126926550 is fixed. - public void registerAppUsageLimitObserver(int observerId, @NonNull String[] observedEntities, - long timeLimit, @NonNull TimeUnit timeUnit, @Nullable PendingIntent callbackIntent) { - final Duration timeLimitDuration = Duration.ofMillis(timeUnit.toMillis(timeLimit)); - registerAppUsageLimitObserver(observerId, observedEntities, - timeLimitDuration, timeLimitDuration, callbackIntent); - } - /** * Register a usage limit observer that receives a callback on the provided intent when the * sum of usages of apps and tokens in the provided {@code observedEntities} array exceeds the -- GitLab From f64ba348d7ea28f13c4439d8934928c929fd01bd Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Thu, 14 Mar 2019 11:34:27 +0000 Subject: [PATCH 012/349] Add self to OWNERS for MediaProjection. Bug: N/A Test: N/A Change-Id: Ia33983576f55d0d3ea1443655db9103800e38d45 --- media/java/android/media/projection/OWNERS | 1 + packages/SystemUI/src/com/android/systemui/media/OWNERS | 1 + services/core/java/com/android/server/media/projection/OWNERS | 1 + 3 files changed, 3 insertions(+) create mode 100644 media/java/android/media/projection/OWNERS create mode 100644 packages/SystemUI/src/com/android/systemui/media/OWNERS create mode 100644 services/core/java/com/android/server/media/projection/OWNERS diff --git a/media/java/android/media/projection/OWNERS b/media/java/android/media/projection/OWNERS new file mode 100644 index 000000000000..7e7335d68d3b --- /dev/null +++ b/media/java/android/media/projection/OWNERS @@ -0,0 +1 @@ +michaelwr@google.com diff --git a/packages/SystemUI/src/com/android/systemui/media/OWNERS b/packages/SystemUI/src/com/android/systemui/media/OWNERS new file mode 100644 index 000000000000..69ea57bfd397 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/OWNERS @@ -0,0 +1 @@ +per-file MediaProjectionPermissionActivity.java = michaelwr@google.com diff --git a/services/core/java/com/android/server/media/projection/OWNERS b/services/core/java/com/android/server/media/projection/OWNERS new file mode 100644 index 000000000000..7e7335d68d3b --- /dev/null +++ b/services/core/java/com/android/server/media/projection/OWNERS @@ -0,0 +1 @@ +michaelwr@google.com -- GitLab From b99050d89c0ef8a4a13f34246e06c4152e35712c Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Wed, 13 Mar 2019 15:29:48 +0000 Subject: [PATCH 013/349] Require the ANDROID_TZDATA_ROOT env var The ANDROID_TZDATA_ROOT serves a similar purpose to the ANDROID_RUNTIME_ROOT: it determines the location that can be used to find time zone data files. Since the Android Core Library will soon require it to be set it makes sense to check it alongside the ANDROID_RUNTIME_ROOT variable. Bug: 128422035 Test: build / boot Change-Id: Ie4860f60760905a06a744bd48fd773d0a4e8cf6d --- core/jni/AndroidRuntime.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 388285a5687f..79850d03160a 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -1112,6 +1112,12 @@ void AndroidRuntime::start(const char* className, const Vector& options return; } + const char* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT"); + if (tzdataRootDir == NULL) { + LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable."); + return; + } + //const char* kernelHack = getenv("LD_ASSUME_KERNEL"); //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); -- GitLab From 9f98789d3f3642bacc3f339009e8a7938ce5761b Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 14 Mar 2019 18:28:00 +0000 Subject: [PATCH 014/349] Revert "Revert "Update VPN capabilities when its underlying network set is null."" This reverts commit 6a050c7c50fa0838d7e29b8c6e244018044246db. Reason for revert: Retargeted for June monthly release Bug: 119129310 Change-Id: I9d543415c5707859cfa2a14a1a8ce5909aae7d11 Merged-In: Id0abc4d304bb096e92479a118168690ccce634ed --- .../android/server/ConnectivityService.java | 55 ++++++++- .../com/android/server/connectivity/Vpn.java | 66 +++++++--- .../server/ConnectivityServiceTest.java | 115 +++++++++++++++--- .../android/server/connectivity/VpnTest.java | 12 +- 4 files changed, 208 insertions(+), 40 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c9f9ab675a75..1c66c5a77151 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -867,7 +867,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mPermissionMonitor = new PermissionMonitor(mContext, mNetd); - //set up the listener for user state for creating user VPNs + // Set up the listener for user state for creating user VPNs. + // Should run on mHandler to avoid any races. IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTED); intentFilter.addAction(Intent.ACTION_USER_STOPPED); @@ -875,7 +876,11 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser( - mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); + mUserIntentReceiver, + UserHandle.ALL, + intentFilter, + null /* broadcastPermission */, + mHandler); mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_USER_PRESENT), null, null); @@ -3815,17 +3820,27 @@ public class ConnectivityService extends IConnectivityManager.Stub * handler thread through their agent, this is asynchronous. When the capabilities objects * are computed they will be up-to-date as they are computed synchronously from here and * this is running on the ConnectivityService thread. - * TODO : Fix this and call updateCapabilities inline to remove out-of-order events. */ private void updateAllVpnsCapabilities() { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { for (int i = 0; i < mVpns.size(); i++) { final Vpn vpn = mVpns.valueAt(i); - vpn.updateCapabilities(); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } + private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) { + ensureRunningOnConnectivityServiceThread(); + NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId()); + if (vpnNai == null || nc == null) { + return; + } + updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc); + } + @Override public boolean updateLockdownVpn() { if (Binder.getCallingUid() != Process.SYSTEM_UID) { @@ -4132,21 +4147,27 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserAdded(int userId) { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserAdded(userId); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } private void onUserRemoved(int userId) { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserRemoved(userId); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } @@ -4165,6 +4186,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + ensureRunningOnConnectivityServiceThread(); final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (userId == UserHandle.USER_NULL) return; @@ -4650,6 +4672,19 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkForRequest(mDefaultRequest.requestId); } + @Nullable + private Network getNetwork(@Nullable NetworkAgentInfo nai) { + return nai != null ? nai.network : null; + } + + private void ensureRunningOnConnectivityServiceThread() { + if (mHandler.getLooper().getThread() != Thread.currentThread()) { + throw new IllegalStateException( + "Not running on ConnectivityService thread: " + + Thread.currentThread().getName()); + } + } + private boolean isDefaultNetwork(NetworkAgentInfo nai) { return nai == getDefaultNetwork(); } @@ -5197,6 +5232,8 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(newNetwork); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); notifyIfacesChangedForNetworkStats(); + // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. + updateAllVpnsCapabilities(); } private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { @@ -5630,6 +5667,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // doing. updateSignalStrengthThresholds(networkAgent, "CONNECT", null); + if (networkAgent.isVPN()) { + updateAllVpnsCapabilities(); + } + // Consider network even though it is not yet validated. final long now = SystemClock.elapsedRealtime(); rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now); @@ -5823,7 +5864,11 @@ public class ConnectivityService extends IConnectivityManager.Stub success = mVpns.get(user).setUnderlyingNetworks(networks); } if (success) { - mHandler.post(() -> notifyIfacesChangedForNetworkStats()); + mHandler.post(() -> { + // Update VPN's capabilities based on updated underlying network set. + updateAllVpnsCapabilities(); + notifyIfacesChangedForNetworkStats(); + }); } return success; } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 2a80f0e7c291..56510b7e18b3 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -273,7 +273,7 @@ public class Vpn { mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); - updateCapabilities(); + updateCapabilities(null /* defaultNetwork */); loadAlwaysOnPackage(); } @@ -300,18 +300,39 @@ public class Vpn { updateAlwaysOnNotification(detailedState); } - public void updateCapabilities() { - final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null; - updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks, - mNetworkCapabilities); + /** + * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a + * defensive copy. + * + *

Does not propagate updated capabilities to apps. + * + * @param defaultNetwork underlying network for VPNs following platform's default + */ + public synchronized NetworkCapabilities updateCapabilities( + @Nullable Network defaultNetwork) { + if (mConfig == null) { + // VPN is not running. + return null; + } - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + Network[] underlyingNetworks = mConfig.underlyingNetworks; + if (underlyingNetworks == null && defaultNetwork != null) { + // null underlying networks means to track the default. + underlyingNetworks = new Network[] { defaultNetwork }; } + + applyUnderlyingCapabilities( + mContext.getSystemService(ConnectivityManager.class), + underlyingNetworks, + mNetworkCapabilities); + + return new NetworkCapabilities(mNetworkCapabilities); } @VisibleForTesting - public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks, + public static void applyUnderlyingCapabilities( + ConnectivityManager cm, + Network[] underlyingNetworks, NetworkCapabilities caps) { int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN }; int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; @@ -323,6 +344,7 @@ public class Vpn { boolean hadUnderlyingNetworks = false; if (null != underlyingNetworks) { for (Network underlying : underlyingNetworks) { + // TODO(b/124469351): Get capabilities directly from ConnectivityService instead. final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying); if (underlyingCaps == null) continue; hadUnderlyingNetworks = true; @@ -993,9 +1015,8 @@ public class Vpn { } /** - * Establish a VPN network and return the file descriptor of the VPN - * interface. This methods returns {@code null} if the application is - * revoked or not prepared. + * Establish a VPN network and return the file descriptor of the VPN interface. This methods + * returns {@code null} if the application is revoked or not prepared. * * @param config The parameters to configure the network. * @return The file descriptor of the VPN interface. @@ -1242,6 +1263,11 @@ public class Vpn { return ranges; } + /** + * Updates UID ranges for this VPN and also updates its internal capabilities. + * + *

Should be called on primary ConnectivityService thread. + */ public void onUserAdded(int userHandle) { // If the user is restricted tie them to the parent user's VPN UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); @@ -1252,8 +1278,9 @@ public class Vpn { try { addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications, mConfig.disallowedApplications); + // ConnectivityService will call {@link #updateCapabilities} and apply + // those for VPN network. mNetworkCapabilities.setUids(existingRanges); - updateCapabilities(); } catch (Exception e) { Log.wtf(TAG, "Failed to add restricted user to owner", e); } @@ -1263,6 +1290,11 @@ public class Vpn { } } + /** + * Updates UID ranges for this VPN and also updates its capabilities. + * + *

Should be called on primary ConnectivityService thread. + */ public void onUserRemoved(int userHandle) { // clean up if restricted UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); @@ -1274,8 +1306,9 @@ public class Vpn { final List removedRanges = uidRangesForUser(userHandle, existingRanges); existingRanges.removeAll(removedRanges); + // ConnectivityService will call {@link #updateCapabilities} and + // apply those for VPN network. mNetworkCapabilities.setUids(existingRanges); - updateCapabilities(); } catch (Exception e) { Log.wtf(TAG, "Failed to remove restricted user to owner", e); } @@ -1483,6 +1516,12 @@ public class Vpn { return success; } + /** + * Updates underlying network set. + * + *

Note: Does not updates capabilities. Call {@link #updateCapabilities} from + * ConnectivityService thread to get updated capabilities. + */ public synchronized boolean setUnderlyingNetworks(Network[] networks) { if (!isCallerEstablishedOwnerLocked()) { return false; @@ -1499,7 +1538,6 @@ public class Vpn { } } } - updateCapabilities(); return true; } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c2c627d06e47..0dcb21ab8386 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -20,6 +20,7 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; @@ -775,11 +776,14 @@ public class ConnectivityServiceTest { public void setUids(Set uids) { mNetworkCapabilities.setUids(uids); - updateCapabilities(); + updateCapabilities(null /* defaultNetwork */); } @Override public int getNetId() { + if (mMockNetworkAgent == null) { + return NETID_UNSET; + } return mMockNetworkAgent.getNetwork().netId; } @@ -800,12 +804,13 @@ public class ConnectivityServiceTest { } @Override - public void updateCapabilities() { - if (!mConnected) return; - super.updateCapabilities(); - // Because super.updateCapabilities will update the capabilities of the agent but not - // the mock agent, the mock agent needs to know about them. + public NetworkCapabilities updateCapabilities(Network defaultNetwork) { + if (!mConnected) return null; + super.updateCapabilities(defaultNetwork); + // Because super.updateCapabilities will update the capabilities of the agent but + // not the mock agent, the mock agent needs to know about them. copyCapabilitiesToNetworkAgent(); + return new NetworkCapabilities(mNetworkCapabilities); } private void copyCapabilitiesToNetworkAgent() { @@ -4218,6 +4223,7 @@ public class ConnectivityServiceTest { mMockVpn.setUids(ranges); vpnNetworkAgent.connect(false); mMockVpn.connect(); + mMockVpn.setUnderlyingNetworks(new Network[0]); genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4250,6 +4256,7 @@ public class ConnectivityServiceTest { ranges.add(new UidRange(uid, uid)); mMockVpn.setUids(ranges); + vpnNetworkAgent.setUids(ranges); genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4283,12 +4290,11 @@ public class ConnectivityServiceTest { } @Test - public void testVpnWithAndWithoutInternet() { + public void testVpnWithoutInternet() { final int uid = Process.myUid(); final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - defaultCallback.assertNoCallback(); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); @@ -4310,11 +4316,30 @@ public class ConnectivityServiceTest { vpnNetworkAgent.disconnect(); defaultCallback.assertNoCallback(); - vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + mCm.unregisterNetworkCallback(defaultCallback); + } + + @Test + public void testVpnWithInternet() { + final int uid = Process.myUid(); + + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.setUids(ranges); vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); mMockVpn.connect(); + defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); @@ -4322,14 +4347,6 @@ public class ConnectivityServiceTest { defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); - ranges.clear(); - mMockVpn.setNetworkAgent(vpnNetworkAgent); - mMockVpn.setUids(ranges); - vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); - mMockVpn.connect(); - defaultCallback.assertNoCallback(); - mCm.unregisterNetworkCallback(defaultCallback); } @@ -4430,4 +4447,68 @@ public class ConnectivityServiceTest { mMockVpn.disconnect(); } + + @Test + public void testNullUnderlyingNetworks() { + final int uid = Process.myUid(); + + final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback(); + final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_NOT_VPN) + .addTransportType(TRANSPORT_VPN) + .build(); + NetworkCapabilities nc; + mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); + vpnNetworkCallback.assertNoCallback(); + + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.connect(); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */); + + vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); + nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork()); + assertTrue(nc.hasTransport(TRANSPORT_VPN)); + assertFalse(nc.hasTransport(TRANSPORT_CELLULAR)); + assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + // By default, VPN is set to track default network (i.e. its underlying networks is null). + // In case of no default network, VPN is considered metered. + assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); + + // Connect to Cell; Cell is the default network. + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.connect(true); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) + && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + // Connect to WiFi; WiFi is the new default. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiNetworkAgent.connect(true); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) + && caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + // Disconnect Cell. The default network did not change, so there shouldn't be any changes in + // the capabilities. + mCellNetworkAgent.disconnect(); + + // Disconnect wifi too. Now we have no default network. + mWiFiNetworkAgent.disconnect(); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) + && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + mMockVpn.disconnect(); + } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index e377a472530e..a0a4ad1feb68 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -457,7 +457,8 @@ public class VpnTest { final NetworkCapabilities caps = new NetworkCapabilities(); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -467,7 +468,8 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {mobile}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -477,7 +479,8 @@ public class VpnTest { assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {wifi}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); @@ -487,7 +490,8 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {mobile, wifi}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); -- GitLab From 99473d17ce5ba3c4808c7ceb96e7796482378d03 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Fri, 15 Mar 2019 08:41:52 -0400 Subject: [PATCH 015/349] Reland "Make Paint default to filtering Bitmaps" Bug: 77949917 Test: Iac4922cfa86c0c2b3b6c88b39d9b702ab046cd34 In P, the switch to Skia HW rendering lost a feature of HWUI's old renderer: using a Paint with a BitmapShader resulted in filtering the Bitmap, regardless of whether FILTER_BITMAP_FLAG was set. This somewhat restores that behavior, in that it results in filtering BitmapShaders so long as the client doesn't explicitly turn it off. This also means that it continues to be possible to get a pixellated drawing if the client *does* explicitly turn it off. This reverts commit 1b6927dbb1620cc5edf9b14a2627de5a7a975c17. Original CL was reverted due to a broken CTS test, which will be updated along with this. Change-Id: I61394b4ca6b93ba8405a0127b9c308444abfcbc2 --- graphics/java/android/graphics/Paint.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 346c7ab970dd..c48546103a6f 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -229,7 +229,8 @@ public class Paint { public static final int VERTICAL_TEXT_FLAG = 0x1000; // These flags are always set on a new/reset paint, even if flags 0 is passed. - static final int HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG; + static final int HIDDEN_DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG | EMBEDDED_BITMAP_TEXT_FLAG + | FILTER_BITMAP_FLAG; /** * Font hinter option that disables font hinting. -- GitLab From 7f3a9d08c63e3a5e32d13d92532cc8447badd81a Mon Sep 17 00:00:00 2001 From: Minoru Sakuma Date: Wed, 25 Oct 2017 15:52:31 +0900 Subject: [PATCH 016/349] Add a new carrier config to show the WFC location privacy policy UI Controls whether to show the privacy policy prompt message before opening Wi-Fi call settings. Test: manual - Passed make build Bug: 67872298 Change-Id: I58df76ae97b54009b55a7a78fcaec95cd9b27ca6 --- .../java/android/telephony/CarrierConfigManager.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 524d080c2ea5..bcf442e60535 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2658,6 +2658,14 @@ public class CarrierConfigManager { public static final String KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY = "cdma_enhanced_roaming_indicator_for_home_network_int_array"; + /** + * Determines whether wifi calling location privacy policy is shown. + * + * @hide + */ + public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = + "show_wfc_location_privacy_policy_bool"; + /** * Indicates use 3GPP application to replace 3GPP2 application even if it's a CDMA/CDMA-LTE * phone, becasue some carriers's CSIM application is present but not supported. @@ -3063,6 +3071,7 @@ public class CarrierConfigManager { }); sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]); sDefaults.putBoolean(KEY_USE_USIM_BOOL, false); + sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, true); sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false); sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN, false); -- GitLab From c227aec278593412f3edab579832109886503428 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Wed, 6 Feb 2019 20:19:09 -0800 Subject: [PATCH 017/349] Add option to "Enable USB" Under the updated flow, the user is given an option to re-enable USB port and disable contaminant detection until the next unplug of the USB accessory. Also, display a Toast message conveying that the USB port has been re-enabled. Bug: 128534822 Test: Tested with the mock circuit. Change-Id: Ifd0a6658a443ae8966ae9128a20e827ed5b03380 --- packages/SystemUI/res/values/strings.xml | 6 ++++++ .../systemui/usb/UsbContaminantActivity.java | 19 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 16222f7ebd8d..9779e53a9161 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -165,6 +165,12 @@ To protect your device from liquid or debris, the USB port is disabled and won\u2019t detect any accessories.\n\nYou\u2019ll be notified when it\u2019s safe to use the USB port again. + + USB port enabled to detect chargers and accessories + + + Enable USB + Zoom to fill screen diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java index fa4b3fe4be18..ecf608beb91c 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbContaminantActivity.java @@ -16,14 +16,17 @@ package com.android.systemui.usb; +import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.hardware.usb.ParcelableUsbPort; import android.hardware.usb.UsbManager; import android.hardware.usb.UsbPort; import android.os.Bundle; +import android.util.Log; import android.view.Window; import android.view.WindowManager; +import android.widget.Toast; import com.android.internal.app.AlertActivity; import com.android.internal.app.AlertController; @@ -36,7 +39,6 @@ public class UsbContaminantActivity extends AlertActivity implements DialogInterface.OnClickListener { private static final String TAG = "UsbContaminantActivity"; - private UsbDisconnectedReceiver mDisconnectedReceiver; private UsbPort mUsbPort; @Override @@ -55,8 +57,10 @@ public class UsbContaminantActivity extends AlertActivity final AlertController.AlertParams ap = mAlertParams; ap.mTitle = getString(R.string.usb_contaminant_title); ap.mMessage = getString(R.string.usb_contaminant_message); - ap.mPositiveButtonText = getString(android.R.string.ok); - ap.mPositiveButtonListener = this; + ap.mNegativeButtonText = getString(android.R.string.ok); + ap.mNeutralButtonText = getString(R.string.usb_disable_contaminant_detection); + ap.mNegativeButtonListener = this; + ap.mNeutralButtonListener = this; setupAlert(); } @@ -68,6 +72,15 @@ public class UsbContaminantActivity extends AlertActivity @Override public void onClick(DialogInterface dialog, int which) { + if (which == AlertDialog.BUTTON_NEUTRAL) { + try { + mUsbPort.enableContaminantDetection(false); + Toast.makeText(this, R.string.usb_port_enabled, + Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + Log.e(TAG, "Unable to notify Usb service", e); + } + } finish(); } } -- GitLab From 397a98c806c86e6f978672916063c704962f5f47 Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Wed, 6 Feb 2019 20:19:24 -0800 Subject: [PATCH 018/349] Refactor actions that are needed to be taken during port status changes. For any change in port status, the following needs to be done: 1. Send port changed Broadcast 2. Log to statsd 3. Update contaminant notification. Bug: 128534822 Test: Tested with the mock circuit. Change-Id: I2c279a2ea0255a69c0a74a98ebf5bf680cae1fe1 --- .../android/server/usb/UsbPortManager.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index ae05750eed9f..b972b5f10a39 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -948,22 +948,25 @@ public class UsbPortManager { } } - private void handlePortAddedLocked(PortInfo portInfo, IndentingPrintWriter pw) { - logAndPrint(Log.INFO, pw, "USB port added: " + portInfo); + private void handlePortLocked(PortInfo portInfo, IndentingPrintWriter pw) { sendPortChangedBroadcastLocked(portInfo); + logToStatsd(portInfo); updateContaminantNotification(); } + private void handlePortAddedLocked(PortInfo portInfo, IndentingPrintWriter pw) { + logAndPrint(Log.INFO, pw, "USB port added: " + portInfo); + handlePortLocked(portInfo, pw); + } + private void handlePortChangedLocked(PortInfo portInfo, IndentingPrintWriter pw) { logAndPrint(Log.INFO, pw, "USB port changed: " + portInfo); - sendPortChangedBroadcastLocked(portInfo); - updateContaminantNotification(); + handlePortLocked(portInfo, pw); } private void handlePortRemovedLocked(PortInfo portInfo, IndentingPrintWriter pw) { logAndPrint(Log.INFO, pw, "USB port removed: " + portInfo); - sendPortChangedBroadcastLocked(portInfo); - updateContaminantNotification(); + handlePortLocked(portInfo, pw); } // Constants have to be converted between USB HAL V1.2 ContaminantDetectionStatus @@ -996,9 +999,9 @@ public class UsbPortManager { // instead of from within the critical section. mHandler.post(() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL, Manifest.permission.MANAGE_USB)); + } - // Log to statsd - + private void logToStatsd(PortInfo portInfo) { // Port is removed if (portInfo.mUsbPortStatus == null) { if (mConnected.containsKey(portInfo.mUsbPort.getId())) { -- GitLab From 26c490c568e88ac38cf203e06fa5ccd4cbfe0dcd Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Thu, 7 Feb 2019 14:27:18 -0800 Subject: [PATCH 019/349] Support contaminant detection disable workflow Do not show "Safe to use USB port" when contaminant detection is disabled by the user. Bug: 128534822 Test: Tested with the mock circuit. Change-Id: Iebd12f04a6d8bfd7be5d673cf5a6742cf3d6f281 --- .../android/server/usb/UsbPortManager.java | 85 ++++++++++++------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index b972b5f10a39..aec85d37bf09 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -150,8 +150,8 @@ public class UsbPortManager { private NotificationManager mNotificationManager; /** - * If there currently is a notification about contaminated USB port shown the id of the - * notification, or 0 if there is none. + * If there currently is a notification related to contaminated USB port management + * shown the id of the notification, or 0 if there is none. */ private int mIsPortContaminatedNotificationId; @@ -191,18 +191,24 @@ public class UsbPortManager { private void updateContaminantNotification() { PortInfo currentPortInfo = null; Resources r = mContext.getResources(); + int contaminantStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED; // Not handling multiple ports here. Showing the notification // for the first port that returns CONTAMINANT_PRESENCE_DETECTED. for (PortInfo portInfo : mPorts.values()) { - if (portInfo.mUsbPortStatus.getContaminantDetectionStatus() - == UsbPortStatus.CONTAMINANT_DETECTION_DETECTED) { + contaminantStatus = portInfo.mUsbPortStatus.getContaminantDetectionStatus(); + if (contaminantStatus == UsbPortStatus.CONTAMINANT_DETECTION_DETECTED + || contaminantStatus == UsbPortStatus.CONTAMINANT_DETECTION_DISABLED) { currentPortInfo = portInfo; break; } } - if (currentPortInfo != null && mIsPortContaminatedNotificationId + // Current contminant status is detected while "safe to use usb port" + // notification is displayed. Remove safe to use usb port notification + // and push contaminant detected notification. + if (contaminantStatus == UsbPortStatus.CONTAMINANT_DETECTION_DETECTED + && mIsPortContaminatedNotificationId != SystemMessage.NOTE_USB_CONTAMINANT_DETECTED) { if (mIsPortContaminatedNotificationId == SystemMessage.NOTE_USB_CONTAMINANT_NOT_DETECTED) { @@ -242,32 +248,41 @@ public class UsbPortManager { Notification notification = builder.build(); mNotificationManager.notifyAsUser(null, mIsPortContaminatedNotificationId, notification, UserHandle.ALL); - } else if (currentPortInfo == null && mIsPortContaminatedNotificationId + // No contaminant is detected but contaminant detection notification is displayed. + // Remove contaminant detection notification and push safe to use USB port notification. + } else if (contaminantStatus != UsbPortStatus.CONTAMINANT_DETECTION_DETECTED + && mIsPortContaminatedNotificationId == SystemMessage.NOTE_USB_CONTAMINANT_DETECTED) { mNotificationManager.cancelAsUser(null, mIsPortContaminatedNotificationId, UserHandle.ALL); - - mIsPortContaminatedNotificationId = SystemMessage.NOTE_USB_CONTAMINANT_NOT_DETECTED; - int titleRes = com.android.internal.R.string.usb_contaminant_not_detected_title; - CharSequence title = r.getText(titleRes); - String channel = SystemNotificationChannels.ALERTS; - CharSequence message = r.getText( - com.android.internal.R.string.usb_contaminant_not_detected_message); - - Notification.Builder builder = new Notification.Builder(mContext, channel) - .setSmallIcon(com.android.internal.R.drawable.ic_usb_48dp) - .setTicker(title) - .setColor(mContext.getColor( - com.android.internal.R.color - .system_notification_accent_color)) - .setContentTitle(title) - .setContentText(message) - .setVisibility(Notification.VISIBILITY_PUBLIC) - .setStyle(new Notification.BigTextStyle() - .bigText(message)); - Notification notification = builder.build(); - mNotificationManager.notifyAsUser(null, mIsPortContaminatedNotificationId, notification, - UserHandle.ALL); + mIsPortContaminatedNotificationId = 0; + + // Dont show safe to use notification when contaminant detection is disabled. + // Show only when the status is changing from detected to not detected. + if (contaminantStatus == UsbPortStatus.CONTAMINANT_DETECTION_NOT_DETECTED) { + mIsPortContaminatedNotificationId = + SystemMessage.NOTE_USB_CONTAMINANT_NOT_DETECTED; + int titleRes = com.android.internal.R.string.usb_contaminant_not_detected_title; + CharSequence title = r.getText(titleRes); + String channel = SystemNotificationChannels.ALERTS; + CharSequence message = r.getText( + com.android.internal.R.string.usb_contaminant_not_detected_message); + + Notification.Builder builder = new Notification.Builder(mContext, channel) + .setSmallIcon(com.android.internal.R.drawable.ic_usb_48dp) + .setTicker(title) + .setColor(mContext.getColor( + com.android.internal.R.color + .system_notification_accent_color)) + .setContentTitle(title) + .setContentText(message) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setStyle(new Notification.BigTextStyle() + .bigText(message)); + Notification notification = builder.build(); + mNotificationManager.notifyAsUser(null, mIsPortContaminatedNotificationId, + notification, UserHandle.ALL); + } } } @@ -319,8 +334,8 @@ public class UsbPortManager { } try { - // Oneway call into the hal - android.hardware.usb.V1_2.IUsb proxy = (android.hardware.usb.V1_2.IUsb) mProxy; + // Oneway call into the hal. Use the castFrom method from HIDL. + android.hardware.usb.V1_2.IUsb proxy = android.hardware.usb.V1_2.IUsb.castFrom(mProxy); proxy.enableContaminantPresenceDetection(portId, enable); } catch (RemoteException e) { logAndPrintException(pw, "Failed to set contaminant detection", e); @@ -950,7 +965,7 @@ public class UsbPortManager { private void handlePortLocked(PortInfo portInfo, IndentingPrintWriter pw) { sendPortChangedBroadcastLocked(portInfo); - logToStatsd(portInfo); + logToStatsd(portInfo, pw); updateContaminantNotification(); } @@ -1001,7 +1016,7 @@ public class UsbPortManager { Manifest.permission.MANAGE_USB)); } - private void logToStatsd(PortInfo portInfo) { + private void logToStatsd(PortInfo portInfo, IndentingPrintWriter pw) { // Port is removed if (portInfo.mUsbPortStatus == null) { if (mConnected.containsKey(portInfo.mUsbPort.getId())) { @@ -1037,6 +1052,12 @@ public class UsbPortManager { ? StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_CONNECTED : StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_DISCONNECTED, portInfo.mUsbPort.getId(), portInfo.mLastConnectDurationMillis); + // Contaminant detection might have been temporarily disabled by the user + // through SystemUI. + // Re-enable contaminant detection when the accessory is unplugged. + if (!portInfo.mUsbPortStatus.isConnected()) { + enableContaminantDetection(portInfo.mUsbPort.getId(), true, pw); + } } if (!mContaminantStatus.containsKey(portInfo.mUsbPort.getId()) -- GitLab From 3df511319c2f8fe8b3184e46f9157e9996be1cac Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Thu, 14 Mar 2019 15:26:19 -0700 Subject: [PATCH 020/349] UsbPortManager: Re-enable contaminant detection when port is unplugged SystemUI disables contaminant detection when user wants to continue using the port. Re-enable contaminant detection when the accessory is unplugged. Bug: 128534822 Test: Tested with the mock circuit. Change-Id: I22a3c839264876409c68c6a3145c9fcc6278f381 --- .../android/server/usb/UsbPortManager.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index aec85d37bf09..96e12ce837ca 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -965,6 +965,7 @@ public class UsbPortManager { private void handlePortLocked(PortInfo portInfo, IndentingPrintWriter pw) { sendPortChangedBroadcastLocked(portInfo); + enableContaminantDetectionIfNeeded(portInfo, pw); logToStatsd(portInfo, pw); updateContaminantNotification(); } @@ -1016,6 +1017,22 @@ public class UsbPortManager { Manifest.permission.MANAGE_USB)); } + private void enableContaminantDetectionIfNeeded(PortInfo portInfo, IndentingPrintWriter pw) { + if (!mConnected.containsKey(portInfo.mUsbPort.getId())) { + return; + } + + if (mConnected.get(portInfo.mUsbPort.getId()) + && !portInfo.mUsbPortStatus.isConnected() + && portInfo.mUsbPortStatus.getContaminantDetectionStatus() + == UsbPortStatus.CONTAMINANT_DETECTION_DISABLED) { + // Contaminant detection might have been temporarily disabled by the user + // through SystemUI. + // Re-enable contaminant detection when the accessory is unplugged. + enableContaminantDetection(portInfo.mUsbPort.getId(), true, pw); + } + } + private void logToStatsd(PortInfo portInfo, IndentingPrintWriter pw) { // Port is removed if (portInfo.mUsbPortStatus == null) { @@ -1052,12 +1069,6 @@ public class UsbPortManager { ? StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_CONNECTED : StatsLog.USB_CONNECTOR_STATE_CHANGED__STATE__STATE_DISCONNECTED, portInfo.mUsbPort.getId(), portInfo.mLastConnectDurationMillis); - // Contaminant detection might have been temporarily disabled by the user - // through SystemUI. - // Re-enable contaminant detection when the accessory is unplugged. - if (!portInfo.mUsbPortStatus.isConnected()) { - enableContaminantDetection(portInfo.mUsbPort.getId(), true, pw); - } } if (!mContaminantStatus.containsKey(portInfo.mUsbPort.getId()) -- GitLab From 810eeb3eed455812f2240040858a4d4882df7a4e Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Thu, 7 Mar 2019 19:08:52 -0800 Subject: [PATCH 021/349] Mainline logging to statsd: native static libs Creates an annotation to specify if an atom needs to be logged from a specific mainline module. Creates options in stats-log-api-gen so that if the same module name is passed in, cpp/h files will be generated with only those atoms that are specified. These files can be used to create a static library per mainline module to log to statsd. Test: builds Test: atest stats-log-api-gen-test Test: does not affect existing shared libstatslog Test: manually created a static lib for netd and used it to log to statsd. Used testdrive to validate the data was properly flowing. Bug: 126134616 Change-Id: I78064f81fb4971eede8e97dacce5424e3eefd8bb --- cmds/statsd/src/atom_field_options.proto | 2 + tools/stats_log_api_gen/Android.bp | 1 + tools/stats_log_api_gen/Collation.cpp | 49 ++- tools/stats_log_api_gen/Collation.h | 7 +- tools/stats_log_api_gen/main.cpp | 402 ++++++++++++++------- tools/stats_log_api_gen/test.proto | 20 + tools/stats_log_api_gen/test_collation.cpp | 54 ++- 7 files changed, 383 insertions(+), 152 deletions(-) diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto index 2a3eee2a7e18..16c936c41559 100644 --- a/cmds/statsd/src/atom_field_options.proto +++ b/cmds/statsd/src/atom_field_options.proto @@ -84,4 +84,6 @@ extend google.protobuf.FieldOptions { optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC]; optional bool allow_from_any_uid = 50003 [default = false]; + + optional string log_from_module = 50004; } \ No newline at end of file diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp index 5725f0cdae6e..4ce4406211ce 100644 --- a/tools/stats_log_api_gen/Android.bp +++ b/tools/stats_log_api_gen/Android.bp @@ -31,6 +31,7 @@ cc_binary_host { shared_libs: [ "libstats_proto_host", "libprotobuf-cpp-full", + "libbase", ], proto: { diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp index a8d970edaa85..e66ead7ec340 100644 --- a/tools/stats_log_api_gen/Collation.cpp +++ b/tools/stats_log_api_gen/Collation.cpp @@ -49,7 +49,9 @@ AtomDecl::AtomDecl(const AtomDecl& that) exclusiveField(that.exclusiveField), uidField(that.uidField), whitelisted(that.whitelisted), - binaryFields(that.binaryFields) {} + binaryFields(that.binaryFields), + hasModule(that.hasModule), + moduleName(that.moduleName) {} AtomDecl::AtomDecl(int c, const string& n, const string& m) :code(c), @@ -391,7 +393,12 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) { AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name()); if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) { - atomDecl.whitelisted = true; + atomDecl.whitelisted = true; + } + + if (atomField->options().HasExtension(os::statsd::log_from_module)) { + atomDecl.hasModule = true; + atomDecl.moduleName = atomField->options().GetExtension(os::statsd::log_from_module); } vector signature; @@ -399,25 +406,49 @@ int collate_atoms(const Descriptor *descriptor, Atoms *atoms) { if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) { errorCount++; } - atoms->signatures.insert(signature); + + // Add the signature if does not already exist. + auto signature_to_modules_it = atoms->signatures_to_modules.find(signature); + if (signature_to_modules_it == atoms->signatures_to_modules.end()) { + set modules; + if (atomDecl.hasModule) { + modules.insert(atomDecl.moduleName); + } + atoms->signatures_to_modules[signature] = modules; + } else { + if (atomDecl.hasModule) { + signature_to_modules_it->second.insert(atomDecl.moduleName); + } + } atoms->decls.insert(atomDecl); AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name()); vector nonChainedSignature; if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) { - atoms->non_chained_signatures.insert(nonChainedSignature); + auto it = atoms->non_chained_signatures_to_modules.find(signature); + if (it == atoms->non_chained_signatures_to_modules.end()) { + set modules_non_chained; + if (atomDecl.hasModule) { + modules_non_chained.insert(atomDecl.moduleName); + } + atoms->non_chained_signatures_to_modules[nonChainedSignature] = modules_non_chained; + } else { + if (atomDecl.hasModule) { + it->second.insert(atomDecl.moduleName); + } + } atoms->non_chained_decls.insert(nonChainedAtomDecl); } } if (dbg) { printf("signatures = [\n"); - for (set>::const_iterator it = - atoms->signatures.begin(); - it != atoms->signatures.end(); it++) { + for (map, set>::const_iterator it = + atoms->signatures_to_modules.begin(); + it != atoms->signatures_to_modules.end(); it++) { printf(" "); - for (vector::const_iterator jt = it->begin(); - jt != it->end(); jt++) { + for (vector::const_iterator jt = it->first.begin(); + jt != it->first.end(); jt++) { printf(" %d", (int)*jt); } printf("\n"); diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h index 6b86b862dfad..44746c96df1b 100644 --- a/tools/stats_log_api_gen/Collation.h +++ b/tools/stats_log_api_gen/Collation.h @@ -93,6 +93,9 @@ struct AtomDecl { vector binaryFields; + bool hasModule = false; + string moduleName; + AtomDecl(); AtomDecl(const AtomDecl& that); AtomDecl(int code, const string& name, const string& message); @@ -104,10 +107,10 @@ struct AtomDecl { }; struct Atoms { - set> signatures; + map, set> signatures_to_modules; set decls; set non_chained_decls; - set> non_chained_signatures; + map, set> non_chained_signatures_to_modules; }; /** diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp index 0270c72ff240..f7550ae7b9f9 100644 --- a/tools/stats_log_api_gen/main.cpp +++ b/tools/stats_log_api_gen/main.cpp @@ -12,6 +12,8 @@ #include #include +#include "android-base/strings.h" + using namespace google::protobuf; using namespace std; @@ -20,6 +22,10 @@ namespace stats_log_api_gen { int maxPushedAtomId = 2; +const string DEFAULT_MODULE_NAME = "DEFAULT"; +const string DEFAULT_CPP_NAMESPACE = "android,util"; +const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h"; + using android::os::statsd::Atom; /** @@ -97,40 +103,27 @@ java_type_name(java_type_t type) } } -static int write_stats_log_cpp(FILE *out, const Atoms &atoms, - const AtomDecl &attributionDecl) { - // Print prelude - fprintf(out, "// This file is autogenerated\n"); - fprintf(out, "\n"); - - fprintf(out, "#include \n"); - fprintf(out, "#include \n"); - fprintf(out, "#include \n"); - fprintf(out, "#ifdef __ANDROID__\n"); - fprintf(out, "#include \n"); - fprintf(out, "#endif\n"); - fprintf(out, "#include \n"); - fprintf(out, "#include \n"); - fprintf(out, "#include \n"); - fprintf(out, "#include \n"); - fprintf(out, "\n"); +static bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) { + if (moduleName == DEFAULT_MODULE_NAME) { + return true; + } + return atomDecl.hasModule && (moduleName == atomDecl.moduleName); +} - fprintf(out, "namespace android {\n"); - fprintf(out, "namespace util {\n"); - fprintf(out, "// the single event tag id for all stats logs\n"); - fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); - fprintf(out, "#ifdef __ANDROID__\n"); - fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n"); - fprintf(out, "#else\n"); - fprintf(out, "const static bool kStatsdEnabled = false;\n"); - fprintf(out, "#endif\n"); +static bool signature_needed_for_module(const set& modules, const string& moduleName) { + if (moduleName == DEFAULT_MODULE_NAME) { + return true; + } + return modules.find(moduleName) != modules.end(); +} +static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) { std::set kTruncatingAtomNames = {"mobile_radio_power_state_changed", - "audio_state_changed", - "call_state_changed", - "phone_signal_strength_changed", - "mobile_bytes_transfer_by_fg_bg", - "mobile_bytes_transfer"}; + "audio_state_changed", + "call_state_changed", + "phone_signal_strength_changed", + "mobile_bytes_transfer_by_fg_bg", + "mobile_bytes_transfer"}; fprintf(out, "const std::set " "AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n"); @@ -256,6 +249,56 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, "const std::map> " "AtomsInfo::kBytesFieldAtoms = " "getBinaryFieldAtoms();\n"); +} + +// Writes namespaces for the cpp and header files, returning the number of namespaces written. +void write_namespace(FILE* out, const string& cppNamespaces) { + vector cppNamespaceVec = android::base::Split(cppNamespaces, ","); + for (string cppNamespace : cppNamespaceVec) { + fprintf(out, "namespace %s {\n", cppNamespace.c_str()); + } +} + +// Writes namespace closing brackets for cpp and header files. +void write_closing_namespace(FILE* out, const string& cppNamespaces) { + vector cppNamespaceVec = android::base::Split(cppNamespaces, ","); + for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) { + fprintf(out, "} // namespace %s\n", it->c_str()); + } +} + +static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace, + const string& importHeader) { + // Print prelude + fprintf(out, "// This file is autogenerated\n"); + fprintf(out, "\n"); + + fprintf(out, "#include \n"); + fprintf(out, "#include \n"); + fprintf(out, "#include \n"); + fprintf(out, "#ifdef __ANDROID__\n"); + fprintf(out, "#include \n"); + fprintf(out, "#endif\n"); + fprintf(out, "#include \n"); + fprintf(out, "#include \n"); + fprintf(out, "#include <%s>\n", importHeader.c_str()); + fprintf(out, "#include \n"); + fprintf(out, "\n"); + + write_namespace(out, cppNamespace); + fprintf(out, "// the single event tag id for all stats logs\n"); + fprintf(out, "const static int kStatsEventTag = 1937006964;\n"); + fprintf(out, "#ifdef __ANDROID__\n"); + fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n"); + fprintf(out, "#else\n"); + fprintf(out, "const static bool kStatsdEnabled = false;\n"); + fprintf(out, "#endif\n"); + + // AtomsInfo is only used by statsd internally and is not needed for other modules. + if (moduleName == DEFAULT_MODULE_NAME) { + write_atoms_info_cpp(out, atoms); + } fprintf(out, "int64_t lastRetryTimestampNs = -1;\n"); fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n"); @@ -263,15 +306,19 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, // Print write methods fprintf(out, "\n"); - for (set>::const_iterator signature = atoms.signatures.begin(); - signature != atoms.signatures.end(); signature++) { + for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); + signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + vector signature = signature_to_modules_it->first; int argIndex; fprintf(out, "int\n"); fprintf(out, "try_stats_write(int32_t code"); argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -303,8 +350,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " stats_event_list event(kStatsEventTag);\n"); fprintf(out, " event << android::elapsedRealtimeNano();\n\n"); fprintf(out, " event << code;\n\n"); - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (const auto &chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -387,15 +434,19 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "\n"); } - for (set>::const_iterator signature = atoms.signatures.begin(); - signature != atoms.signatures.end(); signature++) { + for (auto signature_to_modules_it = atoms.signatures_to_modules.begin(); + signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) { + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + vector signature = signature_to_modules_it->first; int argIndex; fprintf(out, "int\n"); fprintf(out, "stats_write(int32_t code"); argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -429,8 +480,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " ret = try_stats_write(code"); argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -468,15 +519,19 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "\n"); } - for (set>::const_iterator signature = atoms.non_chained_signatures.begin(); - signature != atoms.non_chained_signatures.end(); signature++) { + for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); + signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { + if (!signature_needed_for_module(signature_it->second, moduleName)) { + continue; + } + vector signature = signature_it->first; int argIndex; fprintf(out, "int\n"); fprintf(out, "try_stats_write_non_chained(int32_t code"); argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); argIndex++; } @@ -488,8 +543,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " stats_event_list event(kStatsEventTag);\n"); fprintf(out, " event << android::elapsedRealtimeNano();\n\n"); fprintf(out, " event << code;\n\n"); - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (argIndex == 1) { fprintf(out, " event.begin();\n\n"); fprintf(out, " event.begin();\n"); @@ -522,15 +577,19 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, "\n"); } - for (set>::const_iterator signature = atoms.non_chained_signatures.begin(); - signature != atoms.non_chained_signatures.end(); signature++) { + for (auto signature_it = atoms.non_chained_signatures_to_modules.begin(); + signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) { + if (!signature_needed_for_module(signature_it->second, moduleName)) { + continue; + } + vector signature = signature_it->first; int argIndex; fprintf(out, "int\n"); fprintf(out, "stats_write_non_chained(int32_t code"); argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex); argIndex++; } @@ -543,8 +602,8 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, fprintf(out, " ret = try_stats_write_non_chained(code"); argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { fprintf(out, ", arg%d", argIndex); argIndex++; } @@ -572,8 +631,7 @@ static int write_stats_log_cpp(FILE *out, const Atoms &atoms, // Print footer fprintf(out, "\n"); - fprintf(out, "} // namespace util\n"); - fprintf(out, "} // namespace android\n"); + write_closing_namespace(out, cppNamespace); return 0; } @@ -623,14 +681,23 @@ static void write_cpp_usage( } static void write_cpp_method_header( - FILE* out, const string& method_name, const set>& signatures, - const AtomDecl &attributionDecl) { - for (set>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + FILE* out, + const string& method_name, + const map, set>& signatures_to_modules, + const AtomDecl &attributionDecl, const string& moduleName) { + + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + // Skip if this signature is not needed for the module. + if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) { + continue; + } + + vector signature = signature_to_modules_it->first; fprintf(out, "int %s(int32_t code", method_name.c_str()); int argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_STRING) { @@ -659,7 +726,8 @@ static void write_cpp_method_header( } static int -write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl) +write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl, + const string& moduleName, const string& cppNamespace) { // Print prelude fprintf(out, "// This file is autogenerated\n"); @@ -672,8 +740,7 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio fprintf(out, "#include \n"); fprintf(out, "\n"); - fprintf(out, "namespace android {\n"); - fprintf(out, "namespace util {\n"); + write_namespace(out, cppNamespace); fprintf(out, "\n"); fprintf(out, "/*\n"); fprintf(out, " * API For logging statistics events.\n"); @@ -691,6 +758,10 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio // Print atom constants for (set::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end(); atom++) { + // Skip if the atom is not needed for the module. + if (!atom_needed_for_module(*atom, moduleName)) { + continue; + } string constant = make_constant_name(atom->name); fprintf(out, "\n"); fprintf(out, " /**\n"); @@ -720,6 +791,11 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio fprintf(out, "//\n\n"); for (set::const_iterator atom = atoms.decls.begin(); atom != atoms.decls.end(); atom++) { + // Skip if the atom is not needed for the module. + if (!atom_needed_for_module(*atom, moduleName)) { + continue; + } + for (vector::const_iterator field = atom->fields.begin(); field != atom->fields.end(); field++) { if (field->javaType == JAVA_TYPE_ENUM) { @@ -747,47 +823,51 @@ write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributio fprintf(out, "};\n"); fprintf(out, "\n"); - fprintf(out, "struct StateAtomFieldOptions {\n"); - fprintf(out, " std::vector primaryFields;\n"); - fprintf(out, " int exclusiveField;\n"); - fprintf(out, "};\n"); - fprintf(out, "\n"); + // This metadata is only used by statsd, which uses the default libstatslog. + if (moduleName == DEFAULT_MODULE_NAME) { - fprintf(out, "struct AtomsInfo {\n"); - fprintf(out, - " const static std::set " - "kNotTruncatingTimestampAtomWhiteList;\n"); - fprintf(out, " const static std::map kAtomsWithUidField;\n"); - fprintf(out, - " const static std::set kAtomsWithAttributionChain;\n"); - fprintf(out, - " const static std::map " - "kStateAtomsFieldOptions;\n"); - fprintf(out, - " const static std::map> " - "kBytesFieldAtoms;"); - fprintf(out, - " const static std::set kWhitelistedAtoms;\n"); - fprintf(out, "};\n"); + fprintf(out, "struct StateAtomFieldOptions {\n"); + fprintf(out, " std::vector primaryFields;\n"); + fprintf(out, " int exclusiveField;\n"); + fprintf(out, "};\n"); + fprintf(out, "\n"); - fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", - maxPushedAtomId); + fprintf(out, "struct AtomsInfo {\n"); + fprintf(out, + " const static std::set " + "kNotTruncatingTimestampAtomWhiteList;\n"); + fprintf(out, " const static std::map kAtomsWithUidField;\n"); + fprintf(out, + " const static std::set kAtomsWithAttributionChain;\n"); + fprintf(out, + " const static std::map " + "kStateAtomsFieldOptions;\n"); + fprintf(out, + " const static std::map> " + "kBytesFieldAtoms;"); + fprintf(out, + " const static std::set kWhitelistedAtoms;\n"); + fprintf(out, "};\n"); + + fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n", + maxPushedAtomId); + } // Print write methods fprintf(out, "//\n"); fprintf(out, "// Write methods\n"); fprintf(out, "//\n"); - write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl); + write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl, + moduleName); fprintf(out, "//\n"); fprintf(out, "// Write flattened methods\n"); fprintf(out, "//\n"); - write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures, - attributionDecl); + write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules, + attributionDecl, moduleName); fprintf(out, "\n"); - fprintf(out, "} // namespace util\n"); - fprintf(out, "} // namespace android\n"); + write_closing_namespace(out, cppNamespace); return 0; } @@ -812,15 +892,19 @@ static void write_java_usage(FILE* out, const string& method_name, const string& } static void write_java_method( - FILE* out, const string& method_name, const set>& signatures, - const AtomDecl &attributionDecl) { - for (set>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + FILE* out, + const string& method_name, + const map, set>& signatures_to_modules, + const AtomDecl &attributionDecl) { + + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector signature = signature_to_modules_it->first; fprintf(out, " /** @hide */\n"); fprintf(out, " public static native int %s(int code", method_name.c_str()); int argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { fprintf(out, ", %s[] %s", @@ -837,15 +921,17 @@ static void write_java_method( } } -static void write_java_work_source_method(FILE* out, const set>& signatures) { +static void write_java_work_source_method(FILE* out, + const map, set>& signatures_to_modules) { fprintf(out, "\n // WorkSource methods.\n"); - for (set>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector signature = signature_to_modules_it->first; // Determine if there is Attribution in this signature. int attributionArg = -1; int argIndexMax = 0; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { argIndexMax++; if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { if (attributionArg > -1) { @@ -865,8 +951,8 @@ static void write_java_work_source_method(FILE* out, const set::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { fprintf(out, ", WorkSource ws"); } else { @@ -974,9 +1060,10 @@ write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionD // Print write methods fprintf(out, " // Write methods\n"); - write_java_method(out, "write", atoms.signatures, attributionDecl); - write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl); - write_java_work_source_method(out, atoms.signatures); + write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl); + write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules, + attributionDecl); + write_java_work_source_method(out, atoms.signatures_to_modules); fprintf(out, "}\n"); @@ -1154,19 +1241,20 @@ static void write_key_value_map_jni(FILE* out) { static int write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name, - const set>& signatures, const AtomDecl &attributionDecl) -{ + const map, set>& signatures_to_modules, + const AtomDecl &attributionDecl) { // Print write methods - for (set>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector signature = signature_to_modules_it->first; int argIndex; fprintf(out, "static int\n"); fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code", - jni_function_name(java_method_name, *signature).c_str()); + jni_function_name(java_method_name, signature).c_str()); argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType), @@ -1187,8 +1275,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp argIndex = 1; bool hadStringOrChain = false; bool isKeyValuePairAtom = false; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_STRING) { hadStringOrChain = true; fprintf(out, " const char* str%d;\n", argIndex); @@ -1288,8 +1376,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp argIndex = 1; fprintf(out, "\n int ret = android::util::%s(code", cpp_method_name.c_str()); - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) { for (auto chainField : attributionDecl.fields) { if (chainField.javaType == JAVA_TYPE_INT) { @@ -1316,8 +1404,8 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp // Clean up strings argIndex = 1; - for (vector::const_iterator arg = signature->begin(); - arg != signature->end(); arg++) { + for (vector::const_iterator arg = signature.begin(); + arg != signature.end(); arg++) { if (*arg == JAVA_TYPE_STRING) { fprintf(out, " if (str%d != NULL) {\n", argIndex); fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n", @@ -1357,13 +1445,15 @@ write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp } void write_jni_registration(FILE* out, const string& java_method_name, - const set>& signatures, const AtomDecl &attributionDecl) { - for (set>::const_iterator signature = signatures.begin(); - signature != signatures.end(); signature++) { + const map, set>& signatures_to_modules, + const AtomDecl &attributionDecl) { + for (auto signature_to_modules_it = signatures_to_modules.begin(); + signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) { + vector signature = signature_to_modules_it->first; fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n", java_method_name.c_str(), - jni_function_signature(*signature, attributionDecl).c_str(), - jni_function_name(java_method_name, *signature).c_str()); + jni_function_signature(signature, attributionDecl).c_str(), + jni_function_name(java_method_name, signature).c_str()); } } @@ -1388,17 +1478,18 @@ write_stats_log_jni(FILE* out, const Atoms& atoms, const AtomDecl &attributionDe fprintf(out, "namespace android {\n"); fprintf(out, "\n"); - write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl); + write_stats_log_jni(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl); write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained", - atoms.non_chained_signatures, attributionDecl); + atoms.non_chained_signatures_to_modules, attributionDecl); // Print registration function table fprintf(out, "/*\n"); fprintf(out, " * JNI registration.\n"); fprintf(out, " */\n"); fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n"); - write_jni_registration(out, "write", atoms.signatures, attributionDecl); - write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl); + write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl); + write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules, + attributionDecl); fprintf(out, "};\n"); fprintf(out, "\n"); @@ -1426,6 +1517,10 @@ print_usage() fprintf(stderr, " --help this message\n"); fprintf(stderr, " --java FILENAME the java file to output\n"); fprintf(stderr, " --jni FILENAME the jni file to output\n"); + fprintf(stderr, " --module NAME optional, module name to generate outputs for\n"); + fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n"); + fprintf(stderr, " comma separated namespace of the files\n"); + fprintf(stderr, " --importHeader NAME required for cpp/jni to say which header to import\n"); } /** @@ -1439,6 +1534,10 @@ run(int argc, char const*const* argv) string javaFilename; string jniFilename; + string moduleName = DEFAULT_MODULE_NAME; + string cppNamespace = DEFAULT_CPP_NAMESPACE; + string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT; + int index = 1; while (index < argc) { if (0 == strcmp("--help", argv[index])) { @@ -1472,6 +1571,27 @@ run(int argc, char const*const* argv) return 1; } jniFilename = argv[index]; + } else if (0 == strcmp("--module", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + moduleName = argv[index]; + } else if (0 == strcmp("--namespace", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + cppNamespace = argv[index]; + } else if (0 == strcmp("--importHeader", argv[index])) { + index++; + if (index >= argc) { + print_usage(); + return 1; + } + cppHeaderImport = argv[index]; } index++; } @@ -1503,8 +1623,18 @@ run(int argc, char const*const* argv) fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str()); return 1; } + // If this is for a specific module, the namespace must also be provided. + if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) { + fprintf(stderr, "Must supply --namespace if supplying a specific module\n"); + return 1; + } + // If this is for a specific module, the header file to import must also be provided. + if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) { + fprintf(stderr, "Must supply --headerImport if supplying a specific module\n"); + return 1; + } errorCount = android::stats_log_api_gen::write_stats_log_cpp( - out, atoms, attributionDecl); + out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport); fclose(out); } @@ -1515,8 +1645,12 @@ run(int argc, char const*const* argv) fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str()); return 1; } + // If this is for a specific module, the namespace must also be provided. + if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) { + fprintf(stderr, "Must supply --namespace if supplying a specific module\n"); + } errorCount = android::stats_log_api_gen::write_stats_log_header( - out, atoms, attributionDecl); + out, atoms, attributionDecl, moduleName, cppNamespace); fclose(out); } diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto index 24ebf4de031a..c3e703826be5 100644 --- a/tools/stats_log_api_gen/test.proto +++ b/tools/stats_log_api_gen/test.proto @@ -213,4 +213,24 @@ message ListedAtoms { // by whitelisted sources NonWhitelistedAtom non_whitelisted_atom = 2; } +} + +message ModuleOneAtom { + optional int32 field = 1; +} + +message ModuleTwoAtom { + optional int32 field = 1; +} + +message NoModuleAtom { + optional string field = 1; +} + +message ModuleAtoms { + oneof event { + ModuleOneAtom module_one_atom = 1 [(android.os.statsd.log_from_module) = "module1"]; + ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.log_from_module) = "module2"]; + NoModuleAtom no_module_atom = 3; + } } \ No newline at end of file diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp index dc585c1c5dd1..bcf18ae8bf19 100644 --- a/tools/stats_log_api_gen/test_collation.cpp +++ b/tools/stats_log_api_gen/test_collation.cpp @@ -32,7 +32,7 @@ using std::vector; * Return whether the set contains a vector of the elements provided. */ static bool -set_contains_vector(const set>& s, int count, ...) +set_contains_vector(const map, set>& s, int count, ...) { va_list args; vector v; @@ -86,17 +86,17 @@ TEST(CollationTest, CollateStats) { int errorCount = collate_atoms(Event::descriptor(), &atoms); EXPECT_EQ(0, errorCount); - EXPECT_EQ(3ul, atoms.signatures.size()); + EXPECT_EQ(3ul, atoms.signatures_to_modules.size()); // IntAtom, AnotherIntAtom - EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT); + EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT); // OutOfOrderAtom - EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT); + EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT, JAVA_TYPE_INT); // AllTypesAtom EXPECT_SET_CONTAINS_SIGNATURE( - atoms.signatures, + atoms.signatures_to_modules, JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain JAVA_TYPE_DOUBLE, // double JAVA_TYPE_FLOAT, // float @@ -228,8 +228,7 @@ TEST(CollationTest, FailOnBadBinaryFieldAtom) { TEST(CollationTest, PassOnWhitelistedAtom) { Atoms atoms; - int errorCount = - collate_atoms(ListedAtoms::descriptor(), &atoms); + int errorCount = collate_atoms(ListedAtoms::descriptor(), &atoms); EXPECT_EQ(errorCount, 0); EXPECT_EQ(atoms.decls.size(), 2ul); } @@ -246,5 +245,46 @@ TEST(CollationTest, RecogniseWhitelistedAtom) { } } +TEST(CollationTest, PassOnLogFromModuleAtom) { + Atoms atoms; + int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms); + EXPECT_EQ(errorCount, 0); + EXPECT_EQ(atoms.decls.size(), 3ul); +} + +TEST(CollationTest, RecognizeModuleAtom) { + Atoms atoms; + int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms); + EXPECT_EQ(errorCount, 0); + EXPECT_EQ(atoms.decls.size(), 3ul); + for (const auto& atomDecl: atoms.decls) { + if (atomDecl.code == 1) { + EXPECT_TRUE(atomDecl.hasModule); + EXPECT_EQ(atomDecl.moduleName, "module1"); + } else if (atomDecl.code == 2) { + EXPECT_TRUE(atomDecl.hasModule); + EXPECT_EQ(atomDecl.moduleName, "module2"); + } else { + EXPECT_FALSE(atomDecl.hasModule); + } + } + + EXPECT_EQ(atoms.signatures_to_modules.size(), 2u); + EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT); + EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_STRING); + for (auto signature_to_modules_it : atoms.signatures_to_modules) { + vector signature = signature_to_modules_it.first; + if (signature[0] == JAVA_TYPE_STRING) { + EXPECT_EQ(signature_to_modules_it.second.size(), 0u); + } else if (signature[0] == JAVA_TYPE_INT) { + set modules = signature_to_modules_it.second; + EXPECT_EQ(modules.size(), 2u); + // Assert that the set contains "module1" and "module2". + EXPECT_NE(modules.find("module1"), modules.end()); + EXPECT_NE(modules.find("module2"), modules.end()); + } + } +} + } // namespace stats_log_api_gen } // namespace android \ No newline at end of file -- GitLab From c09f2d69a129daffaeccc56504acd8b3efe4805e Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Fri, 8 Mar 2019 14:48:59 +0800 Subject: [PATCH 022/349] Support query cancellation for async DNS API Bug: 124882626 Test: built, flashed, booted atest DnsResolverTest DnsPacketTest Change-Id: Iaa72f5c17f58cf0a58663b892bb18cfdf23cd545 --- api/current.txt | 4 +-- core/java/android/net/DnsResolver.java | 38 ++++++++++++++++++++++--- core/java/android/net/NetworkUtils.java | 6 ++++ core/jni/android_net_NetUtils.cpp | 6 ++++ 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/api/current.txt b/api/current.txt index f36c12c5e3e6..7ba503c28fb7 100755 --- a/api/current.txt +++ b/api/current.txt @@ -27228,8 +27228,8 @@ package android.net { public final class DnsResolver { method @NonNull public static android.net.DnsResolver getInstance(); - method public void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback); - method public void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.DnsResolver.AnswerCallback); + method public void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback); + method public void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback); field public static final int CLASS_IN = 1; // 0x1 field public static final int FLAG_EMPTY = 0; // 0x0 field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4 diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java index 93b8cf801d45..59802514c7a3 100644 --- a/core/java/android/net/DnsResolver.java +++ b/core/java/android/net/DnsResolver.java @@ -16,6 +16,7 @@ package android.net; +import static android.net.NetworkUtils.resNetworkCancel; import static android.net.NetworkUtils.resNetworkQuery; import static android.net.NetworkUtils.resNetworkResult; import static android.net.NetworkUtils.resNetworkSend; @@ -26,6 +27,7 @@ import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.os.CancellationSignal; import android.os.Looper; import android.system.ErrnoException; import android.util.Log; @@ -191,11 +193,18 @@ public final class DnsResolver { * @param query blob message * @param flags flags as a combination of the FLAGS_* constants * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. * @param callback an {@link AnswerCallback} which will be called to notify the caller - * of the result of dns query. + * of the result of dns query. */ public void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags, - @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback callback) { + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull AnswerCallback callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } final FileDescriptor queryfd; try { queryfd = resNetworkSend((network != null @@ -205,6 +214,7 @@ public final class DnsResolver { return; } + maybeAddCancellationSignal(cancellationSignal, queryfd); registerFDListener(executor, queryfd, callback); } @@ -219,12 +229,19 @@ public final class DnsResolver { * @param nsType dns resource record (RR) type as one of the TYPE_* constants * @param flags flags as a combination of the FLAGS_* constants * @param executor The {@link Executor} that the callback should be executed on. + * @param cancellationSignal used by the caller to signal if the query should be + * cancelled. May be {@code null}. * @param callback an {@link AnswerCallback} which will be called to notify the caller - * of the result of dns query. + * of the result of dns query. */ public void query(@Nullable Network network, @NonNull String domain, @QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags, - @NonNull @CallbackExecutor Executor executor, @NonNull AnswerCallback callback) { + @NonNull @CallbackExecutor Executor executor, + @Nullable CancellationSignal cancellationSignal, + @NonNull AnswerCallback callback) { + if (cancellationSignal != null && cancellationSignal.isCanceled()) { + return; + } final FileDescriptor queryfd; try { queryfd = resNetworkQuery((network != null @@ -233,6 +250,8 @@ public final class DnsResolver { callback.onQueryException(e); return; } + + maybeAddCancellationSignal(cancellationSignal, queryfd); registerFDListener(executor, queryfd, callback); } @@ -264,6 +283,17 @@ public final class DnsResolver { }); } + private void maybeAddCancellationSignal(@Nullable CancellationSignal cancellationSignal, + @NonNull FileDescriptor queryfd) { + if (cancellationSignal == null) return; + cancellationSignal.setOnCancelListener( + () -> { + Looper.getMainLooper().getQueue() + .removeOnFileDescriptorEventListener(queryfd); + resNetworkCancel(queryfd); + }); + } + private static class DnsAddressAnswer extends DnsPacket { private static final String TAG = "DnsResolver.DnsAddressAnswer"; private static final boolean DBG = false; diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 0ae29b125149..d2d886ba9a7f 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -171,6 +171,12 @@ public class NetworkUtils { */ public static native byte[] resNetworkResult(FileDescriptor fd) throws ErrnoException; + /** + * DNS resolver series jni method. + * Attempts to cancel the in-progress query associated with the {@code fd}. + */ + public static native void resNetworkCancel(FileDescriptor fd); + /** * Add an entry into the ARP cache. */ diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index cfb2dd199f39..d7a981ed3e9d 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -487,6 +487,11 @@ static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, return answer; } +static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) { + int fd = jniGetFDFromFileDescriptor(env, javaFd); + resNetworkCancel(fd); +} + static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) { if (javaFd == NULL) { jniThrowNullPointerException(env, NULL); @@ -546,6 +551,7 @@ static const JNINativeMethod gNetworkUtilMethods[] = { { "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend }, { "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery }, { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult }, + { "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel }, }; int register_android_net_NetworkUtils(JNIEnv* env) -- GitLab From 1c8188f2b40cad3dcefdcc3b7e308451bd705180 Mon Sep 17 00:00:00 2001 From: Kyunglyul Hyun Date: Fri, 1 Feb 2019 10:50:11 +0900 Subject: [PATCH 023/349] Media: Add MediaRouterManager to control media route of other apps This CL is a draft for supporting seamless transfer MediaRouterManager is added to notify providers seamless transfer request. It also adds MediaRouter.setControlCategories() to let application notify their control categories and filter out irrelevant routes. Test: atest mediaroutertest after installing mediarouteprovider.apk Change-Id: I7446855271d27ffaad2e82dda133bed80b9f9630 --- Android.bp | 5 +- .../android/media/IMediaRoute2Callback.aidl | 24 ++ .../android/media/IMediaRoute2Provider.aidl | 27 ++ .../media/IMediaRouter2ManagerClient.aidl | 25 ++ .../android/media/IMediaRouterService.aidl | 8 + .../media/MediaRoute2ProviderService.java | 108 ++++++ media/java/android/media/MediaRouter.java | 30 ++ .../android/media/MediaRouter2Manager.java | 241 +++++++++++++ media/tests/MediaRouteProvider/Android.bp | 18 + .../MediaRouteProvider/AndroidManifest.xml | 30 ++ .../MediaRouteProvider/res/values/strings.xml | 5 + .../SampleMediaRoute2ProviderService.java | 33 ++ media/tests/MediaRouter/Android.bp | 18 + media/tests/MediaRouter/AndroidManifest.xml | 29 ++ media/tests/MediaRouter/AndroidTest.xml | 16 + .../tests/MediaRouter/res/values/strings.xml | 5 + .../MediaRouterManagerTest.java | 110 ++++++ .../media/MediaRoute2ProviderProxy.java | 341 ++++++++++++++++++ .../media/MediaRoute2ProviderWatcher.java | 176 +++++++++ .../server/media/MediaRouterService.java | 305 +++++++++++++++- 20 files changed, 1547 insertions(+), 7 deletions(-) create mode 100644 media/java/android/media/IMediaRoute2Callback.aidl create mode 100644 media/java/android/media/IMediaRoute2Provider.aidl create mode 100644 media/java/android/media/IMediaRouter2ManagerClient.aidl create mode 100644 media/java/android/media/MediaRoute2ProviderService.java create mode 100644 media/java/android/media/MediaRouter2Manager.java create mode 100644 media/tests/MediaRouteProvider/Android.bp create mode 100644 media/tests/MediaRouteProvider/AndroidManifest.xml create mode 100644 media/tests/MediaRouteProvider/res/values/strings.xml create mode 100644 media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java create mode 100644 media/tests/MediaRouter/Android.bp create mode 100644 media/tests/MediaRouter/AndroidManifest.xml create mode 100644 media/tests/MediaRouter/AndroidTest.xml create mode 100644 media/tests/MediaRouter/res/values/strings.xml create mode 100644 media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java create mode 100644 services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java create mode 100644 services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java diff --git a/Android.bp b/Android.bp index 87388d4ae3c0..5f0d723bfd5c 100644 --- a/Android.bp +++ b/Android.bp @@ -474,7 +474,10 @@ java_defaults { "media/java/android/media/IMediaHTTPConnection.aidl", "media/java/android/media/IMediaHTTPService.aidl", "media/java/android/media/IMediaResourceMonitor.aidl", + "media/java/android/media/IMediaRoute2Callback.aidl", + "media/java/android/media/IMediaRoute2Provider.aidl", "media/java/android/media/IMediaRouterClient.aidl", + "media/java/android/media/IMediaRouter2ManagerClient.aidl", "media/java/android/media/IMediaRouterService.aidl", "media/java/android/media/IMediaScannerListener.aidl", "media/java/android/media/IMediaScannerService.aidl", @@ -1801,4 +1804,4 @@ aidl_mapping { name: "framework-aidl-mappings", srcs: [":framework-defaults"], output: "framework-aidl-mappings.txt" -} \ No newline at end of file +} diff --git a/media/java/android/media/IMediaRoute2Callback.aidl b/media/java/android/media/IMediaRoute2Callback.aidl new file mode 100644 index 000000000000..f03c8ab444c4 --- /dev/null +++ b/media/java/android/media/IMediaRoute2Callback.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +/** + * @hide + */ +oneway interface IMediaRoute2Callback { + void onRouteSelected(int uid, String routeId); +} diff --git a/media/java/android/media/IMediaRoute2Provider.aidl b/media/java/android/media/IMediaRoute2Provider.aidl new file mode 100644 index 000000000000..b97dcc521a04 --- /dev/null +++ b/media/java/android/media/IMediaRoute2Provider.aidl @@ -0,0 +1,27 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.media.IMediaRoute2Callback; + +/** + * {@hide} + */ +oneway interface IMediaRoute2Provider { + void setCallback(IMediaRoute2Callback callback); + void selectRoute(int uid, String id); +} diff --git a/media/java/android/media/IMediaRouter2ManagerClient.aidl b/media/java/android/media/IMediaRouter2ManagerClient.aidl new file mode 100644 index 000000000000..234551b37a10 --- /dev/null +++ b/media/java/android/media/IMediaRouter2ManagerClient.aidl @@ -0,0 +1,25 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +/** + * {@hide} + */ +oneway interface IMediaRouter2ManagerClient { + void onRouteSelected(int uid, String routeId); + void onControlCategoriesChanged(int uid, in List categories); +} diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 3308fc929b03..59f1d0dcbed8 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -17,6 +17,7 @@ package android.media; import android.media.IMediaRouterClient; +import android.media.IMediaRouter2ManagerClient; import android.media.MediaRouterClientState; /** @@ -29,8 +30,15 @@ interface IMediaRouterService { MediaRouterClientState getState(IMediaRouterClient client); boolean isPlaybackActive(IMediaRouterClient client); + void setControlCategories(IMediaRouterClient client, in List categories); void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan); void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit); void requestSetVolume(IMediaRouterClient client, String routeId, int volume); void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction); + + void registerManagerAsUser(IMediaRouter2ManagerClient callback, + String packageName, int userId); + void unregisterManager(IMediaRouter2ManagerClient callback); + void setRemoteRoute(IMediaRouter2ManagerClient callback, + int uid, String routeId, boolean explicit); } diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java new file mode 100644 index 000000000000..04ddc3089b91 --- /dev/null +++ b/media/java/android/media/MediaRoute2ProviderService.java @@ -0,0 +1,108 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; + +/** + * @hide + */ +public abstract class MediaRoute2ProviderService extends Service { + private static final String TAG = "MediaRouteProviderSrv"; + + public static final String SERVICE_INTERFACE = "android.media.MediaRoute2ProviderService"; + + private final Handler mHandler; + private ProviderStub mStub; + private IMediaRoute2Callback mCallback; + + public MediaRoute2ProviderService() { + mHandler = new Handler(Looper.getMainLooper()); + } + + @Override + public IBinder onBind(Intent intent) { + if (SERVICE_INTERFACE.equals(intent.getAction())) { + if (mStub == null) { + mStub = new ProviderStub(); + } + return mStub; + } + return null; + } + + /** + * Called when selectRoute is called on a route of the provider. + * + * @param uid The target application uid + * @param routeId The id of the target route + */ + public abstract void onSelect(int uid, String routeId); + + /** + * Updates provider info from selected route and appliation. + * + * TODO: When provider descriptor is defined, this should update the descriptor correctly. + * + * @param uid + * @param routeId + */ + public void updateProvider(int uid, String routeId) { + if (mCallback != null) { + try { + //TODO: After publishState() is fully implemented, delete this. + mCallback.onRouteSelected(uid, routeId); + } catch (RemoteException ex) { + Log.d(TAG, "Failed to update provider"); + } + } + publishState(); + } + + void setCallback(IMediaRoute2Callback callback) { + mCallback = callback; + publishState(); + } + + void publishState() { + //TODO: Send provider descriptor to the MediaRouterService + } + + final class ProviderStub extends IMediaRoute2Provider.Stub { + ProviderStub() { } + + @Override + public void setCallback(IMediaRoute2Callback callback) { + mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::setCallback, + MediaRoute2ProviderService.this, callback)); + } + + @Override + public void selectRoute(int uid, String id) { + mHandler.sendMessage(obtainMessage(MediaRoute2ProviderService::onSelect, + MediaRoute2ProviderService.this, uid, id)); + } + } +} diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 3444e9277949..5a89d8c82f3a 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -347,6 +347,17 @@ public class MediaRouter { return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION); } + void setControlCategories(List categories) { + if (mClient != null) { + try { + mMediaRouterService.setControlCategories(mClient, + categories); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to set control categories.", ex); + } + } + } + private void updatePresentationDisplays(int changedDisplayId) { final int count = mRoutes.size(); for (int i = 0; i < count; i++) { @@ -919,6 +930,25 @@ public class MediaRouter { return -1; } + //TODO: Remove @hide when it is ready. + //TODO: Provide pre-defined categories for app developers. + /** + * Sets control categories of the client application. + * Control categories can be used to filter out media routes + * that don't correspond with the client application. + * The only routes that match any of the categories will be shown on other applications. + * + * @hide + * @param categories Categories to set + */ + public void setControlCategories(@NonNull List categories) { + if (categories == null) { + throw new IllegalArgumentException("Categories must not be null"); + } + sStatic.setControlCategories(categories); + } + + /** * Select the specified route to use for output of the given media types. *

diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java new file mode 100644 index 000000000000..ac5958ea9aa1 --- /dev/null +++ b/media/java/android/media/MediaRouter2Manager.java @@ -0,0 +1,241 @@ +/* + * Copyright 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.CallbackExecutor; +import android.annotation.NonNull; +import android.content.Context; +import android.os.Handler; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.util.Log; + +import com.android.internal.annotations.GuardedBy; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; + +/** + * @hide + */ +public class MediaRouter2Manager { + private static final String TAG = "MediaRouter2Manager"; + private static final Object sLock = new Object(); + + @GuardedBy("sLock") + private static MediaRouter2Manager sInstance; + + final String mPackageName; + + private Context mContext; + private Client mClient; + private final IMediaRouterService mMediaRouterService; + final Handler mHandler; + + @GuardedBy("sLock") + final ArrayList mCallbacks = new ArrayList<>(); + + /** + * Gets an instance of media router manager that controls media route of other apps. + * @param context + * @return + */ + public static MediaRouter2Manager getInstance(@NonNull Context context) { + if (context == null) { + throw new IllegalArgumentException("context must not be null"); + } + synchronized (sLock) { + if (sInstance == null) { + sInstance = new MediaRouter2Manager(context); + } + return sInstance; + } + } + + private MediaRouter2Manager(Context context) { + mContext = context.getApplicationContext(); + mMediaRouterService = IMediaRouterService.Stub.asInterface( + ServiceManager.getService(Context.MEDIA_ROUTER_SERVICE)); + mPackageName = mContext.getPackageName(); + mHandler = new Handler(context.getMainLooper()); + } + + /** + * Registers a callback to listen route info. + * + * @param executor The executor that runs the callback. + * @param callback The callback to add. + */ + public void addCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull Callback callback) { + + if (executor == null) { + throw new IllegalArgumentException("executor must not be null"); + } + if (callback == null) { + throw new IllegalArgumentException("callback must not be null"); + } + + synchronized (sLock) { + final int index = findCallbackRecord(callback); + if (index >= 0) { + Log.w(TAG, "Ignore adding the same callback twice."); + return; + } + if (mCallbacks.size() == 0) { + Client client = new Client(); + try { + mMediaRouterService.registerManagerAsUser(client, mPackageName, + UserHandle.myUserId()); + mClient = client; + } catch (RemoteException ex) { + Log.e(TAG, "Unable to register media router manager.", ex); + } + } + mCallbacks.add(new CallbackRecord(executor, callback)); + } + } + + /** + * Removes the specified callback. + * + * @param callback The callback to remove. + */ + public void removeCallback(@NonNull Callback callback) { + if (callback == null) { + throw new IllegalArgumentException("callback must not be null"); + } + + synchronized (sLock) { + final int index = findCallbackRecord(callback); + if (index < 0) { + Log.w(TAG, "Ignore removing unknown callback. " + callback); + return; + } + mCallbacks.remove(index); + if (mCallbacks.size() == 0 && mClient != null) { + try { + mMediaRouterService.unregisterManager(mClient); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to unregister media router manager", ex); + } + mClient = null; + } + } + } + + private int findCallbackRecord(Callback callback) { + final int count = mCallbacks.size(); + for (int i = 0; i < count; i++) { + if (mCallbacks.get(i).mCallback == callback) { + return i; + } + } + return -1; + } + + /** + * Selects media route for the specified application uid. + * + * @param uid The uid of the application that should change it's media route. + * @param routeId The id of the route to select + */ + public void selectRoute(int uid, String routeId) { + if (mClient != null) { + try { + mMediaRouterService.setRemoteRoute(mClient, uid, routeId, /* explicit= */true); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to select media route", ex); + } + } + } + + /** + * Unselects media route for the specified application uid. + * + * @param uid The uid of the application that should stop routing. + */ + public void unselectRoute(int uid) { + if (mClient != null) { + try { + mMediaRouterService.setRemoteRoute(mClient, uid, null, /* explicit= */ true); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to select media route", ex); + } + } + } + + void notifyRouteSelected(int uid, String routeId) { + for (CallbackRecord record : mCallbacks) { + record.mExecutor.execute(() -> record.mCallback.onRouteSelected(uid, routeId)); + } + } + + void notifyControlCategoriesChanged(int uid, List categories) { + for (CallbackRecord record : mCallbacks) { + record.mExecutor.execute( + () -> record.mCallback.onControlCategoriesChanged(uid, categories)); + } + } + + /** + * Interface for receiving events about media routing changes. + */ + public abstract static class Callback { + /** + * Called when a route is selected for some application uid. + * @param uid + * @param routeId + */ + public abstract void onRouteSelected(int uid, String routeId); + + /** + * Called when the control categories of an application is changed. + * @param uid the uid of the app that changed control categories + * @param categories the changed categories + */ + public abstract void onControlCategoriesChanged(int uid, List categories); + } + + final class CallbackRecord { + public final Executor mExecutor; + public final Callback mCallback; + + CallbackRecord(Executor executor, Callback callback) { + mExecutor = executor; + mCallback = callback; + } + } + + class Client extends IMediaRouter2ManagerClient.Stub { + @Override + public void onRouteSelected(int uid, String routeId) { + mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyRouteSelected, + MediaRouter2Manager.this, uid, routeId)); + } + + @Override + public void onControlCategoriesChanged(int uid, List categories) { + mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifyControlCategoriesChanged, + MediaRouter2Manager.this, uid, categories)); + } + } +} diff --git a/media/tests/MediaRouteProvider/Android.bp b/media/tests/MediaRouteProvider/Android.bp new file mode 100644 index 000000000000..da4282495ac2 --- /dev/null +++ b/media/tests/MediaRouteProvider/Android.bp @@ -0,0 +1,18 @@ +android_test { + name: "mediarouteprovider", + + srcs: ["**/*.java"], + + libs: [ + "android.test.runner", + "android.test.base", + ], + + static_libs: [ + "android-support-test", + "mockito-target-minus-junit4", + ], + + platform_apis: true, + certificate: "platform", +} \ No newline at end of file diff --git a/media/tests/MediaRouteProvider/AndroidManifest.xml b/media/tests/MediaRouteProvider/AndroidManifest.xml new file mode 100644 index 000000000000..489a6214ecbd --- /dev/null +++ b/media/tests/MediaRouteProvider/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + diff --git a/media/tests/MediaRouteProvider/res/values/strings.xml b/media/tests/MediaRouteProvider/res/values/strings.xml new file mode 100644 index 000000000000..bb970641ffda --- /dev/null +++ b/media/tests/MediaRouteProvider/res/values/strings.xml @@ -0,0 +1,5 @@ + + + + SampleMediaRouteProvider + \ No newline at end of file diff --git a/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java new file mode 100644 index 000000000000..22fbd85d6979 --- /dev/null +++ b/media/tests/MediaRouteProvider/src/com/android/mediarouteprovider/example/SampleMediaRoute2ProviderService.java @@ -0,0 +1,33 @@ +/* + * Copyright 2019 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.mediarouteprovider.example; + +import android.content.Intent; +import android.media.MediaRoute2ProviderService; +import android.os.IBinder; + +public class SampleMediaRoute2ProviderService extends MediaRoute2ProviderService { + @Override + public IBinder onBind(Intent intent) { + return super.onBind(intent); + } + + @Override + public void onSelect(int uid, String routeId) { + updateProvider(uid, routeId); + } +} diff --git a/media/tests/MediaRouter/Android.bp b/media/tests/MediaRouter/Android.bp new file mode 100644 index 000000000000..611b25a2f128 --- /dev/null +++ b/media/tests/MediaRouter/Android.bp @@ -0,0 +1,18 @@ +android_test { + name: "mediaroutertest", + + srcs: ["**/*.java"], + + libs: [ + "android.test.runner", + "android.test.base", + ], + + static_libs: [ + "android-support-test", + "mockito-target-minus-junit4", + ], + + platform_apis: true, + certificate: "platform", +} \ No newline at end of file diff --git a/media/tests/MediaRouter/AndroidManifest.xml b/media/tests/MediaRouter/AndroidManifest.xml new file mode 100644 index 000000000000..a34a264e1247 --- /dev/null +++ b/media/tests/MediaRouter/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/media/tests/MediaRouter/AndroidTest.xml b/media/tests/MediaRouter/AndroidTest.xml new file mode 100644 index 000000000000..1301062db496 --- /dev/null +++ b/media/tests/MediaRouter/AndroidTest.xml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/media/tests/MediaRouter/res/values/strings.xml b/media/tests/MediaRouter/res/values/strings.xml new file mode 100644 index 000000000000..07370207a3c9 --- /dev/null +++ b/media/tests/MediaRouter/res/values/strings.xml @@ -0,0 +1,5 @@ + + + + mediaRouterTest + \ No newline at end of file diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java new file mode 100644 index 000000000000..a4bde6592516 --- /dev/null +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 2019 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.mediaroutertest; + +import static org.mockito.Mockito.after; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.media.MediaRouter; +import android.media.MediaRouter2Manager; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class MediaRouterManagerTest { + private static final String TAG = "MediaRouterManagerTest"; + + private static final int TARGET_UID = 109992; + private static final String ROUTE_1 = "MediaRoute1"; + + private static final int AWAIT_MS = 1000; + private static final int TIMEOUT_MS = 1000; + + private Context mContext; + private MediaRouter2Manager mManager; + private MediaRouter mRouter; + private Executor mExecutor; + + private static final List TEST_CONTROL_CATEGORIES = new ArrayList(); + private static final String CONTROL_CATEGORY_1 = "android.media.mediarouter.MEDIA1"; + private static final String CONTROL_CATEGORY_2 = "android.media.mediarouter.MEDIA2"; + static { + TEST_CONTROL_CATEGORIES.add(CONTROL_CATEGORY_1); + TEST_CONTROL_CATEGORIES.add(CONTROL_CATEGORY_2); + } + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getTargetContext(); + mManager = MediaRouter2Manager.getInstance(mContext); + mRouter = (MediaRouter) mContext.getSystemService(Context.MEDIA_ROUTER_SERVICE); + mExecutor = new ThreadPoolExecutor( + 1, 20, 3, TimeUnit.SECONDS, + new SynchronousQueue()); + } + + @Test + public void transferTest() throws Exception { + MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class); + + mManager.addCallback(mExecutor, mockCallback); + + verify(mockCallback, after(AWAIT_MS).never()) + .onRouteSelected(eq(TARGET_UID), any(String.class)); + + mManager.selectRoute(TARGET_UID, ROUTE_1); + verify(mockCallback, timeout(TIMEOUT_MS)).onRouteSelected(TARGET_UID, ROUTE_1); + + mManager.removeCallback(mockCallback); + } + + @Test + public void controlCategoryTest() throws Exception { + final int uid = android.os.Process.myUid(); + + MediaRouter2Manager.Callback mockCallback = mock(MediaRouter2Manager.Callback.class); + mManager.addCallback(mExecutor, mockCallback); + + verify(mockCallback, after(AWAIT_MS).never()).onControlCategoriesChanged(eq(uid), + any(List.class)); + + mRouter.setControlCategories(TEST_CONTROL_CATEGORIES); + verify(mockCallback, timeout(TIMEOUT_MS).atLeastOnce()) + .onControlCategoriesChanged(uid, TEST_CONTROL_CATEGORIES); + + mManager.removeCallback(mockCallback); + } + +} diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java new file mode 100644 index 000000000000..d284c6091f73 --- /dev/null +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderProxy.java @@ -0,0 +1,341 @@ +/* + * Copyright 2019 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.media; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.media.IMediaRoute2Callback; +import android.media.IMediaRoute2Provider; +import android.media.MediaRoute2ProviderService; +import android.os.Handler; +import android.os.IBinder; +import android.os.IBinder.DeathRecipient; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; +import android.util.Slog; + +import java.io.PrintWriter; +import java.lang.ref.WeakReference; + +/** + * Maintains a connection to a particular media route provider service. + */ +final class MediaRoute2ProviderProxy implements ServiceConnection { + private static final String TAG = "MediaRoute2ProviderProxy"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final Context mContext; + private final ComponentName mComponentName; + private final int mUserId; + private final Handler mHandler; + + private Callback mCallback; + + // Selected Route info + public int mSelectedUid; + public String mSelectedRouteId; + + // Connection state + private boolean mRunning; + private boolean mBound; + private Connection mActiveConnection; + private boolean mConnectionReady; + + MediaRoute2ProviderProxy(Context context, ComponentName componentName, int userId) { + mContext = context; + mComponentName = componentName; + mUserId = userId; + mHandler = new Handler(); + } + + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "Proxy"); + pw.println(prefix + " mUserId=" + mUserId); + pw.println(prefix + " mRunning=" + mRunning); + pw.println(prefix + " mBound=" + mBound); + pw.println(prefix + " mActiveConnection=" + mActiveConnection); + pw.println(prefix + " mConnectionReady=" + mConnectionReady); + } + + public void setCallback(Callback callback) { + mCallback = callback; + } + + public void setSelectedRoute(int uid, String routeId) { + if (mConnectionReady) { + mActiveConnection.selectRoute(uid, routeId); + updateBinding(); + } + } + + public boolean hasComponentName(String packageName, String className) { + return mComponentName.getPackageName().equals(packageName) + && mComponentName.getClassName().equals(className); + } + + public String getFlattenedComponentName() { + return mComponentName.flattenToShortString(); + } + + public void start() { + if (!mRunning) { + if (DEBUG) { + Slog.d(TAG, this + ": Starting"); + } + + mRunning = true; + updateBinding(); + } + } + + public void stop() { + if (mRunning) { + if (DEBUG) { + Slog.d(TAG, this + ": Stopping"); + } + + mRunning = false; + updateBinding(); + } + } + + public void rebindIfDisconnected() { + if (mActiveConnection == null && shouldBind()) { + unbind(); + bind(); + } + } + + private void updateBinding() { + if (shouldBind()) { + bind(); + } else { + unbind(); + } + } + + private boolean shouldBind() { + //TODO: binding could be delayed until it's necessary. + if (mRunning) { + return true; + } + return false; + } + + private void bind() { + if (!mBound) { + if (DEBUG) { + Slog.d(TAG, this + ": Binding"); + } + + Intent service = new Intent(MediaRoute2ProviderService.SERVICE_INTERFACE); + service.setComponent(mComponentName); + try { + mBound = mContext.bindServiceAsUser(service, this, + Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, + new UserHandle(mUserId)); + if (!mBound && DEBUG) { + Slog.d(TAG, this + ": Bind failed"); + } + } catch (SecurityException ex) { + if (DEBUG) { + Slog.d(TAG, this + ": Bind failed", ex); + } + } + } + } + + private void unbind() { + if (mBound) { + if (DEBUG) { + Slog.d(TAG, this + ": Unbinding"); + } + + mBound = false; + disconnect(); + mContext.unbindService(this); + } + } + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + if (DEBUG) { + Slog.d(TAG, this + ": Connected"); + } + + if (mBound) { + disconnect(); + + IMediaRoute2Provider provider = IMediaRoute2Provider.Stub.asInterface(service); + if (provider != null) { + Connection connection = new Connection(provider); + if (connection.register()) { + mActiveConnection = connection; + } else { + if (DEBUG) { + Slog.d(TAG, this + ": Registration failed"); + } + } + } else { + Slog.e(TAG, this + ": Service returned invalid remote display provider binder"); + } + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + if (DEBUG) { + Slog.d(TAG, this + ": Service disconnected"); + } + disconnect(); + } + + private void onConnectionReady(Connection connection) { + if (mActiveConnection == connection) { + mConnectionReady = true; + } + } + + private void onConnectionDied(Connection connection) { + if (mActiveConnection == connection) { + if (DEBUG) { + Slog.d(TAG, this + ": Service connection died"); + } + disconnect(); + } + } + + private void onRouteSelected(Connection connection, int uid, String routeId) { + mSelectedUid = uid; + mSelectedRouteId = routeId; + + if (mActiveConnection == connection) { + if (DEBUG) { + Slog.d(TAG, this + ": State changed "); + } + mHandler.post(mStateChanged); + } + } + + private void disconnect() { + if (mActiveConnection != null) { + mConnectionReady = false; + mActiveConnection.dispose(); + mActiveConnection = null; + } + } + + @Override + public String toString() { + return "Service connection " + mComponentName.flattenToShortString(); + } + + private final Runnable mStateChanged = new Runnable() { + @Override + public void run() { + if (mCallback != null) { + mCallback.onProviderStateChanged(MediaRoute2ProviderProxy.this); + } + } + }; + + public interface Callback { + void onProviderStateChanged(MediaRoute2ProviderProxy provider); + } + + private final class Connection implements DeathRecipient { + private final IMediaRoute2Provider mProvider; + private final ProviderCallback mCallback; + + Connection(IMediaRoute2Provider provider) { + mProvider = provider; + mCallback = new ProviderCallback(this); + } + + public boolean register() { + try { + mProvider.asBinder().linkToDeath(this, 0); + mProvider.setCallback(mCallback); + mHandler.post(new Runnable() { + @Override + public void run() { + onConnectionReady(Connection.this); + } + }); + return true; + } catch (RemoteException ex) { + binderDied(); + } + return false; + } + + public void dispose() { + mProvider.asBinder().unlinkToDeath(this, 0); + mCallback.dispose(); + } + + public void selectRoute(int uid, String id) { + try { + mProvider.selectRoute(uid, id); + } catch (RemoteException ex) { + Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex); + } + } + + @Override + public void binderDied() { + mHandler.post(new Runnable() { + @Override + public void run() { + onConnectionDied(Connection.this); + } + }); + } + + void postRouteSelected(int uid, String routeId) { + mHandler.post(new Runnable() { + @Override + public void run() { + onRouteSelected(Connection.this, uid, routeId); + } + }); + } + } + + private static final class ProviderCallback extends IMediaRoute2Callback.Stub { + private final WeakReference mConnectionRef; + + ProviderCallback(Connection connection) { + mConnectionRef = new WeakReference(connection); + } + + public void dispose() { + mConnectionRef.clear(); + } + + @Override + public void onRouteSelected(int uid, String routeId) throws RemoteException { + Connection connection = mConnectionRef.get(); + if (connection != null) { + connection.postRouteSelected(uid, routeId); + } + } + } +} diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java new file mode 100644 index 000000000000..08d8c58f6f87 --- /dev/null +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java @@ -0,0 +1,176 @@ +/* + * Copyright 2019 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.media; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.media.MediaRoute2ProviderService; +import android.os.Handler; +import android.os.UserHandle; +import android.util.Log; +import android.util.Slog; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; + +/** + */ +final class MediaRoute2ProviderWatcher { + private static final String TAG = "MediaRouteProvider"; // max. 23 chars + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private final Context mContext; + private final Callback mCallback; + private final Handler mHandler; + private final int mUserId; + private final PackageManager mPackageManager; + + private final ArrayList mProviders = new ArrayList<>(); + private boolean mRunning; + + MediaRoute2ProviderWatcher(Context context, + Callback callback, Handler handler, int userId) { + mContext = context; + mCallback = callback; + mHandler = handler; + mUserId = userId; + mPackageManager = context.getPackageManager(); + } + + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "Watcher"); + pw.println(prefix + " mUserId=" + mUserId); + pw.println(prefix + " mRunning=" + mRunning); + pw.println(prefix + " mProviders.size()=" + mProviders.size()); + } + + public void start() { + if (!mRunning) { + mRunning = true; + + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REPLACED); + filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); + filter.addDataScheme("package"); + mContext.registerReceiverAsUser(mScanPackagesReceiver, + new UserHandle(mUserId), filter, null, mHandler); + + // Scan packages. + // Also has the side-effect of restarting providers if needed. + mHandler.post(mScanPackagesRunnable); + } + } + + public void stop() { + if (mRunning) { + mRunning = false; + + mContext.unregisterReceiver(mScanPackagesReceiver); + mHandler.removeCallbacks(mScanPackagesRunnable); + + // Stop all providers. + for (int i = mProviders.size() - 1; i >= 0; i--) { + mProviders.get(i).stop(); + } + } + } + + private void scanPackages() { + if (!mRunning) { + return; + } + + // Add providers for all new services. + // Reorder the list so that providers left at the end will be the ones to remove. + int targetIndex = 0; + Intent intent = new Intent(MediaRoute2ProviderService.SERVICE_INTERFACE); + for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser( + intent, 0, mUserId)) { + ServiceInfo serviceInfo = resolveInfo.serviceInfo; + if (serviceInfo != null) { + int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name); + if (sourceIndex < 0) { + MediaRoute2ProviderProxy provider = + new MediaRoute2ProviderProxy(mContext, + new ComponentName(serviceInfo.packageName, serviceInfo.name), + mUserId); + provider.start(); + mProviders.add(targetIndex++, provider); + mCallback.addProvider(provider); + } else if (sourceIndex >= targetIndex) { + MediaRoute2ProviderProxy provider = mProviders.get(sourceIndex); + provider.start(); // restart the provider if needed + provider.rebindIfDisconnected(); + Collections.swap(mProviders, sourceIndex, targetIndex++); + } + } + } + + // Remove providers for missing services. + if (targetIndex < mProviders.size()) { + for (int i = mProviders.size() - 1; i >= targetIndex; i--) { + MediaRoute2ProviderProxy provider = mProviders.get(i); + mCallback.removeProvider(provider); + mProviders.remove(provider); + provider.stop(); + } + } + } + + private int findProvider(String packageName, String className) { + int count = mProviders.size(); + for (int i = 0; i < count; i++) { + MediaRoute2ProviderProxy provider = mProviders.get(i); + if (provider.hasComponentName(packageName, className)) { + return i; + } + } + return -1; + } + + private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (DEBUG) { + Slog.d(TAG, "Received package manager broadcast: " + intent); + } + scanPackages(); + } + }; + + private final Runnable mScanPackagesRunnable = new Runnable() { + @Override + public void run() { + scanPackages(); + } + }; + + public interface Callback { + void addProvider(MediaRoute2ProviderProxy provider); + void removeProvider(MediaRoute2ProviderProxy provider); + } +} diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 3eb732157a44..f822e82ecdfc 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -16,14 +16,10 @@ package com.android.server.media; -import com.android.internal.util.DumpUtils; -import com.android.server.Watchdog; - import android.annotation.NonNull; import android.app.ActivityManager; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothProfile; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -34,6 +30,7 @@ import android.media.AudioRoutesInfo; import android.media.AudioSystem; import android.media.IAudioRoutesObserver; import android.media.IAudioService; +import android.media.IMediaRouter2ManagerClient; import android.media.IMediaRouterClient; import android.media.IMediaRouterService; import android.media.MediaRouter; @@ -53,10 +50,14 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.IntArray; import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; +import com.android.internal.util.DumpUtils; +import com.android.server.Watchdog; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; @@ -97,6 +98,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final Object mLock = new Object(); private final SparseArray mUserRecords = new SparseArray<>(); private final ArrayMap mAllClientRecords = new ArrayMap<>(); + private final ArrayMap mAllManagerRecords = new ArrayMap<>(); private int mCurrentUserId = -1; private final IAudioService mAudioService; private final AudioPlayerStateMonitor mAudioPlayerStateMonitor; @@ -304,6 +306,22 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } + // Binder call + @Override + public void setControlCategories(IMediaRouterClient client, List categories) { + if (client == null) { + throw new IllegalArgumentException("client must not be null"); + } + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + setControlCategoriesLocked(client, categories); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + // Binder call @Override public void setDiscoveryRequest(IMediaRouterClient client, @@ -404,6 +422,65 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } + // Binder call + @Override + public void registerManagerAsUser(IMediaRouter2ManagerClient client, + String packageName, int userId) { + if (client == null) { + throw new IllegalArgumentException("client must not be null"); + } + //TODO: should check permission + final boolean trusted = true; + + final int uid = Binder.getCallingUid(); + if (!validatePackageName(uid, packageName)) { + throw new SecurityException("packageName must match the calling uid"); + } + + final int pid = Binder.getCallingPid(); + final int resolvedUserId = ActivityManager.handleIncomingUser(pid, uid, userId, + false /*allowAll*/, true /*requireFull*/, "registerManagerAsUser", packageName); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + registerManagerLocked(client, uid, pid, packageName, resolvedUserId, trusted); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + // Binder call + @Override + public void unregisterManager(IMediaRouter2ManagerClient client) { + if (client == null) { + throw new IllegalArgumentException("client must not be null"); + } + + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + unregisterManagerLocked(client, false); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + // Binder call + @Override + public void setRemoteRoute(IMediaRouter2ManagerClient client, + int uid, String routeId, boolean explicit) { + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + setRemoteRouteLocked(client, uid, routeId, explicit); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + void restoreBluetoothA2dp() { try { boolean a2dpOn; @@ -475,6 +552,12 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } + void clientDied(ManagerRecord managerRecord) { + synchronized (mLock) { + unregisterManagerLocked(managerRecord.mClient, true); + } + } + private void registerClientLocked(IMediaRouterClient client, int uid, int pid, String packageName, int userId, boolean trusted) { final IBinder binder = client.asBinder(); @@ -522,6 +605,17 @@ public final class MediaRouterService extends IMediaRouterService.Stub return null; } + private void setControlCategoriesLocked(IMediaRouterClient client, List categories) { + final IBinder binder = client.asBinder(); + ClientRecord clientRecord = mAllClientRecords.get(binder); + + if (clientRecord != null) { + clientRecord.mControlCategories = categories; + clientRecord.mUserRecord.mHandler.obtainMessage( + UserHandler.MSG_UPDATE_CLIENT_USAGE, clientRecord).sendToTarget(); + } + } + private void setDiscoveryRequestLocked(IMediaRouterClient client, int routeTypes, boolean activeScan) { final IBinder binder = client.asBinder(); @@ -575,6 +669,63 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } + private void registerManagerLocked(IMediaRouter2ManagerClient client, + int uid, int pid, String packageName, int userId, boolean trusted) { + final IBinder binder = client.asBinder(); + ManagerRecord managerRecord = mAllManagerRecords.get(binder); + if (managerRecord == null) { + boolean newUser = false; + UserRecord userRecord = mUserRecords.get(userId); + if (userRecord == null) { + userRecord = new UserRecord(userId); + newUser = true; + } + managerRecord = new ManagerRecord(userRecord, client, uid, pid, packageName, trusted); + try { + binder.linkToDeath(managerRecord, 0); + } catch (RemoteException ex) { + throw new RuntimeException("Media router client died prematurely.", ex); + } + + if (newUser) { + mUserRecords.put(userId, userRecord); + initializeUserLocked(userRecord); + } + + userRecord.mManagerRecords.add(managerRecord); + mAllManagerRecords.put(binder, managerRecord); + + // send client usage to manager + final int clientCount = userRecord.mClientRecords.size(); + for (int i = 0; i < clientCount; i++) { + userRecord.mHandler.obtainMessage(UserHandler.MSG_UPDATE_CLIENT_USAGE, + userRecord.mClientRecords.get(i)).sendToTarget(); + } + } + } + + private void unregisterManagerLocked(IMediaRouter2ManagerClient client, boolean died) { + ManagerRecord clientRecord = mAllManagerRecords.remove(client.asBinder()); + if (clientRecord != null) { + UserRecord userRecord = clientRecord.mUserRecord; + userRecord.mManagerRecords.remove(clientRecord); + clientRecord.dispose(); + disposeUserIfNeededLocked(userRecord); // since client removed from user + } + } + + private void setRemoteRouteLocked(IMediaRouter2ManagerClient client, + int uid, String routeId, boolean explicit) { + ManagerRecord managerRecord = mAllManagerRecords.get(client.asBinder()); + if (managerRecord != null) { + if (explicit && managerRecord.mTrusted) { + Pair obj = new Pair<>(uid, routeId); + managerRecord.mUserRecord.mHandler.obtainMessage( + UserHandler.MSG_SELECT_REMOTE_ROUTE, obj).sendToTarget(); + } + } + } + private void requestSetVolumeLocked(IMediaRouterClient client, String routeId, int volume) { final IBinder binder = client.asBinder(); @@ -667,6 +818,46 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } + final class ManagerRecord implements DeathRecipient { + public final UserRecord mUserRecord; + public final IMediaRouter2ManagerClient mClient; + public final int mUid; + public final int mPid; + public final String mPackageName; + public final boolean mTrusted; + + ManagerRecord(UserRecord userRecord, IMediaRouter2ManagerClient client, + int uid, int pid, String packageName, boolean trusted) { + mUserRecord = userRecord; + mClient = client; + mUid = uid; + mPid = pid; + mPackageName = packageName; + mTrusted = trusted; + } + + public void dispose() { + mClient.asBinder().unlinkToDeath(this, 0); + } + + @Override + public void binderDied() { + clientDied(this); + } + + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + this); + + final String indent = prefix + " "; + pw.println(indent + "mTrusted=" + mTrusted); + } + + @Override + public String toString() { + return "Client " + mPackageName + " (pid " + mPid + ")"; + } + } + /** * Information about a particular client of the media router. * The contents of this object is guarded by mLock. @@ -678,6 +869,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub public final int mPid; public final String mPackageName; public final boolean mTrusted; + public List mControlCategories; public int mRouteTypes; public boolean mActiveScan; @@ -728,7 +920,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub */ final class UserRecord { public final int mUserId; - public final ArrayList mClientRecords = new ArrayList(); + public final ArrayList mClientRecords = new ArrayList<>(); + public final ArrayList mManagerRecords = new ArrayList<>(); public final UserHandler mHandler; public MediaRouterClientState mRouterState; @@ -783,7 +976,9 @@ public final class MediaRouterService extends IMediaRouterService.Stub */ static final class UserHandler extends Handler implements RemoteDisplayProviderWatcher.Callback, - RemoteDisplayProviderProxy.Callback { + RemoteDisplayProviderProxy.Callback, + MediaRoute2ProviderWatcher.Callback, + MediaRoute2ProviderProxy.Callback { public static final int MSG_START = 1; public static final int MSG_STOP = 2; public static final int MSG_UPDATE_DISCOVERY_REQUEST = 3; @@ -794,6 +989,9 @@ public final class MediaRouterService extends IMediaRouterService.Stub private static final int MSG_UPDATE_CLIENT_STATE = 8; private static final int MSG_CONNECTION_TIMED_OUT = 9; + private static final int MSG_SELECT_REMOTE_ROUTE = 10; + private static final int MSG_UPDATE_CLIENT_USAGE = 11; + private static final int TIMEOUT_REASON_NOT_AVAILABLE = 1; private static final int TIMEOUT_REASON_CONNECTION_LOST = 2; private static final int TIMEOUT_REASON_WAITING_FOR_CONNECTING = 3; @@ -809,11 +1007,17 @@ public final class MediaRouterService extends IMediaRouterService.Stub private final MediaRouterService mService; private final UserRecord mUserRecord; private final RemoteDisplayProviderWatcher mWatcher; + private final MediaRoute2ProviderWatcher mMediaWatcher; + private final ArrayList mProviderRecords = new ArrayList(); private final ArrayList mTempClients = new ArrayList(); + private final ArrayList mMediaProviders = + new ArrayList<>(); + private final ArrayList mTempManagers = new ArrayList<>(); + private boolean mRunning; private int mDiscoveryMode = RemoteDisplayState.DISCOVERY_MODE_NONE; private RouteRecord mSelectedRouteRecord; @@ -828,6 +1032,8 @@ public final class MediaRouterService extends IMediaRouterService.Stub mUserRecord = userRecord; mWatcher = new RemoteDisplayProviderWatcher(service.mContext, this, this, mUserRecord.mUserId); + mMediaWatcher = new MediaRoute2ProviderWatcher(service.mContext, this, + this, mUserRecord.mUserId); } @Override @@ -869,6 +1075,15 @@ public final class MediaRouterService extends IMediaRouterService.Stub connectionTimedOut(); break; } + case MSG_SELECT_REMOTE_ROUTE: { + Pair obj = (Pair) msg.obj; + selectRemoteRoute(obj.first, obj.second); + break; + } + case MSG_UPDATE_CLIENT_USAGE: { + updateClientUsage((ClientRecord) msg.obj); + break; + } } } @@ -900,6 +1115,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub if (!mRunning) { mRunning = true; mWatcher.start(); // also starts all providers + mMediaWatcher.start(); } } @@ -908,6 +1124,7 @@ public final class MediaRouterService extends IMediaRouterService.Stub mRunning = false; unselectSelectedRoute(); mWatcher.stop(); // also stops all providers + mMediaWatcher.stop(); } } @@ -1039,6 +1256,26 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } + @Override + public void addProvider(MediaRoute2ProviderProxy provider) { + provider.setCallback(this); + mMediaProviders.add(provider); + } + + @Override + public void removeProvider(MediaRoute2ProviderProxy provider) { + mMediaProviders.remove(provider); + } + + @Override + public void onProviderStateChanged(MediaRoute2ProviderProxy provider) { + updateProvider(provider); + } + + private void updateProvider(MediaRoute2ProviderProxy provider) { + scheduleUpdateClientState(); + } + /** * This function is called whenever the state of the selected route may have changed. * It checks the state and updates timeouts or unselects the route as appropriate. @@ -1149,6 +1386,17 @@ public final class MediaRouterService extends IMediaRouterService.Stub unselectSelectedRoute(); } + private void selectRemoteRoute(int uid, String routeId) { + if (routeId != null) { + final int providerCount = mMediaProviders.size(); + + //TODO: should find proper provider (currently assumes a single provider) + for (int i = 0; i < providerCount; ++i) { + mMediaProviders.get(i).setSelectedRoute(uid, routeId); + } + } + } + private void scheduleUpdateClientState() { if (!mClientStateUpdateScheduled) { mClientStateUpdateScheduled = true; @@ -1166,6 +1414,15 @@ public final class MediaRouterService extends IMediaRouterService.Stub mProviderRecords.get(i).appendClientState(routerState); } + //TODO: send provider info + int selectedUid = 0; + String selectedRouteId = null; + final int mediaCount = mMediaProviders.size(); + for (int i = 0; i < mediaCount; i++) { + selectedUid = mMediaProviders.get(i).mSelectedUid; + selectedRouteId = mMediaProviders.get(i).mSelectedRouteId; + } + try { synchronized (mService.mLock) { // Update the UserRecord. @@ -1176,6 +1433,11 @@ public final class MediaRouterService extends IMediaRouterService.Stub for (int i = 0; i < count; i++) { mTempClients.add(mUserRecord.mClientRecords.get(i).mClient); } + + final int count2 = mUserRecord.mManagerRecords.size(); + for (int i = 0; i < count2; i++) { + mTempManagers.add(mUserRecord.mManagerRecords.get(i).mClient); + } } // Notify all clients (outside of the lock). @@ -1187,9 +1449,39 @@ public final class MediaRouterService extends IMediaRouterService.Stub Slog.w(TAG, "Failed to call onStateChanged. Client probably died."); } } + //TODO: Call proper callbacks when provider descriptor is implemented. + final int count2 = mTempManagers.size(); + for (int i = 0; i < count2; i++) { + try { + mTempManagers.get(i).onRouteSelected(selectedUid, selectedRouteId); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to call onStateChanged. Manager probably died.", ex); + } + } } finally { // Clear the list in preparation for the next time. mTempClients.clear(); + mTempManagers.clear(); + } + } + + private void updateClientUsage(ClientRecord clientRecord) { + List managers = new ArrayList<>(); + synchronized (mService.mLock) { + final int count = mUserRecord.mManagerRecords.size(); + for (int i = 0; i < count; i++) { + managers.add(mUserRecord.mManagerRecords.get(i).mClient); + } + } + final int count = managers.size(); + for (int i = 0; i < count; i++) { + try { + managers.get(i).onControlCategoriesChanged(clientRecord.mUid, + clientRecord.mControlCategories); + } catch (RemoteException ex) { + Slog.w(TAG, "Failed to call onControlCategoriesChanged. " + + "Manager probably died.", ex); + } } } @@ -1576,4 +1868,5 @@ public final class MediaRouterService extends IMediaRouterService.Stub } } } + } -- GitLab From fc731abf72db4b288197bb055ca8d8d38a94a73a Mon Sep 17 00:00:00 2001 From: lucaslin Date: Tue, 12 Mar 2019 17:52:15 +0800 Subject: [PATCH 024/349] Modify SettingsLib for partial connectivity Add partial connectivity related settings in SettingsLib. Bug: 113450764 Bug: 128489091 Test: 1. Build pass. 2. Fake partial connectivity case for testing. Change-Id: I4791abe9351c62d9549ada383aa4cc8aa34ddaf2 --- packages/SettingsLib/res/values/strings.xml | 3 +++ .../src/com/android/settingslib/wifi/AccessPoint.java | 3 +++ .../src/com/android/settingslib/wifi/WifiStatusTracker.java | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index bf97d772bb0b..1fbd36cd2c9f 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -113,6 +113,9 @@ Connected, no internet + + Limited connection + No internet diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 800c4014313f..3acbcd3f6b41 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -1424,6 +1424,9 @@ public class AccessPoint implements Comparable { int id = context.getResources() .getIdentifier("network_available_sign_in", "string", "android"); return context.getString(id); + } else if (nc.hasCapability( + NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY)) { + return context.getString(R.string.wifi_limited_connection); } else if (!nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) { return context.getString(R.string.wifi_connected_no_internet); } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index 2ab369cc2065..5352936d7224 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -11,6 +11,7 @@ package com.android.settingslib.wifi; import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL; +import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import android.content.Context; @@ -158,6 +159,9 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) { statusLabel = mContext.getString(R.string.wifi_status_sign_in_required); return; + } else if (networkCapabilities.hasCapability(NET_CAPABILITY_PARTIAL_CONNECTIVITY)) { + statusLabel = mContext.getString(R.string.wifi_limited_connection); + return; } else if (!networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) { statusLabel = mContext.getString(R.string.wifi_status_no_internet); return; -- GitLab From cf89089bfae79fd243bddd968bfd54c3ed92bff1 Mon Sep 17 00:00:00 2001 From: Jin Seok Park Date: Mon, 18 Mar 2019 22:56:42 +0900 Subject: [PATCH 025/349] Remove Session2CommandGroup.Builder methods Remove Session2CommandGroup.Builder#addCommand(int) and Session2CommandGroup.Builder#removeCommand(int) methods. Bug: 128459284 Test: update-api Change-Id: I15d52188a7b74919af40f1f11feae0a88828cadd --- api/current.txt | 2 -- .../android/media/Session2CommandGroup.java | 31 ------------------- 2 files changed, 33 deletions(-) diff --git a/api/current.txt b/api/current.txt index 63ca6da38c96..a891a2929534 100644 --- a/api/current.txt +++ b/api/current.txt @@ -26386,10 +26386,8 @@ package android.media { ctor public Session2CommandGroup.Builder(); ctor public Session2CommandGroup.Builder(@NonNull android.media.Session2CommandGroup); method @NonNull public android.media.Session2CommandGroup.Builder addCommand(@NonNull android.media.Session2Command); - method @NonNull public android.media.Session2CommandGroup.Builder addCommand(int); method @NonNull public android.media.Session2CommandGroup build(); method @NonNull public android.media.Session2CommandGroup.Builder removeCommand(@NonNull android.media.Session2Command); - method @NonNull public android.media.Session2CommandGroup.Builder removeCommand(int); } public final class Session2Token implements android.os.Parcelable { diff --git a/media/apex/java/android/media/Session2CommandGroup.java b/media/apex/java/android/media/Session2CommandGroup.java index 73a59d00ae34..06ae8737fdc0 100644 --- a/media/apex/java/android/media/Session2CommandGroup.java +++ b/media/apex/java/android/media/Session2CommandGroup.java @@ -166,22 +166,6 @@ public final class Session2CommandGroup implements Parcelable { return this; } - /** - * Adds a predefined command with given {@code commandCode} to this command group. - * - * @param commandCode A command code to add. - * Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}. - */ - @NonNull - public Builder addCommand(int commandCode) { - if (commandCode == COMMAND_CODE_CUSTOM) { - throw new IllegalArgumentException( - "Use addCommand(Session2Command) for COMMAND_CODE_CUSTOM."); - } - mCommands.add(new Session2Command(commandCode)); - return this; - } - /** * Removes a command from this group which matches given {@code command}. * @@ -196,21 +180,6 @@ public final class Session2CommandGroup implements Parcelable { return this; } - /** - * Removes a command from this group which matches given {@code commandCode}. - * - * @param commandCode A command code to find. - * Shouldn't be {@link Session2Command#COMMAND_CODE_CUSTOM}. - */ - @NonNull - public Builder removeCommand(int commandCode) { - if (commandCode == COMMAND_CODE_CUSTOM) { - throw new IllegalArgumentException("commandCode shouldn't be COMMAND_CODE_CUSTOM"); - } - mCommands.remove(new Session2Command(commandCode)); - return this; - } - /** * Builds {@link Session2CommandGroup}. * -- GitLab From 0d5e018ab5a951bbbae152aa2cbbea4f1b2c700c Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Wed, 13 Mar 2019 13:49:24 -0700 Subject: [PATCH 026/349] Theme fixit for Car Sys UI Notifications to use recyclerview in CarSysUI SysUI UserSwitcher changes for PLV -> RecyclerView Car SysUI Volume PLV -> RecyclerView Bug: 128545260 Test: manual Change-Id: Ic618b85d6836cfc9e4bb9b40c9ba3c0e0a96af76 --- packages/CarSystemUI/Android.bp | 2 - .../layout/car_fullscreen_user_switcher.xml | 37 ++--- .../CarSystemUI/res/layout/car_qs_panel.xml | 7 +- .../res/layout/car_volume_dialog.xml | 10 +- .../res/layout/car_volume_item.xml | 71 +++++++++ .../layout/notification_center_activity.xml | 9 +- packages/CarSystemUI/res/values/colors.xml | 2 + packages/CarSystemUI/res/values/dimens.xml | 31 +++- packages/CarSystemUI/res/values/styles.xml | 7 - packages/CarSystemUI/res/values/themes.xml | 4 - .../notifications/NotificationsUI.java | 16 +-- .../systemui/qs/car/CarQSFragment.java | 2 +- .../statusbar/car/FullscreenUserSwitcher.java | 2 +- .../statusbar/car/UserGridRecyclerView.java | 35 ++++- .../systemui/volume/CarVolumeDialogImpl.java | 124 ++++++++-------- .../systemui/volume/CarVolumeItem.java | 135 ++++++++++++++++++ .../systemui/volume/CarVolumeItemAdapter.java | 59 ++++++++ 17 files changed, 422 insertions(+), 131 deletions(-) create mode 100644 packages/CarSystemUI/res/layout/car_volume_item.xml create mode 100644 packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java create mode 100644 packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItemAdapter.java diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index 9064ebe80da1..21a437d0a676 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -32,7 +32,6 @@ android_app { "SystemUISharedLib", "SettingsLib", "android.car.userlib", - "androidx.car_car", "androidx.legacy_legacy-support-v4", "androidx.recyclerview_recyclerview", "androidx.preference_preference", @@ -46,7 +45,6 @@ android_app { "androidx.slice_slice-builders", "androidx.arch.core_core-runtime", "androidx.lifecycle_lifecycle-extensions", - "car-theme-lib-bp", "SystemUI-tags", "SystemUI-proto", ], diff --git a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml index e8c5134cd180..395eac1d2ccb 100644 --- a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml +++ b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml @@ -14,12 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. --> - + - + - + android:layout_height="match_parent"> + + diff --git a/packages/CarSystemUI/res/layout/car_qs_panel.xml b/packages/CarSystemUI/res/layout/car_qs_panel.xml index d923e0fbb20b..9c598d71bd22 100644 --- a/packages/CarSystemUI/res/layout/car_qs_panel.xml +++ b/packages/CarSystemUI/res/layout/car_qs_panel.xml @@ -28,7 +28,6 @@ + android:layout_height="match_parent"/> diff --git a/packages/CarSystemUI/res/layout/car_volume_dialog.xml b/packages/CarSystemUI/res/layout/car_volume_dialog.xml index 709797d41060..35551eabfaed 100644 --- a/packages/CarSystemUI/res/layout/car_volume_dialog.xml +++ b/packages/CarSystemUI/res/layout/car_volume_dialog.xml @@ -14,15 +14,9 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - + android:minWidth="@dimen/volume_dialog_panel_width"/> diff --git a/packages/CarSystemUI/res/layout/car_volume_item.xml b/packages/CarSystemUI/res/layout/car_volume_item.xml new file mode 100644 index 000000000000..2275ca6329e2 --- /dev/null +++ b/packages/CarSystemUI/res/layout/car_volume_item.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + diff --git a/packages/CarSystemUI/res/layout/notification_center_activity.xml b/packages/CarSystemUI/res/layout/notification_center_activity.xml index 7c833035d57c..383aba4e400a 100644 --- a/packages/CarSystemUI/res/layout/notification_center_activity.xml +++ b/packages/CarSystemUI/res/layout/notification_center_activity.xml @@ -32,19 +32,14 @@ android:translationZ="2dp" /> - + app:layout_constraintEnd_toEndOf="parent"/> diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml index 7b4e32b407ae..83ec3514c01a 100644 --- a/packages/CarSystemUI/res/values/colors.xml +++ b/packages/CarSystemUI/res/values/colors.xml @@ -45,4 +45,6 @@ @android:color/black @*android:color/car_list_divider_light + @*android:color/car_list_divider + @*android:color/car_card_dark diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml index 07ecca201c12..60ce342b0adc 100644 --- a/packages/CarSystemUI/res/values/dimens.xml +++ b/packages/CarSystemUI/res/values/dimens.xml @@ -26,7 +26,7 @@ 1.75 - 36dp + @*android:dimen/car_primary_icon_size @dimen/car_body1_size @@ -59,4 +59,33 @@ 24dp 96dp 128dp + + 100dp + + + 48dp + + 15dp + + 24dp + + 12dp + + 6dp + + 4dp + + 12dp + + + @*android:dimen/car_single_line_list_item_height + @*android:dimen/car_keyline_1 + @*android:dimen/car_padding_1 + @*android:dimen/car_keyline_3 + @*android:dimen/car_padding_4 + @*android:dimen/car_seekbar_padding + 60dp + 1dp + @*android:dimen/car_padding_4 + @*android:dimen/car_radius_3 diff --git a/packages/CarSystemUI/res/values/styles.xml b/packages/CarSystemUI/res/values/styles.xml index 0d95d308f48b..382d269ecd44 100644 --- a/packages/CarSystemUI/res/values/styles.xml +++ b/packages/CarSystemUI/res/values/styles.xml @@ -46,11 +46,4 @@ 96dp @drawable/nav_button_background - - \ No newline at end of file diff --git a/packages/CarSystemUI/res/values/themes.xml b/packages/CarSystemUI/res/values/themes.xml index 8d1a4d7c08c4..f82be3c0e529 100644 --- a/packages/CarSystemUI/res/values/themes.xml +++ b/packages/CarSystemUI/res/values/themes.xml @@ -18,10 +18,6 @@ --> - - - diff --git a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java index 4a2d2fbc30cf..48cb55b3d90e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java +++ b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java @@ -16,11 +16,11 @@ package com.android.systemui.notifications; -import android.app.ActivityManager; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.SuppressLint; +import android.app.ActivityManager; import android.car.Car; import android.car.CarNotConnectedException; import android.car.drivingstate.CarUxRestrictionsManager; @@ -113,7 +113,7 @@ public class NotificationsUI extends SystemUI ServiceManager.getService(Context.STATUS_BAR_SERVICE)), launchResult -> { if (launchResult == ActivityManager.START_TASK_TO_FRONT - || launchResult == ActivityManager.START_SUCCESS){ + || launchResult == ActivityManager.START_SUCCESS) { closeCarNotifications(DEFAULT_FLING_VELOCITY); } }); @@ -179,8 +179,7 @@ public class NotificationsUI extends SystemUI } }); - RecyclerView notificationList = mCarNotificationWindow - .findViewById(com.android.car.notification.R.id.recycler_view); + RecyclerView notificationList = mCarNotificationWindow.findViewById(R.id.notifications); // register a scroll listener so we can figure out if we are at the bottom of the // list of notifications notificationList.addOnScrollListener(new RecyclerView.OnScrollListener() { @@ -202,7 +201,7 @@ public class NotificationsUI extends SystemUI // There's a view installed at a higher z-order such that we can intercept the ACTION_DOWN // to set the initial click state. mCarNotificationWindow.findViewById(R.id.glass_pane).setOnTouchListener((v, event) -> { - if (event.getActionMasked() == MotionEvent.ACTION_UP ) { + if (event.getActionMasked() == MotionEvent.ACTION_UP) { mNotificationListAtBottomAtTimeOfTouch = false; } if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { @@ -259,7 +258,7 @@ public class NotificationsUI extends SystemUI public boolean onTouch(View v, MotionEvent event) { // reset mNotificationListAtBottomAtTimeOfTouch here since the "glass pane" will not // get the up event - if (event.getActionMasked() == MotionEvent.ACTION_UP ) { + if (event.getActionMasked() == MotionEvent.ACTION_UP) { mNotificationListAtBottomAtTimeOfTouch = false; } boolean wasScrolledUp = mScrollUpDetector.onTouchEvent(event); @@ -351,7 +350,7 @@ public class NotificationsUI extends SystemUI public boolean onFling(MotionEvent event1, MotionEvent event2, float velocityX, float velocityY) { if (Math.abs(event1.getX() - event2.getX()) > SWIPE_MAX_OFF_PATH - || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY){ + || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) { // swipe was not vertical or was not fast enough return false; } @@ -435,8 +434,7 @@ public class NotificationsUI extends SystemUI mNotificationViewController.disable(); mIsShowing = false; mIsTracking = false; - RecyclerView notificationListView = mCarNotificationWindow.findViewById( - com.android.car.notification.R.id.recycler_view); + RecyclerView notificationListView = mCarNotificationWindow.findViewById(R.id.notifications); notificationListView.scrollToPosition(0); } diff --git a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java index 41c37d3bbc19..769fc52a574c 100644 --- a/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java +++ b/packages/CarSystemUI/src/com/android/systemui/qs/car/CarQSFragment.java @@ -79,7 +79,7 @@ public class CarQSFragment extends Fragment implements QS { mUserGridView = mUserSwitcherContainer.findViewById(R.id.user_grid); GridLayoutManager layoutManager = new GridLayoutManager(context, context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col)); - mUserGridView.getRecyclerView().setLayoutManager(layoutManager); + mUserGridView.setLayoutManager(layoutManager); mUserGridView.buildAdapter(); mUserSwitchCallback = new UserSwitchCallback(); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java index 23fe5944573e..f896cf1bf10c 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/FullscreenUserSwitcher.java @@ -45,7 +45,7 @@ public class FullscreenUserSwitcher { mUserGridView = container.findViewById(R.id.user_grid); GridLayoutManager layoutManager = new GridLayoutManager(context, context.getResources().getInteger(R.integer.user_fullscreen_switcher_num_col)); - mUserGridView.getRecyclerView().setLayoutManager(layoutManager); + mUserGridView.setLayoutManager(layoutManager); mUserGridView.buildAdapter(); mUserGridView.setUserSelectionListener(this::onUserSelected); diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java index fb2b57b6d490..57603781e3f0 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java @@ -28,6 +28,7 @@ import android.content.DialogInterface; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Rect; import android.os.AsyncTask; import android.util.AttributeSet; import android.view.LayoutInflater; @@ -36,9 +37,9 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; -import androidx.car.widget.PagedListView; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; +import androidx.recyclerview.widget.GridLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.android.internal.util.UserIcons; @@ -52,7 +53,7 @@ import java.util.List; * Displays a GridLayout with icons for the users in the system to allow switching between users. * One of the uses of this is for the lock screen in auto. */ -public class UserGridRecyclerView extends PagedListView implements +public class UserGridRecyclerView extends RecyclerView implements CarUserManagerHelper.OnUsersUpdateListener { private UserSelectionListener mUserSelectionListener; private UserAdapter mAdapter; @@ -63,6 +64,9 @@ public class UserGridRecyclerView extends PagedListView implements super(context, attrs); mContext = context; mCarUserManagerHelper = new CarUserManagerHelper(mContext); + + addItemDecoration(new ItemSpacingDecoration(context.getResources().getDimensionPixelSize( + R.dimen.car_user_switcher_vertical_spacing_between_users))); } /** @@ -391,4 +395,31 @@ public class UserGridRecyclerView extends PagedListView implements void onUserSelected(UserRecord record); } + + /** + * A {@link RecyclerView.ItemDecoration} that will add spacing between each item in the + * RecyclerView that it is added to. + */ + private static class ItemSpacingDecoration extends RecyclerView.ItemDecoration { + private int mItemSpacing; + + private ItemSpacingDecoration(int itemSpacing) { + mItemSpacing = itemSpacing; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, + RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + int position = parent.getChildAdapterPosition(view); + + // Skip offset for last item except for GridLayoutManager. + if (position == state.getItemCount() - 1 + && !(parent.getLayoutManager() instanceof GridLayoutManager)) { + return; + } + + outRect.bottom = mItemSpacing; + } + } } diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java index 10a0ae5a924c..512210be0a46 100644 --- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java @@ -32,9 +32,7 @@ import android.content.DialogInterface; import android.content.ServiceConnection; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; -import android.graphics.Color; import android.graphics.PixelFormat; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.media.AudioManager; import android.os.Debug; @@ -46,7 +44,6 @@ import android.util.AttributeSet; import android.util.Log; import android.util.SparseArray; import android.util.Xml; -import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -56,12 +53,8 @@ import android.view.WindowManager; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; -import androidx.car.widget.ListItem; -import androidx.car.widget.ListItemAdapter; -import androidx.car.widget.ListItemAdapter.BackgroundStyle; -import androidx.car.widget.ListItemProvider.ListProvider; -import androidx.car.widget.PagedListView; -import androidx.car.widget.SeekbarListItem; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import com.android.systemui.R; import com.android.systemui.plugins.VolumeDialog; @@ -96,13 +89,13 @@ public class CarVolumeDialogImpl implements VolumeDialog { private final SparseArray mVolumeItems = new SparseArray<>(); // Available volume items in car audio manager. private final List mAvailableVolumeItems = new ArrayList<>(); - // Volume items in the PagedListView. - private final List mVolumeLineItems = new ArrayList<>(); + // Volume items in the RecyclerView. + private final List mCarVolumeLineItems = new ArrayList<>(); private final KeyguardManager mKeyguard; private Window mWindow; private CustomDialog mDialog; - private PagedListView mListView; - private ListItemAdapter mPagedListAdapter; + private RecyclerView mListView; + private CarVolumeItemAdapter mVolumeItemsAdapter; private Car mCar; private CarAudioManager mCarAudioManager; private final CarAudioManager.CarVolumeCallback mVolumeChangeCallback = @@ -126,7 +119,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { // callback. Updating the seekbar at the same time could block the continuous // seeking. if (value != volumeItem.progress) { - volumeItem.listItem.setProgress(value); + volumeItem.carVolumeItem.setProgress(value); volumeItem.progress = value; } if ((flags & AudioManager.FLAG_SHOW_UI) != 0) { @@ -160,13 +153,13 @@ public class CarVolumeDialogImpl implements VolumeDialog { // The first one is the default item. if (groupId == 0) { mDefaultVolumeItem = volumeItem; - setupDefaultListItem(); + setupDefaultCarVolumeItem(); } } // If list is already initiated, update its content. - if (mPagedListAdapter != null) { - mPagedListAdapter.notifyDataSetChanged(); + if (mVolumeItemsAdapter != null) { + mVolumeItemsAdapter.notifyDataSetChanged(); } mCarAudioManager.registerCarVolumeCallback(mVolumeChangeCallback); } catch (CarNotConnectedException e) { @@ -184,15 +177,15 @@ public class CarVolumeDialogImpl implements VolumeDialog { } }; - private void setupDefaultListItem() { + private void setupDefaultCarVolumeItem() { mDefaultVolumeItem.defaultItem = true; - addSeekbarListItem(mDefaultVolumeItem, /* volumeGroupId = */0, + addCarVolumeListItem(mDefaultVolumeItem, /* volumeGroupId = */0, R.drawable.car_ic_keyboard_arrow_down, new ExpandIconListener() ); } public CarVolumeDialogImpl(Context context) { - mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme); + mContext = context; mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); mCar = Car.createCar(mContext, mServiceConnection); } @@ -238,7 +231,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { private void initDialog() { loadAudioUsageItems(); - mVolumeLineItems.clear(); + mCarVolumeLineItems.clear(); mDialog = new CustomDialog(mContext); mHovering = false; @@ -246,7 +239,6 @@ public class CarVolumeDialogImpl implements VolumeDialog { mExpanded = false; mWindow = mDialog.getWindow(); mWindow.requestFeature(Window.FEATURE_NO_TITLE); - mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE @@ -263,10 +255,11 @@ public class CarVolumeDialogImpl implements VolumeDialog { lp.gravity = Gravity.TOP | Gravity.CENTER_HORIZONTAL; lp.windowAnimations = -1; mWindow.setAttributes(lp); - mWindow.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - mDialog.setCanceledOnTouchOutside(true); mDialog.setContentView(R.layout.car_volume_dialog); + mWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + + mDialog.setCanceledOnTouchOutside(true); mDialog.setOnShowListener(dialog -> { mListView.setTranslationY(-mListView.getHeight()); mListView.setAlpha(0); @@ -277,7 +270,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { .setInterpolator(new SystemUIInterpolators.LogDecelerateInterpolator()) .start(); }); - mListView = (PagedListView) mWindow.findViewById(R.id.volume_list); + mListView = mWindow.findViewById(R.id.volume_list); mListView.setOnHoverListener((v, event) -> { int action = event.getActionMasked(); mHovering = (action == MotionEvent.ACTION_HOVER_ENTER) @@ -286,10 +279,9 @@ public class CarVolumeDialogImpl implements VolumeDialog { return true; }); - mPagedListAdapter = new ListItemAdapter(mContext, new ListProvider(mVolumeLineItems), - BackgroundStyle.PANEL); - mListView.setAdapter(mPagedListAdapter); - mListView.setMaxPages(PagedListView.UNLIMITED_PAGES); + mVolumeItemsAdapter = new CarVolumeItemAdapter(mContext, mCarVolumeLineItems); + mListView.setAdapter(mVolumeItemsAdapter); + mListView.setLayoutManager(new LinearLayoutManager(mContext)); } @@ -302,13 +294,13 @@ public class CarVolumeDialogImpl implements VolumeDialog { mHandler.removeMessages(H.DISMISS); rescheduleTimeoutH(); // Refresh the data set before showing. - mPagedListAdapter.notifyDataSetChanged(); + mVolumeItemsAdapter.notifyDataSetChanged(); if (mShowing) { return; } mShowing = true; - if (mVolumeLineItems.isEmpty()) { - setupDefaultListItem(); + if (mCarVolumeLineItems.isEmpty()) { + setupDefaultCarVolumeItem(); } mDialog.show(); Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked()); @@ -421,40 +413,41 @@ public class CarVolumeDialogImpl implements VolumeDialog { return result; } - private SeekbarListItem addSeekbarListItem(VolumeItem volumeItem, - int volumeGroupId, + private CarVolumeItem addCarVolumeListItem(VolumeItem volumeItem, int volumeGroupId, int supplementalIconId, @Nullable View.OnClickListener supplementalIconOnClickListener) { - SeekbarListItem listItem = new SeekbarListItem(mContext); - listItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId)); + CarVolumeItem carVolumeItem = new CarVolumeItem(); + carVolumeItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId)); int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint); int progress = getSeekbarValue(mCarAudioManager, volumeGroupId); - listItem.setProgress(progress); - listItem.setOnSeekBarChangeListener(new CarVolumeDialogImpl - .VolumeSeekBarChangeListener(volumeGroupId, mCarAudioManager)); + carVolumeItem.setProgress(progress); + carVolumeItem.setOnSeekBarChangeListener( + new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId, + mCarAudioManager)); Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon); primaryIcon.mutate().setTint(color); - listItem.setPrimaryActionIcon(primaryIcon); + carVolumeItem.setPrimaryIcon(primaryIcon); if (supplementalIconId != 0) { Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId); supplementalIcon.mutate().setTint(color); - listItem.setSupplementalIcon(supplementalIcon, true); - listItem.setSupplementalIconListener(supplementalIconOnClickListener); + carVolumeItem.setSupplementalIcon(supplementalIcon, + /* showSupplementalIconDivider= */ true); + carVolumeItem.setSupplementalIconListener(supplementalIconOnClickListener); } else { - listItem.setSupplementalEmptyIcon(true); - listItem.setSupplementalIconListener(null); + carVolumeItem.setSupplementalIcon(/* drawable= */ null, + /* showSupplementalIconDivider= */ false); } - mVolumeLineItems.add(listItem); - volumeItem.listItem = listItem; + mCarVolumeLineItems.add(carVolumeItem); + volumeItem.carVolumeItem = carVolumeItem; volumeItem.progress = progress; - return listItem; + return carVolumeItem; } - private VolumeItem findVolumeItem(SeekbarListItem targetItem) { + private VolumeItem findVolumeItem(CarVolumeItem targetItem) { for (int i = 0; i < mVolumeItems.size(); ++i) { VolumeItem volumeItem = mVolumeItems.valueAt(i); - if (volumeItem.listItem == targetItem) { + if (volumeItem.carVolumeItem == targetItem) { return volumeItem; } } @@ -463,7 +456,7 @@ public class CarVolumeDialogImpl implements VolumeDialog { private void cleanupAudioManager() { mCarAudioManager.unregisterCarVolumeCallback(mVolumeChangeCallback); - mVolumeLineItems.clear(); + mCarVolumeLineItems.clear(); mCarAudioManager = null; } @@ -474,8 +467,9 @@ public class CarVolumeDialogImpl implements VolumeDialog { private int rank; private boolean defaultItem = false; - private @DrawableRes int icon; - private SeekbarListItem listItem; + @DrawableRes + private int icon; + private CarVolumeItem carVolumeItem; private int progress; } @@ -554,9 +548,9 @@ public class CarVolumeDialogImpl implements VolumeDialog { // Adding the items which are not coming from the default item. VolumeItem volumeItem = mAvailableVolumeItems.get(groupId); if (volumeItem.defaultItem) { - updateDefaultVolumeItem(volumeItem.listItem); + updateDefaultVolumeItem(volumeItem.carVolumeItem); } else { - addSeekbarListItem(volumeItem, groupId, 0, null); + addCarVolumeListItem(volumeItem, groupId, 0, null); } } inAnimator = AnimatorInflater.loadAnimator( @@ -564,14 +558,14 @@ public class CarVolumeDialogImpl implements VolumeDialog { } else { // Only keeping the default stream if it is not expended. - Iterator itr = mVolumeLineItems.iterator(); + Iterator itr = mCarVolumeLineItems.iterator(); while (itr.hasNext()) { - SeekbarListItem seekbarListItem = (SeekbarListItem) itr.next(); - VolumeItem volumeItem = findVolumeItem(seekbarListItem); + CarVolumeItem carVolumeItem = (CarVolumeItem) itr.next(); + VolumeItem volumeItem = findVolumeItem(carVolumeItem); if (!volumeItem.defaultItem) { itr.remove(); } else { - updateDefaultVolumeItem(seekbarListItem); + updateDefaultVolumeItem(carVolumeItem); } } inAnimator = AnimatorInflater.loadAnimator( @@ -590,22 +584,22 @@ public class CarVolumeDialogImpl implements VolumeDialog { } animators.setTarget(mExpandIcon); animators.start(); - mPagedListAdapter.notifyDataSetChanged(); + mVolumeItemsAdapter.notifyDataSetChanged(); } - private void updateDefaultVolumeItem(SeekbarListItem seekbarListItem){ - VolumeItem volumeItem = findVolumeItem(seekbarListItem); + private void updateDefaultVolumeItem(CarVolumeItem carVolumeItem) { + VolumeItem volumeItem = findVolumeItem(carVolumeItem); // When volume dialog is expanded or collapsed the default list item is never // reset. Whereas all other list items are removed when the dialog is collapsed and then - // added when the dialog is expanded using {@link CarVolumeDialogImpl#addSeekbarListItem}. + // added when the dialog is expanded using {@link CarVolumeDialogImpl#addCarVolumeListItem}. // This sets the progressbar and the tint color of icons for all items other than default // if they were changed. For default list item it should be done manually here. int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint); Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon); primaryIcon.mutate().setTint(color); - volumeItem.listItem.setPrimaryActionIcon(primaryIcon); - volumeItem.listItem.setProgress(volumeItem.progress); + volumeItem.carVolumeItem.setPrimaryIcon(primaryIcon); + volumeItem.carVolumeItem.setProgress(volumeItem.progress); } private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener { @@ -646,4 +640,4 @@ public class CarVolumeDialogImpl implements VolumeDialog { public void onStopTrackingTouch(SeekBar seekBar) { } } -} \ No newline at end of file +} diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java new file mode 100644 index 000000000000..9613de1bfaaa --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2019 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.systemui.volume; + +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.ImageView; +import android.widget.SeekBar; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.android.systemui.R; + +/** Holds all related data to represent a volume group. */ +public class CarVolumeItem { + + private boolean mIsDirty; + + private Drawable mPrimaryIcon; + private Drawable mSupplementalIcon; + private View.OnClickListener mSupplementalIconOnClickListener; + private boolean mShowSupplementalIconDivider; + + private int mMax; + private int mProgress; + private SeekBar.OnSeekBarChangeListener mOnSeekBarChangeListener; + + public CarVolumeItem() { + mIsDirty = true; + } + + /** + * Called when {@link CarVolumeItem} is bound to its ViewHolder. + */ + void bind(CarVolumeItemViewHolder viewHolder) { + if (mIsDirty) { + viewHolder.bind(/* carVolumeItem= */ this); + mIsDirty = false; + } + } + + /** Sets progress of seekbar. */ + public void setProgress(int progress) { + mProgress = progress; + mIsDirty = true; + } + + /** Sets max value of seekbar. */ + public void setMax(int max) { + mMax = max; + mIsDirty = true; + } + + /** Sets {@link SeekBar.OnSeekBarChangeListener}. */ + public void setOnSeekBarChangeListener(SeekBar.OnSeekBarChangeListener listener) { + mOnSeekBarChangeListener = listener; + mIsDirty = true; + } + + /** Sets the primary icon. */ + public void setPrimaryIcon(Drawable drawable) { + mPrimaryIcon = drawable; + mIsDirty = true; + } + + /** Sets the supplemental icon and the visibility of the supplemental icon divider. */ + public void setSupplementalIcon(Drawable drawable, boolean showSupplementalIconDivider) { + mSupplementalIcon = drawable; + mShowSupplementalIconDivider = showSupplementalIconDivider; + mIsDirty = true; + } + + /** Sets {@code OnClickListener} for the supplemental icon. */ + public void setSupplementalIconListener(View.OnClickListener listener) { + mSupplementalIconOnClickListener = listener; + mIsDirty = true; + } + + /** Defines the view holder which shows the information held by {@link CarVolumeItem}. */ + public static class CarVolumeItemViewHolder extends RecyclerView.ViewHolder { + + private SeekBar mSeekBar; + private ImageView mPrimaryIcon; + private View mSupplementalIconDivider; + private ImageView mSupplementalIcon; + + public CarVolumeItemViewHolder(@NonNull View itemView) { + super(itemView); + + mSeekBar = itemView.findViewById(R.id.seek_bar); + mPrimaryIcon = itemView.findViewById(R.id.primary_icon); + mSupplementalIcon = itemView.findViewById(R.id.supplemental_icon); + mSupplementalIconDivider = itemView.findViewById(R.id.supplemental_icon_divider); + } + + /** + * Binds {@link CarVolumeItem} to the {@link CarVolumeItemViewHolder}. + */ + void bind(CarVolumeItem carVolumeItem) { + // Progress bar + mSeekBar.setMax(carVolumeItem.mMax); + mSeekBar.setProgress(carVolumeItem.mProgress); + mSeekBar.setOnSeekBarChangeListener(carVolumeItem.mOnSeekBarChangeListener); + + // Primary icon + mPrimaryIcon.setVisibility(View.VISIBLE); + mPrimaryIcon.setImageDrawable(carVolumeItem.mPrimaryIcon); + + // Supplemental icon + mSupplementalIcon.setVisibility(View.VISIBLE); + mSupplementalIconDivider.setVisibility( + carVolumeItem.mShowSupplementalIconDivider ? View.VISIBLE : View.INVISIBLE); + mSupplementalIcon.setImageDrawable(carVolumeItem.mSupplementalIcon); + mSupplementalIcon.setOnClickListener( + carVolumeItem.mSupplementalIconOnClickListener); + mSupplementalIcon.setClickable( + carVolumeItem.mSupplementalIconOnClickListener != null); + } + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItemAdapter.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItemAdapter.java new file mode 100644 index 000000000000..5c1f8170afc4 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItemAdapter.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 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.systemui.volume; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.RecyclerView; + +import com.android.systemui.R; + +import java.util.List; + +/** The {@link RecyclerView.Adapter} to show the volume items in the sysUI volume dialog. */ +public class CarVolumeItemAdapter extends + RecyclerView.Adapter { + + private final Context mContext; + private final List mItems; + + public CarVolumeItemAdapter(Context context, List items) { + mContext = context; + mItems = items; + } + + @Override + public CarVolumeItem.CarVolumeItemViewHolder onCreateViewHolder(ViewGroup parent, + int viewType) { + LayoutInflater inflater = LayoutInflater.from(mContext); + View view = inflater.inflate(R.layout.car_volume_item, parent, false); + return new CarVolumeItem.CarVolumeItemViewHolder(view); + } + + @Override + public void onBindViewHolder(CarVolumeItem.CarVolumeItemViewHolder holder, int position) { + mItems.get(position).bind(holder); + } + + @Override + public int getItemCount() { + return mItems.size(); + } +} -- GitLab From d7400f7b9045fefffbd498719d29281dd65ef350 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Mon, 18 Mar 2019 13:47:43 -0700 Subject: [PATCH 027/349] media: refine MediaCodecInfo video PerformancePoints Added internal constructors to test API Made bare fields test API-only getters Bug: 126440182 Bug: 126442533 Bug: 126442812 Bug: 126360150 Bug: 126701033 Change-Id: I1983a10f760e9a359a55e7cfd1992f0a2d63e146 --- api/current.txt | 69 +++--- api/test-current.txt | 8 + media/java/android/media/MediaCodecInfo.java | 244 +++++++++++++++---- 3 files changed, 243 insertions(+), 78 deletions(-) diff --git a/api/current.txt b/api/current.txt index ece35366967c..74788e69d2bb 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24618,42 +24618,39 @@ package android.media { ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int); method public boolean covers(@NonNull android.media.MediaFormat); method public boolean covers(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint); - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50; - field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60; - field public final int frameRate; - field public final long macroBlockRate; - field public final int macroBlocks; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50; + field @NonNull public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60; } public final class MediaCodecList { diff --git a/api/test-current.txt b/api/test-current.txt index 4ccfa1c06745..ec395fe9c1a6 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1070,6 +1070,14 @@ package android.media { method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int); } + public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint { + ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size); + ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size); + method public int getMaxFrameRate(); + method public long getMaxMacroBlockRate(); + method public int getMaxMacroBlocks(); + } + public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable { method public android.media.MediaPlayer2.DrmInfo getDrmInfo(@NonNull android.media.DataSourceDesc); method public android.media.MediaDrm.KeyRequest getDrmKeyRequest(@NonNull android.media.DataSourceDesc, @Nullable byte[], @Nullable byte[], @Nullable String, int, @Nullable java.util.Map) throws android.media.MediaPlayer2.NoDrmSchemeException; diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index 2ec935598c1b..8538a5472cc1 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -21,6 +21,7 @@ import static android.media.Utils.sortDistinctRanges; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.os.Build; import android.util.Log; @@ -31,6 +32,7 @@ import android.util.Size; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -1332,7 +1334,7 @@ public final class MediaCodecInfo { private Range mBlockAspectRatioRange; private Range mBlocksPerSecondRange; private Map> mMeasuredFrameRates; - private Vector mPerformancePoints; + private List mPerformancePoints; private Range mFrameRateRange; private int mBlockWidth; @@ -1620,45 +1622,136 @@ public final class MediaCodecInfo { * rate. */ public static final class PerformancePoint { + private Size mBlockSize; // codec block size in macroblocks + private int mWidth; // width in macroblocks + private int mHeight; // height in macroblocks + private int mMaxFrameRate; // max frames per second + private long mMaxMacroBlockRate; // max macro block rate + /** - * (Maximum) number of macroblocks in the frame. + * Maximum number of macroblocks in the frame. * * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks. * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance * is characterized using such blocks. + * + * @hide */ - public final int macroBlocks; + @TestApi + public int getMaxMacroBlocks() { + return saturateLongToInt(mWidth * (long)mHeight); + } /** - * (Maximum) frame rate in frames per second. + * Maximum frame rate in frames per second. + * + * @hide + */ + @TestApi + public int getMaxFrameRate() { + return mMaxFrameRate; + } + + /** + * Maximum number of macroblocks processed per second. + * + * @hide */ - public final int frameRate; + @TestApi + public long getMaxMacroBlockRate() { + return mMaxMacroBlockRate; + } + + /** Convert to a debug string */ + public String toString() { + int blockWidth = 16 * mBlockSize.getWidth(); + int blockHeight = 16 * mBlockSize.getHeight(); + int origRate = (int)Utils.divUp(mMaxMacroBlockRate, getMaxMacroBlocks()); + String info = (mWidth * 16) + "x" + (mHeight * 16) + "@" + origRate; + if (origRate < mMaxFrameRate) { + info += ", max " + mMaxFrameRate + "fps"; + } + if (blockWidth > 16 || blockHeight > 16) { + info += ", " + blockWidth + "x" + blockHeight + " blocks"; + } + return "PerformancePoint(" + info + ")"; + } /** - * (Maximum) number of macroblocks processed per second. + * Create a detailed performance point with custom max frame rate and macroblock size. + * + * @param width frame width in pixels + * @param height frame height in pixels + * @param frameRate frames per second for frame width and height + * @param maxFrameRate maximum frames per second for any frame size + * @param blockSize block size for codec implementation. Must be powers of two in both + * width and height. + * + * @throws IllegalArgumentException if the blockSize dimensions are not powers of two. + * + * @hide */ - public final long macroBlockRate; + @TestApi + public PerformancePoint( + int width, int height, int frameRate, int maxFrameRate, + @NonNull Size blockSize) { + checkPowerOfTwo(blockSize.getWidth(), "block width"); + checkPowerOfTwo(blockSize.getHeight(), "block height"); + + mBlockSize = new Size(Utils.divUp(blockSize.getWidth(), 16), + Utils.divUp(blockSize.getHeight(), 16)); + // these are guaranteed not to overflow as we decimate by 16 + mWidth = (int)(Utils.divUp(Math.max(1L, width), + Math.max(blockSize.getWidth(), 16)) + * mBlockSize.getWidth()); + mHeight = (int)(Utils.divUp(Math.max(1L, height), + Math.max(blockSize.getHeight(), 16)) + * mBlockSize.getHeight()); + mMaxFrameRate = Math.max(1, Math.max(frameRate, maxFrameRate)); + mMaxMacroBlockRate = Math.max(1, frameRate) * getMaxMacroBlocks(); + Log.i("PP", "Created " + this); + } - /* package private */ - PerformancePoint(int width_, int height_, int frameRate_, int maxFrameRate_) { - macroBlocks = saturateLongToInt( - ((Math.max(1, (long)width_) + 15) / 16) - * ((Math.max(1, (long)height_) + 15) / 16)); - frameRate = Math.max(1, frameRate_); - macroBlockRate = Math.max(maxFrameRate_, frameRate) * macroBlocks; + /** + * Convert a performance point to a larger blocksize. + * + * @param pp performance point + * @param blockSize block size for codec implementation + * + * @hide + */ + @TestApi + public PerformancePoint(@NonNull PerformancePoint pp, @NonNull Size newBlockSize) { + this( + pp.mWidth * 16, pp.mHeight * 16, + // guaranteed not to overflow as these were multiplied at construction + (int)Utils.divUp(pp.mMaxMacroBlockRate, pp.getMaxMacroBlocks()), + pp.mMaxFrameRate, + new Size(Math.max(newBlockSize.getWidth(), pp.mBlockSize.getWidth() * 16), + Math.max(newBlockSize.getHeight(), pp.mBlockSize.getHeight() * 16)) + ); + /* + // these are guaranteed not to overflow as size * blockSize is decimated by 16 + width = align(pp.width * pp.blockSize.getWidth(), blockSize.getWidth()); + height = align(pp.height * pp.blockSize.getHeight(), blockSize.getHeight()); + frameRate = pp.frameRate; + macroBlockRate = align(pp.macroBlockRate, blockSize.getWidth * blockSize.getHeight()); + */ + Log.i("PP", " from " + pp + " and " + newBlockSize); } /** * Create a performance point for a given frame size and frame rate. * - * @param width_ width of the frame in pixels - * @param height_ height of the frame in pixels - * @param frameRate_ frame rate in frames per second + * @param width width of the frame in pixels + * @param height height of the frame in pixels + * @param frameRate frame rate in frames per second */ - public PerformancePoint(int width_, int height_, int frameRate_) { - this(width_, height_, frameRate_, frameRate_ /* maxFrameRate */); + public PerformancePoint(int width, int height, int frameRate) { + this(width, height, frameRate, frameRate /* maxFrameRate */, new Size(16, 16)); } + /** Saturates a long value to int */ private int saturateLongToInt(long value) { if (value < Integer.MIN_VALUE) { return Integer.MIN_VALUE; @@ -1669,6 +1762,19 @@ public final class MediaCodecInfo { } } + /* This method may overflow */ + private int align(int value, int alignment) { + return Utils.divUp(value, alignment) * alignment; + } + + /** Checks that value is a power of two. */ + private void checkPowerOfTwo2(int value, @NonNull String description) { + if (value == 0 || (value & (value - 1)) != 0) { + throw new IllegalArgumentException( + description + " (" + value + ") must be a power of 2"); + } + } + /** * Checks whether the performance point covers a media format. * @@ -1680,7 +1786,7 @@ public final class MediaCodecInfo { PerformancePoint other = new PerformancePoint( format.getInteger(MediaFormat.KEY_WIDTH, 0), format.getInteger(MediaFormat.KEY_HEIGHT, 0), - // safely convert ceil(double) to int through float case and Math.round + // safely convert ceil(double) to int through float cast and Math.round Math.round((float)( Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0) .doubleValue())))); @@ -1690,7 +1796,7 @@ public final class MediaCodecInfo { /** * Checks whether the performance point covers another performance point. Use this * method to determine if a performance point advertised by a codec covers the - * performance point required. This method can also be used for lose ordering as this + * performance point required. This method can also be used for loose ordering as this * method is transitive. * * @param other other performance point considered @@ -1698,91 +1804,139 @@ public final class MediaCodecInfo { * @return {@code true} if the performance point covers the other. */ public boolean covers(@NonNull PerformancePoint other) { - return (macroBlocks >= other.macroBlocks - && frameRate >= other.frameRate - && macroBlockRate >= other.macroBlockRate); + // convert performance points to common block size + Size commonSize = getCommonBlockSize(other); + PerformancePoint aligned = new PerformancePoint(this, commonSize); + PerformancePoint otherAligned = new PerformancePoint(other, commonSize); + + return (aligned.getMaxMacroBlocks() >= otherAligned.getMaxMacroBlocks() + && aligned.mMaxFrameRate >= otherAligned.mMaxFrameRate + && aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate); } + private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) { + return new Size( + Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16, + Math.max(mBlockSize.getHeight(), other.mBlockSize.getHeight()) * 16); + } @Override public boolean equals(Object o) { if (o instanceof PerformancePoint) { + // convert performance points to common block size PerformancePoint other = (PerformancePoint)o; - return (macroBlocks == other.macroBlocks - && frameRate == other.frameRate - && macroBlockRate == other.macroBlockRate); + Size commonSize = getCommonBlockSize(other); + PerformancePoint aligned = new PerformancePoint(this, commonSize); + PerformancePoint otherAligned = new PerformancePoint(other, commonSize); + + return (aligned.getMaxMacroBlocks() == otherAligned.getMaxMacroBlocks() + && aligned.mMaxFrameRate == otherAligned.mMaxFrameRate + && aligned.mMaxMacroBlockRate == otherAligned.mMaxMacroBlockRate); } return false; } /** 480p 24fps */ + @NonNull public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24); /** 576p 25fps */ + @NonNull public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25); /** 480p 30fps */ + @NonNull public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30); /** 480p 48fps */ + @NonNull public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48); /** 576p 50fps */ + @NonNull public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50); /** 480p 60fps */ + @NonNull public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60); /** 720p 24fps */ + @NonNull public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24); /** 720p 25fps */ + @NonNull public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25); /** 720p 30fps */ + @NonNull public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30); /** 720p 50fps */ + @NonNull public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50); /** 720p 60fps */ + @NonNull public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60); /** 720p 100fps */ + @NonNull public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100); /** 720p 120fps */ + @NonNull public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120); /** 720p 200fps */ + @NonNull public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200); /** 720p 240fps */ + @NonNull public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240); /** 1080p 24fps */ + @NonNull public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24); /** 1080p 25fps */ + @NonNull public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25); /** 1080p 30fps */ + @NonNull public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30); /** 1080p 50fps */ + @NonNull public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50); /** 1080p 60fps */ + @NonNull public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60); /** 1080p 100fps */ + @NonNull public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100); /** 1080p 120fps */ + @NonNull public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120); /** 1080p 200fps */ + @NonNull public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200); /** 1080p 240fps */ + @NonNull public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240); /** 2160p 24fps */ + @NonNull public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24); /** 2160p 25fps */ + @NonNull public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25); /** 2160p 30fps */ + @NonNull public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30); /** 2160p 50fps */ + @NonNull public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50); /** 2160p 60fps */ + @NonNull public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60); /** 2160p 100fps */ + @NonNull public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100); /** 2160p 120fps */ + @NonNull public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120); /** 2160p 200fps */ + @NonNull public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200); /** 2160p 240fps */ + @NonNull public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240); } @@ -1803,10 +1957,7 @@ public final class MediaCodecInfo { */ @Nullable public List getSupportedPerformancePoints() { - if (mPerformancePoints == null) { - return null; - } - return new ArrayList(mPerformancePoints); + return mPerformancePoints; } /** @@ -1945,7 +2096,7 @@ public final class MediaCodecInfo { mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper(); } - private @Nullable Vector getPerformancePoints(Map map) { + private @Nullable List getPerformancePoints(Map map) { Vector ret = new Vector<>(); final String prefix = "performance-point-"; Set keys = map.keySet(); @@ -1959,7 +2110,7 @@ public final class MediaCodecInfo { // This means that component knowingly did not publish performance points. // This is different from when the component forgot to publish performance // points. - return ret; + return Collections.unmodifiableList(ret); } String[] temp = key.split("-"); if (temp.length != 4) { @@ -1974,23 +2125,32 @@ public final class MediaCodecInfo { if (range == null || range.getLower() < 0 || range.getUpper() < 0) { continue; } - ret.add(new PerformancePoint( + PerformancePoint given = new PerformancePoint( size.getWidth(), size.getHeight(), range.getLower().intValue(), - range.getUpper().intValue())); + range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight)); + PerformancePoint rotated = new PerformancePoint( + size.getHeight(), size.getWidth(), range.getLower().intValue(), + range.getUpper().intValue(), new Size(mBlockWidth, mBlockHeight)); + ret.add(given); + if (!given.covers(rotated)) { + ret.add(rotated); + } } + // check if the component specified no performance point indication if (ret.size() == 0) { return null; } // sort reversed by area first, then by frame rate - ret.sort((a, b) -> -((a.macroBlocks != b.macroBlocks) ? - (a.macroBlocks < b.macroBlocks ? -1 : 1) : - (a.macroBlockRate != b.macroBlockRate) ? - (a.macroBlockRate < b.macroBlockRate ? -1 : 1) : - (a.frameRate != b.frameRate) ? - (a.frameRate < b.frameRate ? -1 : 1) : 0)); - return ret; + ret.sort((a, b) -> + -((a.getMaxMacroBlocks() != b.getMaxMacroBlocks()) ? + (a.getMaxMacroBlocks() < b.getMaxMacroBlocks() ? -1 : 1) : + (a.getMaxMacroBlockRate() != b.getMaxMacroBlockRate()) ? + (a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) : + (a.getMaxFrameRate() != b.getMaxFrameRate()) ? + (a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0)); + return Collections.unmodifiableList(ret); } private Map> getMeasuredFrameRates(Map map) { -- GitLab From 174205a9f18069b6cadea8f10f2ab52ee95ace96 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Fri, 15 Mar 2019 13:37:41 -0700 Subject: [PATCH 028/349] Make AppPreference summary and appendix stack vertically They each can contain lots of text, putting them side by side doesn't make sense. Fixes: 123317946 Test: visual Change-Id: I2ccd76b3ac70301e5165580db820b291672d0c9b --- .../res/layout/preference_app.xml | 49 +++++++++---------- .../widget/apppreference/AppPreference.java | 3 -- .../apppreference/AppPreferenceTest.java | 18 ------- 3 files changed, 22 insertions(+), 48 deletions(-) diff --git a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml index b198f5a35630..711dad4b5b55 100644 --- a/packages/SettingsLib/AppPreference/res/layout/preference_app.xml +++ b/packages/SettingsLib/AppPreference/res/layout/preference_app.xml @@ -48,37 +48,32 @@ android:paddingTop="16dp" android:paddingBottom="16dp"> - + - - + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:attr/textColorSecondary"/> + + - - Date: Mon, 18 Mar 2019 14:55:38 -0700 Subject: [PATCH 029/349] Aligning job readiness checks. areComponentsInPlaceLocked fell out of sync with isReadyToBeExecutedLocked. The former is used to determine if constraint exceptions should be done for a job. The latter is used to determine if the job can be added to the pending jobs list. If they're out of sync, we may do a little bit of unnecessary work. Bug: 125505588 Test: atest CtsJobSchedulerTestCases Change-Id: Ie11daa1dad7a97ff6a582706db8b4ca38f53a76e --- .../server/job/JobSchedulerService.java | 40 ++++++++----------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 14b73012d126..d5883bb3befb 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -19,6 +19,7 @@ package com.android.server.job; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; +import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.Activity; import android.app.ActivityManager; @@ -2496,8 +2497,13 @@ public class JobSchedulerService extends com.android.server.SystemService // The expensive check: validate that the defined package+service is // still present & viable. + return isComponentUsable(job); + } + + private boolean isComponentUsable(@NonNull JobStatus job) { final ServiceInfo service; try { + // TODO: cache result until we're notified that something in the package changed. service = AppGlobals.getPackageManager().getServiceInfo( job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING, job.getUserId()); @@ -2507,7 +2513,7 @@ public class JobSchedulerService extends com.android.server.SystemService if (service == null) { if (DEBUG) { - Slog.v(TAG, "isReadyToBeExecutedLocked: " + job.toShortString() + Slog.v(TAG, "isComponentUsable: " + job.toShortString() + " component not present"); } return false; @@ -2515,10 +2521,8 @@ public class JobSchedulerService extends com.android.server.SystemService // Everything else checked out so far, so this is the final yes/no check final boolean appIsBad = mActivityManagerInternal.isAppBad(service.applicationInfo); - if (DEBUG) { - if (appIsBad) { - Slog.i(TAG, "App is bad for " + job.toShortString() + " so not runnable"); - } + if (DEBUG && appIsBad) { + Slog.i(TAG, "App is bad for " + job.toShortString() + " so not runnable"); } return !appIsBad; } @@ -2552,30 +2556,18 @@ public class JobSchedulerService extends com.android.server.SystemService return false; } + if (isJobThermalConstrainedLocked(job)) { + return false; + } + // Job pending/active doesn't affect the readiness of a job. - // Skipping the hearbeat check as this will only come into play when using the rolling + // Skipping the heartbeat check as this will only come into play when using the rolling // window quota management system. - // The expensive check last: validate that the defined package+service is + // The expensive check: validate that the defined package+service is // still present & viable. - final boolean componentPresent; - try { - // TODO: cache result until we're notified that something in the package changed. - componentPresent = (AppGlobals.getPackageManager().getServiceInfo( - job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING, - job.getUserId()) != null); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); - } - - if (DEBUG) { - Slog.v(TAG, "areComponentsInPlaceLocked: " + job.toShortString() - + " componentPresent=" + componentPresent); - } - - // Everything else checked out so far, so this is the final yes/no check - return componentPresent; + return isComponentUsable(job); } /** -- GitLab From 99e57c3c4091c37abeafccd5424e6cade9245c81 Mon Sep 17 00:00:00 2001 From: Mike Ma Date: Thu, 15 Mar 2018 14:40:37 -0700 Subject: [PATCH 030/349] Remove which from BatteryStats BatteryStats tracks three "which" states: STATS_SINCE_CHARGED, STATS_CURRENT, STATS_SINCE_UNPLUGGED However, only STATS_SINCE_CHARGED is really needed; the other two just take up a lot of unjustifiable RAM. We therefore remove them from the implementation here. We also remove mLastTime and mLastCount from Timers and Counters, since it was always zero anyway. While the other two "whiches" are left as constants, they are ignored, and all functions treat any which as STATS_SINCE_CHARGED. In particular, SystemHealthManager now uses STATS_SINCE_CHARGED, rather than STATS_SINCE_UNPLUGGED for all of its Battery statistics. This is adapted from ag/4310406, but slimmed down to just the 'which' removal parts. Bug: 70892428 Test: com.android.internal.os.BatteryStatsTests Change-Id: I86f2743ff30afc15bbaa12c68f3206ea528857a1 --- core/java/android/os/BatteryStats.java | 88 +-- .../os/health/SystemHealthManager.java | 12 +- .../android/internal/os/BatteryStatsImpl.java | 537 +++--------------- .../internal/os/BatteryStatsCounterTest.java | 22 - .../os/BatteryStatsDurationTimerTest.java | 62 ++ .../internal/os/BatteryStatsImplTest.java | 8 +- .../internal/os/BatteryStatsNoteTest.java | 3 +- .../internal/os/BatteryStatsServTest.java | 214 +------ .../internal/os/BatteryStatsTimeBaseTest.java | 12 - .../internal/os/BatteryStatsTimerTest.java | 164 +----- .../os/LongSamplingCounterArrayTest.java | 118 ++-- .../internal/os/LongSamplingCounterTest.java | 1 - .../com/android/server/BatteryService.java | 2 + .../am/HealthStatsBatteryStatsWriter.java | 108 ++-- 14 files changed, 269 insertions(+), 1082 deletions(-) diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 4fae3a8d52a8..3177fe8a5209 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -200,13 +200,21 @@ public abstract class BatteryStats implements Parcelable { /** * Include only the current run in the stats. + * + * @deprecated As of {@link android.os.Build.VERSION_CODES#Q}, only {@link #STATS_SINCE_CHARGED} + * is supported. */ @UnsupportedAppUsage + @Deprecated public static final int STATS_CURRENT = 1; /** * Include only the run since the last time the device was unplugged in the stats. + * + * @deprecated As of {@link android.os.Build.VERSION_CODES#Q}, only {@link #STATS_SINCE_CHARGED} + * is supported. */ + @Deprecated public static final int STATS_SINCE_UNPLUGGED = 2; // NOTE: Update this list if you add/change any stats above. @@ -255,8 +263,10 @@ public abstract class BatteryStats implements Parcelable { * - Ambient display properly output in data dump. * New in version 33: * - Fixed bug in min learned capacity updating process. + * New in version 34: + * - Deprecated STATS_SINCE_UNPLUGGED and STATS_CURRENT. */ - static final int CHECKIN_VERSION = 33; + static final int CHECKIN_VERSION = 34; /** * Old version, we hit 9 and ran out of room, need to remove. @@ -3848,28 +3858,13 @@ public abstract class BatteryStats implements Parcelable { multicastWakeLockTimeTotalMicros / 1000, multicastWakeLockCountTotal); - if (which == STATS_SINCE_UNPLUGGED) { - dumpLine(pw, 0 /* uid */, category, BATTERY_LEVEL_DATA, getDischargeStartLevel(), - getDischargeCurrentLevel()); - } - - if (which == STATS_SINCE_UNPLUGGED) { - dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA, - getDischargeStartLevel()-getDischargeCurrentLevel(), - getDischargeStartLevel()-getDischargeCurrentLevel(), - getDischargeAmountScreenOn(), getDischargeAmountScreenOff(), - dischargeCount / 1000, dischargeScreenOffCount / 1000, - getDischargeAmountScreenDoze(), dischargeScreenDozeCount / 1000, - dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000); - } else { - dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA, - getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(), - getDischargeAmountScreenOnSinceCharge(), - getDischargeAmountScreenOffSinceCharge(), - dischargeCount / 1000, dischargeScreenOffCount / 1000, - getDischargeAmountScreenDozeSinceCharge(), dischargeScreenDozeCount / 1000, - dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000); - } + dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA, + getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(), + getDischargeAmountScreenOnSinceCharge(), + getDischargeAmountScreenOffSinceCharge(), + dischargeCount / 1000, dischargeScreenOffCount / 1000, + getDischargeAmountScreenDozeSinceCharge(), dischargeScreenDozeCount / 1000, + dischargeLightDozeCount / 1000, dischargeDeepDozeCount / 1000); if (reqUid < 0) { final Map kernelWakelocks = getKernelWakelockStats(); @@ -5044,41 +5039,18 @@ public abstract class BatteryStats implements Parcelable { pw.println(); - if (which == STATS_SINCE_UNPLUGGED) { - if (getIsOnBattery()) { - pw.print(prefix); pw.println(" Device is currently unplugged"); - pw.print(prefix); pw.print(" Discharge cycle start level: "); - pw.println(getDischargeStartLevel()); - pw.print(prefix); pw.print(" Discharge cycle current level: "); - pw.println(getDischargeCurrentLevel()); - } else { - pw.print(prefix); pw.println(" Device is currently plugged into power"); - pw.print(prefix); pw.print(" Last discharge cycle start level: "); - pw.println(getDischargeStartLevel()); - pw.print(prefix); pw.print(" Last discharge cycle end level: "); - pw.println(getDischargeCurrentLevel()); - } - pw.print(prefix); pw.print(" Amount discharged while screen on: "); - pw.println(getDischargeAmountScreenOn()); - pw.print(prefix); pw.print(" Amount discharged while screen off: "); - pw.println(getDischargeAmountScreenOff()); - pw.print(prefix); pw.print(" Amount discharged while screen doze: "); - pw.println(getDischargeAmountScreenDoze()); - pw.println(" "); - } else { - pw.print(prefix); pw.println(" Device battery use since last full charge"); - pw.print(prefix); pw.print(" Amount discharged (lower bound): "); - pw.println(getLowDischargeAmountSinceCharge()); - pw.print(prefix); pw.print(" Amount discharged (upper bound): "); - pw.println(getHighDischargeAmountSinceCharge()); - pw.print(prefix); pw.print(" Amount discharged while screen on: "); - pw.println(getDischargeAmountScreenOnSinceCharge()); - pw.print(prefix); pw.print(" Amount discharged while screen off: "); - pw.println(getDischargeAmountScreenOffSinceCharge()); - pw.print(prefix); pw.print(" Amount discharged while screen doze: "); - pw.println(getDischargeAmountScreenDozeSinceCharge()); - pw.println(); - } + pw.print(prefix); pw.println(" Device battery use since last full charge"); + pw.print(prefix); pw.print(" Amount discharged (lower bound): "); + pw.println(getLowDischargeAmountSinceCharge()); + pw.print(prefix); pw.print(" Amount discharged (upper bound): "); + pw.println(getHighDischargeAmountSinceCharge()); + pw.print(prefix); pw.print(" Amount discharged while screen on: "); + pw.println(getDischargeAmountScreenOnSinceCharge()); + pw.print(prefix); pw.print(" Amount discharged while screen off: "); + pw.println(getDischargeAmountScreenOffSinceCharge()); + pw.print(prefix); pw.print(" Amount discharged while screen doze: "); + pw.println(getDischargeAmountScreenDozeSinceCharge()); + pw.println(); final BatteryStatsHelper helper = new BatteryStatsHelper(context, false, wifiOnly); helper.create(this); diff --git a/core/java/android/os/health/SystemHealthManager.java b/core/java/android/os/health/SystemHealthManager.java index 71eda19e165b..a92e28a47660 100644 --- a/core/java/android/os/health/SystemHealthManager.java +++ b/core/java/android/os/health/SystemHealthManager.java @@ -37,11 +37,13 @@ import com.android.internal.app.IBatteryStats; * by the logging itself. It can be substantial. *

* Battery Usage
- * The statistics related to power (battery) usage are recorded since the device - * was last unplugged. It is expected that applications schedule more work to do - * while the device is plugged in (e.g. using {@link android.app.job.JobScheduler - * JobScheduler}), and while that can affect charging rates, it is still preferable - * to actually draining the battery. + * Since Android version {@link android.os.Build.VERSION_CODES#Q}, the statistics related to power + * (battery) usage are recorded since the device was last considered fully charged (for previous + * versions, it is instead since the device was last unplugged). + * It is expected that applications schedule more work to do while the device is + * plugged in (e.g. using {@link android.app.job.JobScheduler JobScheduler}), and + * while that can affect charging rates, it is still preferable to actually draining + * the battery. */ @SystemService(Context.SYSTEM_HEALTH_SERVICE) public class SystemHealthManager { diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 8679dcba2f80..47ee01e95fe1 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -145,7 +145,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - static final int VERSION = 185 + (USE_OLD_HISTORY ? 1000 : 0); + static final int VERSION = 186 + (USE_OLD_HISTORY ? 1000 : 0); // The maximum number of names wakelocks we will keep track of // per uid; once the limit is reached, we batch the remaining wakelocks @@ -991,8 +991,6 @@ public class BatteryStatsImpl extends BatteryStats { private int mPhoneSimStateRaw = -1; private int mNumConnectivityChange; - private int mLoadedNumConnectivityChange; - private int mUnpluggedNumConnectivityChange; private int mEstimatedBatteryCapacity = -1; @@ -1225,27 +1223,11 @@ public class BatteryStatsImpl extends BatteryStats { } public long computeUptime(long curTime, int which) { - switch (which) { - case STATS_SINCE_CHARGED: - return mUptime + getUptime(curTime); - case STATS_CURRENT: - return getUptime(curTime); - case STATS_SINCE_UNPLUGGED: - return getUptime(curTime) - mUnpluggedUptime; - } - return 0; + return mUptime + getUptime(curTime); } public long computeRealtime(long curTime, int which) { - switch (which) { - case STATS_SINCE_CHARGED: - return mRealtime + getRealtime(curTime); - case STATS_CURRENT: - return getRealtime(curTime); - case STATS_SINCE_UNPLUGGED: - return getRealtime(curTime) - mUnpluggedRealtime; - } - return 0; + return mRealtime + getRealtime(curTime); } public long getUptime(long curTime) { @@ -1352,16 +1334,10 @@ public class BatteryStatsImpl extends BatteryStats { @UnsupportedAppUsage final AtomicInteger mCount = new AtomicInteger(); final TimeBase mTimeBase; - int mLoadedCount; - int mUnpluggedCount; - int mPluggedCount; public Counter(TimeBase timeBase, Parcel in) { mTimeBase = timeBase; - mPluggedCount = in.readInt(); - mCount.set(mPluggedCount); - mLoadedCount = in.readInt(); - mUnpluggedCount = in.readInt(); + mCount.set(in.readInt()); timeBase.add(this); } @@ -1372,18 +1348,14 @@ public class BatteryStatsImpl extends BatteryStats { public void writeToParcel(Parcel out) { out.writeInt(mCount.get()); - out.writeInt(mLoadedCount); - out.writeInt(mUnpluggedCount); } @Override public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) { - mUnpluggedCount = mPluggedCount; } @Override public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) { - mPluggedCount = mCount.get(); } /** @@ -1417,21 +1389,11 @@ public class BatteryStatsImpl extends BatteryStats { @Override public int getCountLocked(int which) { - int val = mCount.get(); - if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedCount; - } else if (which != STATS_SINCE_CHARGED) { - val -= mLoadedCount; - } - - return val; + return mCount.get(); } public void logState(Printer pw, String prefix) { - pw.println(prefix + "mCount=" + mCount.get() - + " mLoadedCount=" + mLoadedCount - + " mUnpluggedCount=" + mUnpluggedCount - + " mPluggedCount=" + mPluggedCount); + pw.println(prefix + "mCount=" + mCount.get()); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) @@ -1453,7 +1415,6 @@ public class BatteryStatsImpl extends BatteryStats { @Override public boolean reset(boolean detachIfReset) { mCount.set(0); - mLoadedCount = mPluggedCount = mUnpluggedCount = 0; if (detachIfReset) { detach(); } @@ -1467,15 +1428,12 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public void writeSummaryFromParcelLocked(Parcel out) { - int count = mCount.get(); - out.writeInt(count); + out.writeInt(mCount.get()); } @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public void readSummaryFromParcelLocked(Parcel in) { - mLoadedCount = in.readInt(); - mCount.set(mLoadedCount); - mUnpluggedCount = mPluggedCount = mLoadedCount; + mCount.set(in.readInt()); } } @@ -1483,14 +1441,10 @@ public class BatteryStatsImpl extends BatteryStats { public static class LongSamplingCounterArray extends LongCounterArray implements TimeBaseObs { final TimeBase mTimeBase; public long[] mCounts; - public long[] mLoadedCounts; - public long[] mUnpluggedCounts; private LongSamplingCounterArray(TimeBase timeBase, Parcel in) { mTimeBase = timeBase; mCounts = in.createLongArray(); - mLoadedCounts = in.createLongArray(); - mUnpluggedCounts = in.createLongArray(); timeBase.add(this); } @@ -1501,13 +1455,10 @@ public class BatteryStatsImpl extends BatteryStats { private void writeToParcel(Parcel out) { out.writeLongArray(mCounts); - out.writeLongArray(mLoadedCounts); - out.writeLongArray(mUnpluggedCounts); } @Override public void onTimeStarted(long elapsedRealTime, long baseUptime, long baseRealtime) { - mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts); } @Override @@ -1516,20 +1467,12 @@ public class BatteryStatsImpl extends BatteryStats { @Override public long[] getCountsLocked(int which) { - long[] val = copyArray(mCounts, null); - if (which == STATS_SINCE_UNPLUGGED) { - subtract(val, mUnpluggedCounts); - } else if (which != STATS_SINCE_CHARGED) { - subtract(val, mLoadedCounts); - } - return val; + return mCounts == null ? null : Arrays.copyOf(mCounts, mCounts.length); } @Override public void logState(Printer pw, String prefix) { - pw.println(prefix + "mCounts=" + Arrays.toString(mCounts) - + " mLoadedCounts=" + Arrays.toString(mLoadedCounts) - + " mUnpluggedCounts=" + Arrays.toString(mUnpluggedCounts)); + pw.println(prefix + "mCounts=" + Arrays.toString(mCounts)); } public void addCountLocked(long[] counts) { @@ -1559,9 +1502,9 @@ public class BatteryStatsImpl extends BatteryStats { */ @Override public boolean reset(boolean detachIfReset) { - fillArray(mCounts, 0); - fillArray(mLoadedCounts, 0); - fillArray(mUnpluggedCounts, 0); + if (mCounts != null) { + Arrays.fill(mCounts, 0); + } if (detachIfReset) { detach(); } @@ -1579,8 +1522,6 @@ public class BatteryStatsImpl extends BatteryStats { private void readSummaryFromParcelLocked(Parcel in) { mCounts = in.createLongArray(); - mLoadedCounts = copyArray(mCounts, mLoadedCounts); - mUnpluggedCounts = copyArray(mCounts, mUnpluggedCounts); } public static void writeToParcel(Parcel out, LongSamplingCounterArray counterArray) { @@ -1621,33 +1562,6 @@ public class BatteryStatsImpl extends BatteryStats { return null; } } - - private static void fillArray(long[] a, long val) { - if (a != null) { - Arrays.fill(a, val); - } - } - - private static void subtract(@NonNull long[] val, long[] toSubtract) { - if (toSubtract == null) { - return; - } - for (int i = 0; i < val.length; i++) { - val[i] -= toSubtract[i]; - } - } - - private static long[] copyArray(long[] src, long[] dest) { - if (src == null) { - return null; - } else { - if (dest == null) { - dest = new long[src.length]; - } - System.arraycopy(src, 0, dest, 0, src.length); - return dest; - } - } } @VisibleForTesting @@ -1655,15 +1569,11 @@ public class BatteryStatsImpl extends BatteryStats { final TimeBase mTimeBase; public long mCount; public long mCurrentCount; - public long mLoadedCount; - public long mUnpluggedCount; public LongSamplingCounter(TimeBase timeBase, Parcel in) { mTimeBase = timeBase; mCount = in.readLong(); mCurrentCount = in.readLong(); - mLoadedCount = in.readLong(); - mUnpluggedCount = in.readLong(); timeBase.add(this); } @@ -1675,13 +1585,10 @@ public class BatteryStatsImpl extends BatteryStats { public void writeToParcel(Parcel out) { out.writeLong(mCount); out.writeLong(mCurrentCount); - out.writeLong(mLoadedCount); - out.writeLong(mUnpluggedCount); } @Override public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) { - mUnpluggedCount = mCount; } @Override @@ -1689,21 +1596,12 @@ public class BatteryStatsImpl extends BatteryStats { } public long getCountLocked(int which) { - long val = mCount; - if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedCount; - } else if (which != STATS_SINCE_CHARGED) { - val -= mLoadedCount; - } - return val; + return mCount; } @Override public void logState(Printer pw, String prefix) { - pw.println(prefix + "mCount=" + mCount - + " mCurrentCount=" + mCurrentCount - + " mLoadedCount=" + mLoadedCount - + " mUnpluggedCount=" + mUnpluggedCount); + pw.println(prefix + "mCount=" + mCount + " mCurrentCount=" + mCurrentCount); } public void addCountLocked(long count) { @@ -1734,7 +1632,6 @@ public class BatteryStatsImpl extends BatteryStats { @Override public boolean reset(boolean detachIfReset) { mCount = 0; - mLoadedCount = mUnpluggedCount = 0; if (detachIfReset) { detach(); } @@ -1751,7 +1648,7 @@ public class BatteryStatsImpl extends BatteryStats { } public void readSummaryFromParcelLocked(Parcel in) { - mCount = mUnpluggedCount= mLoadedCount = in.readLong(); + mCount = in.readLong(); } } @@ -1764,9 +1661,6 @@ public class BatteryStatsImpl extends BatteryStats { protected final TimeBase mTimeBase; protected int mCount; - protected int mLoadedCount; - protected int mLastCount; - protected int mUnpluggedCount; // Times are in microseconds for better accuracy when dividing by the // lock count, and are in "battery realtime" units. @@ -1778,25 +1672,6 @@ public class BatteryStatsImpl extends BatteryStats { */ protected long mTotalTime; - /** - * The total time we loaded for the previous runs. Subtract this from - * mTotalTime to find the time for the current run of the system. - */ - protected long mLoadedTime; - - /** - * The run time of the last run of the system, as loaded from the - * saved data. - */ - protected long mLastTime; - - /** - * The value of mTotalTime when unplug() was last called. Subtract - * this from mTotalTime to find the time since the last unplug from - * power. - */ - protected long mUnpluggedTime; - /** * The total time this timer has been running until the latest mark has been set. * Subtract this from mTotalTime to get the time spent running since the mark was set. @@ -1815,13 +1690,7 @@ public class BatteryStatsImpl extends BatteryStats { mTimeBase = timeBase; mCount = in.readInt(); - mLoadedCount = in.readInt(); - mLastCount = 0; - mUnpluggedCount = in.readInt(); mTotalTime = in.readLong(); - mLoadedTime = in.readLong(); - mLastTime = 0; - mUnpluggedTime = in.readLong(); mTimeBeforeMark = in.readLong(); timeBase.add(this); if (DEBUG) Log.i(TAG, "**** READ TIMER #" + mType + ": mTotalTime=" + mTotalTime); @@ -1834,6 +1703,16 @@ public class BatteryStatsImpl extends BatteryStats { timeBase.add(this); } + public void writeToParcel(Parcel out, long elapsedRealtimeUs) { + if (DEBUG) { + Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime=" + + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs))); + } + out.writeInt(computeCurrentCountLocked()); + out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs))); + out.writeLong(mTimeBeforeMark); + } + protected abstract long computeRunTimeLocked(long curBatteryRealtime); protected abstract int computeCurrentCountLocked(); @@ -1844,8 +1723,8 @@ public class BatteryStatsImpl extends BatteryStats { */ @Override public boolean reset(boolean detachIfReset) { - mTotalTime = mLoadedTime = mLastTime = mTimeBeforeMark = 0; - mCount = mLoadedCount = mLastCount = 0; + mTotalTime = mTimeBeforeMark = 0; + mCount = 0; if (detachIfReset) { detach(); } @@ -1857,32 +1736,8 @@ public class BatteryStatsImpl extends BatteryStats { mTimeBase.remove(this); } - public void writeToParcel(Parcel out, long elapsedRealtimeUs) { - if (DEBUG) Log.i(TAG, "**** WRITING TIMER #" + mType + ": mTotalTime=" - + computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs))); - out.writeInt(computeCurrentCountLocked()); - out.writeInt(mLoadedCount); - out.writeInt(mUnpluggedCount); - out.writeLong(computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs))); - out.writeLong(mLoadedTime); - out.writeLong(mUnpluggedTime); - out.writeLong(mTimeBeforeMark); - } - @Override public void onTimeStarted(long elapsedRealtime, long timeBaseUptime, long baseRealtime) { - if (DEBUG && mType < 0) { - Log.v(TAG, "unplug #" + mType + ": realtime=" + baseRealtime - + " old mUnpluggedTime=" + mUnpluggedTime - + " old mUnpluggedCount=" + mUnpluggedCount); - } - mUnpluggedTime = computeRunTimeLocked(baseRealtime); - mUnpluggedCount = computeCurrentCountLocked(); - if (DEBUG && mType < 0) { - Log.v(TAG, "unplug #" + mType - + ": new mUnpluggedTime=" + mUnpluggedTime - + " new mUnpluggedCount=" + mUnpluggedCount); - } } @Override @@ -1894,8 +1749,7 @@ public class BatteryStatsImpl extends BatteryStats { mTotalTime = computeRunTimeLocked(baseRealtime); mCount = computeCurrentCountLocked(); if (DEBUG && mType < 0) { - Log.v(TAG, "plug #" + mType - + ": new mTotalTime=" + mTotalTime); + Log.v(TAG, "plug #" + mType + ": new mTotalTime=" + mTotalTime); } } @@ -1912,34 +1766,19 @@ public class BatteryStatsImpl extends BatteryStats { return; } out.writeInt(1); // indicates non-null - timer.writeToParcel(out, elapsedRealtimeUs); } @Override @UnsupportedAppUsage public long getTotalTimeLocked(long elapsedRealtimeUs, int which) { - long val = computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)); - if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedTime; - } else if (which != STATS_SINCE_CHARGED) { - val -= mLoadedTime; - } - - return val; + return computeRunTimeLocked(mTimeBase.getRealtime(elapsedRealtimeUs)); } @Override @UnsupportedAppUsage public int getCountLocked(int which) { - int val = computeCurrentCountLocked(); - if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedCount; - } else if (which != STATS_SINCE_CHARGED) { - val -= mLoadedCount; - } - - return val; + return computeCurrentCountLocked(); } @Override @@ -1950,13 +1789,8 @@ public class BatteryStatsImpl extends BatteryStats { @Override public void logState(Printer pw, String prefix) { - pw.println(prefix + "mCount=" + mCount - + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount - + " mUnpluggedCount=" + mUnpluggedCount); - pw.println(prefix + "mTotalTime=" + mTotalTime - + " mLoadedTime=" + mLoadedTime); - pw.println(prefix + "mLastTime=" + mLastTime - + " mUnpluggedTime=" + mUnpluggedTime); + pw.println(prefix + "mCount=" + mCount); + pw.println(prefix + "mTotalTime=" + mTotalTime); } @@ -1968,13 +1802,8 @@ public class BatteryStatsImpl extends BatteryStats { public void readSummaryFromParcelLocked(Parcel in) { // Multiply by 1000 for backwards compatibility - mTotalTime = mLoadedTime = in.readLong(); - mLastTime = 0; - mUnpluggedTime = mTotalTime; - mCount = mLoadedCount = in.readInt(); - mLastCount = 0; - mUnpluggedCount = mCount; - + mTotalTime = in.readLong(); + mCount = in.readInt(); // When reading the summary, we set the mark to be the latest information. mTimeBeforeMark = mTotalTime; } @@ -2233,7 +2062,7 @@ public class BatteryStatsImpl extends BatteryStats { private long computeOverage(long curTime) { if (mLastAddedTime > 0) { - return mLastTime + mLastAddedDuration - curTime; + return mLastAddedDuration - curTime; } return 0; } @@ -2452,7 +2281,7 @@ public class BatteryStatsImpl extends BatteryStats { mTotalDurationMs = 0; mCurrentDurationMs = 0; if (mNesting > 0) { - mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime()*1000) / 1000; + mStartTimeMs = mTimeBase.getRealtime(mClocks.elapsedRealtime() * 1000) / 1000; } else { mStartTimeMs = -1; } @@ -2491,7 +2320,7 @@ public class BatteryStatsImpl extends BatteryStats { public long getCurrentDurationMsLocked(long elapsedRealtimeMs) { long durationMs = mCurrentDurationMs; if (mNesting > 0 && mTimeBase.isRunning()) { - durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs*1000)/1000) + durationMs += (mTimeBase.getRealtime(elapsedRealtimeMs * 1000) / 1000) - mStartTimeMs; } return durationMs; @@ -6401,13 +6230,7 @@ public class BatteryStatsImpl extends BatteryStats { } @Override public int getNumConnectivityChange(int which) { - int val = mNumConnectivityChange; - if (which == STATS_CURRENT) { - val -= mLoadedNumConnectivityChange; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedNumConnectivityChange; - } - return val; + return mNumConnectivityChange; } @Override public long getGpsSignalQualityTime(int strengthBin, @@ -9122,66 +8945,6 @@ public class BatteryStatsImpl extends BatteryStats { */ int mNumAnrs; - /** - * The amount of user time loaded from a previous save. - */ - long mLoadedUserTime; - - /** - * The amount of system time loaded from a previous save. - */ - long mLoadedSystemTime; - - /** - * The amount of foreground time loaded from a previous save. - */ - long mLoadedForegroundTime; - - /** - * The number of times the process has started from a previous save. - */ - int mLoadedStarts; - - /** - * Number of times the process has crashed from a previous save. - */ - int mLoadedNumCrashes; - - /** - * Number of times the process has had an ANR from a previous save. - */ - int mLoadedNumAnrs; - - /** - * The amount of user time when last unplugged. - */ - long mUnpluggedUserTime; - - /** - * The amount of system time when last unplugged. - */ - long mUnpluggedSystemTime; - - /** - * The amount of foreground time since unplugged. - */ - long mUnpluggedForegroundTime; - - /** - * The number of times the process has started before unplugged. - */ - int mUnpluggedStarts; - - /** - * Number of times the process has crashed before unplugged. - */ - int mUnpluggedNumCrashes; - - /** - * Number of times the process has had an ANR before unplugged. - */ - int mUnpluggedNumAnrs; - ArrayList mExcessivePower; public Proc(BatteryStatsImpl bsi, String name) { @@ -9191,12 +8954,6 @@ public class BatteryStatsImpl extends BatteryStats { } public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) { - mUnpluggedUserTime = mUserTime; - mUnpluggedSystemTime = mSystemTime; - mUnpluggedForegroundTime = mForegroundTime; - mUnpluggedStarts = mStarts; - mUnpluggedNumCrashes = mNumCrashes; - mUnpluggedNumAnrs = mNumAnrs; } public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) { @@ -9283,18 +9040,6 @@ public class BatteryStatsImpl extends BatteryStats { out.writeInt(mStarts); out.writeInt(mNumCrashes); out.writeInt(mNumAnrs); - out.writeLong(mLoadedUserTime); - out.writeLong(mLoadedSystemTime); - out.writeLong(mLoadedForegroundTime); - out.writeInt(mLoadedStarts); - out.writeInt(mLoadedNumCrashes); - out.writeInt(mLoadedNumAnrs); - out.writeLong(mUnpluggedUserTime); - out.writeLong(mUnpluggedSystemTime); - out.writeLong(mUnpluggedForegroundTime); - out.writeInt(mUnpluggedStarts); - out.writeInt(mUnpluggedNumCrashes); - out.writeInt(mUnpluggedNumAnrs); writeExcessivePowerToParcelLocked(out); } @@ -9305,18 +9050,6 @@ public class BatteryStatsImpl extends BatteryStats { mStarts = in.readInt(); mNumCrashes = in.readInt(); mNumAnrs = in.readInt(); - mLoadedUserTime = in.readLong(); - mLoadedSystemTime = in.readLong(); - mLoadedForegroundTime = in.readLong(); - mLoadedStarts = in.readInt(); - mLoadedNumCrashes = in.readInt(); - mLoadedNumAnrs = in.readInt(); - mUnpluggedUserTime = in.readLong(); - mUnpluggedSystemTime = in.readLong(); - mUnpluggedForegroundTime = in.readLong(); - mUnpluggedStarts = in.readInt(); - mUnpluggedNumCrashes = in.readInt(); - mUnpluggedNumAnrs = in.readInt(); readExcessivePowerFromParcelLocked(in); } @@ -9358,71 +9091,35 @@ public class BatteryStatsImpl extends BatteryStats { @Override @UnsupportedAppUsage public long getUserTime(int which) { - long val = mUserTime; - if (which == STATS_CURRENT) { - val -= mLoadedUserTime; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedUserTime; - } - return val; + return mUserTime; } @Override @UnsupportedAppUsage public long getSystemTime(int which) { - long val = mSystemTime; - if (which == STATS_CURRENT) { - val -= mLoadedSystemTime; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedSystemTime; - } - return val; + return mSystemTime; } @Override @UnsupportedAppUsage public long getForegroundTime(int which) { - long val = mForegroundTime; - if (which == STATS_CURRENT) { - val -= mLoadedForegroundTime; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedForegroundTime; - } - return val; + return mForegroundTime; } @Override @UnsupportedAppUsage public int getStarts(int which) { - int val = mStarts; - if (which == STATS_CURRENT) { - val -= mLoadedStarts; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedStarts; - } - return val; + return mStarts; } @Override public int getNumCrashes(int which) { - int val = mNumCrashes; - if (which == STATS_CURRENT) { - val -= mLoadedNumCrashes; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedNumCrashes; - } - return val; + return mNumCrashes; } @Override public int getNumAnrs(int which) { - int val = mNumAnrs; - if (which == STATS_CURRENT) { - val -= mLoadedNumAnrs; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedNumAnrs; - } - return val; + return mNumAnrs; } } @@ -9587,54 +9284,6 @@ public class BatteryStatsImpl extends BatteryStats { */ protected int mLaunches; - /** - * The amount of time spent started loaded from a previous save - * (ms in battery uptime). - */ - protected long mLoadedStartTime; - - /** - * The number of starts loaded from a previous save. - */ - protected int mLoadedStarts; - - /** - * The number of launches loaded from a previous save. - */ - protected int mLoadedLaunches; - - /** - * The amount of time spent started as of the last run (ms - * in battery uptime). - */ - protected long mLastStartTime; - - /** - * The number of starts as of the last run. - */ - protected int mLastStarts; - - /** - * The number of launches as of the last run. - */ - protected int mLastLaunches; - - /** - * The amount of time spent started when last unplugged (ms - * in battery uptime). - */ - protected long mUnpluggedStartTime; - - /** - * The number of starts when last unplugged. - */ - protected int mUnpluggedStarts; - - /** - * The number of launches when last unplugged. - */ - protected int mUnpluggedLaunches; - /** * Construct a Serv. Also adds it to the on-battery time base as a listener. */ @@ -9645,9 +9294,6 @@ public class BatteryStatsImpl extends BatteryStats { public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) { - mUnpluggedStartTime = getStartTimeToNowLocked(baseUptime); - mUnpluggedStarts = mStarts; - mUnpluggedLaunches = mLaunches; } public void onTimeStopped(long elapsedRealtime, long baseUptime, @@ -9679,15 +9325,6 @@ public class BatteryStatsImpl extends BatteryStats { mLaunchedSince = in.readLong(); mLaunched = in.readInt() != 0; mLaunches = in.readInt(); - mLoadedStartTime = in.readLong(); - mLoadedStarts = in.readInt(); - mLoadedLaunches = in.readInt(); - mLastStartTime = 0; - mLastStarts = 0; - mLastLaunches = 0; - mUnpluggedStartTime = in.readLong(); - mUnpluggedStarts = in.readInt(); - mUnpluggedLaunches = in.readInt(); } public void writeToParcelLocked(Parcel out) { @@ -9699,12 +9336,6 @@ public class BatteryStatsImpl extends BatteryStats { out.writeLong(mLaunchedSince); out.writeInt(mLaunched ? 1 : 0); out.writeInt(mLaunches); - out.writeLong(mLoadedStartTime); - out.writeInt(mLoadedStarts); - out.writeInt(mLoadedLaunches); - out.writeLong(mUnpluggedStartTime); - out.writeInt(mUnpluggedStarts); - out.writeInt(mUnpluggedLaunches); } public long getLaunchTimeToNowLocked(long batteryUptime) { @@ -9768,36 +9399,17 @@ public class BatteryStatsImpl extends BatteryStats { @Override public int getLaunches(int which) { - int val = mLaunches; - if (which == STATS_CURRENT) { - val -= mLoadedLaunches; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedLaunches; - } - return val; + return mLaunches; } @Override public long getStartTime(long now, int which) { - long val = getStartTimeToNowLocked(now); - if (which == STATS_CURRENT) { - val -= mLoadedStartTime; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedStartTime; - } - return val; + return getStartTimeToNowLocked(now); } @Override public int getStarts(int which) { - int val = mStarts; - if (which == STATS_CURRENT) { - val -= mLoadedStarts; - } else if (which == STATS_SINCE_UNPLUGGED) { - val -= mUnpluggedStarts; - } - - return val; + return mStarts; } } @@ -10932,7 +10544,7 @@ public class BatteryStatsImpl extends BatteryStats { } mBluetoothActivity.reset(false); mModemActivity.reset(false); - mNumConnectivityChange = mLoadedNumConnectivityChange = mUnpluggedNumConnectivityChange = 0; + mNumConnectivityChange = 0; for (int i=0; i Date: Fri, 15 Mar 2019 11:37:02 -0700 Subject: [PATCH 031/349] LongSamplingCounter - remove update() It wasn't being used anywhere and was requiring an extra long. Since LongSamplingCounter takes up (cumulatively, due the huge number of them) a lot of memory, each byte counts for a lot. (It was added in ag/3771500, but appears to have never been used, so we restore its original algorithm.) Test: atest LongSamplingCounterTest Change-Id: I7349e927ae6fe8c941e408c4d0843b638bf070e9 --- .../android/internal/os/BatteryStatsImpl.java | 23 +---- .../internal/os/LongSamplingCounterTest.java | 84 ++++++------------- 2 files changed, 31 insertions(+), 76 deletions(-) diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 47ee01e95fe1..1fc76351254b 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -1567,13 +1567,11 @@ public class BatteryStatsImpl extends BatteryStats { @VisibleForTesting public static class LongSamplingCounter extends LongCounter implements TimeBaseObs { final TimeBase mTimeBase; - public long mCount; - public long mCurrentCount; + private long mCount; public LongSamplingCounter(TimeBase timeBase, Parcel in) { mTimeBase = timeBase; mCount = in.readLong(); - mCurrentCount = in.readLong(); timeBase.add(this); } @@ -1584,7 +1582,6 @@ public class BatteryStatsImpl extends BatteryStats { public void writeToParcel(Parcel out) { out.writeLong(mCount); - out.writeLong(mCurrentCount); } @Override @@ -1601,29 +1598,17 @@ public class BatteryStatsImpl extends BatteryStats { @Override public void logState(Printer pw, String prefix) { - pw.println(prefix + "mCount=" + mCount + " mCurrentCount=" + mCurrentCount); + pw.println(prefix + "mCount=" + mCount); } public void addCountLocked(long count) { - update(mCurrentCount + count, mTimeBase.isRunning()); + addCountLocked(count, mTimeBase.isRunning()); } public void addCountLocked(long count, boolean isRunning) { - update(mCurrentCount + count, isRunning); - } - - public void update(long count) { - update(count, mTimeBase.isRunning()); - } - - public void update(long count, boolean isRunning) { - if (count < mCurrentCount) { - mCurrentCount = 0; - } if (isRunning) { - mCount += count - mCurrentCount; + mCount += count; } - mCurrentCount = count; } /** diff --git a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java index 77cf130b63af..dccc3d3d76fa 100644 --- a/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java +++ b/core/tests/coretests/src/com/android/internal/os/LongSamplingCounterTest.java @@ -51,7 +51,6 @@ import org.mockito.MockitoAnnotations; public class LongSamplingCounterTest { private static final long COUNT = 1111; - private static final long CURRENT_COUNT = 5555; @Mock private TimeBase mTimeBase; @@ -67,115 +66,87 @@ public class LongSamplingCounterTest { @Test public void testReadWriteParcel() { final Parcel parcel = Parcel.obtain(); - updateCounts(COUNT, CURRENT_COUNT); + mCounter.addCountLocked(COUNT, true); + assertEquals(COUNT, getCount()); mCounter.writeToParcel(parcel); parcel.setDataPosition(0); - // Now clear counterArray and verify values are read from parcel correctly. - updateCounts(0, 0); + // Now change count but verify values are read from parcel correctly. + mCounter.addCountLocked(7 * COUNT, true); + assertEquals(8 * COUNT, getCount()); mCounter = new LongSamplingCounter(mTimeBase, parcel); - assertEquals(COUNT, mCounter.mCount); - assertEquals(CURRENT_COUNT, mCounter.mCurrentCount); + assertEquals(COUNT, getCount()); parcel.recycle(); } @Test public void testReadWriteSummaryParcel() { final Parcel parcel = Parcel.obtain(); - updateCounts(COUNT, CURRENT_COUNT); + mCounter.addCountLocked(COUNT, true); + assertEquals(COUNT, getCount()); mCounter.writeSummaryFromParcelLocked(parcel); parcel.setDataPosition(0); - // Now clear counterArray and verify values are read from parcel correctly. - updateCounts(0, 0); + // Now change count but verify values are read from parcel correctly. + mCounter.addCountLocked(7 * COUNT, true); + assertEquals(8 * COUNT, getCount()); mCounter.readSummaryFromParcelLocked(parcel); - assertEquals(COUNT, mCounter.mCount); + assertEquals(COUNT, getCount()); parcel.recycle(); } @Test public void testOnTimeStarted() { - updateCounts(COUNT, CURRENT_COUNT); + mCounter.addCountLocked(COUNT, true); + assertEquals(COUNT, getCount()); mCounter.onTimeStarted(0, 0, 0); - assertEquals(COUNT, mCounter.mCount); + assertEquals(COUNT, getCount()); } @Test public void testOnTimeStopped() { - updateCounts(COUNT, CURRENT_COUNT); + mCounter.addCountLocked(COUNT, true); + assertEquals(COUNT, getCount()); mCounter.onTimeStopped(0, 0, 0); - assertEquals(COUNT, mCounter.mCount); + assertEquals(COUNT, getCount()); } @Test public void testAddCountLocked() { - updateCounts(0, 0); - assertEquals(0, mCounter.getCountLocked(0)); + assertEquals(0, getCount()); when(mTimeBase.isRunning()).thenReturn(true); mCounter.addCountLocked(111); assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(111, mCounter.mCurrentCount); mCounter.addCountLocked(222); assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(333, mCounter.mCurrentCount); when(mTimeBase.isRunning()).thenReturn(false); mCounter.addCountLocked(456); assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(789, mCounter.mCurrentCount); mCounter.addCountLocked(444, true); assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(1233, mCounter.mCurrentCount); mCounter.addCountLocked(567, false); assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(1800, mCounter.mCurrentCount); } - @Test - public void testUpdate() { - updateCounts(0, 0); - assertEquals(0, mCounter.getCountLocked(0)); - when(mTimeBase.isRunning()).thenReturn(true); - mCounter.update(111); - assertEquals(111, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(111, mCounter.mCurrentCount); - mCounter.update(333); - assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(333, mCounter.mCurrentCount); - - when(mTimeBase.isRunning()).thenReturn(false); - mCounter.update(789); - assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(789, mCounter.mCurrentCount); - mCounter.update(100); - assertEquals(333, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(100, mCounter.mCurrentCount); - - mCounter.update(544, true); - assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(544, mCounter.mCurrentCount); - mCounter.update(1544, false); - assertEquals(777, mCounter.getCountLocked(STATS_SINCE_CHARGED)); - assertEquals(1544, mCounter.mCurrentCount); - } @Test public void testReset() { - updateCounts(COUNT, CURRENT_COUNT); + mCounter.addCountLocked(COUNT, true); + assertEquals(COUNT, getCount()); // Test with detachIfReset=false mCounter.reset(false /* detachIfReset */); - assertEquals(0, mCounter.mCount); - assertEquals(CURRENT_COUNT, mCounter.mCurrentCount); + assertEquals(0, getCount()); verifyZeroInteractions(mTimeBase); - updateCounts(COUNT, CURRENT_COUNT); + mCounter.addCountLocked(COUNT, true); + assertEquals(COUNT, getCount()); // Test with detachIfReset=true mCounter.reset(true /* detachIfReset */); - assertEquals(0, mCounter.mCount); - assertEquals(CURRENT_COUNT, mCounter.mCurrentCount); + assertEquals(0, getCount()); verify(mTimeBase).remove(mCounter); verifyNoMoreInteractions(mTimeBase); } @@ -187,8 +158,7 @@ public class LongSamplingCounterTest { verifyNoMoreInteractions(mTimeBase); } - private void updateCounts(long total, long current) { - mCounter.mCount = total; - mCounter.mCurrentCount = current; + private long getCount() { + return mCounter.getCountLocked(STATS_SINCE_CHARGED); } } -- GitLab From 7119e99d7378c4ec12befd1eec6cfb705e985f28 Mon Sep 17 00:00:00 2001 From: Christine Franks Date: Thu, 14 Mar 2019 17:28:21 -0700 Subject: [PATCH 032/349] Split global saturation into a dedicated helper Bug: 124474236 Test: atest FrameworksServicesTests:GlobalSaturationTintControllerTest Change-Id: Ib70f84a917b3ce370b146f40cebbaa570574da47 --- .../display/color/ColorDisplayService.java | 145 +----------------- .../color/GlobalSaturationTintController.java | 81 ++++++++++ .../server/display/color/TintController.java | 98 ++++++++++++ .../GlobalSaturationTintControllerTest.java | 48 ++++++ 4 files changed, 235 insertions(+), 137 deletions(-) create mode 100644 services/core/java/com/android/server/display/color/GlobalSaturationTintController.java create mode 100644 services/core/java/com/android/server/display/color/TintController.java create mode 100644 services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java diff --git a/services/core/java/com/android/server/display/color/ColorDisplayService.java b/services/core/java/com/android/server/display/color/ColorDisplayService.java index 45567e5a34cb..9c02aab22e9d 100644 --- a/services/core/java/com/android/server/display/color/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/color/ColorDisplayService.java @@ -26,7 +26,6 @@ import static android.hardware.display.ColorDisplayManager.COLOR_MODE_SATURATED; import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE; import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY; -import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION; import android.Manifest; import android.animation.Animator; @@ -88,19 +87,13 @@ import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; import java.time.format.DateTimeParseException; -import java.util.Arrays; /** * Controls the display's color transforms. */ public final class ColorDisplayService extends SystemService { - private static final String TAG = "ColorDisplayService"; - - /** - * The transition time, in milliseconds, for Night Display to turn on/off. - */ - private static final long TRANSITION_DURATION = 3000L; + static final String TAG = "ColorDisplayService"; /** * The identity matrix, used if one of the given matrices is {@code null}. @@ -111,6 +104,11 @@ public final class ColorDisplayService extends SystemService { Matrix.setIdentityM(MATRIX_IDENTITY, 0); } + /** + * The transition time, in milliseconds, for Night Display to turn on/off. + */ + private static final long TRANSITION_DURATION = 3000L; + private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 0; private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 1; private static final int MSG_APPLY_GLOBAL_SATURATION = 2; @@ -133,59 +131,8 @@ public final class ColorDisplayService extends SystemService { final DisplayWhiteBalanceTintController mDisplayWhiteBalanceTintController = new DisplayWhiteBalanceTintController(); - private final TintController mGlobalSaturationTintController = new TintController() { - - private float[] mMatrixGlobalSaturation = new float[16]; - - @Override - public void setUp(Context context, boolean needsLinear) { - } - - @Override - public float[] getMatrix() { - return Arrays.copyOf(mMatrixGlobalSaturation, mMatrixGlobalSaturation.length); - } - - @Override - public void setMatrix(int saturationLevel) { - if (saturationLevel < 0) { - saturationLevel = 0; - } else if (saturationLevel > 100) { - saturationLevel = 100; - } - Slog.d(TAG, "Setting saturation level: " + saturationLevel); - - if (saturationLevel == 100) { - setActivated(false); - Matrix.setIdentityM(mMatrixGlobalSaturation, 0); - } else { - setActivated(true); - float saturation = saturationLevel * 0.1f; - float desaturation = 1.0f - saturation; - float[] luminance = {0.231f * desaturation, 0.715f * desaturation, - 0.072f * desaturation}; - mMatrixGlobalSaturation[0] = luminance[0] + saturation; - mMatrixGlobalSaturation[1] = luminance[0]; - mMatrixGlobalSaturation[2] = luminance[0]; - mMatrixGlobalSaturation[4] = luminance[1]; - mMatrixGlobalSaturation[5] = luminance[1] + saturation; - mMatrixGlobalSaturation[6] = luminance[1]; - mMatrixGlobalSaturation[8] = luminance[2]; - mMatrixGlobalSaturation[9] = luminance[2]; - mMatrixGlobalSaturation[10] = luminance[2] + saturation; - } - } - - @Override - public int getLevel() { - return LEVEL_COLOR_MATRIX_SATURATION; - } - - @Override - public boolean isAvailable(Context context) { - return ColorDisplayManager.isColorTransformAccelerated(context); - } - }; + private final TintController mGlobalSaturationTintController = + new GlobalSaturationTintController(); /** * Matrix and offset used for converting color to grayscale. @@ -1084,82 +1031,6 @@ public final class ColorDisplayService extends SystemService { } } - private abstract static class TintController { - - private ValueAnimator mAnimator; - private Boolean mIsActivated; - - public ValueAnimator getAnimator() { - return mAnimator; - } - - public void setAnimator(ValueAnimator animator) { - mAnimator = animator; - } - - /** - * Cancel the animator if it's still running. - */ - public void cancelAnimator() { - if (mAnimator != null) { - mAnimator.cancel(); - } - } - - /** - * End the animator if it's still running, jumping to the end state. - */ - public void endAnimator() { - if (mAnimator != null) { - mAnimator.end(); - mAnimator = null; - } - } - - public void setActivated(Boolean isActivated) { - mIsActivated = isActivated; - } - - public boolean isActivated() { - return mIsActivated != null && mIsActivated; - } - - public boolean isActivatedStateNotSet() { - return mIsActivated == null; - } - - /** - * Dump debug information. - */ - public void dump(PrintWriter pw) { - } - - /** - * Set up any constants needed for computing the matrix. - */ - public abstract void setUp(Context context, boolean needsLinear); - - /** - * Sets the 4x4 matrix to apply. - */ - public abstract void setMatrix(int value); - - /** - * Get the 4x4 matrix to apply. - */ - public abstract float[] getMatrix(); - - /** - * Get the color transform level to apply the matrix. - */ - public abstract int getLevel(); - - /** - * Returns whether or not this transform type is available on this device. - */ - public abstract boolean isAvailable(Context context); - } - private final class NightDisplayTintController extends TintController { private final float[] mMatrix = new float[16]; diff --git a/services/core/java/com/android/server/display/color/GlobalSaturationTintController.java b/services/core/java/com/android/server/display/color/GlobalSaturationTintController.java new file mode 100644 index 000000000000..71fdcc73a57e --- /dev/null +++ b/services/core/java/com/android/server/display/color/GlobalSaturationTintController.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2019 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.display.color; + +import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_SATURATION; + +import android.content.Context; +import android.hardware.display.ColorDisplayManager; +import android.opengl.Matrix; +import android.util.Slog; + +import java.util.Arrays; + +/** Control the color transform for global device saturation. */ +public class GlobalSaturationTintController extends TintController { + + private final float[] mMatrixGlobalSaturation = new float[16]; + + @Override + public void setUp(Context context, boolean needsLinear) { + } + + @Override + public float[] getMatrix() { + return Arrays.copyOf(mMatrixGlobalSaturation, mMatrixGlobalSaturation.length); + } + + @Override + public void setMatrix(int saturationLevel) { + if (saturationLevel < 0) { + saturationLevel = 0; + } else if (saturationLevel > 100) { + saturationLevel = 100; + } + Slog.d(ColorDisplayService.TAG, "Setting saturation level: " + saturationLevel); + + if (saturationLevel == 100) { + setActivated(false); + Matrix.setIdentityM(mMatrixGlobalSaturation, 0); + } else { + setActivated(true); + float saturation = saturationLevel * 0.01f; + float desaturation = 1.0f - saturation; + float[] luminance = {0.231f * desaturation, 0.715f * desaturation, + 0.072f * desaturation}; + mMatrixGlobalSaturation[0] = luminance[0] + saturation; + mMatrixGlobalSaturation[1] = luminance[0]; + mMatrixGlobalSaturation[2] = luminance[0]; + mMatrixGlobalSaturation[4] = luminance[1]; + mMatrixGlobalSaturation[5] = luminance[1] + saturation; + mMatrixGlobalSaturation[6] = luminance[1]; + mMatrixGlobalSaturation[8] = luminance[2]; + mMatrixGlobalSaturation[9] = luminance[2]; + mMatrixGlobalSaturation[10] = luminance[2] + saturation; + } + } + + @Override + public int getLevel() { + return LEVEL_COLOR_MATRIX_SATURATION; + } + + @Override + public boolean isAvailable(Context context) { + return ColorDisplayManager.isColorTransformAccelerated(context); + } +} diff --git a/services/core/java/com/android/server/display/color/TintController.java b/services/core/java/com/android/server/display/color/TintController.java new file mode 100644 index 000000000000..b291c645027a --- /dev/null +++ b/services/core/java/com/android/server/display/color/TintController.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2019 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.display.color; + +import android.animation.ValueAnimator; +import android.content.Context; + +import java.io.PrintWriter; + +abstract class TintController { + + private ValueAnimator mAnimator; + private Boolean mIsActivated; + + public ValueAnimator getAnimator() { + return mAnimator; + } + + public void setAnimator(ValueAnimator animator) { + mAnimator = animator; + } + + /** + * Cancel the animator if it's still running. + */ + public void cancelAnimator() { + if (mAnimator != null) { + mAnimator.cancel(); + } + } + + /** + * End the animator if it's still running, jumping to the end state. + */ + public void endAnimator() { + if (mAnimator != null) { + mAnimator.end(); + mAnimator = null; + } + } + + public void setActivated(Boolean isActivated) { + mIsActivated = isActivated; + } + + public boolean isActivated() { + return mIsActivated != null && mIsActivated; + } + + public boolean isActivatedStateNotSet() { + return mIsActivated == null; + } + + /** + * Dump debug information. + */ + public void dump(PrintWriter pw) { + } + + /** + * Set up any constants needed for computing the matrix. + */ + public abstract void setUp(Context context, boolean needsLinear); + + /** + * Sets the 4x4 matrix to apply. + */ + public abstract void setMatrix(int value); + + /** + * Get the 4x4 matrix to apply. + */ + public abstract float[] getMatrix(); + + /** + * Get the color transform level to apply the matrix. + */ + public abstract int getLevel(); + + /** + * Returns whether or not this transform type is available on this device. + */ + public abstract boolean isAvailable(Context context); +} diff --git a/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java b/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java new file mode 100644 index 000000000000..7b88a0e012de --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/display/color/GlobalSaturationTintControllerTest.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 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.display.color; + +import static com.google.common.truth.Truth.assertThat; + +import android.opengl.Matrix; + +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class GlobalSaturationTintControllerTest { + + @Test + public void setAndGetMatrix() { + final GlobalSaturationTintController tintController = new GlobalSaturationTintController(); + tintController.setMatrix(50); + assertThat(tintController.getMatrix()).hasValuesWithin(0.00001f) + .of(new float[]{0.6155f, 0.1155f, 0.1155f, 0.0f, 0.3575f, 0.85749996f, 0.3575f, + 0.0f, 0.036f, 0.036f, 0.536f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}); + } + + @Test + public void resetMatrix() { + final GlobalSaturationTintController tintController = new GlobalSaturationTintController(); + tintController.setMatrix(100); + final float[] matrix = new float[16]; + Matrix.setIdentityM(matrix, 0); + assertThat(tintController.getMatrix()).hasValuesWithin(0.00001f).of(matrix); + } +} -- GitLab From 655ec8bd6711d507164a614c83041a89a1dd4f48 Mon Sep 17 00:00:00 2001 From: Fabian Kozynski Date: Tue, 19 Mar 2019 10:16:18 -0400 Subject: [PATCH 033/349] Fixes focus of TalkBack in QuickStatusBarHeader Now TB focuses on quick_qs_status_icons (but it's not clickable). Test: manual using talkback Test: No regressions on clicking around that area Fixes: 128892822 Change-Id: I02949c45cc77d848d37bfe1edd379e698b00f5b8 --- packages/SystemUI/res/layout/quick_qs_status_icons.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/SystemUI/res/layout/quick_qs_status_icons.xml b/packages/SystemUI/res/layout/quick_qs_status_icons.xml index 74002ac38c02..fa74536532b8 100644 --- a/packages/SystemUI/res/layout/quick_qs_status_icons.xml +++ b/packages/SystemUI/res/layout/quick_qs_status_icons.xml @@ -26,7 +26,9 @@ android:layout_below="@id/quick_status_bar_system_icons" android:clipChildren="false" android:clipToPadding="false" - android:minHeight="20dp" > + android:minHeight="20dp" + android:clickable="false" + android:focusable="true"> Date: Tue, 5 Mar 2019 14:23:47 +0800 Subject: [PATCH 034/349] Support starting gsid lazily The aosp/914714 made the gsid to start when needed. The DynamicAndroidService must support this behavior as well. Bug:126622385 Test: adb shell am start-activity \ -n com.android.dynandroid/com.android.dynandroid.VerificationActivity \ -a android.content.action.START_INSTALL \ --es KEY_SYSTEM_URL file:///storage/emulated/0/Download/system.raw.gz \ --el KEY_SYSTEM_SIZE $(du -b system.raw) \ --el KEY_USERDATA_SIZE 8589934592 Change-Id: Ifb9d642d183ed3e7181ed643f9415850178ef58d --- .../android/server/DynamicAndroidService.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/DynamicAndroidService.java b/services/core/java/com/android/server/DynamicAndroidService.java index 8488941587fb..b02bfb111727 100644 --- a/services/core/java/com/android/server/DynamicAndroidService.java +++ b/services/core/java/com/android/server/DynamicAndroidService.java @@ -25,6 +25,7 @@ import android.os.IBinder.DeathRecipient; import android.os.IDynamicAndroidService; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.SystemProperties; import android.util.Slog; /** @@ -34,6 +35,7 @@ import android.util.Slog; public class DynamicAndroidService extends IDynamicAndroidService.Stub implements DeathRecipient { private static final String TAG = "DynamicAndroidService"; private static final String NO_SERVICE_ERROR = "no gsiservice"; + private static final int GSID_ROUGH_TIMEOUT_MS = 8192; private Context mContext; private volatile IGsiService mGsiService; @@ -66,12 +68,27 @@ public class DynamicAndroidService extends IDynamicAndroidService.Stub implement private IGsiService getGsiService() throws RemoteException { checkPermission(); - synchronized (this) { - if (mGsiService == null) { - mGsiService = connect(this); + if (!"running".equals(SystemProperties.get("init.svc.gsid"))) { + SystemProperties.set("ctl.start", "gsid"); + } + for (int sleepMs = 64; sleepMs <= (GSID_ROUGH_TIMEOUT_MS << 1); sleepMs <<= 1) { + try { + Thread.sleep(sleepMs); + } catch (InterruptedException e) { + Slog.e(TAG, "Interrupted when waiting for GSID"); + break; + } + if ("running".equals(SystemProperties.get("init.svc.gsid"))) { + synchronized (this) { + if (mGsiService == null) { + mGsiService = connect(this); + } + return mGsiService; + } } - return mGsiService; } + Slog.e(TAG, "Unable to start gsid"); + return null; } private void checkPermission() { -- GitLab From 50b43b7b72c05b7de18a6370b42328669004c9fe Mon Sep 17 00:00:00 2001 From: Heemin Seog Date: Sun, 17 Mar 2019 23:54:23 -0700 Subject: [PATCH 035/349] Remove androidx.car_car resources from SysUI Test: Manual Change-Id: I7632bad7563d6639a3da9cf2a4e3456244b2d5e4 --- core/res/res/values/dimens_car.xml | 1 + core/res/res/values/symbols.xml | 1 + .../drawable/keyguard_button_background.xml | 4 ++-- .../layout-land/keyguard_pattern_view.xml | 6 +++--- .../res-keyguard/layout-land/keyguard_pin_view.xml | 6 +++--- .../res-keyguard/layout/keyguard_message_area.xml | 4 ++-- .../res-keyguard/layout/keyguard_password_view.xml | 6 +++--- .../res-keyguard/layout/keyguard_pattern_view.xml | 4 ++-- .../res-keyguard/layout/keyguard_pin_view.xml | 4 ++-- .../res-keyguard/values-land/dimens.xml | 4 ++-- .../CarSystemUI/res-keyguard/values/colors.xml | 4 ++-- .../CarSystemUI/res-keyguard/values/dimens.xml | 4 ++-- .../CarSystemUI/res-keyguard/values/styles.xml | 4 ++-- .../CarSystemUI/res/drawable/car_ic_add_white.xml | 4 ++-- .../res/drawable/car_rounded_bg_bottom.xml | 4 ++-- .../CarSystemUI/res/drawable/car_seekbar_thumb.xml | 14 +++++++------- .../CarSystemUI/res/layout/car_navigation_bar.xml | 4 ++-- .../layout/car_navigation_bar_unprovisioned.xml | 6 +++--- .../res/layout/car_top_navigation_bar.xml | 10 +++++----- packages/CarSystemUI/res/values/colors_car.xml | 10 +++++----- packages/CarSystemUI/res/values/dimens.xml | 2 +- packages/CarSystemUI/res/values/dimens_car.xml | 12 ++++++------ packages/CarSystemUI/res/values/styles.xml | 8 ++++---- .../statusbar/car/UserGridRecyclerView.java | 6 ++++-- 24 files changed, 68 insertions(+), 64 deletions(-) diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml index 5014a29f4eab..423cb920b3c5 100644 --- a/core/res/res/values/dimens_car.xml +++ b/core/res/res/values/dimens_car.xml @@ -21,6 +21,7 @@ 356dp 96dp 96dp + 96dp diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 503bbced1937..7e7114d4b04a 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3582,6 +3582,7 @@ + diff --git a/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml b/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml index b428931670f5..8b2779d10481 100644 --- a/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml +++ b/packages/CarSystemUI/res-keyguard/drawable/keyguard_button_background.xml @@ -18,13 +18,13 @@ - + - + diff --git a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml index b115a1f3c131..a465254afebb 100644 --- a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml +++ b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pattern_view.xml @@ -28,7 +28,7 @@ android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingHorizontal="@dimen/car_margin"> + android:paddingHorizontal="@*android:dimen/car_margin"> diff --git a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml index ed88c6235d58..5746102f5f27 100644 --- a/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml +++ b/packages/CarSystemUI/res-keyguard/layout-land/keyguard_pin_view.xml @@ -29,7 +29,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" - android:paddingHorizontal="@dimen/car_margin"> + android:paddingHorizontal="@*android:dimen/car_margin"> diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml index c2304147982a..09cf4722dae0 100644 --- a/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml +++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_message_area.xml @@ -27,5 +27,5 @@ android:singleLine="true" android:ellipsize="marquee" android:focusable="true" - android:layout_marginBottom="@dimen/car_padding_4" - android:textSize="@dimen/car_body2_size" /> + android:layout_marginBottom="@*android:dimen/car_padding_4" + android:textSize="@*android:dimen/car_body2_size" /> diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml index e701fdb956f5..7004fb64ba06 100644 --- a/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml +++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_password_view.xml @@ -51,7 +51,7 @@ android:singleLine="true" android:textStyle="normal" android:inputType="textPassword" - android:textSize="@dimen/car_body1_size" + android:textSize="@*android:dimen/car_body1_size" android:textColor="?attr/wallpaperTextColor" android:textAppearance="?android:attr/textAppearanceMedium" android:imeOptions="flagForceAscii|actionDone" @@ -61,10 +61,10 @@