New internal interface method to get the active scorer metadata.

Returns the cached NetworkScorerAppData from the connected service.

Test: runtest frameworks-services -c com.android.server.NetworkScoreServiceTest
Bug: 34773276
Change-Id: Ia8986e770c4ede0c0f7e2ad4f5bc0a0117a9ae2b
This commit is contained in:
Jeremy Joslin
2017-02-02 14:27:05 -08:00
parent 3f7bf2e96c
commit a5172f69ca
6 changed files with 143 additions and 2 deletions

View File

@@ -18,6 +18,7 @@ package android.net;
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
import android.net.NetworkScorerAppManager;
import android.net.RecommendationRequest;
import android.net.RecommendationResult;
import android.net.ScoredNetwork;
@@ -130,4 +131,6 @@ interface INetworkScoreService
*/
oneway void requestRecommendationAsync(in RecommendationRequest request,
in RemoteCallback remoteCallback);
NetworkScorerAppManager.NetworkScorerAppData getActiveScorer();
}

View File

@@ -185,6 +185,20 @@ public class NetworkScoreManager {
}
}
/**
* Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
*
* @hide
*/
@Nullable
public NetworkScorerAppData getActiveScorer() {
try {
return mService.getActiveScorer();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Update network scores.
*

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2017, 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.net;
parcelable NetworkScorerAppManager.NetworkScorerAppData;

View File

@@ -24,6 +24,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -54,7 +56,7 @@ public class NetworkScorerAppManager {
/**
* Holds metadata about a discovered network scorer/recommendation application.
*/
public static class NetworkScorerAppData {
public static final class NetworkScorerAppData implements Parcelable {
/** UID of the scorer app. */
public final int packageUid;
private final ComponentName mRecommendationService;
@@ -64,6 +66,35 @@ public class NetworkScorerAppManager {
this.mRecommendationService = recommendationServiceComp;
}
protected NetworkScorerAppData(Parcel in) {
packageUid = in.readInt();
mRecommendationService = ComponentName.readFromParcel(in);
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(packageUid);
ComponentName.writeToParcel(mRecommendationService, dest);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<NetworkScorerAppData> CREATOR =
new Creator<NetworkScorerAppData>() {
@Override
public NetworkScorerAppData createFromParcel(Parcel in) {
return new NetworkScorerAppData(in);
}
@Override
public NetworkScorerAppData[] newArray(int size) {
return new NetworkScorerAppData[size];
}
};
public String getRecommendationServicePackageName() {
return mRecommendationService.getPackageName();
}

View File

@@ -53,6 +53,7 @@ import android.os.IBinder;
import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
@@ -676,6 +677,10 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
}
}
private boolean isCallerSystemProcess(int callingUid) {
return callingUid == Process.SYSTEM_UID;
}
/**
* Obtain the package name of the current active network scorer.
*
@@ -692,6 +697,27 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
return null;
}
/**
* Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
*/
@Override
public NetworkScorerAppData getActiveScorer() {
// Only the system can access this data.
if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
synchronized (mServiceConnectionLock) {
if (mServiceConnection != null) {
return mServiceConnection.mAppData;
}
}
} else {
throw new SecurityException(
"Caller is neither the system process nor a score requester.");
}
return null;
}
@Override
public void disableScoring() {
// Only the active scorer or the system should be allowed to disable scoring.

View File

@@ -829,6 +829,50 @@ public class NetworkScoreServiceTest {
assertEquals(expectedList, actualList);
}
@Test
public void testGetActiveScorer_notConnected_canRequestScores() throws Exception {
when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_GRANTED);
assertNull(mNetworkScoreService.getActiveScorer());
}
@Test
public void testGetActiveScorer_notConnected_canNotRequestScores() throws Exception {
when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_DENIED);
try {
mNetworkScoreService.getActiveScorer();
fail("SecurityException expected.");
} catch (SecurityException e) {
// expected
}
}
@Test
public void testGetActiveScorer_connected_canRequestScores()
throws Exception {
when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_GRANTED);
NetworkScorerAppData expectedAppData =
new NetworkScorerAppData(Binder.getCallingUid(), RECOMMENDATION_SERVICE_COMP);
bindToScorer(expectedAppData);
assertEquals(expectedAppData, mNetworkScoreService.getActiveScorer());
}
@Test
public void testGetActiveScorer_connected_canNotRequestScores()
throws Exception {
when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
.thenReturn(PackageManager.PERMISSION_DENIED);
bindToScorer(false);
try {
mNetworkScoreService.getActiveScorer();
fail("SecurityException expected.");
} catch (SecurityException e) {
// expected
}
}
// "injects" the mock INetworkRecommendationProvider into the NetworkScoreService.
private void injectProvider() {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
@@ -849,9 +893,13 @@ public class NetworkScoreServiceTest {
}
private void bindToScorer(boolean callerIsScorer) {
final int callingUid = callerIsScorer ? Binder.getCallingUid() : 0;
final int callingUid = callerIsScorer ? Binder.getCallingUid() : Binder.getCallingUid() + 1;
NetworkScorerAppData appData =
new NetworkScorerAppData(callingUid, RECOMMENDATION_SERVICE_COMP);
bindToScorer(appData);
}
private void bindToScorer(NetworkScorerAppData appData) {
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
isA(UserHandle.class))).thenReturn(true);