Merge "Fix issue #28930592: Scoring service binding is not reestablished." into nyc-dev am: 49b515a2a5
am: 0b6676d7bc
* commit '0b6676d7bc32c9ebb18f5e91fc64974756d98f09':
Fix issue #28930592: Scoring service binding is not reestablished.
Change-Id: I72614c0862bca74b7c0180b97ee9138a01f18657
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 2a78f90..3745e0b 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -17,12 +17,10 @@
package com.android.server;
import android.Manifest.permission;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.net.INetworkScoreCache;
@@ -33,7 +31,6 @@
import android.net.ScoredNetwork;
import android.os.Binder;
import android.os.IBinder;
-import android.os.PatternMatcher;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
@@ -42,6 +39,7 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageMonitor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -62,39 +60,75 @@
private final Context mContext;
private final Map<Integer, INetworkScoreCache> mScoreCaches;
- /** Lock used to update mReceiver when scorer package changes occur. */
- private final Object mReceiverLock = new Object[0];
+ /** Lock used to update mPackageMonitor when scorer package changes occur. */
+ private final Object mPackageMonitorLock = new Object[0];
- /** Clears scores when the active scorer package is no longer valid. */
- @GuardedBy("mReceiverLock")
- private ScorerChangedReceiver mReceiver;
+ @GuardedBy("mPackageMonitorLock")
+ private NetworkScorerPackageMonitor mPackageMonitor;
private ScoringServiceConnection mServiceConnection;
- private class ScorerChangedReceiver extends BroadcastReceiver {
+ /**
+ * Clears scores when the active scorer package is no longer valid and
+ * manages the service connection.
+ */
+ private class NetworkScorerPackageMonitor extends PackageMonitor {
final String mRegisteredPackage;
- ScorerChangedReceiver(String packageName) {
- mRegisteredPackage = packageName;
+ private NetworkScorerPackageMonitor(String mRegisteredPackage) {
+ this.mRegisteredPackage = mRegisteredPackage;
}
@Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_PACKAGE_CHANGED.equals(action)
- || Intent.ACTION_PACKAGE_REPLACED.equals(action)
- || Intent.ACTION_PACKAGE_FULLY_REMOVED.equals(action)) {
- NetworkScorerAppData activeScorer =
+ public void onPackageAdded(String packageName, int uid) {
+ evaluateBinding(packageName, true /* forceUnbind */);
+ }
+
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ evaluateBinding(packageName, true /* forceUnbind */);
+ }
+
+ @Override
+ public void onPackageModified(String packageName) {
+ evaluateBinding(packageName, false /* forceUnbind */);
+ }
+
+ @Override
+ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
+ if (doit) { // "doit" means the force stop happened instead of just being queried for.
+ for (String packageName : packages) {
+ evaluateBinding(packageName, true /* forceUnbind */);
+ }
+ }
+ return super.onHandleForceStop(intent, packages, uid, doit);
+ }
+
+ @Override
+ public void onPackageUpdateFinished(String packageName, int uid) {
+ evaluateBinding(packageName, true /* forceUnbind */);
+ }
+
+ private void evaluateBinding(String scorerPackageName, boolean forceUnbind) {
+ if (mRegisteredPackage.equals(scorerPackageName)) {
+ if (DBG) {
+ Log.d(TAG, "Evaluating binding for: " + scorerPackageName
+ + ", forceUnbind=" + forceUnbind);
+ }
+ final NetworkScorerAppData activeScorer =
NetworkScorerAppManager.getActiveScorer(mContext);
if (activeScorer == null) {
- // Package change has invalidated a scorer.
+ // Package change has invalidated a scorer, this will also unbind any service
+ // connection.
Log.i(TAG, "Package " + mRegisteredPackage +
" is no longer valid, disabling scoring.");
setScorerInternal(null);
} else if (activeScorer.mScoringServiceClassName == null) {
// The scoring service is not available, make sure it's unbound.
unbindFromScoringServiceIfNeeded();
- } else {
- // The scoring service may have changed or been added.
+ } else { // The scoring service changed in some way.
+ if (forceUnbind) {
+ unbindFromScoringServiceIfNeeded();
+ }
bindToScoringServiceIfNeeded(activeScorer);
}
}
@@ -121,7 +155,7 @@
Settings.Global.putInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 1);
}
- registerPackageReceiverIfNeeded();
+ registerPackageMonitorIfNeeded();
}
/** Called when the system is ready for us to start third-party code. */
@@ -130,33 +164,29 @@
bindToScoringServiceIfNeeded();
}
- private void registerPackageReceiverIfNeeded() {
- if (DBG) Log.d(TAG, "registerPackageReceiverIfNeeded");
+ private void registerPackageMonitorIfNeeded() {
+ if (DBG) Log.d(TAG, "registerPackageMonitorIfNeeded");
NetworkScorerAppData scorer = NetworkScorerAppManager.getActiveScorer(mContext);
- synchronized (mReceiverLock) {
- // Unregister the receiver if the current scorer has changed since last registration.
- if (mReceiver != null) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Unregistering receiver for " + mReceiver.mRegisteredPackage);
+ synchronized (mPackageMonitorLock) {
+ // Unregister the current monitor if needed.
+ if (mPackageMonitor != null) {
+ if (DBG) {
+ Log.d(TAG, "Unregistering package monitor for "
+ + mPackageMonitor.mRegisteredPackage);
}
- mContext.unregisterReceiver(mReceiver);
- mReceiver = null;
+ mPackageMonitor.unregister();
+ mPackageMonitor = null;
}
- // Register receiver if a scorer is active.
+ // Create and register the monitor if a scorer is active.
if (scorer != null) {
- IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- filter.addAction(Intent.ACTION_PACKAGE_FULLY_REMOVED);
- filter.addDataScheme("package");
- filter.addDataSchemeSpecificPart(scorer.mPackageName,
- PatternMatcher.PATTERN_LITERAL);
- mReceiver = new ScorerChangedReceiver(scorer.mPackageName);
+ mPackageMonitor = new NetworkScorerPackageMonitor(scorer.mPackageName);
// TODO: Need to update when we support per-user scorers. http://b/23422763
- mContext.registerReceiverAsUser(mReceiver, UserHandle.SYSTEM, filter, null, null);
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "Registered receiver for " + scorer.mPackageName);
+ mPackageMonitor.register(mContext, null /* thread */, UserHandle.SYSTEM,
+ false /* externalStorage */);
+ if (DBG) {
+ Log.d(TAG, "Registered package monitor for "
+ + mPackageMonitor.mRegisteredPackage);
}
}
}
@@ -299,7 +329,7 @@
// will be made to bind to the new scorer.
bindToScoringServiceIfNeeded();
if (result) { // new scorer successfully set
- registerPackageReceiverIfNeeded();
+ registerPackageMonitorIfNeeded();
Intent intent = new Intent(NetworkScoreManager.ACTION_SCORER_CHANGED);
if (prevScorer != null) { // Directly notify the old scorer.
@@ -391,20 +421,24 @@
private static class ScoringServiceConnection implements ServiceConnection {
private final ComponentName mComponentName;
private boolean mBound = false;
+ private boolean mConnected = false;
ScoringServiceConnection(ComponentName componentName) {
mComponentName = componentName;
}
void connect(Context context) {
- disconnect(context);
- Intent service = new Intent();
- service.setComponent(mComponentName);
- mBound = context.bindServiceAsUser(service, this,
- Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
- UserHandle.SYSTEM);
if (!mBound) {
- Log.w(TAG, "Bind call failed for " + service);
+ Intent service = new Intent();
+ service.setComponent(mComponentName);
+ mBound = context.bindServiceAsUser(service, this,
+ Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+ UserHandle.SYSTEM);
+ if (!mBound) {
+ Log.w(TAG, "Bind call failed for " + service);
+ } else {
+ if (DBG) Log.d(TAG, "ScoringServiceConnection bound.");
+ }
}
}
@@ -413,6 +447,7 @@
if (mBound) {
mBound = false;
context.unbindService(this);
+ if (DBG) Log.d(TAG, "ScoringServiceConnection unbound.");
}
} catch (RuntimeException e) {
Log.e(TAG, "Unbind failed.", e);
@@ -422,15 +457,20 @@
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DBG) Log.d(TAG, "ScoringServiceConnection: " + name.flattenToString());
+ mConnected = true;
}
@Override
public void onServiceDisconnected(ComponentName name) {
- if (DBG) Log.d(TAG, "ScoringServiceConnection, disconnected: " + name.flattenToString());
+ if (DBG) {
+ Log.d(TAG, "ScoringServiceConnection, disconnected: " + name.flattenToString());
+ }
+ mConnected = false;
}
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- writer.println("ScoringServiceConnection: " + mComponentName + ", bound: " + mBound);
+ writer.println("ScoringServiceConnection: " + mComponentName + ", bound: " + mBound
+ + ", connected: " + mConnected);
}
}
}