Cache NetworkScorerAppData in the ScoringServiceConnection.
Store the entire NetworkScorerAppData instance in the ScoringServiceConnection instead of just most of its fields. Test: runtest frameworks-services -c com.android.server.NetworkScoreServiceTest Bug: 34773276 Change-Id: Id2ed7c431dee9895e85e1966903ac919f1704eba
This commit is contained in:
@@ -18,6 +18,7 @@ package android.net;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -33,6 +34,7 @@ import com.android.internal.R;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Internal class for discovering and managing the network scorer/recommendation application.
|
||||
@@ -53,33 +55,43 @@ public class NetworkScorerAppManager {
|
||||
* Holds metadata about a discovered network scorer/recommendation application.
|
||||
*/
|
||||
public static class NetworkScorerAppData {
|
||||
/** Package name of this scorer app. */
|
||||
public final String packageName;
|
||||
|
||||
/** UID of the scorer app. */
|
||||
public final int packageUid;
|
||||
private final ComponentName mRecommendationService;
|
||||
|
||||
/**
|
||||
* Name of the recommendation service we can bind to.
|
||||
*/
|
||||
public final String recommendationServiceClassName;
|
||||
|
||||
public NetworkScorerAppData(String packageName, int packageUid,
|
||||
String recommendationServiceClassName) {
|
||||
this.packageName = packageName;
|
||||
public NetworkScorerAppData(int packageUid, ComponentName recommendationServiceComp) {
|
||||
this.packageUid = packageUid;
|
||||
this.recommendationServiceClassName = recommendationServiceClassName;
|
||||
this.mRecommendationService = recommendationServiceComp;
|
||||
}
|
||||
|
||||
public String getRecommendationServicePackageName() {
|
||||
return mRecommendationService.getPackageName();
|
||||
}
|
||||
|
||||
public ComponentName getRecommendationServiceComponent() {
|
||||
return mRecommendationService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder("NetworkScorerAppData{");
|
||||
sb.append("mPackageName='").append(packageName).append('\'');
|
||||
sb.append(", packageUid=").append(packageUid);
|
||||
sb.append(", recommendationServiceClassName='")
|
||||
.append(recommendationServiceClassName).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
return "NetworkScorerAppData{" +
|
||||
"packageUid=" + packageUid +
|
||||
", mRecommendationService=" + mRecommendationService +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
NetworkScorerAppData that = (NetworkScorerAppData) o;
|
||||
return packageUid == that.packageUid &&
|
||||
Objects.equals(mRecommendationService, that.mRecommendationService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(packageUid, mRecommendationService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,16 +122,16 @@ public class NetworkScorerAppManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PackageManager pm = mContext.getPackageManager();
|
||||
for (int i = 0; i < potentialPkgs.size(); i++) {
|
||||
final String potentialPkg = potentialPkgs.get(i);
|
||||
|
||||
// Look for the recommendation service class and required receiver.
|
||||
final ResolveInfo resolveServiceInfo = findRecommendationService(potentialPkg);
|
||||
if (resolveServiceInfo != null) {
|
||||
return new NetworkScorerAppData(potentialPkg,
|
||||
resolveServiceInfo.serviceInfo.applicationInfo.uid,
|
||||
resolveServiceInfo.serviceInfo.name);
|
||||
final ComponentName componentName =
|
||||
new ComponentName(potentialPkg, resolveServiceInfo.serviceInfo.name);
|
||||
return new NetworkScorerAppData(resolveServiceInfo.serviceInfo.applicationInfo.uid,
|
||||
componentName);
|
||||
} else {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, potentialPkg + " does not have the required components, skipping.");
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.net;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.Manifest.permission;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -30,13 +31,16 @@ import android.content.res.Resources;
|
||||
import android.net.NetworkScorerAppManager.NetworkScorerAppData;
|
||||
import android.provider.Settings;
|
||||
import android.test.InstrumentationTestCase;
|
||||
|
||||
import com.android.internal.R;
|
||||
import java.util.List;
|
||||
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
|
||||
@Mock private Context mMockContext;
|
||||
@Mock private PackageManager mMockPm;
|
||||
@@ -114,39 +118,40 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
|
||||
|
||||
public void testGetNetworkRecommendationProviderData_scoreNetworksNotGranted()
|
||||
throws Exception {
|
||||
setNetworkRecommendationPackageNames("package1");
|
||||
mockScoreNetworksDenied("package1");
|
||||
mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
|
||||
final ComponentName recoComponent = new ComponentName("package1", "class1");
|
||||
setNetworkRecommendationPackageNames(recoComponent.getPackageName());
|
||||
mockScoreNetworksDenied(recoComponent.getPackageName());
|
||||
mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
|
||||
|
||||
assertNull(mNetworkScorerAppManager.getNetworkRecommendationProviderData());
|
||||
}
|
||||
|
||||
public void testGetNetworkRecommendationProviderData_available() throws Exception {
|
||||
setNetworkRecommendationPackageNames("package1");
|
||||
mockScoreNetworksGranted("package1");
|
||||
mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
|
||||
final ComponentName recoComponent = new ComponentName("package1", "class1");
|
||||
setNetworkRecommendationPackageNames(recoComponent.getPackageName());
|
||||
mockScoreNetworksGranted(recoComponent.getPackageName());
|
||||
mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
|
||||
|
||||
NetworkScorerAppData appData =
|
||||
mNetworkScorerAppManager.getNetworkRecommendationProviderData();
|
||||
assertNotNull(appData);
|
||||
assertEquals("package1", appData.packageName);
|
||||
assertEquals(recoComponent, appData.getRecommendationServiceComponent());
|
||||
assertEquals(924, appData.packageUid);
|
||||
assertEquals(".RecommendationService", appData.recommendationServiceClassName);
|
||||
}
|
||||
|
||||
public void testGetActiveScorer_providerAvailable() throws Exception {
|
||||
setNetworkRecommendationPackageNames("package1");
|
||||
mockScoreNetworksGranted("package1");
|
||||
mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
|
||||
final ComponentName recoComponent = new ComponentName("package1", "class1");
|
||||
setNetworkRecommendationPackageNames(recoComponent.getPackageName());
|
||||
mockScoreNetworksGranted(recoComponent.getPackageName());
|
||||
mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
|
||||
|
||||
ContentResolver cr = mTargetContext.getContentResolver();
|
||||
Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 1);
|
||||
|
||||
final NetworkScorerAppData activeScorer = mNetworkScorerAppManager.getActiveScorer();
|
||||
assertNotNull(activeScorer);
|
||||
assertEquals("package1", activeScorer.packageName);
|
||||
assertEquals(recoComponent, activeScorer.getRecommendationServiceComponent());
|
||||
assertEquals(924, activeScorer.packageUid);
|
||||
assertEquals(".RecommendationService", activeScorer.recommendationServiceClassName);
|
||||
}
|
||||
|
||||
public void testGetActiveScorer_providerNotAvailable()
|
||||
@@ -159,9 +164,10 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
|
||||
}
|
||||
|
||||
public void testGetActiveScorer_recommendationsDisabled() throws Exception {
|
||||
setNetworkRecommendationPackageNames("package1");
|
||||
mockScoreNetworksGranted("package1");
|
||||
mockRecommendationServiceAvailable("package1", 924 /* packageUid */);
|
||||
final ComponentName recoComponent = new ComponentName("package1", "class1");
|
||||
setNetworkRecommendationPackageNames(recoComponent.getPackageName());
|
||||
mockScoreNetworksGranted(recoComponent.getPackageName());
|
||||
mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */);
|
||||
ContentResolver cr = mTargetContext.getContentResolver();
|
||||
Settings.Global.putInt(cr, Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0);
|
||||
|
||||
@@ -187,11 +193,11 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
|
||||
.thenReturn(PackageManager.PERMISSION_DENIED);
|
||||
}
|
||||
|
||||
private void mockRecommendationServiceAvailable(final String packageName, int packageUid) {
|
||||
private void mockRecommendationServiceAvailable(final ComponentName compName, int packageUid) {
|
||||
final ResolveInfo serviceInfo = new ResolveInfo();
|
||||
serviceInfo.serviceInfo = new ServiceInfo();
|
||||
serviceInfo.serviceInfo.name = ".RecommendationService";
|
||||
serviceInfo.serviceInfo.packageName = packageName;
|
||||
serviceInfo.serviceInfo.name = compName.getClassName();
|
||||
serviceInfo.serviceInfo.packageName = compName.getPackageName();
|
||||
serviceInfo.serviceInfo.applicationInfo = new ApplicationInfo();
|
||||
serviceInfo.serviceInfo.applicationInfo.uid = packageUid;
|
||||
|
||||
@@ -203,7 +209,7 @@ public class NetworkScorerAppManagerTest extends InstrumentationTestCase {
|
||||
Intent intent = (Intent) object;
|
||||
return NetworkScoreManager.ACTION_RECOMMEND_NETWORKS
|
||||
.equals(intent.getAction())
|
||||
&& packageName.equals(intent.getPackage());
|
||||
&& compName.getPackageName().equals(intent.getPackage());
|
||||
}
|
||||
}), Mockito.eq(flags))).thenReturn(serviceInfo);
|
||||
}
|
||||
|
||||
@@ -183,11 +183,12 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
// connection.
|
||||
if (DBG) Log.d(TAG, "No active scorers available.");
|
||||
unbindFromScoringServiceIfNeeded();
|
||||
} else if (activeScorer.packageName.equals(scorerPackageName)) {
|
||||
} else if (activeScorer.getRecommendationServicePackageName().equals(scorerPackageName))
|
||||
{
|
||||
// The active scoring service changed in some way.
|
||||
if (DBG) {
|
||||
Log.d(TAG, "Possible change to the active scorer: "
|
||||
+ activeScorer.packageName);
|
||||
+ activeScorer.getRecommendationServicePackageName());
|
||||
}
|
||||
if (forceUnbind) {
|
||||
unbindFromScoringServiceIfNeeded();
|
||||
@@ -198,7 +199,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
// bound to the correct scoring app. The logic in bindToScoringServiceIfNeeded()
|
||||
// will sort that out to leave us bound to the most recent active scorer.
|
||||
if (DBG) {
|
||||
Log.d(TAG, "Binding to " + activeScorer.packageName + " if needed.");
|
||||
Log.d(TAG, "Binding to " + activeScorer.getRecommendationServiceComponent()
|
||||
+ " if needed.");
|
||||
}
|
||||
bindToScoringServiceIfNeeded(activeScorer);
|
||||
}
|
||||
@@ -334,22 +336,19 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
bindToScoringServiceIfNeeded(scorerData);
|
||||
}
|
||||
|
||||
private void bindToScoringServiceIfNeeded(NetworkScorerAppData scorerData) {
|
||||
if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + scorerData + ")");
|
||||
if (scorerData != null && scorerData.recommendationServiceClassName != null) {
|
||||
ComponentName componentName = new ComponentName(scorerData.packageName,
|
||||
scorerData.recommendationServiceClassName);
|
||||
private void bindToScoringServiceIfNeeded(NetworkScorerAppData appData) {
|
||||
if (DBG) Log.d(TAG, "bindToScoringServiceIfNeeded(" + appData + ")");
|
||||
if (appData != null) {
|
||||
synchronized (mServiceConnectionLock) {
|
||||
// If we're connected to a different component then drop it.
|
||||
if (mServiceConnection != null
|
||||
&& !mServiceConnection.mComponentName.equals(componentName)) {
|
||||
&& !mServiceConnection.mAppData.equals(appData)) {
|
||||
unbindFromScoringServiceIfNeeded();
|
||||
}
|
||||
|
||||
// If we're not connected at all then create a new connection.
|
||||
if (mServiceConnection == null) {
|
||||
mServiceConnection = new ScoringServiceConnection(componentName,
|
||||
scorerData.packageUid);
|
||||
mServiceConnection = new ScoringServiceConnection(appData);
|
||||
}
|
||||
|
||||
// Make sure the connection is connected (idempotent)
|
||||
@@ -672,7 +671,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
@Override
|
||||
public boolean isCallerActiveScorer(int callingUid) {
|
||||
synchronized (mServiceConnectionLock) {
|
||||
return mServiceConnection != null && mServiceConnection.mScoringAppUid == callingUid;
|
||||
return mServiceConnection != null
|
||||
&& mServiceConnection.mAppData.packageUid == callingUid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -686,7 +686,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
public String getActiveScorerPackage() {
|
||||
synchronized (mServiceConnectionLock) {
|
||||
if (mServiceConnection != null) {
|
||||
return mServiceConnection.mComponentName.getPackageName();
|
||||
return mServiceConnection.getPackageName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -881,7 +881,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
writer.println("Scoring is disabled.");
|
||||
return;
|
||||
}
|
||||
writer.println("Current scorer: " + currentScorer.packageName);
|
||||
writer.println("Current scorer: " + currentScorer);
|
||||
|
||||
sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
|
||||
@Override
|
||||
@@ -966,21 +966,19 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
}
|
||||
|
||||
private static class ScoringServiceConnection implements ServiceConnection {
|
||||
private final ComponentName mComponentName;
|
||||
private final int mScoringAppUid;
|
||||
private final NetworkScorerAppData mAppData;
|
||||
private volatile boolean mBound = false;
|
||||
private volatile boolean mConnected = false;
|
||||
private volatile INetworkRecommendationProvider mRecommendationProvider;
|
||||
|
||||
ScoringServiceConnection(ComponentName componentName, int scoringAppUid) {
|
||||
mComponentName = componentName;
|
||||
mScoringAppUid = scoringAppUid;
|
||||
ScoringServiceConnection(NetworkScorerAppData appData) {
|
||||
mAppData = appData;
|
||||
}
|
||||
|
||||
void connect(Context context) {
|
||||
if (!mBound) {
|
||||
Intent service = new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS);
|
||||
service.setComponent(mComponentName);
|
||||
service.setComponent(mAppData.getRecommendationServiceComponent());
|
||||
mBound = context.bindServiceAsUser(service, this,
|
||||
Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
|
||||
UserHandle.SYSTEM);
|
||||
@@ -1010,6 +1008,10 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
return mRecommendationProvider;
|
||||
}
|
||||
|
||||
String getPackageName() {
|
||||
return mAppData.getRecommendationServiceComponent().getPackageName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
if (DBG) Log.d(TAG, "ScoringServiceConnection: " + name.flattenToString());
|
||||
@@ -1027,7 +1029,9 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
|
||||
writer.println("ScoringServiceConnection: " + mComponentName + ", bound: " + mBound
|
||||
writer.println("ScoringServiceConnection: "
|
||||
+ mAppData.getRecommendationServiceComponent()
|
||||
+ ", bound: " + mBound
|
||||
+ ", connected: " + mConnected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,8 @@ public class NetworkScoreServiceTest {
|
||||
private static final String SSID = "ssid";
|
||||
private static final String SSID_2 = "ssid_2";
|
||||
private static final String SSID_3 = "ssid_3";
|
||||
private static final ComponentName RECOMMENDATION_SERVICE_COMP =
|
||||
new ComponentName("newPackageName", "newScoringServiceClass");
|
||||
private static final ScoredNetwork SCORED_NETWORK =
|
||||
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID), "00:00:00:00:00:00")),
|
||||
null /* rssiCurve*/);
|
||||
@@ -124,7 +126,7 @@ public class NetworkScoreServiceTest {
|
||||
new ScoredNetwork(new NetworkKey(new WifiKey(quote(SSID_2), "00:00:00:00:00:00")),
|
||||
null /* rssiCurve*/);
|
||||
private static final NetworkScorerAppData NEW_SCORER =
|
||||
new NetworkScorerAppData("newPackageName", 1, "newScoringServiceClass");
|
||||
new NetworkScorerAppData(1, RECOMMENDATION_SERVICE_COMP);
|
||||
|
||||
@Mock private NetworkScorerAppManager mNetworkScorerAppManager;
|
||||
@Mock private Context mContext;
|
||||
@@ -203,8 +205,7 @@ public class NetworkScoreServiceTest {
|
||||
|
||||
verify(mContext).bindServiceAsUser(MockUtils.checkIntent(
|
||||
new Intent(NetworkScoreManager.ACTION_RECOMMEND_NETWORKS)
|
||||
.setComponent(new ComponentName(NEW_SCORER.packageName,
|
||||
NEW_SCORER.recommendationServiceClassName))),
|
||||
.setComponent(RECOMMENDATION_SERVICE_COMP)),
|
||||
any(ServiceConnection.class),
|
||||
eq(Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE),
|
||||
eq(UserHandle.SYSTEM));
|
||||
@@ -657,7 +658,8 @@ public class NetworkScoreServiceTest {
|
||||
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
|
||||
mNetworkScoreService.systemRunning();
|
||||
|
||||
assertEquals(NEW_SCORER.packageName, mNetworkScoreService.getActiveScorerPackage());
|
||||
assertEquals(NEW_SCORER.getRecommendationServicePackageName(),
|
||||
mNetworkScoreService.getActiveScorerPackage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -829,8 +831,6 @@ public class NetworkScoreServiceTest {
|
||||
|
||||
// "injects" the mock INetworkRecommendationProvider into the NetworkScoreService.
|
||||
private void injectProvider() {
|
||||
final ComponentName componentName = new ComponentName(NEW_SCORER.packageName,
|
||||
NEW_SCORER.recommendationServiceClassName);
|
||||
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(NEW_SCORER);
|
||||
when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
|
||||
isA(UserHandle.class))).thenAnswer(new Answer<Boolean>() {
|
||||
@@ -840,7 +840,8 @@ public class NetworkScoreServiceTest {
|
||||
when(mockBinder.queryLocalInterface(anyString()))
|
||||
.thenReturn(mRecommendationProvider);
|
||||
invocation.getArgumentAt(1, ServiceConnection.class)
|
||||
.onServiceConnected(componentName, mockBinder);
|
||||
.onServiceConnected(NEW_SCORER.getRecommendationServiceComponent(),
|
||||
mockBinder);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@@ -849,8 +850,8 @@ public class NetworkScoreServiceTest {
|
||||
|
||||
private void bindToScorer(boolean callerIsScorer) {
|
||||
final int callingUid = callerIsScorer ? Binder.getCallingUid() : 0;
|
||||
NetworkScorerAppData appData = new NetworkScorerAppData(NEW_SCORER.packageName,
|
||||
callingUid, NEW_SCORER.recommendationServiceClassName);
|
||||
NetworkScorerAppData appData =
|
||||
new NetworkScorerAppData(callingUid, RECOMMENDATION_SERVICE_COMP);
|
||||
when(mNetworkScorerAppManager.getActiveScorer()).thenReturn(appData);
|
||||
when(mContext.bindServiceAsUser(isA(Intent.class), isA(ServiceConnection.class), anyInt(),
|
||||
isA(UserHandle.class))).thenReturn(true);
|
||||
|
||||
Reference in New Issue
Block a user