Merge "NetworkScoreManager: Add @SystemApi for wifi mainline module" am: 5b57190f08
am: 0564779e76
Change-Id: I04580ad32eefb2ce4c8df8f1037b8457238c30eb
diff --git a/api/system-current.txt b/api/system-current.txt
index ac8581a..0b8cdf2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4179,6 +4179,7 @@
public class NetworkKey implements android.os.Parcelable {
ctor public NetworkKey(android.net.WifiKey);
+ method @Nullable public static android.net.NetworkKey createFromScanResult(@Nullable android.net.wifi.ScanResult);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkKey> CREATOR;
@@ -4201,16 +4202,23 @@
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean clearScores() throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public void disableScoring() throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public String getActiveScorerPackage();
+ method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public void registerNetworkScoreCallback(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkScoreManager.NetworkScoreCallback) throws java.lang.SecurityException;
+ method @RequiresPermission("android.permission.REQUEST_NETWORK_SCORES") public boolean requestScores(@NonNull android.net.NetworkKey[]) throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, "android.permission.REQUEST_NETWORK_SCORES"}) public boolean setActiveScorer(String) throws java.lang.SecurityException;
- method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(android.net.ScoredNetwork[]) throws java.lang.SecurityException;
- field public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
+ method @RequiresPermission(android.Manifest.permission.SCORE_NETWORKS) public boolean updateScores(@NonNull android.net.ScoredNetwork[]) throws java.lang.SecurityException;
+ field @Deprecated public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
field public static final String ACTION_CUSTOM_ENABLE = "android.net.scoring.CUSTOM_ENABLE";
field public static final String ACTION_RECOMMEND_NETWORKS = "android.net.action.RECOMMEND_NETWORKS";
field public static final String ACTION_SCORER_CHANGED = "android.net.scoring.SCORER_CHANGED";
- field public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
- field public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
+ field @Deprecated public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
+ field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
field public static final String EXTRA_NEW_SCORER = "newScorer";
- field public static final String EXTRA_PACKAGE_NAME = "packageName";
+ field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName";
+ }
+
+ public static interface NetworkScoreManager.NetworkScoreCallback {
+ method public void clearScores();
+ method public void updateScores(@NonNull java.util.List<android.net.ScoredNetwork>);
}
public class NetworkStack {
diff --git a/core/java/android/net/NetworkKey.java b/core/java/android/net/NetworkKey.java
index 04cb877..9af1407 100644
--- a/core/java/android/net/NetworkKey.java
+++ b/core/java/android/net/NetworkKey.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -27,6 +28,8 @@
import android.text.TextUtils;
import android.util.Log;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -48,6 +51,13 @@
/** A wifi network, for which {@link #wifiKey} will be populated. */
public static final int TYPE_WIFI = 1;
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"TYPE_"}, value = {
+ TYPE_WIFI
+ })
+ public @interface NetworkType {}
+
/**
* The type of this network.
* @see #TYPE_WIFI
@@ -65,7 +75,6 @@
*
* @return A new {@link NetworkKey} instance or <code>null</code> if the given
* {@link ScanResult} instance is malformed.
- * @hide
*/
@Nullable
public static NetworkKey createFromScanResult(@Nullable ScanResult result) {
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 50dd468..f6dc525 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -17,7 +17,9 @@
package android.net;
import android.Manifest.permission;
+import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -25,13 +27,16 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Class that manages communication between network subsystems and a network scorer.
@@ -50,19 +55,25 @@
@SystemApi
@SystemService(Context.NETWORK_SCORE_SERVICE)
public class NetworkScoreManager {
+ private static final String TAG = "NetworkScoreManager";
+
/**
* Activity action: ask the user to change the active network scorer. This will show a dialog
* that asks the user whether they want to replace the current active scorer with the one
* specified in {@link #EXTRA_PACKAGE_NAME}. The activity will finish with RESULT_OK if the
* active scorer was changed or RESULT_CANCELED if it failed for any reason.
+ * @deprecated No longer sent.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CHANGE_ACTIVE = "android.net.scoring.CHANGE_ACTIVE";
/**
* Extra used with {@link #ACTION_CHANGE_ACTIVE} to specify the new scorer package. Set with
* {@link android.content.Intent#putExtra(String, String)}.
+ * @deprecated No longer sent.
*/
+ @Deprecated
public static final String EXTRA_PACKAGE_NAME = "packageName";
/**
@@ -73,7 +84,9 @@
* configured by the user as well as any open networks.
*
* <p class="note">This is a protected intent that can only be sent by the system.
+ * @deprecated Use {@link #ACTION_RECOMMEND_NETWORKS} to bind scorer app instead.
*/
+ @Deprecated
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_SCORE_NETWORKS = "android.net.scoring.SCORE_NETWORKS";
@@ -81,7 +94,9 @@
* Extra used with {@link #ACTION_SCORE_NETWORKS} to specify the networks to be scored, as an
* array of {@link NetworkKey}s. Can be obtained with
* {@link android.content.Intent#getParcelableArrayExtra(String)}}.
+ * @deprecated Use {@link #ACTION_RECOMMEND_NETWORKS} to bind scorer app instead.
*/
+ @Deprecated
public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore";
/**
@@ -285,7 +300,7 @@
* @throws SecurityException if the caller is not the active scorer.
*/
@RequiresPermission(android.Manifest.permission.SCORE_NETWORKS)
- public boolean updateScores(ScoredNetwork[] networks) throws SecurityException {
+ public boolean updateScores(@NonNull ScoredNetwork[] networks) throws SecurityException {
try {
return mService.updateScores(networks);
} catch (RemoteException e) {
@@ -359,13 +374,21 @@
/**
* Request scoring for networks.
*
- * @return true if the broadcast was sent, or false if there is no active scorer.
+ * <p>
+ * Note: The results (i.e scores) for these networks, when available will be provided via the
+ * callback registered with {@link #registerNetworkScoreCallback(int, int, Executor,
+ * NetworkScoreCallback)}. The calling module is responsible for registering a callback to
+ * receive the results before requesting new scores via this API.
+ *
+ * @return true if the request was successfully sent, or false if there is no active scorer.
* @throws SecurityException if the caller does not hold the
* {@link permission#REQUEST_NETWORK_SCORES} permission.
+ *
* @hide
*/
+ @SystemApi
@RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
- public boolean requestScores(NetworkKey[] networks) throws SecurityException {
+ public boolean requestScores(@NonNull NetworkKey[] networks) throws SecurityException {
try {
return mService.requestScores(networks);
} catch (RemoteException e) {
@@ -431,6 +454,88 @@
}
/**
+ * Base class for network score cache callback. Should be extended by applications and set
+ * when calling {@link #registerNetworkScoreCallback(int, int, NetworkScoreCallback,
+ * Executor)}
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface NetworkScoreCallback {
+ /**
+ * Called when a new set of network scores are available.
+ * This is triggered in response when the client invokes
+ * {@link #requestScores(NetworkKey[])} to score a new set of networks.
+ *
+ * @param networks List of {@link ScoredNetwork} containing updated scores.
+ */
+ void updateScores(@NonNull List<ScoredNetwork> networks);
+
+ /**
+ * Invokes when all the previously provided scores are no longer valid.
+ */
+ void clearScores();
+ }
+
+ /**
+ * Callback proxy for {@link NetworkScoreCallback} objects.
+ */
+ private class NetworkScoreCallbackProxy extends INetworkScoreCache.Stub {
+ private final Executor mExecutor;
+ private final NetworkScoreCallback mCallback;
+
+ NetworkScoreCallbackProxy(Executor executor, NetworkScoreCallback callback) {
+ mExecutor = executor;
+ mCallback = callback;
+ }
+
+ @Override
+ public void updateScores(@NonNull List<ScoredNetwork> networks) {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
+ mCallback.updateScores(networks);
+ });
+ }
+
+ @Override
+ public void clearScores() {
+ Binder.clearCallingIdentity();
+ mExecutor.execute(() -> {
+ mCallback.clearScores();
+ });
+ }
+ }
+
+ /**
+ * Register a network score callback.
+ *
+ * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}
+ * @param filterType the {@link CacheUpdateFilter} to apply
+ * @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the
+ * scores change.
+ * @param executor The executor on which to execute the callbacks.
+ * @throws SecurityException if the caller does not hold the
+ * {@link permission#REQUEST_NETWORK_SCORES} permission.
+ * @throws IllegalArgumentException if a callback is already registered for this type.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES)
+ public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType,
+ @CacheUpdateFilter int filterType,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull NetworkScoreCallback callback) throws SecurityException {
+ if (callback == null || executor == null) {
+ throw new IllegalArgumentException("callback / executor cannot be null");
+ }
+ Log.v(TAG, "registerNetworkScoreCallback: callback=" + callback + ", executor="
+ + executor);
+ // Use the @hide method.
+ registerNetworkScoreCache(
+ networkType, new NetworkScoreCallbackProxy(executor, callback), filterType);
+ }
+
+ /**
* Determine whether the application with the given UID is the enabled scorer.
*
* @param callingUid the UID to check
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 80d7ac9..9a7a4e7 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -60,12 +60,9 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.os.TransferPipe;
-import com.android.internal.telephony.SmsApplication;
import com.android.internal.util.DumpUtils;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
@@ -908,17 +905,6 @@
}
writer.println("Current scorer: " + currentScorer);
- sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
- @Override
- public void accept(INetworkScoreCache networkScoreCache, Object cookie) {
- try {
- TransferPipe.dumpAsync(networkScoreCache.asBinder(), fd, args);
- } catch (IOException | RemoteException e) {
- writer.println("Failed to dump score cache: " + e);
- }
- }
- }, getScoreCacheLists());
-
synchronized (mServiceConnectionLock) {
if (mServiceConnection != null) {
mServiceConnection.dump(fd, writer, args);
diff --git a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
index b22ae070..5a212a8 100755
--- a/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
+++ b/wifi/java/android/net/wifi/WifiNetworkScoreCache.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
+import android.net.NetworkScoreManager;
import android.net.ScoredNetwork;
import android.os.Handler;
import android.os.Process;
@@ -40,7 +41,8 @@
*
* @hide
*/
-public class WifiNetworkScoreCache extends INetworkScoreCache.Stub {
+public class WifiNetworkScoreCache extends INetworkScoreCache.Stub
+ implements NetworkScoreManager.NetworkScoreCallback {
private static final String TAG = "WifiNetworkScoreCache";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
@@ -246,6 +248,17 @@
}
@Override protected final void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ dumpWithLatestScanResults(fd, writer, args, wifiManager.getScanResults());
+ }
+
+ /**
+ * This is directly invoked from within Wifi-Service (on it's instance of this class), hence
+ * avoid making the WifiManager.getScanResults() call to avoid a deadlock.
+ */
+ public final void dumpWithLatestScanResults(
+ FileDescriptor fd, PrintWriter writer, String[] args,
+ List<ScanResult> latestScanResults) {
mContext.enforceCallingOrSelfPermission(permission.DUMP, TAG);
String header = String.format("WifiNetworkScoreCache (%s/%d)",
mContext.getPackageName(), Process.myUid());
@@ -256,8 +269,7 @@
writer.println(" " + score);
}
writer.println(" Network scores for latest ScanResults:");
- WifiManager wifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- for (ScanResult scanResult : wifiManager.getScanResults()) {
+ for (ScanResult scanResult : latestScanResults) {
writer.println(
" " + buildNetworkKey(scanResult) + ": " + getNetworkScore(scanResult));
}