diff options
78 files changed, 1661 insertions, 747 deletions
diff --git a/apct-tests/perftests/textclassifier/Android.bp b/apct-tests/perftests/textclassifier/Android.bp index 9f795a7ed54a..c40e0252cb7e 100644 --- a/apct-tests/perftests/textclassifier/Android.bp +++ b/apct-tests/perftests/textclassifier/Android.bp @@ -19,7 +19,7 @@ android_test { "androidx.test.rules", "androidx.annotation_annotation", "apct-perftests-utils", - "collector-device-lib-platform", + "collector-device-lib", ], data: [":perfetto_artifacts"], platform_apis: true, diff --git a/api/system-current.txt b/api/system-current.txt index 56059dd9d864..88fe40a93010 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -12732,6 +12732,9 @@ package android.webkit { public interface PacProcessor { method @Nullable public String findProxyForUrl(@NonNull String); method @NonNull public static android.webkit.PacProcessor getInstance(); + method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long); + method public default long getNetworkHandle(); + method public default void releasePacProcessor(); method public boolean setProxyScript(@NonNull String); } @@ -12871,6 +12874,7 @@ package android.webkit { method public android.webkit.CookieManager getCookieManager(); method public android.webkit.GeolocationPermissions getGeolocationPermissions(); method @NonNull public default android.webkit.PacProcessor getPacProcessor(); + method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long); method public android.webkit.ServiceWorkerController getServiceWorkerController(); method public android.webkit.WebViewFactoryProvider.Statics getStatics(); method @Deprecated public android.webkit.TokenBindingService getTokenBindingService(); diff --git a/config/hiddenapi-force-blacklist.txt b/config/hiddenapi-force-blocked.txt index b328f2ac1955..b328f2ac1955 100644 --- a/config/hiddenapi-force-blacklist.txt +++ b/config/hiddenapi-force-blocked.txt diff --git a/config/hiddenapi-greylist-max-o.txt b/config/hiddenapi-max-target-o.txt index 023bf3876228..023bf3876228 100644 --- a/config/hiddenapi-greylist-max-o.txt +++ b/config/hiddenapi-max-target-o.txt diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-max-target-p.txt index 351e71dd9538..351e71dd9538 100644 --- a/config/hiddenapi-greylist-max-p.txt +++ b/config/hiddenapi-max-target-p.txt diff --git a/config/hiddenapi-greylist-max-q.txt b/config/hiddenapi-max-target-q.txt index 4832dd184ec5..4832dd184ec5 100644 --- a/config/hiddenapi-greylist-max-q.txt +++ b/config/hiddenapi-max-target-q.txt diff --git a/config/hiddenapi-greylist-packages.txt b/config/hiddenapi-unsupported-packages.txt index 986d2591a007..986d2591a007 100644 --- a/config/hiddenapi-greylist-packages.txt +++ b/config/hiddenapi-unsupported-packages.txt diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-unsupported.txt index a3543dc7f4ee..a3543dc7f4ee 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-unsupported.txt diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index bca6f39e1ded..54f3f1026050 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -215,7 +215,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { private long mMisses = 0; @GuardedBy("mLock") - private long mMissDisabled[] = new long[]{ 0, 0, 0 }; + private long mSkips[] = new long[]{ 0, 0, 0 }; @GuardedBy("mLock") private long mMissOverflow = 0; @@ -223,6 +223,9 @@ public abstract class PropertyInvalidatedCache<Query, Result> { @GuardedBy("mLock") private long mHighWaterMark = 0; + @GuardedBy("mLock") + private long mClears = 0; + // Most invalidation is done in a static context, so the counters need to be accessible. @GuardedBy("sCorkLock") private static final HashMap<String, Long> sInvalidates = new HashMap<>(); @@ -273,6 +276,13 @@ public abstract class PropertyInvalidatedCache<Query, Result> { */ private volatile SystemProperties.Handle mPropertyHandle; + /** + * The name by which this cache is known. This should normally be the + * binder call that is being cached, but the constructors default it to + * the property name. + */ + private final String mCacheName; + @GuardedBy("mLock") private final LinkedHashMap<Query, Result> mCache; @@ -297,9 +307,23 @@ public abstract class PropertyInvalidatedCache<Query, Result> { * * @param maxEntries Maximum number of entries to cache; LRU discard * @param propertyName Name of the system property holding the cache invalidation nonce + * Defaults the cache name to the property name. */ public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName) { + this(maxEntries, propertyName, propertyName); + } + + /** + * Make a new property invalidated cache. + * + * @param maxEntries Maximum number of entries to cache; LRU discard + * @param propertyName Name of the system property holding the cache invalidation nonce + * @param cacheName Name of this cache in debug and dumpsys + */ + public PropertyInvalidatedCache(int maxEntries, @NonNull String propertyName, + @NonNull String cacheName) { mPropertyName = propertyName; + mCacheName = cacheName; mMaxEntries = maxEntries; mCache = new LinkedHashMap<Query, Result>( 2 /* start small */, @@ -320,7 +344,6 @@ public abstract class PropertyInvalidatedCache<Query, Result> { }; synchronized (sCorkLock) { sCaches.put(this, null); - sInvalidates.put(propertyName, (long) 0); } } @@ -333,6 +356,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { Log.d(TAG, "clearing cache for " + mPropertyName); } mCache.clear(); + mClears++; } } @@ -413,7 +437,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { // Do not bother collecting statistics if the cache is // locally disabled. synchronized (mLock) { - mMissDisabled[(int) currentNonce]++; + mSkips[(int) currentNonce]++; } } @@ -742,12 +766,16 @@ public abstract class PropertyInvalidatedCache<Query, Result> { boolean alreadyQueued = mUncorkDeadlineMs >= 0; if (DEBUG) { Log.w(TAG, String.format( - "autoCork mUncorkDeadlineMs=%s", mUncorkDeadlineMs)); + "autoCork %s mUncorkDeadlineMs=%s", mPropertyName, + mUncorkDeadlineMs)); } mUncorkDeadlineMs = SystemClock.uptimeMillis() + mAutoCorkDelayMs; if (!alreadyQueued) { getHandlerLocked().sendEmptyMessageAtTime(0, mUncorkDeadlineMs); PropertyInvalidatedCache.corkInvalidations(mPropertyName); + } else { + final long count = sCorkedInvalidates.getOrDefault(mPropertyName, (long) 0); + sCorkedInvalidates.put(mPropertyName, count + 1); } } } @@ -756,7 +784,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> { synchronized (mLock) { if (DEBUG) { Log.w(TAG, String.format( - "handleMsesage mUncorkDeadlineMs=%s", mUncorkDeadlineMs)); + "handleMsesage %s mUncorkDeadlineMs=%s", + mPropertyName, mUncorkDeadlineMs)); } if (mUncorkDeadlineMs < 0) { @@ -816,7 +845,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { * method is public so clients can use it. */ public String cacheName() { - return mPropertyName; + return mCacheName; } /** @@ -864,16 +893,20 @@ public abstract class PropertyInvalidatedCache<Query, Result> { } synchronized (mLock) { - pw.println(String.format(" Cache Property Name: %s", cacheName())); - pw.println(String.format(" Hits: %d, Misses: %d, Invalidates: %d, Overflows: %d", - mHits, mMisses, invalidateCount, mMissOverflow)); - pw.println(String.format(" Miss-corked: %d, Miss-unset: %d, Miss-other: %d," + - " CorkedInvalidates: %d", - mMissDisabled[NONCE_CORKED], mMissDisabled[NONCE_UNSET], - mMissDisabled[NONCE_DISABLED], corkedInvalidates)); - pw.println(String.format(" Last Observed Nonce: %d", mLastSeenNonce)); - pw.println(String.format(" Current Size: %d, Max Size: %d, HW Mark: %d", - mCache.size(), mMaxEntries, mHighWaterMark)); + pw.println(String.format(" Cache Name: %s", cacheName())); + pw.println(String.format(" Property: %s", mPropertyName)); + final long skips = mSkips[NONCE_CORKED] + mSkips[NONCE_UNSET] + mSkips[NONCE_DISABLED]; + pw.println(String.format(" Hits: %d, Misses: %d, Skips: %d, Clears: %d", + mHits, mMisses, skips, mClears)); + pw.println(String.format(" Skip-corked: %d, Skip-unset: %d, Skip-other: %d", + mSkips[NONCE_CORKED], mSkips[NONCE_UNSET], + mSkips[NONCE_DISABLED])); + pw.println(String.format( + " Nonce: 0x%016x, Invalidates: %d, CorkedInvalidates: %d", + mLastSeenNonce, invalidateCount, corkedInvalidates)); + pw.println(String.format( + " Current Size: %d, Max Size: %d, HW Mark: %d, Overflows: %d", + mCache.size(), mMaxEntries, mHighWaterMark, mMissOverflow)); pw.println(String.format(" Enabled: %s", mDisabled ? "false" : "true")); Set<Map.Entry<Query, Result>> cacheEntries = mCache.entrySet(); diff --git a/core/java/android/app/UiModeManager.java b/core/java/android/app/UiModeManager.java index 7c6eff143724..06d1b74abc86 100644 --- a/core/java/android/app/UiModeManager.java +++ b/core/java/android/app/UiModeManager.java @@ -510,6 +510,9 @@ public class UiModeManager { } /** + * Activating night mode for the current user + * + * @return {@code true} if the change is successful * @hide */ public boolean setNightModeActivated(boolean active) { diff --git a/core/java/android/app/people/ConversationChannel.java b/core/java/android/app/people/ConversationChannel.java new file mode 100644 index 000000000000..39c5c85e456c --- /dev/null +++ b/core/java/android/app/people/ConversationChannel.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2020 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.app.people; + +import android.app.NotificationChannel; +import android.content.pm.ShortcutInfo; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * The non-customized notification channel of a conversation. It contains the information to render + * the conversation and allows the user to open and customize the conversation setting. + * + * @hide + */ +public final class ConversationChannel implements Parcelable { + + private ShortcutInfo mShortcutInfo; + private NotificationChannel mParentNotificationChannel; + private long mLastEventTimestamp; + private boolean mHasActiveNotifications; + + public static final Creator<ConversationChannel> CREATOR = new Creator<ConversationChannel>() { + @Override + public ConversationChannel createFromParcel(Parcel in) { + return new ConversationChannel(in); + } + + @Override + public ConversationChannel[] newArray(int size) { + return new ConversationChannel[size]; + } + }; + + public ConversationChannel(ShortcutInfo shortcutInfo, + NotificationChannel parentNotificationChannel, long lastEventTimestamp, + boolean hasActiveNotifications) { + mShortcutInfo = shortcutInfo; + mParentNotificationChannel = parentNotificationChannel; + mLastEventTimestamp = lastEventTimestamp; + mHasActiveNotifications = hasActiveNotifications; + } + + public ConversationChannel(Parcel in) { + mShortcutInfo = in.readParcelable(ShortcutInfo.class.getClassLoader()); + mParentNotificationChannel = in.readParcelable(NotificationChannel.class.getClassLoader()); + mLastEventTimestamp = in.readLong(); + mHasActiveNotifications = in.readBoolean(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(mShortcutInfo, flags); + dest.writeParcelable(mParentNotificationChannel, flags); + dest.writeLong(mLastEventTimestamp); + dest.writeBoolean(mHasActiveNotifications); + } + + public ShortcutInfo getShortcutInfo() { + return mShortcutInfo; + } + + public NotificationChannel getParentNotificationChannel() { + return mParentNotificationChannel; + } + + public long getLastEventTimestamp() { + return mLastEventTimestamp; + } + + /** + * Whether this conversation has any active notifications. If it's true, the shortcut for this + * conversation can't be uncached until all its active notifications are dismissed. + */ + public boolean hasActiveNotifications() { + return mHasActiveNotifications; + } +} diff --git a/core/java/android/app/people/IPeopleManager.aidl b/core/java/android/app/people/IPeopleManager.aidl new file mode 100644 index 000000000000..61dac0d64422 --- /dev/null +++ b/core/java/android/app/people/IPeopleManager.aidl @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2020 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.app.people; + +import android.content.pm.ParceledListSlice; +import android.net.Uri; +import android.os.IBinder; + +/** + * System private API for talking with the people service. + * {@hide} + */ +interface IPeopleManager { + /** + * Returns the recent conversations. The conversations that have customized notification + * settings are excluded from the returned list. + */ + ParceledListSlice getRecentConversations(); + + /** + * Removes the specified conversation from the recent conversations list and uncaches the + * shortcut associated with the conversation. + */ + void removeRecentConversation(in String packageName, int userId, in String shortcutId); + + /** Removes all the recent conversations and uncaches their cached shortcuts. */ + void removeAllRecentConversations(); +} diff --git a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java index 6bd365fad6f6..0770aff4e9bb 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetectorImpl.java @@ -117,7 +117,7 @@ public final class TimeZoneDetectorImpl implements TimeZoneDetector { } private void notifyConfigurationListeners(@NonNull TimeZoneConfiguration configuration) { - ArraySet<TimeZoneConfigurationListener> configurationListeners; + final ArraySet<TimeZoneConfigurationListener> configurationListeners; synchronized (this) { configurationListeners = new ArraySet<>(mConfigurationListeners); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 16cdf2334ad8..52b04675b7a5 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3496,6 +3496,7 @@ public abstract class Context { //@hide: TIME_ZONE_DETECTOR_SERVICE, PERMISSION_SERVICE, LIGHTS_SERVICE, + //@hide: PEOPLE_SERVICE, }) @Retention(RetentionPolicy.SOURCE) public @interface ServiceName {} @@ -5189,6 +5190,14 @@ public abstract class Context { public static final String SMS_SERVICE = "sms"; /** + * Use with {@link #getSystemService(String)} to access people service. + * + * @see #getSystemService(String) + * @hide + */ + public static final String PEOPLE_SERVICE = "people"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 42a610700051..e08af5534afd 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -8089,7 +8089,8 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo> sApplicationInfoCache = new PropertyInvalidatedCache<ApplicationInfoQuery, ApplicationInfo>( - 16, PermissionManager.CACHE_KEY_PACKAGE_INFO) { + 16, PermissionManager.CACHE_KEY_PACKAGE_INFO, + "getApplicationInfo") { @Override protected ApplicationInfo recompute(ApplicationInfoQuery query) { return getApplicationInfoAsUserUncached( @@ -8190,7 +8191,8 @@ public abstract class PackageManager { private static final PropertyInvalidatedCache<PackageInfoQuery, PackageInfo> sPackageInfoCache = new PropertyInvalidatedCache<PackageInfoQuery, PackageInfo>( - 32, PermissionManager.CACHE_KEY_PACKAGE_INFO) { + 32, PermissionManager.CACHE_KEY_PACKAGE_INFO, + "getPackageInfo") { @Override protected PackageInfo recompute(PackageInfoQuery query) { return getPackageInfoAsUserUncached( diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index bf3d46fa4a44..0c190719af57 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -608,7 +608,7 @@ public final class PermissionManager { /** @hide */ private static final PropertyInvalidatedCache<PermissionQuery, Integer> sPermissionCache = new PropertyInvalidatedCache<PermissionQuery, Integer>( - 16, CACHE_KEY_PACKAGE_INFO) { + 16, CACHE_KEY_PACKAGE_INFO, "checkPermission") { @Override protected Integer recompute(PermissionQuery query) { return checkPermissionUncached(query.permission, query.pid, query.uid); @@ -689,7 +689,7 @@ public final class PermissionManager { private static PropertyInvalidatedCache<PackageNamePermissionQuery, Integer> sPackageNamePermissionCache = new PropertyInvalidatedCache<PackageNamePermissionQuery, Integer>( - 16, CACHE_KEY_PACKAGE_INFO) { + 16, CACHE_KEY_PACKAGE_INFO, "checkPackageNamePermission") { @Override protected Integer recompute(PackageNamePermissionQuery query) { return checkPackageNamePermissionUncached( diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 5acc11a868bf..660455e59a4a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7912,6 +7912,13 @@ public final class Settings { public static final String TAPS_APP_TO_EXIT = "taps_app_to_exit"; /** + * Internal use, one handed mode tutorial showed times. + * @hide + */ + public static final String ONE_HANDED_TUTORIAL_SHOW_COUNT = + "one_handed_tutorial_show_count"; + + /** * The current night mode that has been selected by the user. Owned * and controlled by UiModeManagerService. Constants are as per * UiModeManager. diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 64ddb2f4d9d9..3f02d701f71f 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1814,19 +1814,13 @@ public final class ViewRootImpl implements ViewParent, /** * Called after window layout to update the bounds surface. If the surface insets have changed * or the surface has resized, update the bounds surface. - * - * @param shouldReparent Whether it should reparent the bounds layer to the main SurfaceControl. */ - private void updateBoundsLayer(boolean shouldReparent) { + private void updateBoundsLayer() { if (mBoundsLayer != null) { setBoundsLayerCrop(); - mTransaction.deferTransactionUntil(mBoundsLayer, getRenderSurfaceControl(), - mSurface.getNextFrameNumber()); - - if (shouldReparent) { - mTransaction.reparent(mBoundsLayer, getRenderSurfaceControl()); - } - mTransaction.apply(); + mTransaction.deferTransactionUntil(mBoundsLayer, + getRenderSurfaceControl(), mSurface.getNextFrameNumber()) + .apply(); } } @@ -2905,16 +2899,7 @@ public final class ViewRootImpl implements ViewParent, } if (surfaceSizeChanged || surfaceReplaced || surfaceCreated || windowAttributesChanged) { - // If the surface has been replaced, there's a chance the bounds layer is not parented - // to the new layer. When updating bounds layer, also reparent to the main VRI - // SurfaceControl to ensure it's correctly placed in the hierarchy. - // - // This needs to be done on the client side since WMS won't reparent the children to the - // new surface if it thinks the app is closing. WMS gets the signal that the app is - // stopping, but on the client side it doesn't get stopped since it's restarted quick - // enough. WMS doesn't want to keep around old children since they will leak when the - // client creates new children. - updateBoundsLayer(surfaceReplaced); + updateBoundsLayer(); } final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw); diff --git a/core/java/android/webkit/PacProcessor.java b/core/java/android/webkit/PacProcessor.java index 5ef450fa65dd..7e7b987f72f3 100644 --- a/core/java/android/webkit/PacProcessor.java +++ b/core/java/android/webkit/PacProcessor.java @@ -19,7 +19,7 @@ package android.webkit; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; - +import android.net.Network; /** * Class to evaluate PAC scripts. @@ -40,6 +40,20 @@ public interface PacProcessor { } /** + * Returns PacProcessor instance associated with the {@link Network}. + * The host resolution is done on this {@link Network}. + * + * @param networkHandle a handle representing {@link Network} handle. + * @return PacProcessor instance for the specified network. + * @see Network#getNetworkHandle + * @see Network#fromNetworkHandle + */ + @NonNull + static PacProcessor getInstanceForNetwork(long networkHandle) { + return WebViewFactory.getProvider().getPacProcessorForNetwork(networkHandle); + } + + /** * Set PAC script to use. * * @param script PAC script. @@ -55,4 +69,23 @@ public interface PacProcessor { */ @Nullable String findProxyForUrl(@NonNull String url); + + /** + * Stops support for this {@link PacProcessor} and release its resources. + * No methods of this class must be called after calling this method. + */ + default void releasePacProcessor() { + throw new UnsupportedOperationException("Not implemented"); + } + + /** + * Returns a network handle associated with this {@link PacProcessor}. + * + * @return a network handle or 0 if a network is unspecified. + * @see Network#getNetworkHandle + * @see Network#fromNetworkHandle + */ + default long getNetworkHandle() { + throw new UnsupportedOperationException("Not implemented"); + } } diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java index f7c3ec09dd67..f1863e319689 100644 --- a/core/java/android/webkit/WebViewFactoryProvider.java +++ b/core/java/android/webkit/WebViewFactoryProvider.java @@ -20,6 +20,7 @@ import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.content.Intent; +import android.net.Network; import android.net.Uri; import java.util.List; @@ -175,7 +176,7 @@ public interface WebViewFactoryProvider { WebViewDatabase getWebViewDatabase(Context context); /** - * Gets the singleton PacProcessor instance. + * Gets the default PacProcessor instance. * @return the PacProcessor instance */ @NonNull @@ -184,6 +185,20 @@ public interface WebViewFactoryProvider { } /** + * Returns PacProcessor instance associated with the {@link Network}. + * The host resolution is done on this {@link Network}. + * + * @param networkHandle a network handle representing the {@link Network}. + * @return the {@link PacProcessor} instance associated with {@link Network}. + * @see Network#getNetworkHandle + * @see Network#fromNetworkHandle + */ + @NonNull + default PacProcessor getPacProcessorForNetwork(long networkHandle) { + throw new UnsupportedOperationException("Not implemented"); + } + + /** * Gets the classloader used to load internal WebView implementation classes. This interface * should only be used by the WebView Support Library. */ diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 844e929774a1..10887fabb5c7 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -11575,6 +11575,9 @@ package android.webkit { public interface PacProcessor { method @Nullable public String findProxyForUrl(@NonNull String); method @NonNull public static android.webkit.PacProcessor getInstance(); + method @NonNull public static android.webkit.PacProcessor getInstanceForNetwork(long); + method public default long getNetworkHandle(); + method public default void releasePacProcessor(); method public boolean setProxyScript(@NonNull String); } @@ -11714,6 +11717,7 @@ package android.webkit { method public android.webkit.CookieManager getCookieManager(); method public android.webkit.GeolocationPermissions getGeolocationPermissions(); method @NonNull public default android.webkit.PacProcessor getPacProcessor(); + method @NonNull public default android.webkit.PacProcessor getPacProcessorForNetwork(long); method public android.webkit.ServiceWorkerController getServiceWorkerController(); method public android.webkit.WebViewFactoryProvider.Statics getStatics(); method @Deprecated public android.webkit.TokenBindingService getTokenBindingService(); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java index 5dcb9de4755e..a2cd0446d1e8 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/sideloaded/SideLoadedAppDetector.java @@ -39,7 +39,7 @@ import javax.inject.Singleton; /** * A class that detects unsafe apps. - * An app is considered safe if is a system app or installed through whitelisted sources. + * An app is considered safe if is a system app or installed through allowed sources. */ @Singleton public class SideLoadedAppDetector { diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/PrimarySwitchController.java index a12aa83e9d4b..a08f566b8375 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/MasterSwitchController.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/PrimarySwitchController.java @@ -19,9 +19,9 @@ package com.android.settingslib.drawer; import android.os.Bundle; /** - * A controller that manages event for master switch. + * A controller that manages event for Primary switch. */ -public abstract class MasterSwitchController extends SwitchController { +public abstract class PrimarySwitchController extends SwitchController { @Override protected final MetaData getMetaData() { diff --git a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java index 73f1a904b04b..f2b3e30dc252 100644 --- a/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java +++ b/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java @@ -88,7 +88,7 @@ public abstract class SwitchesProvider extends ContentProvider { controller.setAuthority(mAuthority); mControllerMap.put(key, controller); - if (!(controller instanceof MasterSwitchController)) { + if (!(controller instanceof PrimarySwitchController)) { mSwitchDataList.add(controller.getBundle()); } }); @@ -116,7 +116,7 @@ public abstract class SwitchesProvider extends ContentProvider { switch (method) { case METHOD_GET_SWITCH_DATA: - if (!(controller instanceof MasterSwitchController)) { + if (!(controller instanceof PrimarySwitchController)) { return controller.getBundle(); } break; diff --git a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java index f757aa4e4dab..b29595eab5c7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java @@ -24,7 +24,7 @@ import androidx.preference.PreferenceScreen; import com.android.settingslib.core.AbstractPreferenceController; /** - * This controller is used handle changes for the master switch in the developer options page. + * This controller is used handle changes for the primary switch in the developer options page. * * All Preference Controllers that are a part of the developer options page should inherit this * class. diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java index 3c647a7ec465..c501b3aab4d4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerAllowlistBackend.java @@ -34,44 +34,50 @@ import com.android.internal.telephony.SmsApplication; import com.android.internal.util.ArrayUtils; /** - * Handles getting/changing the whitelist for the exceptions to battery saving features. + * Handles getting/changing the allowlist for the exceptions to battery saving features. */ -public class PowerWhitelistBackend { +public class PowerAllowlistBackend { - private static final String TAG = "PowerWhitelistBackend"; + private static final String TAG = "PowerAllowlistBackend"; private static final String DEVICE_IDLE_SERVICE = "deviceidle"; - private static PowerWhitelistBackend sInstance; + private static PowerAllowlistBackend sInstance; private final Context mAppContext; private final IDeviceIdleController mDeviceIdleService; - private final ArraySet<String> mWhitelistedApps = new ArraySet<>(); - private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>(); + private final ArraySet<String> mAllowlistedApps = new ArraySet<>(); + private final ArraySet<String> mSysAllowlistedApps = new ArraySet<>(); private final ArraySet<String> mDefaultActiveApps = new ArraySet<>(); - public PowerWhitelistBackend(Context context) { + public PowerAllowlistBackend(Context context) { this(context, IDeviceIdleController.Stub.asInterface( ServiceManager.getService(DEVICE_IDLE_SERVICE))); } @VisibleForTesting - PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService) { + PowerAllowlistBackend(Context context, IDeviceIdleController deviceIdleService) { mAppContext = context.getApplicationContext(); mDeviceIdleService = deviceIdleService; refreshList(); } - public int getWhitelistSize() { - return mWhitelistedApps.size(); + public int getAllowlistSize() { + return mAllowlistedApps.size(); } - public boolean isSysWhitelisted(String pkg) { - return mSysWhitelistedApps.contains(pkg); + /** + * Check if target package is in System allow list + */ + public boolean isSysAllowlisted(String pkg) { + return mSysAllowlistedApps.contains(pkg); } - public boolean isWhitelisted(String pkg) { - if (mWhitelistedApps.contains(pkg)) { + /** + * Check if target package is in allow list + */ + public boolean isAllowlisted(String pkg) { + if (mAllowlistedApps.contains(pkg)) { return true; } @@ -87,7 +93,7 @@ public class PowerWhitelistBackend { */ public boolean isDefaultActiveApp(String pkg) { // Additionally, check if pkg is default dialer/sms. They are considered essential apps and - // should be automatically whitelisted (otherwise user may be able to set restriction on + // should be automatically allowlisted (otherwise user may be able to set restriction on // them, leading to bad device behavior.) if (mDefaultActiveApps.contains(pkg)) { @@ -103,12 +109,17 @@ public class PowerWhitelistBackend { return false; } - public boolean isWhitelisted(String[] pkgs) { + /** + * + * @param pkgs a list of packageName + * @return true when one of package is in allow list + */ + public boolean isAllowlisted(String[] pkgs) { if (ArrayUtils.isEmpty(pkgs)) { return false; } for (String pkg : pkgs) { - if (isWhitelisted(pkg)) { + if (isAllowlisted(pkg)) { return true; } } @@ -116,40 +127,51 @@ public class PowerWhitelistBackend { return false; } + /** + * Add app into power save allow list. + * @param pkg packageName + */ public void addApp(String pkg) { try { mDeviceIdleService.addPowerSaveWhitelistApp(pkg); - mWhitelistedApps.add(pkg); + mAllowlistedApps.add(pkg); } catch (RemoteException e) { Log.w(TAG, "Unable to reach IDeviceIdleController", e); } } + /** + * Remove package from power save allow list. + * @param pkg + */ public void removeApp(String pkg) { try { mDeviceIdleService.removePowerSaveWhitelistApp(pkg); - mWhitelistedApps.remove(pkg); + mAllowlistedApps.remove(pkg); } catch (RemoteException e) { Log.w(TAG, "Unable to reach IDeviceIdleController", e); } } + /** + * Refresh all of lists + */ @VisibleForTesting public void refreshList() { - mSysWhitelistedApps.clear(); - mWhitelistedApps.clear(); + mSysAllowlistedApps.clear(); + mAllowlistedApps.clear(); mDefaultActiveApps.clear(); if (mDeviceIdleService == null) { return; } try { - final String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist(); - for (String app : whitelistedApps) { - mWhitelistedApps.add(app); + final String[] allowlistedApps = mDeviceIdleService.getFullPowerWhitelist(); + for (String app : allowlistedApps) { + mAllowlistedApps.add(app); } - final String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist(); - for (String app : sysWhitelistedApps) { - mSysWhitelistedApps.add(app); + final String[] sysAllowlistedApps = mDeviceIdleService.getSystemPowerWhitelist(); + for (String app : sysAllowlistedApps) { + mSysAllowlistedApps.add(app); } final boolean hasTelephony = mAppContext.getPackageManager().hasSystemFeature( PackageManager.FEATURE_TELEPHONY); @@ -171,9 +193,13 @@ public class PowerWhitelistBackend { } } - public static PowerWhitelistBackend getInstance(Context context) { + /** + * @param context + * @return a PowerAllowlistBackend object + */ + public static PowerAllowlistBackend getInstance(Context context) { if (sInstance == null) { - sInstance = new PowerWhitelistBackend(context); + sInstance = new PowerAllowlistBackend(context); } return sInstance; } diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java index 4941f7e42bf6..8ac434957cd9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java @@ -135,7 +135,7 @@ public class AppRestrictionsHelper { // Ignore } } else { - // Blacklist all other apps, system or downloaded + // Denylist all other apps, system or downloaded try { ApplicationInfo info = mIPm.getApplicationInfo(packageName, 0, userId); if (info != null) { @@ -258,11 +258,11 @@ public class AppRestrictionsHelper { } } - // Establish master/slave relationship for entries that share a package name + // Establish primary/secondary relationship for entries that share a package name HashMap<String,SelectableAppInfo> packageMap = new HashMap<String,SelectableAppInfo>(); for (SelectableAppInfo info : mVisibleApps) { if (packageMap.containsKey(info.packageName)) { - info.masterEntry = packageMap.get(info.packageName); + info.primaryEntry = packageMap.get(info.packageName); } else { packageMap.put(info.packageName, info); } @@ -366,12 +366,12 @@ public class AppRestrictionsHelper { public CharSequence appName; public CharSequence activityName; public Drawable icon; - public SelectableAppInfo masterEntry; + public SelectableAppInfo primaryEntry; @Override public String toString() { return packageName + ": appName=" + appName + "; activityName=" + activityName - + "; icon=" + icon + "; masterEntry=" + masterEntry; + + "; icon=" + icon + "; primaryEntry=" + primaryEntry; } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java index 11c799ea9df5..94e28f2b5e22 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java @@ -290,12 +290,12 @@ public class RestrictedLockUtilsTest { @Test public void sendShowAdminSupportDetailsIntent_extraRestrictionProvided() { EnforcedAdmin enforcedAdmin = new EnforcedAdmin(); - enforcedAdmin.enforcedRestriction = "Dummy"; + enforcedAdmin.enforcedRestriction = "Fake"; RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, enforcedAdmin); ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class); verify(mContext).startActivityAsUser(intentCaptor.capture(), any()); - assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isEqualTo("Dummy"); + assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isEqualTo("Fake"); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/PrimarySwitchControllerTest.java index 69d0f2e71c17..9e4cde866ef2 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/MasterSwitchControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/PrimarySwitchControllerTest.java @@ -23,16 +23,16 @@ import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) -public class MasterSwitchControllerTest { +public class PrimarySwitchControllerTest { @Rule public final ExpectedException thrown = ExpectedException.none(); - private MasterSwitchController mController; + private PrimarySwitchController mController; @Before public void setUp() { - mController = new TestMasterSwitchController("123"); + mController = new TestPrimarySwitchController("123"); } @Test @@ -49,11 +49,11 @@ public class MasterSwitchControllerTest { mController.getBundle(); } - static class TestMasterSwitchController extends MasterSwitchController { + static class TestPrimarySwitchController extends PrimarySwitchController { private String mKey; - TestMasterSwitchController(String key) { + TestPrimarySwitchController(String key) { mKey = key; } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java index a740e683642a..bd0100b67a94 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/SwitchesProviderTest.java @@ -35,7 +35,7 @@ import android.content.Context; import android.content.pm.ProviderInfo; import android.os.Bundle; -import com.android.settingslib.drawer.MasterSwitchControllerTest.TestMasterSwitchController; +import com.android.settingslib.drawer.PrimarySwitchControllerTest.TestPrimarySwitchController; import com.android.settingslib.drawer.SwitchController.MetaData; import org.junit.Before; @@ -124,8 +124,8 @@ public class SwitchesProviderTest { } @Test - public void getSwitchData_shouldNotReturnMasterSwitchData() { - final SwitchController controller = new TestMasterSwitchController("123"); + public void getSwitchData_shouldNotReturnPrimarySwitchData() { + final SwitchController controller = new TestPrimarySwitchController("123"); mSwitchesProvider.addSwitchController(controller); mSwitchesProvider.attachInfo(mContext, mProviderInfo); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java index 20908925feff..4f11fb1f782f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerAllowlistBackendTest.java @@ -47,7 +47,7 @@ import org.robolectric.shadows.ShadowPackageManager; @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class}) -public class PowerWhitelistBackendTest { +public class PowerAllowlistBackendTest { private static final String PACKAGE_ONE = "com.example.packageone"; private static final String PACKAGE_TWO = "com.example.packagetwo"; @@ -56,7 +56,7 @@ public class PowerWhitelistBackendTest { private IDeviceIdleController mDeviceIdleService; @Mock private DevicePolicyManager mDevicePolicyManager; - private PowerWhitelistBackend mPowerWhitelistBackend; + private PowerAllowlistBackend mPowerAllowlistBackend; private ShadowPackageManager mPackageManager; private Context mContext; @@ -74,81 +74,81 @@ public class PowerWhitelistBackendTest { mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true); doReturn(mDevicePolicyManager).when(mContext).getSystemService(DevicePolicyManager.class); - mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService); + mPowerAllowlistBackend = new PowerAllowlistBackend(mContext, mDeviceIdleService); } @Test - public void testIsWhitelisted() throws Exception { + public void testIsAllowlisted() throws Exception { doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getFullPowerWhitelist(); - mPowerWhitelistBackend.refreshList(); + mPowerAllowlistBackend.refreshList(); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse(); - assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue(); - assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse(); + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse(); + assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE})).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO})).isFalse(); - mPowerWhitelistBackend.addApp(PACKAGE_TWO); + mPowerAllowlistBackend.addApp(PACKAGE_TWO); verify(mDeviceIdleService, atLeastOnce()).addPowerSaveWhitelistApp(PACKAGE_TWO); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue(); - assertThat(mPowerWhitelistBackend.isWhitelisted( + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted( new String[] {PACKAGE_ONE, PACKAGE_TWO})).isTrue(); - mPowerWhitelistBackend.removeApp(PACKAGE_TWO); + mPowerAllowlistBackend.removeApp(PACKAGE_TWO); verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse(); - assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue(); - assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse(); + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse(); + assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_ONE})).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted(new String[] {PACKAGE_TWO})).isFalse(); - mPowerWhitelistBackend.removeApp(PACKAGE_ONE); + mPowerAllowlistBackend.removeApp(PACKAGE_ONE); verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_ONE); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse(); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse(); - assertThat(mPowerWhitelistBackend.isWhitelisted( + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isFalse(); + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_TWO)).isFalse(); + assertThat(mPowerAllowlistBackend.isAllowlisted( new String[] {PACKAGE_ONE, PACKAGE_TWO})).isFalse(); } @Test - public void isWhitelisted_shouldWhitelistDefaultSms() { + public void isAllowlisted_shouldAllowlistDefaultSms() { final String testSms = "com.android.test.defaultsms"; ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver")); - mPowerWhitelistBackend.refreshList(); + mPowerAllowlistBackend.refreshList(); - assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue(); - assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testSms)).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted(testSms)).isTrue(); + assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testSms)).isTrue(); } @Test - public void isWhitelisted_shouldWhitelistDefaultDialer() { + public void isAllowlisted_shouldAllowlistDefaultDialer() { final String testDialer = "com.android.test.defaultdialer"; ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer); - mPowerWhitelistBackend.refreshList(); + mPowerAllowlistBackend.refreshList(); - assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue(); - assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testDialer)).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted(testDialer)).isTrue(); + assertThat(mPowerAllowlistBackend.isDefaultActiveApp(testDialer)).isTrue(); } @Test - public void isWhitelisted_shouldWhitelistActiveDeviceAdminApp() { + public void isAllowlisted_shouldAllowlistActiveDeviceAdminApp() { doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue(); - assertThat(mPowerWhitelistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue(); + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isTrue(); + assertThat(mPowerAllowlistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue(); } @Test - public void testIsSystemWhitelisted() throws Exception { + public void testIsSystemAllowlisted() throws Exception { doReturn(new String[] {PACKAGE_ONE}).when(mDeviceIdleService).getSystemPowerWhitelist(); - mPowerWhitelistBackend.refreshList(); + mPowerAllowlistBackend.refreshList(); - assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_ONE)).isTrue(); - assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_TWO)).isFalse(); - assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse(); + assertThat(mPowerAllowlistBackend.isSysAllowlisted(PACKAGE_ONE)).isTrue(); + assertThat(mPowerAllowlistBackend.isSysAllowlisted(PACKAGE_TWO)).isFalse(); + assertThat(mPowerAllowlistBackend.isAllowlisted(PACKAGE_ONE)).isFalse(); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java index b930aa6ee1bd..84d722ad16df 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompatTest.java @@ -197,61 +197,61 @@ public class InputMethodAndSubtypeUtilCompatTest { public void isValidSystemNonAuxAsciiCapableIme() { // System IME w/ no subtype assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( - createDummyIme(true, false))) + createFakeIme(true, false))) .isFalse(); // System IME w/ non-Aux and non-ASCII-capable "keyboard" subtype assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( - createDummyIme(true, false, createDummySubtype("keyboard", false, false)))) + createFakeIme(true, false, createFakeSubtype("keyboard", false, false)))) .isFalse(); // System IME w/ non-Aux and ASCII-capable "keyboard" subtype assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( - createDummyIme(true, false, createDummySubtype("keyboard", false, true)))) + createFakeIme(true, false, createFakeSubtype("keyboard", false, true)))) .isTrue(); // System IME w/ Aux and ASCII-capable "keyboard" subtype assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( - createDummyIme(true, true, createDummySubtype("keyboard", true, true)))) + createFakeIme(true, true, createFakeSubtype("keyboard", true, true)))) .isFalse(); // System IME w/ non-Aux and ASCII-capable "voice" subtype assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( - createDummyIme(true, false, createDummySubtype("voice", false, true)))) + createFakeIme(true, false, createFakeSubtype("voice", false, true)))) .isFalse(); // System IME w/ non-Aux and non-ASCII-capable subtype + Non-Aux and ASCII-capable subtype assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( - createDummyIme(true, false, - createDummySubtype("keyboard", false, true), - createDummySubtype("keyboard", false, false)))) + createFakeIme(true, false, + createFakeSubtype("keyboard", false, true), + createFakeSubtype("keyboard", false, false)))) .isTrue(); // Non-system IME w/ non-Aux and ASCII-capable "keyboard" subtype assertThat(InputMethodAndSubtypeUtilCompat.isValidSystemNonAuxAsciiCapableIme( - createDummyIme(false, false, createDummySubtype("keyboard", false, true)))) + createFakeIme(false, false, createFakeSubtype("keyboard", false, true)))) .isFalse(); } - private static InputMethodInfo createDummyIme(boolean isSystem, boolean isAuxIme, + private static InputMethodInfo createFakeIme(boolean isSystem, boolean isAuxIme, InputMethodSubtype... subtypes) { final ResolveInfo ri = new ResolveInfo(); final ServiceInfo si = new ServiceInfo(); final ApplicationInfo ai = new ApplicationInfo(); - ai.packageName = "com.example.android.dummyime"; + ai.packageName = "com.example.android.fakeime"; ai.enabled = true; ai.flags |= (isSystem ? ApplicationInfo.FLAG_SYSTEM : 0); si.applicationInfo = ai; si.enabled = true; - si.packageName = "com.example.android.dummyime"; - si.name = "Dummy IME"; + si.packageName = "com.example.android.fakeime"; + si.name = "Fake IME"; si.exported = true; - si.nonLocalizedLabel = "Dummy IME"; + si.nonLocalizedLabel = "Fake IME"; ri.serviceInfo = si; return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false); } - private static InputMethodSubtype createDummySubtype( + private static InputMethodSubtype createFakeSubtype( String mode, boolean isAuxiliary, boolean isAsciiCapable) { return new InputMethodSubtypeBuilder() .setSubtypeNameResId(0) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java index 5171dda9bff7..97d87051402e 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilTest.java @@ -195,55 +195,55 @@ public class InputMethodAndSubtypeUtilTest { public void isValidNonAuxAsciiCapableIme() { // IME w/ no subtype assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme( - createDummyIme(false))) + createFakeIme(false))) .isFalse(); // IME w/ non-Aux and non-ASCII-capable "keyboard" subtype assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme( - createDummyIme(false, createDummySubtype("keyboard", false, false)))) + createFakeIme(false, createFakeSubtype("keyboard", false, false)))) .isFalse(); // IME w/ non-Aux and ASCII-capable "keyboard" subtype assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme( - createDummyIme(false, createDummySubtype("keyboard", false, true)))) + createFakeIme(false, createFakeSubtype("keyboard", false, true)))) .isTrue(); // IME w/ Aux and ASCII-capable "keyboard" subtype assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme( - createDummyIme(true, createDummySubtype("keyboard", true, true)))) + createFakeIme(true, createFakeSubtype("keyboard", true, true)))) .isFalse(); // IME w/ non-Aux and ASCII-capable "voice" subtype assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme( - createDummyIme(false, createDummySubtype("voice", false, true)))) + createFakeIme(false, createFakeSubtype("voice", false, true)))) .isFalse(); // IME w/ non-Aux and non-ASCII-capable subtype + Non-Aux and ASCII-capable subtype assertThat(InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme( - createDummyIme(false, - createDummySubtype("keyboard", false, true), - createDummySubtype("keyboard", false, false)))) + createFakeIme(false, + createFakeSubtype("keyboard", false, true), + createFakeSubtype("keyboard", false, false)))) .isTrue(); } - private static InputMethodInfo createDummyIme(boolean isAuxIme, + private static InputMethodInfo createFakeIme(boolean isAuxIme, InputMethodSubtype... subtypes) { final ResolveInfo ri = new ResolveInfo(); final ServiceInfo si = new ServiceInfo(); final ApplicationInfo ai = new ApplicationInfo(); - ai.packageName = "com.example.android.dummyime"; + ai.packageName = "com.example.android.fakeime"; ai.enabled = true; si.applicationInfo = ai; si.enabled = true; - si.packageName = "com.example.android.dummyime"; - si.name = "Dummy IME"; + si.packageName = "com.example.android.fakeime"; + si.name = "Fake IME"; si.exported = true; - si.nonLocalizedLabel = "Dummy IME"; + si.nonLocalizedLabel = "Fake IME"; ri.serviceInfo = si; return new InputMethodInfo(ri, isAuxIme, "", Arrays.asList(subtypes), 1, false); } - private static InputMethodSubtype createDummySubtype( + private static InputMethodSubtype createFakeSubtype( String mode, boolean isAuxiliary, boolean isAsciiCapable) { return new InputMethodSubtypeBuilder() .setSubtypeNameResId(0) diff --git a/packages/SimAppDialog/Android.bp b/packages/SimAppDialog/Android.bp index 176035f73b65..1c680bb9d25e 100644 --- a/packages/SimAppDialog/Android.bp +++ b/packages/SimAppDialog/Android.bp @@ -7,7 +7,8 @@ android_app { static_libs: [ "androidx.legacy_legacy-support-v4", - "setup-wizard-lib", + "setupcompat", + "setupdesign", ], resource_dirs: ["res"], diff --git a/packages/SimAppDialog/AndroidManifest.xml b/packages/SimAppDialog/AndroidManifest.xml index 873f6c5bac54..e7368f35ed5a 100644 --- a/packages/SimAppDialog/AndroidManifest.xml +++ b/packages/SimAppDialog/AndroidManifest.xml @@ -23,7 +23,7 @@ android:name=".InstallCarrierAppActivity" android:exported="true" android:permission="android.permission.NETWORK_SETTINGS" - android:theme="@style/SuwThemeGlif.Light"> + android:theme="@style/SudThemeGlif.Light"> </activity> </application> </manifest> diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml index 12f9bb6b13ea..68113dbf5df0 100644 --- a/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml +++ b/packages/SimAppDialog/res/layout/install_carrier_app_activity.xml @@ -14,18 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. --> -<com.android.setupwizardlib.GlifLayout +<com.google.android.setupdesign.GlifLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/setup_wizard_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:icon="@drawable/ic_signal_cellular_alt_rounded" - app:suwHeaderText="@string/install_carrier_app_title" - app:suwFooter="@layout/install_carrier_app_footer"> + app:sucHeaderText="@string/install_carrier_app_title"> <LinearLayout - style="@style/SuwContentFrame" + style="@style/SudContentFrame" android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -33,12 +32,12 @@ <TextView android:id="@+id/install_carrier_app_description" - style="@style/SuwDescription.Glif" + style="@style/SudDescription.Glif" android:text="@string/install_carrier_app_description_default" android:layout_width="match_parent" android:layout_height="wrap_content"/> - <com.android.setupwizardlib.view.FillContentLayout + <com.google.android.setupdesign.view.FillContentLayout android:id="@+id/illo_container" android:layout_width="match_parent" android:layout_height="wrap_content" @@ -47,12 +46,12 @@ <ImageView android:src="@drawable/illo_sim_app_dialog" - style="@style/SuwContentIllustration" + style="@style/SudContentIllustration" android:contentDescription="@string/install_carrier_app_image_content_description" android:layout_width="match_parent" android:layout_height="match_parent"/> - </com.android.setupwizardlib.view.FillContentLayout> -</LinearLayout> + </com.google.android.setupdesign.view.FillContentLayout> + </LinearLayout> -</com.android.setupwizardlib.GlifLayout> +</com.google.android.setupdesign.GlifLayout> diff --git a/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml b/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml deleted file mode 100644 index 10dcb77a6584..000000000000 --- a/packages/SimAppDialog/res/layout/install_carrier_app_footer.xml +++ /dev/null @@ -1,43 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - Copyright (C) 2018 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. ---> - -<com.android.setupwizardlib.view.ButtonBarLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/footer" - style="@style/SuwGlifButtonBar.Stackable" - android:layout_width="match_parent" - android:layout_height="wrap_content"> - - <Button - android:id="@+id/skip_button" - style="@style/SuwGlifButton.Secondary" - android:text="@string/install_carrier_app_defer_action" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - - <Space - android:layout_width="0dp" - android:layout_height="0dp" - android:layout_weight="1"/> - - <Button - android:id="@+id/download_button" - style="@style/SuwGlifButton.Primary" - android:text="@string/install_carrier_app_download_action" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> -</com.android.setupwizardlib.view.ButtonBarLayout> diff --git a/packages/SimAppDialog/res/values/styles.xml b/packages/SimAppDialog/res/values/styles.xml new file mode 100644 index 000000000000..824e3802aca1 --- /dev/null +++ b/packages/SimAppDialog/res/values/styles.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2020 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. +--> +<resources> + + <style name="SetupWizardPartnerResource"> + <!-- Disable to use partner overlay theme for outside setupwizard flow. --> + <item name="sucUsePartnerResource">false</item> + <!-- Enable heavy theme style inside setupwizard flow. --> + <item name="sudUsePartnerHeavyTheme">true</item> + </style> + +</resources> diff --git a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java index abe82a885a94..0b6f9bb4f9e0 100644 --- a/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java +++ b/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java @@ -17,14 +17,17 @@ package com.android.simappdialog; import android.app.Activity; import android.content.Intent; +import android.content.res.Resources; import android.os.Bundle; import android.sysprop.SetupWizardProperties; import android.text.TextUtils; import android.view.View; -import android.widget.Button; import android.widget.TextView; -import com.android.setupwizardlib.util.WizardManagerHelper; +import com.google.android.setupcompat.template.FooterBarMixin; +import com.google.android.setupcompat.template.FooterButton; +import com.google.android.setupdesign.GlifLayout; +import com.google.android.setupdesign.util.ThemeResolver; /** * Activity that gives a user the choice to download the SIM app or defer until a later time @@ -35,7 +38,7 @@ import com.android.setupwizardlib.util.WizardManagerHelper; * Can display the carrier app name if its passed into the intent with key * {@link #BUNDLE_KEY_CARRIER_NAME} */ -public class InstallCarrierAppActivity extends Activity implements View.OnClickListener { +public class InstallCarrierAppActivity extends Activity { /** * Key for the carrier app name that will be displayed as the app to download. If unset, a * default description will be used @@ -50,20 +53,33 @@ public class InstallCarrierAppActivity extends Activity implements View.OnClickL protected void onCreate(Bundle icicle) { // Setup theme for aosp/pixel setTheme( - WizardManagerHelper.getThemeRes( - SetupWizardProperties.theme().orElse(""), - R.style.SuwThemeGlif_Light - ) - ); + new ThemeResolver.Builder() + .setDefaultTheme(R.style.SudThemeGlifV3_Light) + .build() + .resolve(SetupWizardProperties.theme().orElse(""), + /* suppressDayNight= */ false)); super.onCreate(icicle); setContentView(R.layout.install_carrier_app_activity); - Button notNowButton = findViewById(R.id.skip_button); - notNowButton.setOnClickListener(this); + GlifLayout layout = findViewById(R.id.setup_wizard_layout); + FooterBarMixin mixin = layout.getMixin(FooterBarMixin.class); + mixin.setSecondaryButton( + new FooterButton.Builder(this) + .setText(R.string.install_carrier_app_defer_action) + .setListener(this::onSkipButtonClick) + .setButtonType(FooterButton.ButtonType.SKIP) + .setTheme(R.style.SudGlifButton_Secondary) + .build()); + + mixin.setPrimaryButton( + new FooterButton.Builder(this) + .setText(R.string.install_carrier_app_download_action) + .setListener(this::onDownloadButtonClick) + .setButtonType(FooterButton.ButtonType.OTHER) + .setTheme(R.style.SudGlifButton_Primary) + .build()); - Button downloadButton = findViewById(R.id.download_button); - downloadButton.setOnClickListener(this); // Show/hide illo depending on whether one was provided in a resource overlay boolean showIllo = getResources().getBoolean(R.bool.show_sim_app_dialog_illo); @@ -82,15 +98,17 @@ public class InstallCarrierAppActivity extends Activity implements View.OnClickL } @Override - public void onClick(View v) { - switch (v.getId()) { - case R.id.skip_button: - finish(DEFER_RESULT); - break; - case R.id.download_button: - finish(DOWNLOAD_RESULT); - break; - } + protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { + theme.applyStyle(R.style.SetupWizardPartnerResource, true); + super.onApplyThemeResource(theme, resid, first); + } + + protected void onSkipButtonClick(View view) { + finish(DEFER_RESULT); + } + + protected void onDownloadButtonClick(View view) { + finish(DOWNLOAD_RESULT); } private void finish(int resultCode) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index d0f61817d1cc..fa0d2ba84b4e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -310,7 +310,6 @@ public class BubbleExpandedView extends LinearLayout { // Set ActivityView's alpha value as zero, since there is no view content to be shown. setContentVisibility(false); - mActivityViewContainer.setBackgroundColor(Color.WHITE); mActivityViewContainer.setOutlineProvider(new ViewOutlineProvider() { @Override public void getOutline(View view, Outline outline) { @@ -439,9 +438,11 @@ public class BubbleExpandedView extends LinearLayout { } void applyThemeAttrs() { - final TypedArray ta = mContext.obtainStyledAttributes( - new int[] {android.R.attr.dialogCornerRadius}); + final TypedArray ta = mContext.obtainStyledAttributes(new int[] { + android.R.attr.dialogCornerRadius, + android.R.attr.colorBackgroundFloating}); mCornerRadius = ta.getDimensionPixelSize(0, 0); + mActivityViewContainer.setBackgroundColor(ta.getColor(1, Color.WHITE)); ta.recycle(); if (mActivityView != null && ScreenDecorationsUtils.supportsRoundedCornersOnWindows( diff --git a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java index 8a67da53e6a2..b28730d004f6 100644 --- a/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java +++ b/packages/SystemUI/src/com/android/systemui/onehanded/OneHandedTutorialHandler.java @@ -16,11 +16,13 @@ package com.android.systemui.onehanded; +import android.content.ContentResolver; import android.content.Context; import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.Rect; import android.os.Handler; +import android.provider.Settings; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -48,12 +50,15 @@ import javax.inject.Singleton; @Singleton public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Dumpable { private static final String TAG = "OneHandedTutorialHandler"; + private static final int MAX_TUTORIAL_SHOW_COUNT = 2; private final Rect mLastUpdatedBounds = new Rect(); private final WindowManager mWindowManager; private View mTutorialView; private Point mDisplaySize = new Point(); private Handler mUpdateHandler; + private ContentResolver mContentResolver; + private boolean mCanShowTutorial; /** * Container of the tutorial panel showing at outside region when one handed starting @@ -71,6 +76,7 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du @Inject public OneHandedTutorialHandler(Context context) { context.getDisplay().getRealSize(mDisplaySize); + mContentResolver = context.getContentResolver(); mUpdateHandler = new Handler(); mWindowManager = context.getSystemService(WindowManager.class); mTargetViewContainer = new FrameLayout(context); @@ -79,12 +85,20 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du R.fraction.config_one_handed_offset, 1, 1)); mTutorialView = LayoutInflater.from(context).inflate(R.xml.one_handed_tutorial, null); mTargetViewContainer.addView(mTutorialView); - createOrUpdateTutorialTarget(); + mCanShowTutorial = (Settings.Secure.getInt(mContentResolver, + Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0) >= MAX_TUTORIAL_SHOW_COUNT) + ? false : true; + if (mCanShowTutorial) { + createOrUpdateTutorialTarget(); + } } @Override public void onStartFinished(Rect bounds) { - mUpdateHandler.post(() -> updateFinished(View.VISIBLE, 0f)); + mUpdateHandler.post(() -> { + updateFinished(View.VISIBLE, 0f); + updateTutorialCount(); + }); } @Override @@ -94,10 +108,23 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du } private void updateFinished(int visible, float finalPosition) { + if (!canShowTutorial()) { + return; + } + mTargetViewContainer.setVisibility(visible); mTargetViewContainer.setTranslationY(finalPosition); } + private void updateTutorialCount() { + int showCount = Settings.Secure.getInt(mContentResolver, + Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, 0); + showCount = Math.min(MAX_TUTORIAL_SHOW_COUNT, showCount + 1); + mCanShowTutorial = showCount < MAX_TUTORIAL_SHOW_COUNT; + Settings.Secure.putInt(mContentResolver, + Settings.Secure.ONE_HANDED_TUTORIAL_SHOW_COUNT, showCount); + } + /** * Adds the tutorial target view to the WindowManager and update its layout, so it's ready * to be animated in. @@ -153,7 +180,19 @@ public class OneHandedTutorialHandler implements OneHandedTransitionCallback, Du pw.println(mLastUpdatedBounds); } + private boolean canShowTutorial() { + if (!mCanShowTutorial) { + mTargetViewContainer.setVisibility(View.GONE); + return false; + } + + return true; + } + private void onAnimationUpdate(float value) { + if (!canShowTutorial()) { + return; + } mTargetViewContainer.setVisibility(View.VISIBLE); mTargetViewContainer.setTransitionGroup(true); mTargetViewContainer.setTranslationY(value - mTargetViewContainer.getHeight()); diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java index 3264429a1723..d8548decc5f4 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java @@ -67,7 +67,7 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements private static final String PATTERN_HOUR_MINUTE = "h:mm a"; private static final String PATTERN_HOUR_NINUTE_24 = "HH:mm"; - private final ColorDisplayManager mManager; + private ColorDisplayManager mManager; private final LocationController mLocationController; private final NightDisplayListenerModule.Builder mNightDisplayListenerBuilder; private NightDisplayListener mListener; @@ -126,6 +126,8 @@ public class NightDisplayTile extends QSTileImpl<BooleanState> implements mListener.setCallback(null); } + mManager = getHost().getUserContext().getSystemService(ColorDisplayManager.class); + // Make a new controller for the new user. mListener = mNightDisplayListenerBuilder.setUser(newUserId).build(); if (mIsListening) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java index 07b841ffb6f7..78975a4798ce 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java @@ -58,10 +58,9 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements public static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm a"); private final Icon mIcon = ResourceIcon.get( com.android.internal.R.drawable.ic_qs_ui_mode_night); - private final UiModeManager mUiModeManager; + private UiModeManager mUiModeManager; private final BatteryController mBatteryController; private final LocationController mLocationController; - @Inject public UiModeNightTile( QSHost host, @@ -78,7 +77,7 @@ public class UiModeNightTile extends QSTileImpl<QSTile.BooleanState> implements super(host, backgroundLooper, mainHandler, metricsLogger, statusBarStateController, activityStarter, qsLogger); mBatteryController = batteryController; - mUiModeManager = mContext.getSystemService(UiModeManager.class); + mUiModeManager = host.getUserContext().getSystemService(UiModeManager.class); mLocationController = locationController; configurationController.observe(getLifecycle(), this); batteryController.observe(getLifecycle(), this); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java index 4007abb39903..d40b666860e9 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java @@ -78,6 +78,22 @@ public class Divider extends SystemUI { onUndockingTask(); } } + + @Override + public void onActivityForcedResizable(String packageName, int taskId, + int reason) { + mDividerController.onActivityForcedResizable(packageName, taskId, reason); + } + + @Override + public void onActivityDismissingDockedStack() { + mDividerController.onActivityDismissingSplitScreen(); + } + + @Override + public void onActivityLaunchOnSecondaryDisplayFailed() { + mDividerController.onActivityLaunchOnSecondaryDisplayFailed(); + } } ); } diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java index 81649f608581..1ee8abb411b9 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerController.java @@ -50,8 +50,7 @@ import java.util.function.Consumer; /** * Controls the docked stack divider. */ -public class DividerController implements DividerView.DividerCallbacks, - DisplayController.OnDisplaysChangedListener { +public class DividerController implements DisplayController.OnDisplaysChangedListener { static final boolean DEBUG = false; private static final String TAG = "Divider"; @@ -257,8 +256,8 @@ public class DividerController implements DividerView.DividerCallbacks, mView = (DividerView) LayoutInflater.from(dctx).inflate(R.layout.docked_stack_divider, null); DisplayLayout displayLayout = mDisplayController.getDisplayLayout(mContext.getDisplayId()); - mView.injectDependencies(mWindowManager, mDividerState, this, mSplits, mSplitLayout, - mImePositionProcessor, mWindowManagerProxy); + mView.injectDependencies(mWindowManager, mDividerState, mForcedResizableController, mSplits, + mSplitLayout, mImePositionProcessor, mWindowManagerProxy); mView.setVisibility(mVisible ? View.VISIBLE : View.INVISIBLE); mView.setMinimizedDockStack(mMinimized, mHomeStackResizable, null /* transaction */); final int size = dctx.getResources().getDimensionPixelSize( @@ -397,7 +396,22 @@ public class DividerController implements DividerView.DividerCallbacks, } } - /** Called when there's a task undocking. */ + /** Called when there's an activity forced resizable. */ + public void onActivityForcedResizable(String packageName, int taskId, int reason) { + mForcedResizableController.activityForcedResizable(packageName, taskId, reason); + } + + /** Called when there's an activity dismissing split screen. */ + public void onActivityDismissingSplitScreen() { + mForcedResizableController.activityDismissingSplitScreen(); + } + + /** Called when there's an activity launch on secondary display failed. */ + public void onActivityLaunchOnSecondaryDisplayFailed() { + mForcedResizableController.activityLaunchOnSecondaryDisplayFailed(); + } + + /** Called when there's a task undocking. */ public void onUndockingTask() { if (mView != null) { mView.onUndockingTask(); @@ -426,17 +440,7 @@ public class DividerController implements DividerView.DividerCallbacks, mForcedResizableController.onAppTransitionFinished(); } - @Override - public void onDraggingStart() { - mForcedResizableController.onDraggingStart(); - } - - @Override - public void onDraggingEnd() { - mForcedResizableController.onDraggingEnd(); - } - - /** Dumps current status of Divider.*/ + /** Dumps current status of Split Screen. */ public void dump(PrintWriter pw) { pw.print(" mVisible="); pw.println(mVisible); pw.print(" mMinimized="); pw.println(mMinimized); diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java index f412cc00981b..ff8bab07db05 100644 --- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java @@ -28,15 +28,13 @@ import android.util.ArraySet; import android.widget.Toast; import com.android.systemui.R; -import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.function.Consumer; /** * Controller that decides when to show the {@link ForcedResizableInfoActivity}. */ -public class ForcedResizableInfoActivityController { +final class ForcedResizableInfoActivityController implements DividerView.DividerCallbacks { private static final String SELF_PACKAGE_NAME = "com.android.systemui"; @@ -47,12 +45,7 @@ public class ForcedResizableInfoActivityController { private final ArraySet<String> mPackagesShownInSession = new ArraySet<>(); private boolean mDividerDragging; - private final Runnable mTimeoutRunnable = new Runnable() { - @Override - public void run() { - showPending(); - } - }; + private final Runnable mTimeoutRunnable = this::showPending; private final Consumer<Boolean> mDockedStackExistsListener = exists -> { if (!exists) { @@ -78,44 +71,28 @@ public class ForcedResizableInfoActivityController { public ForcedResizableInfoActivityController(Context context, DividerController dividerController) { mContext = context; - ActivityManagerWrapper.getInstance().registerTaskStackListener( - new TaskStackChangeListener() { - @Override - public void onActivityForcedResizable(String packageName, int taskId, - int reason) { - activityForcedResizable(packageName, taskId, reason); - } - - @Override - public void onActivityDismissingDockedStack() { - activityDismissingDockedStack(); - } - - @Override - public void onActivityLaunchOnSecondaryDisplayFailed() { - activityLaunchOnSecondaryDisplayFailed(); - } - }); dividerController.registerInSplitScreenListener(mDockedStackExistsListener); } - public void onAppTransitionFinished() { - if (!mDividerDragging) { - showPending(); - } - } - - void onDraggingStart() { + @Override + public void onDraggingStart() { mDividerDragging = true; mHandler.removeCallbacks(mTimeoutRunnable); } - void onDraggingEnd() { + @Override + public void onDraggingEnd() { mDividerDragging = false; showPending(); } - private void activityForcedResizable(String packageName, int taskId, int reason) { + void onAppTransitionFinished() { + if (!mDividerDragging) { + showPending(); + } + } + + void activityForcedResizable(String packageName, int taskId, int reason) { if (debounce(packageName)) { return; } @@ -123,12 +100,12 @@ public class ForcedResizableInfoActivityController { postTimeout(); } - private void activityDismissingDockedStack() { + void activityDismissingSplitScreen() { Toast.makeText(mContext, R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT).show(); } - private void activityLaunchOnSecondaryDisplayFailed() { + void activityLaunchOnSecondaryDisplayFailed() { Toast.makeText(mContext, R.string.activity_launch_on_secondary_display_failed_text, Toast.LENGTH_SHORT).show(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 6297052550c3..8c5e2ceaeadf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -375,6 +375,34 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } }; + private static class NavBarViewAttachedListener implements View.OnAttachStateChangeListener { + private NavigationBarFragment mFragment; + private FragmentListener mListener; + + NavBarViewAttachedListener(NavigationBarFragment fragment, FragmentListener listener) { + mFragment = fragment; + mListener = listener; + } + + @Override + public void onViewAttachedToWindow(View v) { + final FragmentHostManager fragmentHost = FragmentHostManager.get(v); + fragmentHost.getFragmentManager().beginTransaction() + .replace(R.id.navigation_bar_frame, mFragment, TAG) + .commit(); + fragmentHost.addTagListener(TAG, mListener); + mFragment = null; + } + + @Override + public void onViewDetachedFromWindow(View v) { + final FragmentHostManager fragmentHost = FragmentHostManager.get(v); + fragmentHost.removeTagListener(TAG, mListener); + FragmentHostManager.removeAndDestroy(v); + v.removeOnAttachStateChangeListener(this); + } + } + private final DeviceConfig.OnPropertiesChangedListener mOnPropertiesChangedListener = new DeviceConfig.OnPropertiesChangedListener() { @Override @@ -1470,26 +1498,10 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView); if (navigationBarView == null) return null; - navigationBarView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(View v) { - final NavigationBarFragment fragment = - FragmentHostManager.get(v).create(NavigationBarFragment.class); - final FragmentHostManager fragmentHost = FragmentHostManager.get(v); - fragmentHost.getFragmentManager().beginTransaction() - .replace(R.id.navigation_bar_frame, fragment, TAG) - .commit(); - fragmentHost.addTagListener(TAG, listener); - } - - @Override - public void onViewDetachedFromWindow(View v) { - final FragmentHostManager fragmentHost = FragmentHostManager.get(v); - fragmentHost.removeTagListener(TAG, listener); - FragmentHostManager.removeAndDestroy(v); - navigationBarView.removeOnAttachStateChangeListener(this); - } - }); + NavigationBarFragment fragment = FragmentHostManager.get(navigationBarView) + .create(NavigationBarFragment.class); + navigationBarView.addOnAttachStateChangeListener(new NavBarViewAttachedListener(fragment, + listener)); context.getSystemService(WindowManager.class).addView(navigationBarView, lp); return navigationBarView; } diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java index b5f98ad47c09..89297fd83bb0 100644 --- a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java +++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java @@ -54,7 +54,7 @@ public class UsbAccessoryUriActivity extends AlertActivity String uriString = intent.getStringExtra("uri"); mUri = (uriString == null ? null : Uri.parse(uriString)); - // sanity check before displaying dialog + // Exception check before displaying dialog if (mUri == null) { Log.e(TAG, "could not parse Uri " + uriString); finish(); diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java index df9dee89f5a2..6dbb1e922f60 100644 --- a/services/core/java/com/android/server/UiModeManagerService.java +++ b/services/core/java/com/android/server/UiModeManagerService.java @@ -137,6 +137,7 @@ final class UiModeManagerService extends SystemService { int mCurUiMode = 0; private int mSetUiMode = 0; private boolean mHoldingConfiguration = false; + private int mCurrentUser; private Configuration mConfiguration = new Configuration(); boolean mSystemReady; @@ -325,6 +326,7 @@ final class UiModeManagerService extends SystemService { @Override public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { + mCurrentUser = to.getUserIdentifier(); getContext().getContentResolver().unregisterContentObserver(mSetupWizardObserver); verifySetupWizardCompleted(); } @@ -727,16 +729,30 @@ final class UiModeManagerService extends SystemService { @Override public boolean setNightModeActivated(boolean active) { + if (isNightModeLocked() && (getContext().checkCallingOrSelfPermission( + android.Manifest.permission.MODIFY_DAY_NIGHT_MODE) + != PackageManager.PERMISSION_GRANTED)) { + Slog.e(TAG, "Night mode locked, requires MODIFY_DAY_NIGHT_MODE permission"); + return false; + } + final int user = Binder.getCallingUserHandle().getIdentifier(); + if (user != mCurrentUser && getContext().checkCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS) + != PackageManager.PERMISSION_GRANTED) { + Slog.e(TAG, "Target user is not current user," + + " INTERACT_ACROSS_USERS permission is required"); + return false; + + } synchronized (mLock) { - final int user = UserHandle.getCallingUserId(); final long ident = Binder.clearCallingIdentity(); try { if (mNightMode == MODE_NIGHT_AUTO || mNightMode == MODE_NIGHT_CUSTOM) { unregisterScreenOffEventLocked(); mOverrideNightModeOff = !active; mOverrideNightModeOn = active; - mOverrideNightModeUser = user; - persistNightModeOverrides(user); + mOverrideNightModeUser = mCurrentUser; + persistNightModeOverrides(mCurrentUser); } else if (mNightMode == UiModeManager.MODE_NIGHT_NO && active) { mNightMode = UiModeManager.MODE_NIGHT_YES; @@ -746,7 +762,7 @@ final class UiModeManagerService extends SystemService { } updateConfigurationLocked(); applyConfigurationExternallyLocked(); - persistNightMode(user); + persistNightMode(mCurrentUser); return true; } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index e546a2812caa..91a1487c5245 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1956,7 +1956,7 @@ public class ActivityManagerService extends IActivityManager.Stub nativeTotalPss += Debug.getPss(stats.get(j).pid, null, null); } memInfo.readMemInfo(); - synchronized (ActivityManagerService.this) { + synchronized (mProcessStats.mLock) { if (DEBUG_PSS) Slog.d(TAG_PSS, "Collected native and kernel memory in " + (SystemClock.uptimeMillis()-start) + "ms"); final long cachedKb = memInfo.getCachedSizeKb(); @@ -7048,9 +7048,7 @@ public class ActivityManagerService extends IActivityManager.Stub mUsageStatsService.prepareShutdown(); } mBatteryStatsService.shutdown(); - synchronized (this) { - mProcessStats.shutdownLocked(); - } + mProcessStats.shutdown(); return timedout; } @@ -12352,7 +12350,7 @@ public class ActivityManagerService extends IActivityManager.Stub MemInfoReader memInfo = new MemInfoReader(); memInfo.readMemInfo(); if (nativeProcTotalPss > 0) { - synchronized (this) { + synchronized (mProcessStats.mLock) { final long cachedKb = memInfo.getCachedSizeKb(); final long freeKb = memInfo.getFreeSizeKb(); final long zramKb = memInfo.getZramTotalSizeKb(); @@ -12934,7 +12932,7 @@ public class ActivityManagerService extends IActivityManager.Stub MemInfoReader memInfo = new MemInfoReader(); memInfo.readMemInfo(); if (nativeProcTotalPss > 0) { - synchronized (this) { + synchronized (mProcessStats.mLock) { final long cachedKb = memInfo.getCachedSizeKb(); final long freeKb = memInfo.getFreeSizeKb(); final long zramKb = memInfo.getZramTotalSizeKb(); @@ -16505,9 +16503,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override public void run() { - synchronized (mService) { - mProcessStats.writeStateAsyncLocked(); - } + mProcessStats.writeStateAsync(); } } @@ -16557,9 +16553,13 @@ public class ActivityManagerService extends IActivityManager.Stub } mLastMemoryLevel = memFactor; mLastNumProcesses = mProcessList.getLruSizeLocked(); - boolean allChanged = mProcessStats.setMemFactorLocked( - memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now); - final int trackerMemFactor = mProcessStats.getMemFactorLocked(); + boolean allChanged; + int trackerMemFactor; + synchronized (mProcessStats.mLock) { + allChanged = mProcessStats.setMemFactorLocked( + memFactor, mAtmInternal != null ? !mAtmInternal.isSleeping() : true, now); + trackerMemFactor = mProcessStats.getMemFactorLocked(); + } if (memFactor != ProcessStats.ADJ_MEM_FACTOR_NORMAL) { if (mLowRamStartTime == 0) { mLowRamStartTime = now; diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index f0343e1d807c..bf15f1737cfc 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -659,13 +659,15 @@ public final class OomAdjuster { updateUidsLocked(activeUids, nowElapsed); - if (mService.mProcessStats.shouldWriteNowLocked(now)) { - mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService, - mService.mProcessStats)); - } + synchronized (mService.mProcessStats.mLock) { + if (mService.mProcessStats.shouldWriteNowLocked(now)) { + mService.mHandler.post(new ActivityManagerService.ProcStatsRunnable(mService, + mService.mProcessStats)); + } - // Run this after making sure all procstates are updated. - mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now); + // Run this after making sure all procstates are updated. + mService.mProcessStats.updateTrackingAssociationsLocked(mAdjSeq, now); + } if (DEBUG_OOM_ADJ) { final long duration = SystemClock.uptimeMillis() - now; diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 1647fdaa57b6..e3e13391a8b0 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -673,30 +673,33 @@ class ProcessRecord implements WindowProcessListener { public void makeActive(IApplicationThread _thread, ProcessStatsService tracker) { if (thread == null) { - final ProcessState origBase = baseProcessTracker; - if (origBase != null) { - origBase.setState(ProcessStats.STATE_NOTHING, - tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList); - for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) { - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - uid, processName, pkgList.keyAt(ipkg), - ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING), - pkgList.valueAt(ipkg).appVersion); - } - origBase.makeInactive(); - } - baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid, - info.longVersionCode, processName); - baseProcessTracker.makeActive(); - for (int i=0; i<pkgList.size(); i++) { - ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i); - if (holder.state != null && holder.state != origBase) { - holder.state.makeInactive(); + synchronized (tracker.mLock) { + final ProcessState origBase = baseProcessTracker; + if (origBase != null) { + origBase.setState(ProcessStats.STATE_NOTHING, + tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), + pkgList.mPkgList); + for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) { + FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, + uid, processName, pkgList.keyAt(ipkg), + ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING), + pkgList.valueAt(ipkg).appVersion); + } + origBase.makeInactive(); } - tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid, + baseProcessTracker = tracker.getProcessStateLocked(info.packageName, info.uid, info.longVersionCode, processName); - if (holder.state != baseProcessTracker) { - holder.state.makeActive(); + baseProcessTracker.makeActive(); + for (int i = 0, ipkg = pkgList.size(); i < ipkg; i++) { + ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i); + if (holder.state != null && holder.state != origBase) { + holder.state.makeInactive(); + } + tracker.updateProcessStateHolderLocked(holder, pkgList.keyAt(i), info.uid, + info.longVersionCode, processName); + if (holder.state != baseProcessTracker) { + holder.state.makeActive(); + } } } } @@ -707,27 +710,30 @@ class ProcessRecord implements WindowProcessListener { public void makeInactive(ProcessStatsService tracker) { thread = null; mWindowProcessController.setThread(null); - final ProcessState origBase = baseProcessTracker; - if (origBase != null) { + synchronized (tracker.mLock) { + final ProcessState origBase = baseProcessTracker; if (origBase != null) { - origBase.setState(ProcessStats.STATE_NOTHING, - tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), pkgList.mPkgList); - for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) { - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - uid, processName, pkgList.keyAt(ipkg), - ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING), - pkgList.valueAt(ipkg).appVersion); + if (origBase != null) { + origBase.setState(ProcessStats.STATE_NOTHING, + tracker.getMemFactorLocked(), SystemClock.uptimeMillis(), + pkgList.mPkgList); + for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) { + FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, + uid, processName, pkgList.keyAt(ipkg), + ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING), + pkgList.valueAt(ipkg).appVersion); + } + origBase.makeInactive(); } - origBase.makeInactive(); - } - baseProcessTracker = null; - for (int i=0; i<pkgList.size(); i++) { - ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i); - if (holder.state != null && holder.state != origBase) { - holder.state.makeInactive(); + baseProcessTracker = null; + for (int i = 0, ipkg = pkgList.size(); i < ipkg; i++) { + ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i); + if (holder.state != null && holder.state != origBase) { + holder.state.makeInactive(); + } + holder.pkg = null; + holder.state = null; } - holder.pkg = null; - holder.state = null; } } } @@ -1026,17 +1032,19 @@ class ProcessRecord implements WindowProcessListener { */ public boolean addPackage(String pkg, long versionCode, ProcessStatsService tracker) { if (!pkgList.containsKey(pkg)) { - ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder( - versionCode); - if (baseProcessTracker != null) { - tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode, - processName); - pkgList.put(pkg, holder); - if (holder.state != baseProcessTracker) { - holder.state.makeActive(); + synchronized (tracker.mLock) { + ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder( + versionCode); + if (baseProcessTracker != null) { + tracker.updateProcessStateHolderLocked(holder, pkg, info.uid, versionCode, + processName); + pkgList.put(pkg, holder); + if (holder.state != baseProcessTracker) { + holder.state.makeActive(); + } + } else { + pkgList.put(pkg, holder); } - } else { - pkgList.put(pkg, holder); } return true; } @@ -1072,31 +1080,33 @@ class ProcessRecord implements WindowProcessListener { public void resetPackageList(ProcessStatsService tracker) { final int N = pkgList.size(); if (baseProcessTracker != null) { - long now = SystemClock.uptimeMillis(); - baseProcessTracker.setState(ProcessStats.STATE_NOTHING, - tracker.getMemFactorLocked(), now, pkgList.mPkgList); - for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) { - FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, - uid, processName, pkgList.keyAt(ipkg), - ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING), - pkgList.valueAt(ipkg).appVersion); - } - if (N != 1) { - for (int i=0; i<N; i++) { - ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i); - if (holder.state != null && holder.state != baseProcessTracker) { - holder.state.makeInactive(); - } - + synchronized (tracker.mLock) { + long now = SystemClock.uptimeMillis(); + baseProcessTracker.setState(ProcessStats.STATE_NOTHING, + tracker.getMemFactorLocked(), now, pkgList.mPkgList); + for (int ipkg = pkgList.size() - 1; ipkg >= 0; ipkg--) { + FrameworkStatsLog.write(FrameworkStatsLog.PROCESS_STATE_CHANGED, + uid, processName, pkgList.keyAt(ipkg), + ActivityManager.processStateAmToProto(ProcessStats.STATE_NOTHING), + pkgList.valueAt(ipkg).appVersion); } - pkgList.clear(); - ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder( - info.longVersionCode); - tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid, - info.longVersionCode, processName); - pkgList.put(info.packageName, holder); - if (holder.state != baseProcessTracker) { - holder.state.makeActive(); + if (N != 1) { + for (int i = 0; i < N; i++) { + ProcessStats.ProcessStateHolder holder = pkgList.valueAt(i); + if (holder.state != null && holder.state != baseProcessTracker) { + holder.state.makeInactive(); + } + + } + pkgList.clear(); + ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder( + info.longVersionCode); + tracker.updateProcessStateHolderLocked(holder, info.packageName, info.uid, + info.longVersionCode, processName); + pkgList.put(info.packageName, holder); + if (holder.state != baseProcessTracker) { + holder.state.makeActive(); + } } } } else if (N != 1) { diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java index a168af5ad842..4e8c386a3c66 100644 --- a/services/core/java/com/android/server/am/ProcessStatsService.java +++ b/services/core/java/com/android/server/am/ProcessStatsService.java @@ -71,33 +71,62 @@ public final class ProcessStatsService extends IProcessStats.Stub { final ActivityManagerService mAm; final File mBaseDir; - ProcessStats mProcessStats; + + // Note: The locking order of the below 3 locks should be: + // mLock, mPendingWriteLock, mFileLock + + // The lock object to protect the internal state/structures + final Object mLock = new Object(); + + // The lock object to protect the access to pending writes + final Object mPendingWriteLock = new Object(); + + // The lock object to protect the access to all of the file read/write + final ReentrantLock mFileLock = new ReentrantLock(); + + @GuardedBy("mLock") + final ProcessStats mProcessStats; + + @GuardedBy("mFileLock") AtomicFile mFile; + + @GuardedBy("mLock") boolean mCommitPending; + + @GuardedBy("mLock") boolean mShuttingDown; + + @GuardedBy("mLock") int mLastMemOnlyState = -1; boolean mMemFactorLowered; - final ReentrantLock mWriteLock = new ReentrantLock(); - final Object mPendingWriteLock = new Object(); + @GuardedBy("mPendingWriteLock") AtomicFile mPendingWriteFile; + + @GuardedBy("mPendingWriteLock") Parcel mPendingWrite; + + @GuardedBy("mPendingWriteLock") boolean mPendingWriteCommitted; + + @GuardedBy("mLock") long mLastWriteTime; /** For CTS to inject the screen state. */ - @GuardedBy("mAm") + @GuardedBy("mLock") Boolean mInjectedScreenState; public ProcessStatsService(ActivityManagerService am, File file) { mAm = am; mBaseDir = file; mBaseDir.mkdirs(); - mProcessStats = new ProcessStats(true); - updateFile(); + synchronized (mLock) { + mProcessStats = new ProcessStats(true); + updateFileLocked(); + } SystemProperties.addChangeCallback(new Runnable() { @Override public void run() { - synchronized (mAm) { + synchronized (mLock) { if (mProcessStats.evaluateSystemProperties(false)) { mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS; writeStateLocked(true, true); @@ -121,32 +150,33 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } - @GuardedBy("mAm") - public void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder, + @GuardedBy("mLock") + void updateProcessStateHolderLocked(ProcessStats.ProcessStateHolder holder, String packageName, int uid, long versionCode, String processName) { holder.pkg = mProcessStats.getPackageStateLocked(packageName, uid, versionCode); holder.state = mProcessStats.getProcessStateLocked(holder.pkg, processName); } - @GuardedBy("mAm") - public ProcessState getProcessStateLocked(String packageName, + @GuardedBy("mLock") + ProcessState getProcessStateLocked(String packageName, int uid, long versionCode, String processName) { return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName); } - @GuardedBy("mAm") - public ServiceState getServiceStateLocked(String packageName, int uid, + ServiceState getServiceState(String packageName, int uid, long versionCode, String processName, String className) { - return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName, - className); + synchronized (mLock) { + return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName, + className); + } } - public boolean isMemFactorLowered() { + boolean isMemFactorLowered() { return mMemFactorLowered; } - @GuardedBy("mAm") - public boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) { + @GuardedBy("mLock") + boolean setMemFactorLocked(int memFactor, boolean screenOn, long now) { mMemFactorLowered = memFactor < mLastMemOnlyState; mLastMemOnlyState = memFactor; if (mInjectedScreenState != null) { @@ -184,24 +214,24 @@ public final class ProcessStatsService extends IProcessStats.Stub { return false; } - @GuardedBy("mAm") - public int getMemFactorLocked() { + @GuardedBy("mLock") + int getMemFactorLocked() { return mProcessStats.mMemFactor != ProcessStats.STATE_NOTHING ? mProcessStats.mMemFactor : 0; } - @GuardedBy("mAm") - public void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem, + @GuardedBy("mLock") + void addSysMemUsageLocked(long cachedMem, long freeMem, long zramMem, long kernelMem, long nativeMem) { mProcessStats.addSysMemUsage(cachedMem, freeMem, zramMem, kernelMem, nativeMem); } - @GuardedBy("mAm") - public void updateTrackingAssociationsLocked(int curSeq, long now) { + @GuardedBy("mLock") + void updateTrackingAssociationsLocked(int curSeq, long now) { mProcessStats.updateTrackingAssociationsLocked(curSeq, now); } - @GuardedBy("mAm") - public boolean shouldWriteNowLocked(long now) { + @GuardedBy("mLock") + boolean shouldWriteNowLocked(long now) { if (now > (mLastWriteTime+WRITE_PERIOD)) { if (SystemClock.elapsedRealtime() > (mProcessStats.mTimePeriodStartRealtime+ProcessStats.COMMIT_PERIOD) && @@ -214,25 +244,27 @@ public final class ProcessStatsService extends IProcessStats.Stub { return false; } - @GuardedBy("mAm") - public void shutdownLocked() { + void shutdown() { Slog.w(TAG, "Writing process stats before shutdown..."); - mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN; - writeStateSyncLocked(); - mShuttingDown = true; + synchronized (mLock) { + mProcessStats.mFlags |= ProcessStats.FLAG_SHUTDOWN; + writeStateSyncLocked(); + mShuttingDown = true; + } } - @GuardedBy("mAm") - public void writeStateAsyncLocked() { - writeStateLocked(false); + void writeStateAsync() { + synchronized (mLock) { + writeStateLocked(false); + } } - @GuardedBy("mAm") - public void writeStateSyncLocked() { + @GuardedBy("mLock") + private void writeStateSyncLocked() { writeStateLocked(true); } - @GuardedBy("mAm") + @GuardedBy("mLock") private void writeStateLocked(boolean sync) { if (mShuttingDown) { return; @@ -242,8 +274,8 @@ public final class ProcessStatsService extends IProcessStats.Stub { writeStateLocked(sync, commitPending); } - @GuardedBy("mAm") - public void writeStateLocked(boolean sync, final boolean commit) { + @GuardedBy("mLock") + private void writeStateLocked(boolean sync, final boolean commit) { final long totalTime; synchronized (mPendingWriteLock) { final long now = SystemClock.uptimeMillis(); @@ -255,13 +287,13 @@ public final class ProcessStatsService extends IProcessStats.Stub { mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE; } mProcessStats.writeToParcel(mPendingWrite, 0); - mPendingWriteFile = new AtomicFile(mFile.getBaseFile()); + mPendingWriteFile = new AtomicFile(getCurrentFile()); mPendingWriteCommitted = commit; } if (commit) { mProcessStats.resetSafely(); - updateFile(); - mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); + updateFileLocked(); + scheduleRequestPssAllProcs(true, false); } mLastWriteTime = SystemClock.uptimeMillis(); totalTime = SystemClock.uptimeMillis() - now; @@ -279,14 +311,37 @@ public final class ProcessStatsService extends IProcessStats.Stub { performWriteState(totalTime); } - private void updateFile() { - mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX - + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX)); + private void scheduleRequestPssAllProcs(boolean always, boolean memLowered) { + mAm.mHandler.post(() -> { + synchronized (mAm) { + mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), always, memLowered); + } + }); + } + + @GuardedBy("mLock") + private void updateFileLocked() { + mFileLock.lock(); + try { + mFile = new AtomicFile(new File(mBaseDir, STATE_FILE_PREFIX + + mProcessStats.mTimePeriodStartClockStr + STATE_FILE_SUFFIX)); + } finally { + mFileLock.unlock(); + } mLastWriteTime = SystemClock.uptimeMillis(); } - void performWriteState(long initialTime) { - if (DEBUG) Slog.d(TAG, "Performing write to " + mFile.getBaseFile()); + private File getCurrentFile() { + mFileLock.lock(); + try { + return mFile.getBaseFile(); + } finally { + mFileLock.unlock(); + } + } + + private void performWriteState(long initialTime) { + if (DEBUG) Slog.d(TAG, "Performing write to " + getCurrentFile()); Parcel data; AtomicFile file; synchronized (mPendingWriteLock) { @@ -298,7 +353,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } mPendingWrite = null; mPendingWriteFile = null; - mWriteLock.lock(); + mFileLock.lock(); } final long startTime = SystemClock.uptimeMillis(); @@ -316,13 +371,13 @@ public final class ProcessStatsService extends IProcessStats.Stub { file.failWrite(stream); } finally { data.recycle(); - trimHistoricStatesWriteLocked(); - mWriteLock.unlock(); + trimHistoricStatesWriteLF(); + mFileLock.unlock(); } } - @GuardedBy("mAm") - boolean readLocked(ProcessStats stats, AtomicFile file) { + @GuardedBy("mFileLock") + private boolean readLF(ProcessStats stats, AtomicFile file) { try { FileInputStream stream = file.openRead(); stats.read(stream); @@ -387,7 +442,8 @@ public final class ProcessStatsService extends IProcessStats.Stub { return true; } - private ArrayList<String> getCommittedFiles(int minNum, boolean inclCurrent, + @GuardedBy("mFileLock") + private ArrayList<String> getCommittedFilesLF(int minNum, boolean inclCurrent, boolean inclCheckedIn) { File[] files = mBaseDir.listFiles(); if (files == null || files.length <= minNum) { @@ -414,9 +470,9 @@ public final class ProcessStatsService extends IProcessStats.Stub { return filesArray; } - @GuardedBy("mAm") - public void trimHistoricStatesWriteLocked() { - ArrayList<String> filesArray = getCommittedFiles(MAX_HISTORIC_STATES, false, true); + @GuardedBy("mFileLock") + private void trimHistoricStatesWriteLF() { + ArrayList<String> filesArray = getCommittedFilesLF(MAX_HISTORIC_STATES, false, true); if (filesArray == null) { return; } @@ -427,8 +483,8 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } - @GuardedBy("mAm") - boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header, + @GuardedBy("mLock") + private boolean dumpFilteredProcessesCsvLocked(PrintWriter pw, String header, boolean sepScreenStates, int[] screenStates, boolean sepMemStates, int[] memStates, boolean sepProcStates, int[] procStates, long now, String reqPackage) { ArrayList<ProcessState> procs = mProcessStats.collectProcessesLocked( @@ -502,20 +558,21 @@ public final class ProcessStatsService extends IProcessStats.Stub { return res; } + @Override public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) { mAm.mContext.enforceCallingOrSelfPermission( android.Manifest.permission.PACKAGE_USAGE_STATS, null); Parcel current = Parcel.obtain(); - synchronized (mAm) { + synchronized (mLock) { long now = SystemClock.uptimeMillis(); mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); mProcessStats.mTimePeriodEndUptime = now; mProcessStats.writeToParcel(current, now, 0); } - mWriteLock.lock(); + mFileLock.lock(); try { if (historic != null) { - ArrayList<String> files = getCommittedFiles(0, false, true); + ArrayList<String> files = getCommittedFilesLF(0, false, true); if (files != null) { for (int i=files.size()-1; i>=0; i--) { try { @@ -529,7 +586,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } } finally { - mWriteLock.unlock(); + mFileLock.unlock(); } return current.marshall(); } @@ -563,9 +620,9 @@ public final class ProcessStatsService extends IProcessStats.Stub { android.Manifest.permission.PACKAGE_USAGE_STATS, null); long newHighWaterMark = highWaterMarkMs; - mWriteLock.lock(); + mFileLock.lock(); try { - ArrayList<String> files = getCommittedFiles(0, false, true); + ArrayList<String> files = getCommittedFilesLF(0, false, true); if (files != null) { String highWaterMarkStr = DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString(); @@ -612,7 +669,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } catch (IOException e) { Slog.w(TAG, "Failure opening procstat file", e); } finally { - mWriteLock.unlock(); + mFileLock.unlock(); } return newHighWaterMark; } @@ -625,7 +682,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { return mAm.mConstants.MIN_ASSOC_LOG_DURATION; } - private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section) + private static ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section) throws IOException { final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe(); Thread thr = new Thread("ProcessStats pipe output") { @@ -645,12 +702,13 @@ public final class ProcessStatsService extends IProcessStats.Stub { return fds[0]; } + @Override public ParcelFileDescriptor getStatsOverTime(long minTime) { mAm.mContext.enforceCallingOrSelfPermission( android.Manifest.permission.PACKAGE_USAGE_STATS, null); Parcel current = Parcel.obtain(); long curTime; - synchronized (mAm) { + synchronized (mLock) { long now = SystemClock.uptimeMillis(); mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime(); mProcessStats.mTimePeriodEndUptime = now; @@ -658,11 +716,11 @@ public final class ProcessStatsService extends IProcessStats.Stub { curTime = mProcessStats.mTimePeriodEndRealtime - mProcessStats.mTimePeriodStartRealtime; } - mWriteLock.lock(); + mFileLock.lock(); try { if (curTime < minTime) { // Need to add in older stats to reach desired time. - ArrayList<String> files = getCommittedFiles(0, false, true); + ArrayList<String> files = getCommittedFilesLF(0, false, true); if (files != null && files.size() > 0) { current.setDataPosition(0); ProcessStats stats = ProcessStats.CREATOR.createFromParcel(current); @@ -673,7 +731,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { AtomicFile file = new AtomicFile(new File(files.get(i))); i--; ProcessStats moreStats = new ProcessStats(false); - readLocked(moreStats, file); + readLF(moreStats, file); if (moreStats.mReadError == null) { stats.add(moreStats); StringBuilder sb = new StringBuilder(); @@ -712,13 +770,14 @@ public final class ProcessStatsService extends IProcessStats.Stub { } catch (IOException e) { Slog.w(TAG, "Failed building output pipe", e); } finally { - mWriteLock.unlock(); + mFileLock.unlock(); } return null; } + @Override public int getCurrentMemoryState() { - synchronized (mAm) { + synchronized (mLock) { return mLastMemOnlyState; } } @@ -947,7 +1006,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } else if ("--current".equals(arg)) { currentOnly = true; } else if ("--commit".equals(arg)) { - synchronized (mAm) { + synchronized (mLock) { mProcessStats.mFlags |= ProcessStats.FLAG_COMPLETE; writeStateLocked(true, true); pw.println("Process stats committed."); @@ -962,29 +1021,39 @@ public final class ProcessStatsService extends IProcessStats.Stub { } section = parseSectionOptions(args[i]); } else if ("--clear".equals(arg)) { - synchronized (mAm) { + synchronized (mLock) { mProcessStats.resetSafely(); - mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false); - ArrayList<String> files = getCommittedFiles(0, true, true); - if (files != null) { - for (int fi=0; fi<files.size(); fi++) { - (new File(files.get(fi))).delete(); + scheduleRequestPssAllProcs(true, false); + mFileLock.lock(); + try { + ArrayList<String> files = getCommittedFilesLF(0, true, true); + if (files != null) { + for (int fi = files.size() - 1; fi >= 0; fi--) { + (new File(files.get(fi))).delete(); + } } + } finally { + mFileLock.unlock(); } pw.println("All process stats cleared."); quit = true; } } else if ("--write".equals(arg)) { - synchronized (mAm) { + synchronized (mLock) { writeStateSyncLocked(); pw.println("Process stats written."); quit = true; } } else if ("--read".equals(arg)) { - synchronized (mAm) { - readLocked(mProcessStats, mFile); - pw.println("Process stats read."); - quit = true; + synchronized (mLock) { + mFileLock.lock(); + try { + readLF(mProcessStats, mFile); + pw.println("Process stats read."); + quit = true; + } finally { + mFileLock.unlock(); + } } } else if ("--start-testing".equals(arg)) { synchronized (mAm) { @@ -999,17 +1068,17 @@ public final class ProcessStatsService extends IProcessStats.Stub { quit = true; } } else if ("--pretend-screen-on".equals(arg)) { - synchronized (mAm) { + synchronized (mLock) { mInjectedScreenState = true; } quit = true; } else if ("--pretend-screen-off".equals(arg)) { - synchronized (mAm) { + synchronized (mLock) { mInjectedScreenState = false; } quit = true; } else if ("--stop-pretend-screen".equals(arg)) { - synchronized (mAm) { + synchronized (mLock) { mInjectedScreenState = null; } quit = true; @@ -1060,7 +1129,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } pw.println(); - synchronized (mAm) { + synchronized (mLock) { dumpFilteredProcessesCsvLocked(pw, null, csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats, csvSepProcStats, csvProcStats, now, reqPackage); @@ -1090,14 +1159,26 @@ public final class ProcessStatsService extends IProcessStats.Stub { return; } else if (lastIndex > 0) { pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":"); - ArrayList<String> files = getCommittedFiles(0, false, true); - if (lastIndex >= files.size()) { - pw.print("Only have "); pw.print(files.size()); pw.println(" data sets"); - return; + + ArrayList<String> files; + AtomicFile file; + ProcessStats processStats; + + mFileLock.lock(); + try { + files = getCommittedFilesLF(0, false, true); + if (lastIndex >= files.size()) { + pw.print("Only have "); pw.print(files.size()); pw.println(" data sets"); + return; + } + file = new AtomicFile(new File(files.get(lastIndex))); + processStats = new ProcessStats(false); + readLF(processStats, file); + } finally { + mFileLock.unlock(); } - AtomicFile file = new AtomicFile(new File(files.get(lastIndex))); - ProcessStats processStats = new ProcessStats(false); - readLocked(processStats, file); + + // No lock is needed now, since only us have the access to the 'processStats'. if (processStats.mReadError != null) { if (isCheckin || isCompact) pw.print("err,"); pw.print("Failure reading "); pw.print(files.get(lastIndex)); @@ -1118,7 +1199,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll, activeOnly, section); if (dumpAll) { - pw.print(" mFile="); pw.println(mFile.getBaseFile()); + pw.print(" mFile="); pw.println(getCurrentFile()); } } else { processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); @@ -1129,9 +1210,9 @@ public final class ProcessStatsService extends IProcessStats.Stub { boolean sepNeeded = false; if ((dumpAll || isCheckin) && !currentOnly) { - mWriteLock.lock(); + mFileLock.lock(); try { - ArrayList<String> files = getCommittedFiles(0, false, !isCheckin); + ArrayList<String> files = getCommittedFilesLF(0, false, !isCheckin); if (files != null) { int start = isCheckin ? 0 : (files.size() - maxNum); if (start < 0) { @@ -1142,7 +1223,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { try { AtomicFile file = new AtomicFile(new File(files.get(i))); ProcessStats processStats = new ProcessStats(false); - readLocked(processStats, file); + readLF(processStats, file); if (processStats.mReadError != null) { if (isCheckin || isCompact) pw.print("err,"); pw.print("Failure reading "); pw.print(files.get(i)); @@ -1188,11 +1269,11 @@ public final class ProcessStatsService extends IProcessStats.Stub { } } } finally { - mWriteLock.unlock(); + mFileLock.unlock(); } } if (!isCheckin) { - synchronized (mAm) { + synchronized (mLock) { if (isCompact) { mProcessStats.dumpCheckinLocked(pw, reqPackage, section); } else { @@ -1204,7 +1285,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll, activeOnly, section); if (dumpAll) { - pw.print(" mFile="); pw.println(mFile.getBaseFile()); + pw.print(" mFile="); pw.println(getCurrentFile()); } } else { mProcessStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly); @@ -1249,7 +1330,7 @@ public final class ProcessStatsService extends IProcessStats.Stub { // dump current procstats long now; - synchronized (mAm) { + synchronized (mLock) { now = SystemClock.uptimeMillis(); final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW); mProcessStats.dumpDebug(proto, now, ProcessStats.REPORT_ALL); diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 022b04d89774..4a2703056871 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -528,8 +528,9 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN return tracker; } if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) { - tracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName, - serviceInfo.applicationInfo.uid, serviceInfo.applicationInfo.longVersionCode, + tracker = ams.mProcessStats.getServiceState(serviceInfo.packageName, + serviceInfo.applicationInfo.uid, + serviceInfo.applicationInfo.longVersionCode, serviceInfo.processName, serviceInfo.name); tracker.applyNewOwner(this); } @@ -546,7 +547,8 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN public void makeRestarting(int memFactor, long now) { if (restartTracker == null) { if ((serviceInfo.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) { - restartTracker = ams.mProcessStats.getServiceStateLocked(serviceInfo.packageName, + restartTracker = ams.mProcessStats.getServiceState( + serviceInfo.packageName, serviceInfo.applicationInfo.uid, serviceInfo.applicationInfo.longVersionCode, serviceInfo.processName, serviceInfo.name); diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 1f85d1046523..1c93d4eb599b 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -48,6 +48,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; import android.net.ConnectivityManager; +import android.net.DnsResolver; import android.net.INetworkManagementEventObserver; import android.net.Ikev2VpnProfile; import android.net.IpPrefix; @@ -79,6 +80,7 @@ import android.net.ipsec.ike.IkeSessionParams; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.FileUtils; import android.os.IBinder; import android.os.INetworkManagementService; @@ -123,6 +125,7 @@ import java.math.BigInteger; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.UnknownHostException; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.ArrayList; @@ -134,6 +137,8 @@ import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -190,6 +195,7 @@ public class Vpn { // automated reconnection private final Context mContext; + @VisibleForTesting final Dependencies mDeps; private final NetworkInfo mNetworkInfo; @VisibleForTesting protected String mPackage; private int mOwnerUID; @@ -252,17 +258,143 @@ public class Vpn { // Handle of the user initiating VPN. private final int mUserHandle; + interface RetryScheduler { + void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException; + } + + static class Dependencies { + public void startService(final String serviceName) { + SystemService.start(serviceName); + } + + public void stopService(final String serviceName) { + SystemService.stop(serviceName); + } + + public boolean isServiceRunning(final String serviceName) { + return SystemService.isRunning(serviceName); + } + + public boolean isServiceStopped(final String serviceName) { + return SystemService.isStopped(serviceName); + } + + public File getStateFile() { + return new File("/data/misc/vpn/state"); + } + + public void sendArgumentsToDaemon( + final String daemon, final LocalSocket socket, final String[] arguments, + final RetryScheduler retryScheduler) throws IOException, InterruptedException { + final LocalSocketAddress address = new LocalSocketAddress( + daemon, LocalSocketAddress.Namespace.RESERVED); + + // Wait for the socket to connect. + while (true) { + try { + socket.connect(address); + break; + } catch (Exception e) { + // ignore + } + retryScheduler.checkInterruptAndDelay(true /* sleepLonger */); + } + socket.setSoTimeout(500); + + final OutputStream out = socket.getOutputStream(); + for (String argument : arguments) { + byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); + if (bytes.length >= 0xFFFF) { + throw new IllegalArgumentException("Argument is too large"); + } + out.write(bytes.length >> 8); + out.write(bytes.length); + out.write(bytes); + retryScheduler.checkInterruptAndDelay(false /* sleepLonger */); + } + out.write(0xFF); + out.write(0xFF); + + // Wait for End-of-File. + final InputStream in = socket.getInputStream(); + while (true) { + try { + if (in.read() == -1) { + break; + } + } catch (Exception e) { + // ignore + } + retryScheduler.checkInterruptAndDelay(true /* sleepLonger */); + } + } + + @NonNull + public InetAddress resolve(final String endpoint) + throws ExecutionException, InterruptedException { + try { + return InetAddress.parseNumericAddress(endpoint); + } catch (IllegalArgumentException e) { + // Endpoint is not numeric : fall through and resolve + } + + final CancellationSignal cancellationSignal = new CancellationSignal(); + try { + final DnsResolver resolver = DnsResolver.getInstance(); + final CompletableFuture<InetAddress> result = new CompletableFuture(); + final DnsResolver.Callback<List<InetAddress>> cb = + new DnsResolver.Callback<List<InetAddress>>() { + @Override + public void onAnswer(@NonNull final List<InetAddress> answer, + final int rcode) { + if (answer.size() > 0) { + result.complete(answer.get(0)); + } else { + result.completeExceptionally( + new UnknownHostException(endpoint)); + } + } + + @Override + public void onError(@Nullable final DnsResolver.DnsException error) { + // Unfortunately UnknownHostException doesn't accept a cause, so + // print a message here instead. Only show the summary, not the + // full stack trace. + Log.e(TAG, "Async dns resolver error : " + error); + result.completeExceptionally(new UnknownHostException(endpoint)); + } + }; + resolver.query(null /* network, null for default */, endpoint, + DnsResolver.FLAG_EMPTY, r -> r.run(), cancellationSignal, cb); + return result.get(); + } catch (final ExecutionException e) { + Log.e(TAG, "Cannot resolve VPN endpoint : " + endpoint + ".", e); + throw e; + } catch (final InterruptedException e) { + Log.e(TAG, "Legacy VPN was interrupted while resolving the endpoint", e); + cancellationSignal.cancel(); + throw e; + } + } + + public boolean checkInterfacePresent(final Vpn vpn, final String iface) { + return vpn.jniCheck(iface) == 0; + } + } + public Vpn(Looper looper, Context context, INetworkManagementService netService, @UserIdInt int userHandle, @NonNull KeyStore keyStore) { - this(looper, context, netService, userHandle, keyStore, + this(looper, context, new Dependencies(), netService, userHandle, keyStore, new SystemServices(context), new Ikev2SessionCreator()); } @VisibleForTesting - protected Vpn(Looper looper, Context context, INetworkManagementService netService, + protected Vpn(Looper looper, Context context, Dependencies deps, + INetworkManagementService netService, int userHandle, @NonNull KeyStore keyStore, SystemServices systemServices, Ikev2SessionCreator ikev2SessionCreator) { mContext = context; + mDeps = deps; mNetd = netService; mUserHandle = userHandle; mLooper = looper; @@ -2129,7 +2261,8 @@ public class Vpn { } /** This class represents the common interface for all VPN runners. */ - private abstract class VpnRunner extends Thread { + @VisibleForTesting + abstract class VpnRunner extends Thread { protected VpnRunner(String name) { super(name); @@ -2638,7 +2771,7 @@ public class Vpn { } catch (InterruptedException e) { } for (String daemon : mDaemons) { - SystemService.stop(daemon); + mDeps.stopService(daemon); } } agentDisconnect(); @@ -2655,21 +2788,55 @@ public class Vpn { } } + private void checkAndFixupArguments(@NonNull final InetAddress endpointAddress) { + final String endpointAddressString = endpointAddress.getHostAddress(); + // Perform some safety checks before inserting the address in place. + // Position 0 in mDaemons and mArguments must be racoon, and position 1 must be mtpd. + if (!"racoon".equals(mDaemons[0]) || !"mtpd".equals(mDaemons[1])) { + throw new IllegalStateException("Unexpected daemons order"); + } + + // Respectively, the positions at which racoon and mtpd take the server address + // argument are 1 and 2. Not all types of VPN require both daemons however, and + // in that case the corresponding argument array is null. + if (mArguments[0] != null) { + if (!mProfile.server.equals(mArguments[0][1])) { + throw new IllegalStateException("Invalid server argument for racoon"); + } + mArguments[0][1] = endpointAddressString; + } + + if (mArguments[1] != null) { + if (!mProfile.server.equals(mArguments[1][2])) { + throw new IllegalStateException("Invalid server argument for mtpd"); + } + mArguments[1][2] = endpointAddressString; + } + } + private void bringup() { // Catch all exceptions so we can clean up a few things. try { + // resolve never returns null. If it does because of some bug, it will be + // caught by the catch() block below and cleanup gracefully. + final InetAddress endpointAddress = mDeps.resolve(mProfile.server); + + // Big hack : dynamically replace the address of the server in the arguments + // with the resolved address. + checkAndFixupArguments(endpointAddress); + // Initialize the timer. mBringupStartTime = SystemClock.elapsedRealtime(); // Wait for the daemons to stop. for (String daemon : mDaemons) { - while (!SystemService.isStopped(daemon)) { + while (!mDeps.isServiceStopped(daemon)) { checkInterruptAndDelay(true); } } // Clear the previous state. - File state = new File("/data/misc/vpn/state"); + final File state = mDeps.getStateFile(); state.delete(); if (state.exists()) { throw new IllegalStateException("Cannot delete the state"); @@ -2696,57 +2863,19 @@ public class Vpn { // Start the daemon. String daemon = mDaemons[i]; - SystemService.start(daemon); + mDeps.startService(daemon); // Wait for the daemon to start. - while (!SystemService.isRunning(daemon)) { + while (!mDeps.isServiceRunning(daemon)) { checkInterruptAndDelay(true); } // Create the control socket. mSockets[i] = new LocalSocket(); - LocalSocketAddress address = new LocalSocketAddress( - daemon, LocalSocketAddress.Namespace.RESERVED); - - // Wait for the socket to connect. - while (true) { - try { - mSockets[i].connect(address); - break; - } catch (Exception e) { - // ignore - } - checkInterruptAndDelay(true); - } - mSockets[i].setSoTimeout(500); - - // Send over the arguments. - OutputStream out = mSockets[i].getOutputStream(); - for (String argument : arguments) { - byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); - if (bytes.length >= 0xFFFF) { - throw new IllegalArgumentException("Argument is too large"); - } - out.write(bytes.length >> 8); - out.write(bytes.length); - out.write(bytes); - checkInterruptAndDelay(false); - } - out.write(0xFF); - out.write(0xFF); - - // Wait for End-of-File. - InputStream in = mSockets[i].getInputStream(); - while (true) { - try { - if (in.read() == -1) { - break; - } - } catch (Exception e) { - // ignore - } - checkInterruptAndDelay(true); - } + + // Wait for the socket to connect and send over the arguments. + mDeps.sendArgumentsToDaemon(daemon, mSockets[i], arguments, + this::checkInterruptAndDelay); } // Wait for the daemons to create the new state. @@ -2754,7 +2883,7 @@ public class Vpn { // Check if a running daemon is dead. for (int i = 0; i < mDaemons.length; ++i) { String daemon = mDaemons[i]; - if (mArguments[i] != null && !SystemService.isRunning(daemon)) { + if (mArguments[i] != null && !mDeps.isServiceRunning(daemon)) { throw new IllegalStateException(daemon + " is dead"); } } @@ -2764,7 +2893,8 @@ public class Vpn { // Now we are connected. Read and parse the new state. String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1); if (parameters.length != 7) { - throw new IllegalStateException("Cannot parse the state"); + throw new IllegalStateException("Cannot parse the state: '" + + String.join("', '", parameters) + "'"); } // Set the interface and the addresses in the config. @@ -2793,20 +2923,15 @@ public class Vpn { } // Add a throw route for the VPN server endpoint, if one was specified. - String endpoint = parameters[5].isEmpty() ? mProfile.server : parameters[5]; - if (!endpoint.isEmpty()) { - try { - InetAddress addr = InetAddress.parseNumericAddress(endpoint); - if (addr instanceof Inet4Address) { - mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 32), RTN_THROW)); - } else if (addr instanceof Inet6Address) { - mConfig.routes.add(new RouteInfo(new IpPrefix(addr, 128), RTN_THROW)); - } else { - Log.e(TAG, "Unknown IP address family for VPN endpoint: " + endpoint); - } - } catch (IllegalArgumentException e) { - Log.e(TAG, "Exception constructing throw route to " + endpoint + ": " + e); - } + if (endpointAddress instanceof Inet4Address) { + mConfig.routes.add(new RouteInfo( + new IpPrefix(endpointAddress, 32), RTN_THROW)); + } else if (endpointAddress instanceof Inet6Address) { + mConfig.routes.add(new RouteInfo( + new IpPrefix(endpointAddress, 128), RTN_THROW)); + } else { + Log.e(TAG, "Unknown IP address family for VPN endpoint: " + + endpointAddress); } // Here is the last step and it must be done synchronously. @@ -2818,7 +2943,7 @@ public class Vpn { checkInterruptAndDelay(false); // Check if the interface is gone while we are waiting. - if (jniCheck(mConfig.interfaze) == 0) { + if (mDeps.checkInterfacePresent(Vpn.this, mConfig.interfaze)) { throw new IllegalStateException(mConfig.interfaze + " is gone"); } @@ -2849,7 +2974,7 @@ public class Vpn { while (true) { Thread.sleep(2000); for (int i = 0; i < mDaemons.length; i++) { - if (mArguments[i] != null && SystemService.isStopped(mDaemons[i])) { + if (mArguments[i] != null && mDeps.isServiceStopped(mDaemons[i])) { return; } } diff --git a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java index e17cca423822..cea5a69526c6 100644 --- a/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java +++ b/services/core/java/com/android/server/location/gnss/GnssNetworkConnectivityHandler.java @@ -88,7 +88,7 @@ class GnssNetworkConnectivityHandler { // Default time limit in milliseconds for the ConnectivityManager to find a suitable // network with SUPL connectivity or report an error. - private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 10 * 1000; + private static final int SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS = 20 * 1000; private static final int HASH_MAP_INITIAL_CAPACITY_TO_TRACK_CONNECTED_NETWORKS = 5; diff --git a/services/core/java/com/android/server/media/HandlerExecutor.java b/services/core/java/com/android/server/media/HandlerExecutor.java new file mode 100644 index 000000000000..7c9e72bcf384 --- /dev/null +++ b/services/core/java/com/android/server/media/HandlerExecutor.java @@ -0,0 +1,45 @@ +/* + * Copyright 2020 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.annotation.NonNull; +import android.os.Handler; + +import java.util.Objects; +import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; + +/** + * An adapter {@link Executor} that posts all executed tasks onto the given + * {@link Handler}. + * + * @hide + */ +public class HandlerExecutor implements Executor { + private final Handler mHandler; + + public HandlerExecutor(@NonNull Handler handler) { + mHandler = Objects.requireNonNull(handler); + } + + @Override + public void execute(Runnable command) { + if (!mHandler.post(command)) { + throw new RejectedExecutionException(mHandler + " is shutting down"); + } + } +} diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java index 5d1b74912546..162c388dadd1 100644 --- a/services/core/java/com/android/server/media/MediaSession2Record.java +++ b/services/core/java/com/android/server/media/MediaSession2Record.java @@ -20,7 +20,6 @@ import android.media.MediaController2; import android.media.Session2CommandGroup; import android.media.Session2Token; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.Looper; import android.os.ResultReceiver; import android.os.UserHandle; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ba708229c7ed..05026a0cafb6 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -169,7 +169,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final int MSG_STREAM_VALIDATE_AND_COMMIT = 2; private static final int MSG_INSTALL = 3; private static final int MSG_ON_PACKAGE_INSTALLED = 4; - private static final int MSG_SESSION_VERIFICATION_FAILURE = 5; + private static final int MSG_SESSION_VALIDATION_FAILURE = 5; /** XML constants used for persisting a session */ static final String TAG_SESSION = "session"; @@ -475,10 +475,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { packageName, returnCode, message, extras); break; - case MSG_SESSION_VERIFICATION_FAILURE: + case MSG_SESSION_VALIDATION_FAILURE: final int error = msg.arg1; final String detailMessage = (String) msg.obj; - onSessionVerificationFailure(error, detailMessage); + onSessionValidationFailure(error, detailMessage); break; } @@ -1246,14 +1246,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // the parent if (unrecoverableFailure != null) { // {@link #streamValidateAndCommit()} calls - // {@link #onSessionVerificationFailure(PackageManagerException)}, but we don't + // {@link #onSessionValidationFailure(PackageManagerException)}, but we don't // expect it to ever do so for parent sessions. Call that on this parent to clean // it up and notify listeners of the error. - onSessionVerificationFailure(unrecoverableFailure); + onSessionValidationFailure(unrecoverableFailure); // fail other child sessions that did not already fail for (int i = nonFailingSessions.size() - 1; i >= 0; --i) { PackageInstallerSession session = nonFailingSessions.get(i); - session.onSessionVerificationFailure(unrecoverableFailure); + session.onSessionValidationFailure(unrecoverableFailure); } } } @@ -1575,11 +1575,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertMultiPackageConsistencyLocked(childSessions); } } catch (PackageManagerException e) { - throw onSessionVerificationFailure(e); + throw onSessionValidationFailure(e); } catch (Throwable e) { // Convert all exceptions into package manager exceptions as only those are handled // in the code above. - throw onSessionVerificationFailure(new PackageManagerException(e)); + throw onSessionValidationFailure(new PackageManagerException(e)); } } @@ -1613,20 +1613,20 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } return true; } catch (PackageManagerException e) { - throw onSessionVerificationFailure(e); + throw onSessionValidationFailure(e); } catch (Throwable e) { // Convert all exceptions into package manager exceptions as only those are handled // in the code above. - throw onSessionVerificationFailure(new PackageManagerException(e)); + throw onSessionValidationFailure(new PackageManagerException(e)); } } - private PackageManagerException onSessionVerificationFailure(PackageManagerException e) { - onSessionVerificationFailure(e.error, ExceptionUtils.getCompleteMessage(e)); + private PackageManagerException onSessionValidationFailure(PackageManagerException e) { + onSessionValidationFailure(e.error, ExceptionUtils.getCompleteMessage(e)); return e; } - private void onSessionVerificationFailure(int error, String detailMessage) { + private void onSessionValidationFailure(int error, String detailMessage) { // Session is sealed but could not be verified, we need to destroy it. destroyInternal(); // Dispatch message to remove session from PackageInstallerService. @@ -2990,7 +2990,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { mDataLoaderFinished = true; } - dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, + dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, "Failure to obtain data loader"); return; } @@ -3040,7 +3040,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { mDataLoaderFinished = true; } - dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, + dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, "Failed to prepare image."); if (manualStartAndDestroy) { dataLoader.destroy(dataLoaderId); @@ -3061,7 +3061,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { mDataLoaderFinished = true; } - dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, + dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, "DataLoader reported unrecoverable failure."); break; } @@ -3117,7 +3117,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { synchronized (mLock) { mDataLoaderFinished = true; } - dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, + dispatchSessionValidationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, "Image is missing pages required for installation."); break; } @@ -3142,8 +3142,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return false; } - private void dispatchSessionVerificationFailure(int error, String detailMessage) { - mHandler.obtainMessage(MSG_SESSION_VERIFICATION_FAILURE, error, -1, + private void dispatchSessionValidationFailure(int error, String detailMessage) { + mHandler.obtainMessage(MSG_SESSION_VALIDATION_FAILURE, error, -1, detailMessage).sendToTarget(); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 6c0fce75f0be..58a1648e51ad 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8551,6 +8551,15 @@ public class PackageManagerService extends IPackageManager.Stub if (listUninstalled) { list = new ArrayList<>(mSettings.mPackages.size()); for (PackageSetting ps : mSettings.mPackages.values()) { + if (listFactory) { + if (!ps.isSystem()) { + continue; + } + PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps); + if (psDisabled != null) { + ps = psDisabled; + } + } if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) { continue; } @@ -8565,7 +8574,16 @@ public class PackageManagerService extends IPackageManager.Stub } else { list = new ArrayList<>(mPackages.size()); for (AndroidPackage p : mPackages.values()) { - final PackageSetting ps = getPackageSetting(p.getPackageName()); + PackageSetting ps = getPackageSetting(p.getPackageName()); + if (listFactory) { + if (!p.isSystem()) { + continue; + } + PackageSetting psDisabled = mSettings.getDisabledSystemPkgLPr(ps); + if (psDisabled != null) { + ps = psDisabled; + } + } if (filterSharedLibPackageLPr(ps, callingUid, userId, flags)) { continue; } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 0061480c97f1..3e3e3c590491 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -2695,7 +2695,7 @@ public final class Settings { private void writePackageListLPrInternal(int creatingUserId) { // Only derive GIDs for active users (not dying) - final List<UserInfo> users = getUsers(UserManagerService.getInstance(), true); + final List<UserInfo> users = getActiveUsers(UserManagerService.getInstance(), true); int[] userIds = new int[users.size()]; for (int i = 0; i < userIds.length; i++) { userIds[i] = users.get(i).id; @@ -4423,25 +4423,43 @@ public final class Settings { } /** - * Return all users on the device, including partial or dying users. + * Returns all users on the device, including pre-created and dying users. + * * @param userManager UserManagerService instance * @return the list of users */ private static List<UserInfo> getAllUsers(UserManagerService userManager) { - return getUsers(userManager, false); + return getUsers(userManager, /* excludeDying= */ false, /* excludePreCreated= */ false); + } + + /** + * Returns the list of users on the device, excluding pre-created ones. + * + * @param userManager UserManagerService instance + * @param excludeDying Indicates whether to exclude any users marked for deletion. + * + * @return the list of users + */ + private static List<UserInfo> getActiveUsers(UserManagerService userManager, + boolean excludeDying) { + return getUsers(userManager, excludeDying, /* excludePreCreated= */ true); } /** - * Return the list of users on the device. Clear the calling identity before calling into - * UserManagerService. + * Returns the list of users on the device. + * * @param userManager UserManagerService instance * @param excludeDying Indicates whether to exclude any users marked for deletion. + * @param excludePreCreated Indicates whether to exclude any pre-created users. + * * @return the list of users */ - private static List<UserInfo> getUsers(UserManagerService userManager, boolean excludeDying) { + private static List<UserInfo> getUsers(UserManagerService userManager, boolean excludeDying, + boolean excludePreCreated) { long id = Binder.clearCallingIdentity(); try { - return userManager.getUsers(excludeDying); + return userManager.getUsers(/* excludePartial= */ true, excludeDying, + excludePreCreated); } catch (NullPointerException npe) { // packagemanager not yet initialized } finally { diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java index 3ec61fdda917..7467439905eb 100644 --- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java +++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java @@ -18,7 +18,6 @@ package com.android.server.timezonedetector; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UserIdInt; import android.app.timezonedetector.ITimeZoneConfigurationListener; import android.app.timezonedetector.ITimeZoneDetectorService; import android.app.timezonedetector.ManualTimeZoneSuggestion; @@ -38,6 +37,7 @@ import android.os.UserHandle; import android.provider.Settings; import android.util.IndentingPrintWriter; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -60,7 +60,8 @@ import java.util.Objects; * and making calls async, leaving the (consequently more testable) {@link TimeZoneDetectorStrategy} * implementation to deal with the logic around time zone detection. */ -public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub { +public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub + implements IBinder.DeathRecipient { private static final String TAG = "TimeZoneDetectorService"; @@ -104,9 +105,15 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub @NonNull private final TimeZoneDetectorStrategy mTimeZoneDetectorStrategy; + /** + * This sparse array acts as a map from userId to listeners running as that userId. User scoped + * as time zone detection configuration is partially user-specific, so different users can + * get different configuration. + */ @GuardedBy("mConfigurationListeners") @NonNull - private final ArrayList<ConfigListenerInfo> mConfigurationListeners = new ArrayList<>(); + private final SparseArray<ArrayList<ITimeZoneConfigurationListener>> mConfigurationListeners = + new SparseArray<>(); private static TimeZoneDetectorService create( @NonNull Context context, @NonNull Handler handler, @@ -188,18 +195,23 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub Objects.requireNonNull(listener); int userId = UserHandle.getCallingUserId(); - ConfigListenerInfo listenerInfo = new ConfigListenerInfo(userId, listener); - synchronized (mConfigurationListeners) { - if (mConfigurationListeners.contains(listenerInfo)) { + ArrayList<ITimeZoneConfigurationListener> listeners = + mConfigurationListeners.get(userId); + if (listeners != null && listeners.contains(listener)) { return; } try { - // Ensure the reference to the listener is removed if the client process dies. - listenerInfo.linkToDeath(); + if (listeners == null) { + listeners = new ArrayList<>(1); + mConfigurationListeners.put(userId, listeners); + } + + // Ensure the reference to the listener will be removed if the client process dies. + listener.asBinder().linkToDeath(this, 0 /* flags */); // Only add the listener if we can linkToDeath(). - mConfigurationListeners.add(listenerInfo); + listeners.add(listener); } catch (RemoteException e) { Slog.e(TAG, "Unable to linkToDeath() for listener=" + listener, e); } @@ -213,21 +225,56 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub int userId = UserHandle.getCallingUserId(); synchronized (mConfigurationListeners) { - ConfigListenerInfo toRemove = new ConfigListenerInfo(userId, listener); - Iterator<ConfigListenerInfo> listenerIterator = mConfigurationListeners.iterator(); - while (listenerIterator.hasNext()) { - ConfigListenerInfo currentListenerInfo = listenerIterator.next(); - if (currentListenerInfo.equals(toRemove)) { - listenerIterator.remove(); - - // Stop listening for the client process to die. - try { - currentListenerInfo.unlinkToDeath(); - } catch (RemoteException e) { - Slog.e(TAG, "Unable to unlinkToDeath() for listener=" + listener, e); + boolean removedListener = false; + ArrayList<ITimeZoneConfigurationListener> userListeners = + mConfigurationListeners.get(userId); + if (userListeners.remove(listener)) { + // Stop listening for the client process to die. + listener.asBinder().unlinkToDeath(this, 0 /* flags */); + removedListener = true; + } + if (!removedListener) { + Slog.w(TAG, "Client asked to remove listenener=" + listener + + ", but no listeners were removed." + + " mConfigurationListeners=" + mConfigurationListeners); + } + } + } + + @Override + public void binderDied() { + // Should not be used as binderDied(IBinder who) is overridden. + Slog.wtf(TAG, "binderDied() called unexpectedly."); + } + + /** + * Called when one of the ITimeZoneConfigurationListener processes dies before calling + * {@link #removeConfigurationListener(ITimeZoneConfigurationListener)}. + */ + @Override + public void binderDied(IBinder who) { + synchronized (mConfigurationListeners) { + boolean removedListener = false; + final int userCount = mConfigurationListeners.size(); + for (int i = 0; i < userCount; i++) { + ArrayList<ITimeZoneConfigurationListener> userListeners = + mConfigurationListeners.valueAt(i); + Iterator<ITimeZoneConfigurationListener> userListenerIterator = + userListeners.iterator(); + while (userListenerIterator.hasNext()) { + ITimeZoneConfigurationListener userListener = userListenerIterator.next(); + if (userListener.asBinder().equals(who)) { + userListenerIterator.remove(); + removedListener = true; + break; } } } + if (!removedListener) { + Slog.w(TAG, "Notified of binder death for who=" + who + + ", but did not remove any listeners." + + " mConfigurationListeners=" + mConfigurationListeners); + } } } @@ -243,14 +290,24 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub // problem. synchronized (mConfigurationListeners) { - for (ConfigListenerInfo listenerInfo : mConfigurationListeners) { + final int userCount = mConfigurationListeners.size(); + for (int userIndex = 0; userIndex < userCount; userIndex++) { + int userId = mConfigurationListeners.keyAt(userIndex); TimeZoneConfiguration configuration = - mTimeZoneDetectorStrategy.getConfiguration(listenerInfo.getUserId()); - try { - listenerInfo.getListener().onChange(configuration); - } catch (RemoteException e) { - Slog.w(TAG, "Unable to notify listener=" - + listenerInfo + " of updated configuration=" + configuration, e); + mTimeZoneDetectorStrategy.getConfiguration(userId); + + ArrayList<ITimeZoneConfigurationListener> listeners = + mConfigurationListeners.valueAt(userIndex); + final int listenerCount = listeners.size(); + for (int listenerIndex = 0; listenerIndex < listenerCount; listenerIndex++) { + ITimeZoneConfigurationListener listener = listeners.get(listenerIndex); + try { + listener.onChange(configuration); + } catch (RemoteException e) { + Slog.w(TAG, "Unable to notify listener=" + listener + + " for userId=" + userId + + " of updated configuration=" + configuration, e); + } } } } @@ -338,66 +395,5 @@ public final class TimeZoneDetectorService extends ITimeZoneDetectorService.Stub (new TimeZoneDetectorShellCommand(this)).exec( this, in, out, err, args, callback, resultReceiver); } - - private class ConfigListenerInfo implements IBinder.DeathRecipient { - private final @UserIdInt int mUserId; - private final ITimeZoneConfigurationListener mListener; - - ConfigListenerInfo( - @UserIdInt int userId, @NonNull ITimeZoneConfigurationListener listener) { - this.mUserId = userId; - this.mListener = Objects.requireNonNull(listener); - } - - @UserIdInt int getUserId() { - return mUserId; - } - - ITimeZoneConfigurationListener getListener() { - return mListener; - } - - void linkToDeath() throws RemoteException { - mListener.asBinder().linkToDeath(this, 0 /* flags */); - } - - void unlinkToDeath() throws RemoteException { - mListener.asBinder().unlinkToDeath(this, 0 /* flags */); - } - - @Override - public void binderDied() { - synchronized (mConfigurationListeners) { - Slog.i(TAG, "Configuration listener client died: " + this); - mConfigurationListeners.remove(this); - } - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - ConfigListenerInfo that = (ConfigListenerInfo) o; - return mUserId == that.mUserId - && mListener.equals(that.mListener); - } - - @Override - public int hashCode() { - return Objects.hash(mUserId, mListener); - } - - @Override - public String toString() { - return "ConfigListenerInfo{" - + "mUserId=" + mUserId - + ", mListener=" + mListener - + '}'; - } - } } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index a05289f9f651..2c475e0b9bcb 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -130,6 +130,7 @@ import android.util.MergedConfiguration; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; +import android.view.Display; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -1090,9 +1091,9 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // Check if caller is already present on display final boolean uidPresentOnDisplay = displayContent.isUidPresent(callingUid); - final int displayOwnerUid = displayContent.mDisplay.getOwnerUid(); - if (displayContent.mDisplay.getType() == TYPE_VIRTUAL && displayOwnerUid != SYSTEM_UID) { - // Limit launching on virtual displays, because their contents can be read from Surface + final Display display = displayContent.mDisplay; + if (!display.isTrusted()) { + // Limit launching on untrusted displays because their contents can be read from Surface // by apps that created them. if ((aInfo.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) == 0) { if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" @@ -1116,7 +1117,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } // Check if the caller is the owner of the display. - if (displayOwnerUid == callingUid) { + if (display.getOwnerUid() == callingUid) { if (DEBUG_TASKS) Slog.d(TAG, "Launch on display check:" + " allow launch for owner of the display"); return true; diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index f3c7a5dcb6d5..9b18ac8f7702 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; import static android.graphics.Color.WHITE; import static android.graphics.Color.alpha; import static android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR; @@ -142,6 +143,7 @@ class TaskSnapshotSurface implements StartingSurface { private final Handler mHandler; private boolean mSizeMismatch; private final Paint mBackgroundPaint = new Paint(); + private final int mActivityType; private final int mStatusBarColor; @VisibleForTesting final SystemBarBackgroundPainter mSystemBarBackgroundPainter; private final int mOrientationOnCreation; @@ -173,6 +175,7 @@ class TaskSnapshotSurface implements StartingSurface { final int windowFlags; final int windowPrivateFlags; final int currentOrientation; + final int activityType; final InsetsState insetsState; synchronized (service.mGlobalLock) { final WindowState mainWindow = activity.findMainWindow(); @@ -241,6 +244,7 @@ class TaskSnapshotSurface implements StartingSurface { taskBounds = new Rect(); task.getBounds(taskBounds); currentOrientation = topFullscreenOpaqueWindow.getConfiguration().orientation; + activityType = activity.getActivityType(); final InsetsPolicy insetsPolicy = topFullscreenOpaqueWindow.getDisplayContent() .getInsetsPolicy(); @@ -261,7 +265,8 @@ class TaskSnapshotSurface implements StartingSurface { } final TaskSnapshotSurface snapshotSurface = new TaskSnapshotSurface(service, window, surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, sysUiVis, - windowFlags, windowPrivateFlags, taskBounds, currentOrientation, insetsState); + windowFlags, windowPrivateFlags, taskBounds, currentOrientation, activityType, + insetsState); window.setOuter(snapshotSurface); try { session.relayout(window, window.mSeq, layoutParams, -1, -1, View.VISIBLE, 0, -1, @@ -282,7 +287,7 @@ class TaskSnapshotSurface implements StartingSurface { TaskSnapshotSurface(WindowManagerService service, Window window, SurfaceControl surfaceControl, TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription, int sysUiVis, int windowFlags, int windowPrivateFlags, Rect taskBounds, - int currentOrientation, InsetsState insetsState) { + int currentOrientation, int activityType, InsetsState insetsState) { mService = service; mSurface = service.mSurfaceFactory.get(); mHandler = new Handler(mService.mH.getLooper()); @@ -298,6 +303,7 @@ class TaskSnapshotSurface implements StartingSurface { windowPrivateFlags, sysUiVis, taskDescription, 1f, insetsState); mStatusBarColor = taskDescription.getStatusBarColor(); mOrientationOnCreation = currentOrientation; + mActivityType = activityType; mTransaction = mService.mTransactionFactory.get(); } @@ -305,7 +311,9 @@ class TaskSnapshotSurface implements StartingSurface { public void remove() { synchronized (mService.mGlobalLock) { final long now = SystemClock.uptimeMillis(); - if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS) { + if (mSizeMismatch && now - mShownTime < SIZE_MISMATCH_MINIMUM_TIME_MS + // Show the latest content as soon as possible for unlocking to home. + && mActivityType != ACTIVITY_TYPE_HOME) { mHandler.postAtTime(this::remove, mShownTime + SIZE_MISMATCH_MINIMUM_TIME_MS); ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Defer removing snapshot surface in %dms", (now - mShownTime)); diff --git a/services/people/java/com/android/server/people/PeopleService.java b/services/people/java/com/android/server/people/PeopleService.java index 37bf66491882..33317a38853e 100644 --- a/services/people/java/com/android/server/people/PeopleService.java +++ b/services/people/java/com/android/server/people/PeopleService.java @@ -19,6 +19,8 @@ package com.android.server.people; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; +import android.app.people.ConversationChannel; +import android.app.people.IPeopleManager; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionSessionId; import android.app.prediction.AppTarget; @@ -26,8 +28,11 @@ import android.app.prediction.AppTargetEvent; import android.app.prediction.IPredictionCallback; import android.content.Context; import android.content.pm.ParceledListSlice; +import android.os.Binder; import android.os.CancellationSignal; +import android.os.Process; import android.os.RemoteException; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.Slog; @@ -35,6 +40,7 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.server.SystemService; import com.android.server.people.data.DataManager; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Consumer; @@ -68,6 +74,7 @@ public class PeopleService extends SystemService { @Override public void onStart() { + publishBinderService(Context.PEOPLE_SERVICE, new BinderService()); publishLocalService(PeopleServiceInternal.class, new LocalService()); } @@ -81,6 +88,38 @@ public class PeopleService extends SystemService { mDataManager.onUserStopping(user.getUserIdentifier()); } + /** + * Enforces that only the system or root UID can make certain calls. + * + * @param message used as message if SecurityException is thrown + * @throws SecurityException if the caller is not system or root + */ + private static void enforceSystemOrRoot(String message) { + int uid = Binder.getCallingUid(); + if (!UserHandle.isSameApp(uid, Process.SYSTEM_UID) && uid != Process.ROOT_UID) { + throw new SecurityException("Only system may " + message); + } + } + + private final class BinderService extends IPeopleManager.Stub { + + @Override + public ParceledListSlice<ConversationChannel> getRecentConversations() { + enforceSystemOrRoot("get recent conversations"); + return new ParceledListSlice<>(new ArrayList<>()); + } + + @Override + public void removeRecentConversation(String packageName, int userId, String shortcutId) { + enforceSystemOrRoot("remove a recent conversation"); + } + + @Override + public void removeAllRecentConversations() { + enforceSystemOrRoot("remove all recent conversations"); + } + } + @VisibleForTesting final class LocalService extends PeopleServiceInternal { diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java index 2a267c413c31..1b2711d3938b 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java @@ -99,6 +99,7 @@ import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; +import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; @@ -165,7 +166,7 @@ public class MockingOomAdjusterTests { setFieldValue(ActivityManagerService.class, sService, "mHandler", mock(ActivityManagerService.MainHandler.class)); setFieldValue(ActivityManagerService.class, sService, "mProcessStats", - mock(ProcessStatsService.class)); + new ProcessStatsService(sService, new File(sContext.getFilesDir(), "procstats"))); setFieldValue(ActivityManagerService.class, sService, "mBackupTargets", mock(SparseArray.class)); setFieldValue(ActivityManagerService.class, sService, "mOomAdjProfiler", diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java index 153634548c17..8034cacc6923 100644 --- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorServiceTest.java @@ -170,7 +170,7 @@ public class TimeZoneDetectorServiceTest { ITimeZoneConfigurationListener mockListener = mock(ITimeZoneConfigurationListener.class); try { mTimeZoneDetectorService.removeConfigurationListener(mockListener); - fail(); + fail("Expected a SecurityException"); } finally { verify(mMockContext).enforceCallingPermission( eq(android.Manifest.permission.WRITE_SECURE_SETTINGS), diff --git a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java index 1d75967756c3..88b1d191dc4d 100644 --- a/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/UiModeManagerServiceTest.java @@ -16,6 +16,7 @@ package com.android.server; +import android.Manifest; import android.app.AlarmManager; import android.app.IUiModeManager; import android.content.BroadcastReceiver; @@ -24,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Handler; @@ -67,6 +69,7 @@ import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -230,6 +233,17 @@ public class UiModeManagerServiceTest extends UiServiceTestCase { } @Test + public void setNightModeActivated_permissiontoChangeOtherUsers() throws RemoteException { + SystemService.TargetUser user = mock(SystemService.TargetUser.class); + doReturn(9).when(user).getUserIdentifier(); + mUiManagerService.onUserSwitching(user, user); + when(mContext.checkCallingOrSelfPermission( + eq(Manifest.permission.INTERACT_ACROSS_USERS))) + .thenReturn(PackageManager.PERMISSION_DENIED); + assertFalse(mService.setNightModeActivated(true)); + } + + @Test public void autoNightModeSwitch_batterySaverOn() throws RemoteException { mService.setNightMode(MODE_NIGHT_NO); when(mTwilightState.isNight()).thenReturn(false); diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml index 4040fa6a675e..e3c795d03381 100644 --- a/services/tests/wmtests/AndroidManifest.xml +++ b/services/tests/wmtests/AndroidManifest.xml @@ -38,6 +38,7 @@ <uses-permission android:name="android.permission.REORDER_TASKS" /> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" /> <uses-permission android:name="android.permission.STATUS_BAR" /> + <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" /> <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) --> <application android:debuggable="true" diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java index addf1ffe40c2..96b970056c98 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java @@ -38,7 +38,13 @@ import static org.mockito.ArgumentMatchers.eq; import android.app.WaitResult; import android.content.pm.ActivityInfo; +import android.graphics.PixelFormat; +import android.hardware.display.DisplayManager; +import android.hardware.display.VirtualDisplay; +import android.media.ImageReader; import android.platform.test.annotations.Presubmit; +import android.view.Display; +import android.view.DisplayInfo; import androidx.test.filters.MediumTest; @@ -173,4 +179,50 @@ public class ActivityStackSupervisorTests extends WindowTestsBase { verify(taskChangeNotifier).notifyTaskFocusChanged(eq(taskB.mTaskId) /* taskId */, eq(true) /* focused */); } + + @Test + /** Ensures that a trusted virtual display can launch arbitrary activities. */ + public void testTrustedVirtualDisplayCanLaunchActivities() { + final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP); + final Task stack = new StackBuilder(mRootWindowContainer) + .setDisplay(newDisplay).build(); + final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity(); + VirtualDisplay virtualDisplay = createVirtualDisplay(true); + final boolean allowed = mSupervisor.isCallerAllowedToLaunchOnDisplay(1234, 1234, + virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info); + + assertThat(allowed).isTrue(); + } + + @Test + /** Ensures that an untrusted virtual display cannot launch arbitrary activities. */ + public void testUntrustedVirtualDisplayCannotLaunchActivities() { + final DisplayContent newDisplay = addNewDisplayContentAt(DisplayContent.POSITION_TOP); + final Task stack = new StackBuilder(mRootWindowContainer) + .setDisplay(newDisplay).build(); + final ActivityRecord unresizableActivity = stack.getTopNonFinishingActivity(); + VirtualDisplay virtualDisplay = createVirtualDisplay(false); + final boolean allowed = mSupervisor.isCallerAllowedToLaunchOnDisplay(1234, 1234, + virtualDisplay.getDisplay().getDisplayId(), unresizableActivity.info); + + assertThat(allowed).isFalse(); + } + + private VirtualDisplay createVirtualDisplay(boolean trusted) { + final DisplayManager dm = mContext.getSystemService(DisplayManager.class); + final DisplayInfo displayInfo = new DisplayInfo(); + final Display defaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY); + defaultDisplay.getDisplayInfo(displayInfo); + int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC; + if (trusted) { + flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; + } + + final ImageReader imageReader = ImageReader.newInstance( + displayInfo.logicalWidth, displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2); + + return dm.createVirtualDisplay("virtualDisplay", displayInfo.logicalWidth, + displayInfo.logicalHeight, + displayInfo.logicalDensityDpi, imageReader.getSurface(), flags); + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java index d950344538a0..b4a13375aeec 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotSurfaceTest.java @@ -16,6 +16,7 @@ package com.android.server.wm; +import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS; @@ -87,7 +88,7 @@ public class TaskSnapshotSurfaceTest extends WindowTestsBase { 0 /* systemUiVisibility */, false /* isTranslucent */); mSurface = new TaskSnapshotSurface(mWm, new Window(), new SurfaceControl(), snapshot, "Test", createTaskDescription(Color.WHITE, Color.RED, Color.BLUE), sysuiVis, windowFlags, 0, - taskBounds, ORIENTATION_PORTRAIT, new InsetsState()); + taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD, new InsetsState()); } private static TaskDescription createTaskDescription(int background, int statusBar, diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt index 2e4d390ceb60..c0658fe4422e 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt @@ -84,7 +84,7 @@ class CloseImeAutoOpenWindowToHomeTest( navBarLayerIsAlwaysVisible(bugId = 140855415) statusBarLayerIsAlwaysVisible(bugId = 140855415) noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false) - navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0) + navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415) statusBarLayerRotatesScales(rotation, Surface.ROTATION_0) imeLayerBecomesInvisible(bugId = 141458352) imeAppLayerBecomesInvisible(testApp, bugId = 153739621) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt index 1c0da4f920bb..dcf308533ee6 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt @@ -92,7 +92,7 @@ open class CloseImeWindowToHomeTest( navBarLayerIsAlwaysVisible(bugId = 140855415) statusBarLayerIsAlwaysVisible(bugId = 140855415) noUncoveredRegions(rotation, Surface.ROTATION_0, allStates = false) - navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0) + navBarLayerRotatesAndScales(rotation, Surface.ROTATION_0, bugId = 140855415) statusBarLayerRotatesScales(rotation, Surface.ROTATION_0) imeLayerBecomesInvisible(bugId = 153739621) imeAppLayerBecomesInvisible(testApp, bugId = 153739621) diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt index e078f266e5ed..91ec211805f7 100644 --- a/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt +++ b/tests/FlickerTests/src/com/android/server/wm/flicker/splitscreen/OpenAppToSplitScreenTest.kt @@ -90,7 +90,7 @@ class OpenAppToSplitScreenTest( navBarLayerIsAlwaysVisible() statusBarLayerIsAlwaysVisible() noUncoveredRegions(rotation) - navBarLayerRotatesAndScales(rotation) + navBarLayerRotatesAndScales(rotation, bugId = 140855415) statusBarLayerRotatesScales(rotation) all("dividerLayerBecomesVisible") { @@ -102,7 +102,8 @@ class OpenAppToSplitScreenTest( eventLog { focusChanges(testApp.`package`, - "recents_animation_input_consumer", "NexusLauncherActivity") + "recents_animation_input_consumer", "NexusLauncherActivity", + bugId = 151179149) } } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index 4ccf79a0cb37..de1c5759ee87 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -30,6 +30,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -49,6 +50,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.app.NotificationManager; @@ -65,6 +67,7 @@ import android.net.InetAddresses; import android.net.IpPrefix; import android.net.IpSecManager; import android.net.LinkProperties; +import android.net.LocalSocket; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo.DetailedState; @@ -74,6 +77,7 @@ import android.net.VpnManager; import android.net.VpnService; import android.os.Build.VERSION_CODES; import android.os.Bundle; +import android.os.ConditionVariable; import android.os.INetworkManagementService; import android.os.Looper; import android.os.Process; @@ -101,13 +105,20 @@ import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.net.Inet4Address; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import java.util.stream.Stream; /** @@ -133,7 +144,8 @@ public class VpnTest { managedProfileA.profileGroupId = primaryUser.id; } - static final String TEST_VPN_PKG = "com.dummy.vpn"; + static final String EGRESS_IFACE = "wlan0"; + static final String TEST_VPN_PKG = "com.testvpn.vpn"; private static final String TEST_VPN_SERVER = "1.2.3.4"; private static final String TEST_VPN_IDENTITY = "identity"; private static final byte[] TEST_VPN_PSK = "psk".getBytes(); @@ -1012,31 +1024,190 @@ public class VpnTest { // a subsequent CL. } - @Test - public void testStartLegacyVpn() throws Exception { + public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception { final Vpn vpn = createVpn(primaryUser.id); setMockedUsers(primaryUser); // Dummy egress interface - final String egressIface = "DUMMY0"; final LinkProperties lp = new LinkProperties(); - lp.setInterfaceName(egressIface); + lp.setInterfaceName(EGRESS_IFACE); final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), - InetAddresses.parseNumericAddress("192.0.2.0"), egressIface); + InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE); lp.addRoute(defaultRoute); - vpn.startLegacyVpn(mVpnProfile, mKeyStore, lp); + vpn.startLegacyVpn(vpnProfile, mKeyStore, lp); + return vpn; + } + @Test + public void testStartPlatformVpn() throws Exception { + startLegacyVpn(mVpnProfile); // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in - // a subsequent CL. + // a subsequent patch. + } + + @Test + public void testStartRacoonNumericAddress() throws Exception { + startRacoon("1.2.3.4", "1.2.3.4"); + } + + @Test + public void testStartRacoonHostname() throws Exception { + startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve + } + + public void startRacoon(final String serverAddr, final String expectedAddr) + throws Exception { + final ConditionVariable legacyRunnerReady = new ConditionVariable(); + final VpnProfile profile = new VpnProfile("testProfile" /* key */); + profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK; + profile.name = "testProfileName"; + profile.username = "userName"; + profile.password = "thePassword"; + profile.server = serverAddr; + profile.ipsecIdentifier = "id"; + profile.ipsecSecret = "secret"; + profile.l2tpSecret = "l2tpsecret"; + when(mConnectivityManager.getAllNetworks()) + .thenReturn(new Network[] { new Network(101) }); + when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(), + anyInt(), any(), anyInt())).thenAnswer(invocation -> { + // The runner has registered an agent and is now ready. + legacyRunnerReady.open(); + return new Network(102); + }); + final Vpn vpn = startLegacyVpn(profile); + final TestDeps deps = (TestDeps) vpn.mDeps; + try { + // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK + assertArrayEquals( + new String[] { EGRESS_IFACE, expectedAddr, "udppsk", + profile.ipsecIdentifier, profile.ipsecSecret, "1701" }, + deps.racoonArgs.get(10, TimeUnit.SECONDS)); + // literal values are hardcoded in Vpn.java for mtpd args + assertArrayEquals( + new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret, + "name", profile.username, "password", profile.password, + "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns", + "idle", "1800", "mtu", "1400", "mru", "1400" }, + deps.mtpdArgs.get(10, TimeUnit.SECONDS)); + // Now wait for the runner to be ready before testing for the route. + legacyRunnerReady.block(10_000); + // In this test the expected address is always v4 so /32 + final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"), + RouteInfo.RTN_THROW); + assertTrue("Routes lack the expected throw route (" + expectedRoute + ") : " + + vpn.mConfig.routes, + vpn.mConfig.routes.contains(expectedRoute)); + } finally { + // Now interrupt the thread, unblock the runner and clean up. + vpn.mVpnRunner.exitVpnRunner(); + deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier + vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup + } + } + + private static final class TestDeps extends Vpn.Dependencies { + public final CompletableFuture<String[]> racoonArgs = new CompletableFuture(); + public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture(); + public final File mStateFile; + + private final HashMap<String, Boolean> mRunningServices = new HashMap<>(); + + TestDeps() { + try { + mStateFile = File.createTempFile("vpnTest", ".tmp"); + mStateFile.deleteOnExit(); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + @Override + public void startService(final String serviceName) { + mRunningServices.put(serviceName, true); + } + + @Override + public void stopService(final String serviceName) { + mRunningServices.put(serviceName, false); + } + + @Override + public boolean isServiceRunning(final String serviceName) { + return mRunningServices.getOrDefault(serviceName, false); + } + + @Override + public boolean isServiceStopped(final String serviceName) { + return !isServiceRunning(serviceName); + } + + @Override + public File getStateFile() { + return mStateFile; + } + + @Override + public void sendArgumentsToDaemon( + final String daemon, final LocalSocket socket, final String[] arguments, + final Vpn.RetryScheduler interruptChecker) throws IOException { + if ("racoon".equals(daemon)) { + racoonArgs.complete(arguments); + } else if ("mtpd".equals(daemon)) { + writeStateFile(arguments); + mtpdArgs.complete(arguments); + } else { + throw new UnsupportedOperationException("Unsupported daemon : " + daemon); + } + } + + private void writeStateFile(final String[] arguments) throws IOException { + mStateFile.delete(); + mStateFile.createNewFile(); + mStateFile.deleteOnExit(); + final BufferedWriter writer = new BufferedWriter( + new FileWriter(mStateFile, false /* append */)); + writer.write(EGRESS_IFACE); + writer.write("\n"); + // addresses + writer.write("10.0.0.1/24\n"); + // routes + writer.write("192.168.6.0/24\n"); + // dns servers + writer.write("192.168.6.1\n"); + // search domains + writer.write("vpn.searchdomains.com\n"); + // endpoint - intentionally empty + writer.write("\n"); + writer.flush(); + writer.close(); + } + + @Override + @NonNull + public InetAddress resolve(final String endpoint) { + try { + // If a numeric IP address, return it. + return InetAddress.parseNumericAddress(endpoint); + } catch (IllegalArgumentException e) { + // Otherwise, return some token IP to test for. + return InetAddress.parseNumericAddress("5.6.7.8"); + } + } + + @Override + public boolean checkInterfacePresent(final Vpn vpn, final String iface) { + return true; + } } /** * Mock some methods of vpn object. */ private Vpn createVpn(@UserIdInt int userId) { - return new Vpn(Looper.myLooper(), mContext, mNetService, + return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService, userId, mKeyStore, mSystemServices, mIkev2SessionCreator); } diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 3cdfb00d288c..e4937892e2f7 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -122,7 +122,7 @@ interface IWifiManager DhcpInfo getDhcpInfo(); - void setScanAlwaysAvailable(boolean isAvailable); + void setScanAlwaysAvailable(boolean isAvailable, String packageName); boolean isScanAlwaysAvailable(); @@ -142,9 +142,9 @@ interface IWifiManager void updateInterfaceIpState(String ifaceName, int mode); - boolean startSoftAp(in WifiConfiguration wifiConfig); + boolean startSoftAp(in WifiConfiguration wifiConfig, String packageName); - boolean startTetheredHotspot(in SoftApConfiguration softApConfig); + boolean startTetheredHotspot(in SoftApConfiguration softApConfig, String packageName); boolean stopSoftAp(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index ae834f929691..b28b902910bf 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -2802,7 +2802,7 @@ public class WifiManager { @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public void setScanAlwaysAvailable(boolean isAvailable) { try { - mService.setScanAlwaysAvailable(isAvailable); + mService.setScanAlwaysAvailable(isAvailable, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3035,7 +3035,7 @@ public class WifiManager { }) public boolean startSoftAp(@Nullable WifiConfiguration wifiConfig) { try { - return mService.startSoftAp(wifiConfig); + return mService.startSoftAp(wifiConfig, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -3059,7 +3059,7 @@ public class WifiManager { }) public boolean startTetheredHotspot(@Nullable SoftApConfiguration softApConfig) { try { - return mService.startTetheredHotspot(softApConfig); + return mService.startTetheredHotspot(softApConfig, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index cba1690ac635..e7f1916c9e82 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -218,10 +218,10 @@ public class WifiManagerTest { */ @Test public void testStartSoftApCallsServiceWithWifiConfig() throws Exception { - when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(true); + when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(true); assertTrue(mWifiManager.startSoftAp(mApConfig)); - when(mWifiService.startSoftAp(eq(mApConfig))).thenReturn(false); + when(mWifiService.startSoftAp(mApConfig, TEST_PACKAGE_NAME)).thenReturn(false); assertFalse(mWifiManager.startSoftAp(mApConfig)); } @@ -231,10 +231,10 @@ public class WifiManagerTest { */ @Test public void testStartSoftApCallsServiceWithNullConfig() throws Exception { - when(mWifiService.startSoftAp(eq(null))).thenReturn(true); + when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(true); assertTrue(mWifiManager.startSoftAp(null)); - when(mWifiService.startSoftAp(eq(null))).thenReturn(false); + when(mWifiService.startSoftAp(null, TEST_PACKAGE_NAME)).thenReturn(false); assertFalse(mWifiManager.startSoftAp(null)); } @@ -257,10 +257,12 @@ public class WifiManagerTest { @Test public void testStartTetheredHotspotCallsServiceWithSoftApConfig() throws Exception { SoftApConfiguration softApConfig = generatorTestSoftApConfig(); - when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(true); + when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME)) + .thenReturn(true); assertTrue(mWifiManager.startTetheredHotspot(softApConfig)); - when(mWifiService.startTetheredHotspot(eq(softApConfig))).thenReturn(false); + when(mWifiService.startTetheredHotspot(softApConfig, TEST_PACKAGE_NAME)) + .thenReturn(false); assertFalse(mWifiManager.startTetheredHotspot(softApConfig)); } @@ -270,10 +272,10 @@ public class WifiManagerTest { */ @Test public void testStartTetheredHotspotCallsServiceWithNullConfig() throws Exception { - when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(true); + when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(true); assertTrue(mWifiManager.startTetheredHotspot(null)); - when(mWifiService.startTetheredHotspot(eq(null))).thenReturn(false); + when(mWifiService.startTetheredHotspot(null, TEST_PACKAGE_NAME)).thenReturn(false); assertFalse(mWifiManager.startTetheredHotspot(null)); } @@ -2375,7 +2377,7 @@ public class WifiManagerTest { @Test public void testScanAvailable() throws Exception { mWifiManager.setScanAlwaysAvailable(true); - verify(mWifiService).setScanAlwaysAvailable(true); + verify(mWifiService).setScanAlwaysAvailable(true, TEST_PACKAGE_NAME); when(mWifiService.isScanAlwaysAvailable()).thenReturn(false); assertFalse(mWifiManager.isScanAlwaysAvailable()); |