mirror of
https://github.com/moonlight-stream/moonlight-android.git
synced 2025-07-19 11:03:01 +00:00
Significantly improve speed of PC list updates
This commit is contained in:
parent
4f79607015
commit
21822f259c
Binary file not shown.
@ -1,6 +1,7 @@
|
|||||||
package com.limelight.computers;
|
package com.limelight.computers;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
@ -25,7 +26,6 @@ import android.os.Binder;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
|
||||||
public class ComputerManagerService extends Service {
|
public class ComputerManagerService extends Service {
|
||||||
private static final int MAX_CONCURRENT_REQUESTS = 4;
|
|
||||||
private static final int POLLING_PERIOD_MS = 5000;
|
private static final int POLLING_PERIOD_MS = 5000;
|
||||||
private static final int MDNS_QUERY_PERIOD_MS = 1000;
|
private static final int MDNS_QUERY_PERIOD_MS = 1000;
|
||||||
|
|
||||||
@ -35,8 +35,7 @@ public class ComputerManagerService extends Service {
|
|||||||
private AtomicInteger dbRefCount = new AtomicInteger(0);
|
private AtomicInteger dbRefCount = new AtomicInteger(0);
|
||||||
|
|
||||||
private IdentityManager idManager;
|
private IdentityManager idManager;
|
||||||
private ThreadPoolExecutor pollingPool;
|
private HashMap<ComputerDetails, Thread> pollingThreads;
|
||||||
private Timer pollingTimer;
|
|
||||||
private ComputerManagerListener listener = null;
|
private ComputerManagerListener listener = null;
|
||||||
private AtomicInteger activePolls = new AtomicInteger(0);
|
private AtomicInteger activePolls = new AtomicInteger(0);
|
||||||
private boolean stopped;
|
private boolean stopped;
|
||||||
@ -60,6 +59,85 @@ public class ComputerManagerService extends Service {
|
|||||||
discoveryBinder = null;
|
discoveryBinder = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Returns true if the details object was modified
|
||||||
|
private boolean runPoll(ComputerDetails details)
|
||||||
|
{
|
||||||
|
boolean newPc = (details.name == null);
|
||||||
|
|
||||||
|
// This is called from addComputerManually() where we don't
|
||||||
|
// want to block the initial poll if polling is disabled, so
|
||||||
|
// we explicitly let this through if we've never seen this
|
||||||
|
// PC before. This path won't be triggered normally when polling
|
||||||
|
// is disabled because the mDNS discovery is stopped.
|
||||||
|
if (stopped && !newPc) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getLocalDatabaseReference()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
activePolls.incrementAndGet();
|
||||||
|
|
||||||
|
// Poll the machine
|
||||||
|
if (!doPollMachine(details)) {
|
||||||
|
details.state = ComputerDetails.State.OFFLINE;
|
||||||
|
details.reachability = ComputerDetails.Reachability.OFFLINE;
|
||||||
|
}
|
||||||
|
|
||||||
|
activePolls.decrementAndGet();
|
||||||
|
|
||||||
|
// If it's online, update our persistent state
|
||||||
|
if (details.state == ComputerDetails.State.ONLINE) {
|
||||||
|
if (!newPc) {
|
||||||
|
// Check if it's in the database because it could have been
|
||||||
|
// removed after this was issued
|
||||||
|
if (dbManager.getComputerByName(details.name) == null) {
|
||||||
|
// It's gone
|
||||||
|
releaseLocalDatabaseReference();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dbManager.updateComputer(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't call the listener if this is a failed lookup of a new PC
|
||||||
|
if ((!newPc || details.state == ComputerDetails.State.ONLINE) && listener != null) {
|
||||||
|
listener.notifyComputerUpdated(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
releaseLocalDatabaseReference();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Thread createPollingThread(final ComputerDetails details) {
|
||||||
|
Thread t = new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!isInterrupted()) {
|
||||||
|
ComputerDetails originalDetails = new ComputerDetails();
|
||||||
|
originalDetails.update(details);
|
||||||
|
|
||||||
|
// Check if this poll has modified the details
|
||||||
|
if (runPoll(details) && !originalDetails.equals(details)) {
|
||||||
|
// Replace our thread entry with the new one
|
||||||
|
synchronized (pollingThreads) {
|
||||||
|
pollingThreads.remove(originalDetails);
|
||||||
|
pollingThreads.put(details, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until the next polling interval
|
||||||
|
try {
|
||||||
|
Thread.sleep(POLLING_PERIOD_MS);
|
||||||
|
} catch (InterruptedException e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
public class ComputerManagerBinder extends Binder {
|
public class ComputerManagerBinder extends Binder {
|
||||||
public void startPolling(ComputerManagerListener listener) {
|
public void startPolling(ComputerManagerListener listener) {
|
||||||
@ -73,8 +151,19 @@ public class ComputerManagerService extends Service {
|
|||||||
discoveryBinder.startDiscovery(MDNS_QUERY_PERIOD_MS);
|
discoveryBinder.startDiscovery(MDNS_QUERY_PERIOD_MS);
|
||||||
|
|
||||||
// Start polling known machines
|
// Start polling known machines
|
||||||
pollingTimer = new Timer();
|
if (!getLocalDatabaseReference()) {
|
||||||
pollingTimer.schedule(getTimerTask(), 0, POLLING_PERIOD_MS);
|
return;
|
||||||
|
}
|
||||||
|
List<ComputerDetails> computerList = dbManager.getAllComputers();
|
||||||
|
releaseLocalDatabaseReference();
|
||||||
|
|
||||||
|
synchronized (pollingThreads) {
|
||||||
|
for (ComputerDetails computer : computerList) {
|
||||||
|
Thread t = createPollingThread(computer);
|
||||||
|
pollingThreads.put(computer, t);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void waitForReady() {
|
public void waitForReady() {
|
||||||
@ -128,10 +217,11 @@ public class ComputerManagerService extends Service {
|
|||||||
discoveryBinder.stopDiscovery();
|
discoveryBinder.stopDiscovery();
|
||||||
|
|
||||||
// Stop polling
|
// Stop polling
|
||||||
if (pollingTimer != null) {
|
synchronized (pollingThreads) {
|
||||||
pollingTimer.cancel();
|
for (Thread t : pollingThreads.values()) {
|
||||||
pollingTimer = null;
|
t.interrupt();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remove the listener
|
// Remove the listener
|
||||||
listener = null;
|
listener = null;
|
||||||
@ -159,17 +249,21 @@ public class ComputerManagerService extends Service {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addComputer(InetAddress addr) {
|
public void addComputer(InetAddress addr) {
|
||||||
// Setup a placeholder
|
// Setup a placeholder
|
||||||
ComputerDetails fakeDetails = new ComputerDetails();
|
ComputerDetails fakeDetails = new ComputerDetails();
|
||||||
fakeDetails.localIp = addr;
|
fakeDetails.localIp = addr;
|
||||||
fakeDetails.remoteIp = addr;
|
fakeDetails.remoteIp = addr;
|
||||||
|
|
||||||
// Put it in the thread pool to process later
|
// Spawn a thread for this computer
|
||||||
pollingPool.execute(getPollingRunnable(fakeDetails));
|
synchronized (pollingThreads) {
|
||||||
|
Thread t = createPollingThread(fakeDetails);
|
||||||
|
pollingThreads.put(fakeDetails, t);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addComputerBlocking(InetAddress addr) {
|
public boolean addComputerBlocking(InetAddress addr) {
|
||||||
// Setup a placeholder
|
// Setup a placeholder
|
||||||
ComputerDetails fakeDetails = new ComputerDetails();
|
ComputerDetails fakeDetails = new ComputerDetails();
|
||||||
@ -177,7 +271,7 @@ public class ComputerManagerService extends Service {
|
|||||||
fakeDetails.remoteIp = addr;
|
fakeDetails.remoteIp = addr;
|
||||||
|
|
||||||
// Block while we try to fill the details
|
// Block while we try to fill the details
|
||||||
getPollingRunnable(fakeDetails).run();
|
runPoll(fakeDetails);
|
||||||
|
|
||||||
// If the machine is reachable, it was successful
|
// If the machine is reachable, it was successful
|
||||||
return fakeDetails.state == ComputerDetails.State.ONLINE;
|
return fakeDetails.state == ComputerDetails.State.ONLINE;
|
||||||
@ -209,23 +303,6 @@ public class ComputerManagerService extends Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimerTask getTimerTask() {
|
|
||||||
return new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (!getLocalDatabaseReference()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<ComputerDetails> computerList = dbManager.getAllComputers();
|
|
||||||
releaseLocalDatabaseReference();
|
|
||||||
|
|
||||||
for (ComputerDetails computer : computerList) {
|
|
||||||
pollingPool.execute(getPollingRunnable(computer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private ComputerDetails tryPollIp(InetAddress ipAddr) {
|
private ComputerDetails tryPollIp(InetAddress ipAddr) {
|
||||||
try {
|
try {
|
||||||
NvHTTP http = new NvHTTP(ipAddr, idManager.getUniqueId(),
|
NvHTTP http = new NvHTTP(ipAddr, idManager.getUniqueId(),
|
||||||
@ -281,71 +358,13 @@ public class ComputerManagerService extends Service {
|
|||||||
return pollComputer(details, true);
|
return pollComputer(details, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Runnable getPollingRunnable(final ComputerDetails details) {
|
|
||||||
return new Runnable() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
boolean newPc = (details.name == null);
|
|
||||||
|
|
||||||
// This is called from addComputerManually() where we don't
|
|
||||||
// want to block the initial poll if polling is disabled, so
|
|
||||||
// we explicitly let this through if we've never seen this
|
|
||||||
// PC before. This path won't be triggered normally when polling
|
|
||||||
// is disabled because the mDNS discovery is stopped.
|
|
||||||
if (stopped && !newPc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!getLocalDatabaseReference()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
activePolls.incrementAndGet();
|
|
||||||
|
|
||||||
// Poll the machine
|
|
||||||
if (!doPollMachine(details)) {
|
|
||||||
details.state = ComputerDetails.State.OFFLINE;
|
|
||||||
details.reachability = ComputerDetails.Reachability.OFFLINE;
|
|
||||||
}
|
|
||||||
|
|
||||||
activePolls.decrementAndGet();
|
|
||||||
|
|
||||||
// If it's online, update our persistent state
|
|
||||||
if (details.state == ComputerDetails.State.ONLINE) {
|
|
||||||
if (!newPc) {
|
|
||||||
// Check if it's in the database because it could have been
|
|
||||||
// removed after this was issued
|
|
||||||
if (dbManager.getComputerByName(details.name) == null) {
|
|
||||||
// It's gone
|
|
||||||
releaseLocalDatabaseReference();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbManager.updateComputer(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't call the listener if this is a failed lookup of a new PC
|
|
||||||
if ((!newPc || details.state == ComputerDetails.State.ONLINE) && listener != null) {
|
|
||||||
listener.notifyComputerUpdated(details);
|
|
||||||
}
|
|
||||||
|
|
||||||
releaseLocalDatabaseReference();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
// Bind to the discovery service
|
// Bind to the discovery service
|
||||||
bindService(new Intent(this, DiscoveryService.class),
|
bindService(new Intent(this, DiscoveryService.class),
|
||||||
discoveryServiceConnection, Service.BIND_AUTO_CREATE);
|
discoveryServiceConnection, Service.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
// Create the thread pool for updating computer state
|
pollingThreads = new HashMap<ComputerDetails, Thread>();
|
||||||
pollingPool = new ThreadPoolExecutor(MAX_CONCURRENT_REQUESTS, MAX_CONCURRENT_REQUESTS,
|
|
||||||
Long.MAX_VALUE, TimeUnit.DAYS, new LinkedBlockingQueue<Runnable>(),
|
|
||||||
new ThreadPoolExecutor.DiscardPolicy());
|
|
||||||
|
|
||||||
// Lookup or generate this device's UID
|
// Lookup or generate this device's UID
|
||||||
idManager = new IdentityManager(this);
|
idManager = new IdentityManager(this);
|
||||||
@ -362,9 +381,6 @@ public class ComputerManagerService extends Service {
|
|||||||
unbindService(discoveryServiceConnection);
|
unbindService(discoveryServiceConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop the thread pool
|
|
||||||
pollingPool.shutdownNow();
|
|
||||||
|
|
||||||
// FIXME: Should await termination here but we have timeout issues in HttpURLConnection
|
// FIXME: Should await termination here but we have timeout issues in HttpURLConnection
|
||||||
|
|
||||||
// Remove the initial DB reference
|
// Remove the initial DB reference
|
||||||
|
Loading…
x
Reference in New Issue
Block a user