Merge "Fix locking in ServiceListener"

This commit is contained in:
Philip P. Moltmann
2020-07-15 21:29:19 +00:00
committed by Android (Google) Code Review

View File

@@ -22,6 +22,8 @@ import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.text.TextUtils;
import androidx.annotation.GuardedBy;
import com.android.printservice.recommendation.R;
import com.android.printservice.recommendation.util.DiscoveryListenerMultiplexer;
import com.android.printservice.recommendation.util.PrinterHashMap;
@@ -40,7 +42,12 @@ public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
private final String[] mServiceType;
private final Observer mObserver;
private final ServiceResolveQueue mResolveQueue;
private final Object mLock = new Object();
@GuardedBy("mLock")
private List<NsdManager.DiscoveryListener> mListeners = new ArrayList<>();
@GuardedBy("mLock")
public HashMap<String, PrinterHashMap> mVendorHashMap = new HashMap<>();
public interface Observer {
@@ -73,108 +80,120 @@ public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
printerFound(nsdServiceInfo);
}
private synchronized void printerFound(NsdServiceInfo nsdServiceInfo) {
private void printerFound(NsdServiceInfo nsdServiceInfo) {
if (nsdServiceInfo == null) return;
if (TextUtils.isEmpty(PrinterHashMap.getKey(nsdServiceInfo))) return;
String vendor = MDnsUtils.getVendor(nsdServiceInfo);
if (vendor == null) vendor = "";
for(Map.Entry<String,VendorInfo> entry : mVendorInfoHashMap.entrySet()) {
for(String vendorValues : entry.getValue().mDNSValues) {
if (vendor.equalsIgnoreCase(vendorValues)) {
vendor = entry.getValue().mVendorID;
break;
}
}
// intentional pointer check
//noinspection StringEquality
if ((vendor != entry.getValue().mVendorID) &&
MDnsUtils.isVendorPrinter(nsdServiceInfo, entry.getValue().mDNSValues)) {
vendor = entry.getValue().mVendorID;
}
// intentional pointer check
//noinspection StringEquality
if (vendor == entry.getValue().mVendorID) break;
}
if (TextUtils.isEmpty(vendor)) {
return;
}
if (!mObserver.matchesCriteria(vendor, nsdServiceInfo))
return;
boolean mapsChanged;
synchronized (mLock) {
for (Map.Entry<String, VendorInfo> entry : mVendorInfoHashMap.entrySet()) {
for (String vendorValues : entry.getValue().mDNSValues) {
if (vendor.equalsIgnoreCase(vendorValues)) {
vendor = entry.getValue().mVendorID;
break;
}
}
// intentional pointer check
//noinspection StringEquality
if ((vendor != entry.getValue().mVendorID) &&
MDnsUtils.isVendorPrinter(nsdServiceInfo, entry.getValue().mDNSValues)) {
vendor = entry.getValue().mVendorID;
}
// intentional pointer check
//noinspection StringEquality
if (vendor == entry.getValue().mVendorID) break;
}
PrinterHashMap vendorHash = mVendorHashMap.get(vendor);
if (vendorHash == null) {
vendorHash = new PrinterHashMap();
if (TextUtils.isEmpty(vendor)) {
return;
}
if (!mObserver.matchesCriteria(vendor, nsdServiceInfo))
return;
PrinterHashMap vendorHash = mVendorHashMap.get(vendor);
if (vendorHash == null) {
vendorHash = new PrinterHashMap();
}
mapsChanged = (vendorHash.addPrinter(nsdServiceInfo) == null);
mVendorHashMap.put(vendor, vendorHash);
}
mapsChanged = (vendorHash.addPrinter(nsdServiceInfo) == null);
mVendorHashMap.put(vendor, vendorHash);
if (mapsChanged) {
mObserver.dataSetChanged();
}
}
private synchronized void printerRemoved(NsdServiceInfo nsdServiceInfo) {
private void printerRemoved(NsdServiceInfo nsdServiceInfo) {
boolean wasRemoved = false;
Set<String> vendors = mVendorHashMap.keySet();
for(String vendor : vendors) {
PrinterHashMap map = mVendorHashMap.get(vendor);
wasRemoved |= (map.removePrinter(nsdServiceInfo) != null);
if (map.isEmpty()) wasRemoved |= (mVendorHashMap.remove(vendor) != null);
synchronized (mLock) {
Set<String> vendors = mVendorHashMap.keySet();
for (String vendor : vendors) {
PrinterHashMap map = mVendorHashMap.get(vendor);
wasRemoved |= (map.removePrinter(nsdServiceInfo) != null);
if (map.isEmpty()) wasRemoved |= (mVendorHashMap.remove(vendor) != null);
}
}
if (wasRemoved) {
mObserver.dataSetChanged();
}
}
public void start() {
stop();
for(final String service :mServiceType) {
NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() {
@Override
public void onStartDiscoveryFailed(String s, int i) {
synchronized (mLock) {
stop();
}
for (final String service : mServiceType) {
NsdManager.DiscoveryListener listener = new NsdManager.DiscoveryListener() {
@Override
public void onStartDiscoveryFailed(String s, int i) {
@Override
public void onStopDiscoveryFailed(String s, int i) {
}
}
@Override
public void onStopDiscoveryFailed(String s, int i) {
@Override
public void onDiscoveryStarted(String s) {
}
}
@Override
public void onDiscoveryStarted(String s) {
@Override
public void onDiscoveryStopped(String s) {
}
}
@Override
public void onDiscoveryStopped(String s) {
@Override
public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
mResolveQueue.queueRequest(nsdServiceInfo, ServiceListener.this);
}
}
@Override
public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
mResolveQueue.removeRequest(nsdServiceInfo, ServiceListener.this);
printerRemoved(nsdServiceInfo);
}
};
DiscoveryListenerMultiplexer.addListener(mNSDManager, service, listener);
mListeners.add(listener);
@Override
public void onServiceFound(NsdServiceInfo nsdServiceInfo) {
mResolveQueue.queueRequest(nsdServiceInfo, ServiceListener.this);
}
@Override
public void onServiceLost(NsdServiceInfo nsdServiceInfo) {
mResolveQueue.removeRequest(nsdServiceInfo, ServiceListener.this);
printerRemoved(nsdServiceInfo);
}
};
DiscoveryListenerMultiplexer.addListener(mNSDManager, service, listener);
mListeners.add(listener);
}
}
}
public void stop() {
for(NsdManager.DiscoveryListener listener : mListeners) {
DiscoveryListenerMultiplexer.removeListener(mNSDManager, listener);
synchronized (mLock) {
for (NsdManager.DiscoveryListener listener : mListeners) {
DiscoveryListenerMultiplexer.removeListener(mNSDManager, listener);
}
mVendorHashMap.clear();
mListeners.clear();
}
mVendorHashMap.clear();
mListeners.clear();
}
/**
@@ -183,8 +202,10 @@ public class ServiceListener implements ServiceResolveQueue.ResolveCallback {
public ArrayList<InetAddress> getPrinters() {
ArrayList<InetAddress> printerAddressess = new ArrayList<>();
for (PrinterHashMap oneVendorPrinters : mVendorHashMap.values()) {
printerAddressess.addAll(oneVendorPrinters.getPrinterAddresses());
synchronized (mLock) {
for (PrinterHashMap oneVendorPrinters : mVendorHashMap.values()) {
printerAddressess.addAll(oneVendorPrinters.getPrinterAddresses());
}
}
return printerAddressess;