Commit 643ad22b authored by jcivelli's avatar jcivelli Committed by Commit bot

Removed the service number member from BaseChildProcessConnection.

In preparation for making the ChildProcessConnection simpler, removing
the service number member from  BaseChildProcessConnection.
It is pertaining to the allocator, not the connection.

Also replaced the LruCache used for the moderate binding pool in
BindingManagerImpl (which was relying on the service number from the
connection) with a LinkedList. It makes the code clearer since we were
only using the LruCache to evict old connections, not the cache part.

BUG=689758

Review-Url: https://codereview.chromium.org/2855323003
Cr-Commit-Position: refs/heads/master@{#469452}
parent f46f5ae7
...@@ -74,7 +74,7 @@ public abstract class BaseChildProcessConnection { ...@@ -74,7 +74,7 @@ public abstract class BaseChildProcessConnection {
/** Used to create specialization connection instances. */ /** Used to create specialization connection instances. */
interface Factory { interface Factory {
BaseChildProcessConnection create(Context context, int number, boolean sandboxed, BaseChildProcessConnection create(Context context, boolean sandboxed,
DeathCallback deathCallback, String serviceClassName, DeathCallback deathCallback, String serviceClassName,
Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams); Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams);
} }
...@@ -162,7 +162,6 @@ public abstract class BaseChildProcessConnection { ...@@ -162,7 +162,6 @@ public abstract class BaseChildProcessConnection {
// TODO(mnaganov): Get rid of it after the release of the next Android SDK. // TODO(mnaganov): Get rid of it after the release of the next Android SDK.
private static Boolean sNeedsExtrabindFlags[] = new Boolean[2]; private static Boolean sNeedsExtrabindFlags[] = new Boolean[2];
private final Context mContext; private final Context mContext;
private final int mServiceNumber;
private final boolean mSandboxed; private final boolean mSandboxed;
private final BaseChildProcessConnection.DeathCallback mDeathCallback; private final BaseChildProcessConnection.DeathCallback mDeathCallback;
private final ComponentName mServiceName; private final ComponentName mServiceName;
...@@ -216,17 +215,16 @@ public abstract class BaseChildProcessConnection { ...@@ -216,17 +215,16 @@ public abstract class BaseChildProcessConnection {
// Process ID of the corresponding child process. // Process ID of the corresponding child process.
private int mPid; private int mPid;
protected BaseChildProcessConnection(Context context, int number, boolean sandboxed, protected BaseChildProcessConnection(Context context, boolean sandboxed,
DeathCallback deathCallback, String serviceClassName, DeathCallback deathCallback, String serviceClassName,
Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) {
assert LauncherThread.runningOnLauncherThread(); assert LauncherThread.runningOnLauncherThread();
mContext = context; mContext = context;
mServiceNumber = number;
mSandboxed = sandboxed; mSandboxed = sandboxed;
mDeathCallback = deathCallback; mDeathCallback = deathCallback;
String packageName = String packageName =
creationParams != null ? creationParams.getPackageName() : context.getPackageName(); creationParams != null ? creationParams.getPackageName() : context.getPackageName();
mServiceName = new ComponentName(packageName, serviceClassName + mServiceNumber); mServiceName = new ComponentName(packageName, serviceClassName);
mChildProcessCommonParameters = childProcessCommonParameters; mChildProcessCommonParameters = childProcessCommonParameters;
mCreationParams = creationParams; mCreationParams = creationParams;
} }
...@@ -236,11 +234,6 @@ public abstract class BaseChildProcessConnection { ...@@ -236,11 +234,6 @@ public abstract class BaseChildProcessConnection {
return mContext; return mContext;
} }
public final int getServiceNumber() {
assert LauncherThread.runningOnLauncherThread();
return mServiceNumber;
}
public final boolean isSandboxed() { public final boolean isSandboxed() {
assert LauncherThread.runningOnLauncherThread(); assert LauncherThread.runningOnLauncherThread();
return mSandboxed; return mSandboxed;
......
...@@ -4,12 +4,9 @@ ...@@ -4,12 +4,9 @@
package org.chromium.content.browser; package org.chromium.content.browser;
import android.annotation.TargetApi;
import android.content.ComponentCallbacks2; import android.content.ComponentCallbacks2;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Build;
import android.util.LruCache;
import android.util.SparseArray; import android.util.SparseArray;
import org.chromium.base.Log; import org.chromium.base.Log;
...@@ -18,14 +15,14 @@ import org.chromium.base.ThreadUtils; ...@@ -18,14 +15,14 @@ import org.chromium.base.ThreadUtils;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.RecordHistogram; import org.chromium.base.metrics.RecordHistogram;
import java.util.Map; import java.util.LinkedList;
/** /**
* Manages oom bindings used to bound child services. * Manages oom bindings used to bound child services.
* This object must only be accessed from the launcher thread. * This object must only be accessed from the launcher thread.
*/ */
class BindingManagerImpl implements BindingManager { class BindingManagerImpl implements BindingManager {
private static final String TAG = "cr.BindingManager"; private static final String TAG = "cr_BindingManager";
// Low reduce ratio of moderate binding. // Low reduce ratio of moderate binding.
private static final float MODERATE_BINDING_LOW_REDUCE_RATIO = 0.25f; private static final float MODERATE_BINDING_LOW_REDUCE_RATIO = 0.25f;
...@@ -43,12 +40,15 @@ class BindingManagerImpl implements BindingManager { ...@@ -43,12 +40,15 @@ class BindingManagerImpl implements BindingManager {
// createBindingManagerForTesting(). // createBindingManagerForTesting().
private final boolean mIsLowMemoryDevice; private final boolean mIsLowMemoryDevice;
private static class ModerateBindingPool private static class ModerateBindingPool implements ComponentCallbacks2 {
extends LruCache<Integer, ManagedConnection> implements ComponentCallbacks2 { // Stores the connections in MRU order.
private final LinkedList<ManagedConnection> mConnections = new LinkedList<>();
private final int mMaxSize;
private Runnable mDelayedClearer; private Runnable mDelayedClearer;
public ModerateBindingPool(int maxSize) { public ModerateBindingPool(int maxSize) {
super(maxSize); mMaxSize = maxSize;
} }
@Override @Override
...@@ -57,8 +57,8 @@ class BindingManagerImpl implements BindingManager { ...@@ -57,8 +57,8 @@ class BindingManagerImpl implements BindingManager {
LauncherThread.post(new Runnable() { LauncherThread.post(new Runnable() {
@Override @Override
public void run() { public void run() {
Log.i(TAG, "onTrimMemory: level=%d, size=%d", level, size()); Log.i(TAG, "onTrimMemory: level=%d, size=%d", level, mConnections.size());
if (size() <= 0) { if (mConnections.isEmpty()) {
return; return;
} }
if (level <= TRIM_MEMORY_RUNNING_MODERATE) { if (level <= TRIM_MEMORY_RUNNING_MODERATE) {
...@@ -69,7 +69,7 @@ class BindingManagerImpl implements BindingManager { ...@@ -69,7 +69,7 @@ class BindingManagerImpl implements BindingManager {
// This will be handled by |mDelayedClearer|. // This will be handled by |mDelayedClearer|.
return; return;
} else { } else {
evictAll(); removeAllConnections();
} }
} }
}); });
...@@ -81,8 +81,8 @@ class BindingManagerImpl implements BindingManager { ...@@ -81,8 +81,8 @@ class BindingManagerImpl implements BindingManager {
LauncherThread.post(new Runnable() { LauncherThread.post(new Runnable() {
@Override @Override
public void run() { public void run() {
Log.i(TAG, "onLowMemory: evict %d bindings", size()); Log.i(TAG, "onLowMemory: evict %d bindings", mConnections.size());
evictAll(); removeAllConnections();
} }
}); });
} }
...@@ -90,25 +90,12 @@ class BindingManagerImpl implements BindingManager { ...@@ -90,25 +90,12 @@ class BindingManagerImpl implements BindingManager {
@Override @Override
public void onConfigurationChanged(Configuration configuration) {} public void onConfigurationChanged(Configuration configuration) {}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void reduce(float reduceRatio) { private void reduce(float reduceRatio) {
int oldSize = size(); int oldSize = mConnections.size();
int newSize = (int) (oldSize * (1f - reduceRatio)); int newSize = (int) (oldSize * (1f - reduceRatio));
Log.i(TAG, "Reduce connections from %d to %d", oldSize, newSize); Log.i(TAG, "Reduce connections from %d to %d", oldSize, newSize);
if (newSize == 0) { removeOldConnections(oldSize - newSize);
evictAll(); assert mConnections.size() == newSize;
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
trimToSize(newSize);
} else {
// Entries will be removed from the front because snapshot() returns ones ordered
// from least recently accessed to most recently accessed.
int count = 0;
for (Map.Entry<Integer, ManagedConnection> entry : snapshot().entrySet()) {
remove(entry.getKey());
++count;
if (count == oldSize - newSize) break;
}
}
} }
void addConnection(ManagedConnection managedConnection) { void addConnection(ManagedConnection managedConnection) {
...@@ -116,9 +103,9 @@ class BindingManagerImpl implements BindingManager { ...@@ -116,9 +103,9 @@ class BindingManagerImpl implements BindingManager {
if (connection != null && connection.isSandboxed()) { if (connection != null && connection.isSandboxed()) {
managedConnection.addModerateBinding(); managedConnection.addModerateBinding();
if (connection.isModerateBindingBound()) { if (connection.isModerateBindingBound()) {
put(connection.getServiceNumber(), managedConnection); addConnectionImpl(managedConnection);
} else { } else {
remove(connection.getServiceNumber()); removeConnectionImpl(managedConnection);
} }
} }
} }
...@@ -126,31 +113,60 @@ class BindingManagerImpl implements BindingManager { ...@@ -126,31 +113,60 @@ class BindingManagerImpl implements BindingManager {
void removeConnection(ManagedConnection managedConnection) { void removeConnection(ManagedConnection managedConnection) {
ManagedChildProcessConnection connection = managedConnection.mConnection; ManagedChildProcessConnection connection = managedConnection.mConnection;
if (connection != null && connection.isSandboxed()) { if (connection != null && connection.isSandboxed()) {
remove(connection.getServiceNumber()); removeConnectionImpl(managedConnection);
} }
} }
@Override void removeAllConnections() {
protected void entryRemoved(boolean evicted, Integer key, ManagedConnection oldValue, removeOldConnections(mConnections.size());
ManagedConnection newValue) { }
if (oldValue != newValue) {
oldValue.removeModerateBinding(); int size() {
return mConnections.size();
}
private void addConnectionImpl(ManagedConnection managedConnection) {
// Note that the size of connections is currently fairly small (20).
// If it became bigger we should consider using an alternate data structure so we don't
// have to traverse the list every time.
// Remove the connection if it's already in the list, we'll add it at the head.
mConnections.removeFirstOccurrence(managedConnection);
if (mConnections.size() == mMaxSize) {
// Make room for the connection we are about to add.
removeOldConnections(1);
}
mConnections.add(0, managedConnection);
assert mConnections.size() <= mMaxSize;
}
private void removeConnectionImpl(ManagedConnection managedConnection) {
int index = mConnections.indexOf(managedConnection);
if (index != -1) {
ManagedConnection connection = mConnections.remove(index);
connection.mConnection.removeModerateBinding();
}
}
private void removeOldConnections(int numberOfConnections) {
assert numberOfConnections <= mConnections.size();
for (int i = 0; i < numberOfConnections; i++) {
ManagedConnection connection = mConnections.removeLast();
connection.mConnection.removeModerateBinding();
} }
} }
void onSentToBackground(final boolean onTesting) { void onSentToBackground(final boolean onTesting) {
if (size() == 0) return; if (mConnections.isEmpty()) return;
mDelayedClearer = new Runnable() { mDelayedClearer = new Runnable() {
@Override @Override
public void run() { public void run() {
if (mDelayedClearer == null) return; Log.i(TAG, "Release moderate connections: %d", mConnections.size());
mDelayedClearer = null;
Log.i(TAG, "Release moderate connections: %d", size());
if (!onTesting) { if (!onTesting) {
RecordHistogram.recordCountHistogram( RecordHistogram.recordCountHistogram(
"Android.ModerateBindingCount", size()); "Android.ModerateBindingCount", mConnections.size());
} }
evictAll(); removeAllConnections();
} }
}; };
LauncherThread.postDelayed(mDelayedClearer, MODERATE_BINDING_POOL_CLEARER_DELAY_MILLIS); LauncherThread.postDelayed(mDelayedClearer, MODERATE_BINDING_POOL_CLEARER_DELAY_MILLIS);
...@@ -459,7 +475,7 @@ class BindingManagerImpl implements BindingManager { ...@@ -459,7 +475,7 @@ class BindingManagerImpl implements BindingManager {
assert LauncherThread.runningOnLauncherThread(); assert LauncherThread.runningOnLauncherThread();
if (mModerateBindingPool != null) { if (mModerateBindingPool != null) {
Log.i(TAG, "Release all moderate bindings: %d", mModerateBindingPool.size()); Log.i(TAG, "Release all moderate bindings: %d", mModerateBindingPool.size());
mModerateBindingPool.evictAll(); mModerateBindingPool.removeAllConnections();
} }
} }
} }
...@@ -18,6 +18,7 @@ import org.chromium.content.app.PrivilegedProcessService; ...@@ -18,6 +18,7 @@ import org.chromium.content.app.PrivilegedProcessService;
import org.chromium.content.app.SandboxedProcessService; import org.chromium.content.app.SandboxedProcessService;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.Map; import java.util.Map;
...@@ -191,8 +192,9 @@ public class ChildConnectionAllocator { ...@@ -191,8 +192,9 @@ public class ChildConnectionAllocator {
} }
int slot = mFreeConnectionIndices.remove(0); int slot = mFreeConnectionIndices.remove(0);
assert mChildProcessConnections[slot] == null; assert mChildProcessConnections[slot] == null;
mChildProcessConnections[slot] = mConnectionFactory.create(spawnData.getContext(), slot, String serviceClassName = mChildClassName + slot;
mInSandbox, deathCallback, mChildClassName, childProcessCommonParameters, mChildProcessConnections[slot] = mConnectionFactory.create(spawnData.getContext(),
mInSandbox, deathCallback, serviceClassName, childProcessCommonParameters,
spawnData.getCreationParams()); spawnData.getCreationParams());
Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox, slot); Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox, slot);
return mChildProcessConnections[slot]; return mChildProcessConnections[slot];
...@@ -201,15 +203,11 @@ public class ChildConnectionAllocator { ...@@ -201,15 +203,11 @@ public class ChildConnectionAllocator {
// Also return the first ChildSpawnData in the pending queue, if any. // Also return the first ChildSpawnData in the pending queue, if any.
public ChildSpawnData free(BaseChildProcessConnection connection) { public ChildSpawnData free(BaseChildProcessConnection connection) {
assert LauncherThread.runningOnLauncherThread(); assert LauncherThread.runningOnLauncherThread();
int slot = connection.getServiceNumber(); // mChildProcessConnections is relatively short (20 items at max at this point).
if (mChildProcessConnections[slot] != connection) { // We are better of iterating than caching in a map.
int occupier = mChildProcessConnections[slot] == null int slot = Arrays.asList(mChildProcessConnections).indexOf(connection);
? -1 if (slot == -1) {
: mChildProcessConnections[slot].getServiceNumber(); Log.e(TAG, "Unable to find connection to free.");
Log.e(TAG,
"Unable to find connection to free in slot: %d "
+ "already occupied by service: %d",
slot, occupier);
assert false; assert false;
} else { } else {
mChildProcessConnections[slot] = null; mChildProcessConnections[slot] = null;
......
...@@ -491,7 +491,8 @@ public class ChildProcessLauncher { ...@@ -491,7 +491,8 @@ public class ChildProcessLauncher {
String[] commandLine, int childProcessId, FileDescriptorInfo[] filesToBeMapped, String[] commandLine, int childProcessId, FileDescriptorInfo[] filesToBeMapped,
final IBinder childProcessCallback, final LaunchCallback launchCallback) { final IBinder childProcessCallback, final LaunchCallback launchCallback) {
assert LauncherThread.runningOnLauncherThread(); assert LauncherThread.runningOnLauncherThread();
Log.d(TAG, "Setting up connection to process: slot=%d", connection.getServiceNumber()); Log.d(TAG, "Setting up connection to process, connection name=%s",
connection.getServiceName());
BaseChildProcessConnection.ConnectionCallback connectionCallback = BaseChildProcessConnection.ConnectionCallback connectionCallback =
new BaseChildProcessConnection.ConnectionCallback() { new BaseChildProcessConnection.ConnectionCallback() {
@Override @Override
......
...@@ -16,21 +16,21 @@ import org.chromium.base.process_launcher.ChildProcessCreationParams; ...@@ -16,21 +16,21 @@ import org.chromium.base.process_launcher.ChildProcessCreationParams;
public class ImportantChildProcessConnection extends BaseChildProcessConnection { public class ImportantChildProcessConnection extends BaseChildProcessConnection {
public static final Factory FACTORY = new BaseChildProcessConnection.Factory() { public static final Factory FACTORY = new BaseChildProcessConnection.Factory() {
@Override @Override
public BaseChildProcessConnection create(Context context, int number, boolean sandboxed, public BaseChildProcessConnection create(Context context, boolean sandboxed,
DeathCallback deathCallback, String serviceClassName, DeathCallback deathCallback, String serviceClassName,
Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) {
return new ImportantChildProcessConnection(context, number, sandboxed, deathCallback, return new ImportantChildProcessConnection(context, sandboxed, deathCallback,
serviceClassName, childProcessCommonParameters, creationParams); serviceClassName, childProcessCommonParameters, creationParams);
} }
}; };
private final ChildServiceConnection mBinding; private final ChildServiceConnection mBinding;
private ImportantChildProcessConnection(Context context, int number, boolean sandboxed, private ImportantChildProcessConnection(Context context, boolean sandboxed,
DeathCallback deathCallback, String serviceClassName, DeathCallback deathCallback, String serviceClassName,
Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) {
super(context, number, sandboxed, deathCallback, serviceClassName, super(context, sandboxed, deathCallback, serviceClassName, childProcessCommonParameters,
childProcessCommonParameters, creationParams); creationParams);
int flags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT; int flags = Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT;
if (shouldBindAsExportedService()) { if (shouldBindAsExportedService()) {
flags |= Context.BIND_EXTERNAL_SERVICE; flags |= Context.BIND_EXTERNAL_SERVICE;
......
...@@ -21,11 +21,11 @@ public class ManagedChildProcessConnection extends BaseChildProcessConnection { ...@@ -21,11 +21,11 @@ public class ManagedChildProcessConnection extends BaseChildProcessConnection {
public static final Factory FACTORY = new BaseChildProcessConnection.Factory() { public static final Factory FACTORY = new BaseChildProcessConnection.Factory() {
@Override @Override
public BaseChildProcessConnection create(Context context, int number, boolean sandboxed, public BaseChildProcessConnection create(Context context, boolean sandboxed,
DeathCallback deathCallback, String serviceClassName, DeathCallback deathCallback, String serviceClassName,
Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) {
assert LauncherThread.runningOnLauncherThread(); assert LauncherThread.runningOnLauncherThread();
return new ManagedChildProcessConnection(context, number, sandboxed, deathCallback, return new ManagedChildProcessConnection(context, sandboxed, deathCallback,
serviceClassName, childProcessCommonParameters, creationParams); serviceClassName, childProcessCommonParameters, creationParams);
} }
}; };
...@@ -60,11 +60,11 @@ public class ManagedChildProcessConnection extends BaseChildProcessConnection { ...@@ -60,11 +60,11 @@ public class ManagedChildProcessConnection extends BaseChildProcessConnection {
private boolean mUnbound; private boolean mUnbound;
@VisibleForTesting @VisibleForTesting
ManagedChildProcessConnection(Context context, int number, boolean sandboxed, ManagedChildProcessConnection(Context context, boolean sandboxed, DeathCallback deathCallback,
DeathCallback deathCallback, String serviceClassName, String serviceClassName, Bundle childProcessCommonParameters,
Bundle childProcessCommonParameters, ChildProcessCreationParams creationParams) { ChildProcessCreationParams creationParams) {
super(context, number, sandboxed, deathCallback, serviceClassName, super(context, sandboxed, deathCallback, serviceClassName, childProcessCommonParameters,
childProcessCommonParameters, creationParams); creationParams);
int initialFlags = Context.BIND_AUTO_CREATE; int initialFlags = Context.BIND_AUTO_CREATE;
int extraBindFlags = shouldBindAsExportedService() ? Context.BIND_EXTERNAL_SERVICE : 0; int extraBindFlags = shouldBindAsExportedService() ? Context.BIND_EXTERNAL_SERVICE : 0;
......
...@@ -67,9 +67,8 @@ public class BindingManagerImplTest { ...@@ -67,9 +67,8 @@ public class BindingManagerImplTest {
* connection is established: with initial binding bound and no strong binding. * connection is established: with initial binding bound and no strong binding.
*/ */
private TestChildProcessConnection(int pid) { private TestChildProcessConnection(int pid) {
super(null /* context */, pid /* number */, true /* sandboxed */, super(null /* context */, true /* sandboxed */, null /* deathCallback */,
null /* deathCallback */, null /* serviceClassName */, "TestService" /* serviceClassName */, null /* childProcessCommonParameters */,
null /* childProcessCommonParameters */,
new ChildProcessCreationParams("org.chromium.test", new ChildProcessCreationParams("org.chromium.test",
false /* isExternalService */, 0 /* libraryProcessType */, false /* isExternalService */, 0 /* libraryProcessType */,
false /* bindToCallerCheck */)); false /* bindToCallerCheck */));
...@@ -566,7 +565,7 @@ public class BindingManagerImplTest { ...@@ -566,7 +565,7 @@ public class BindingManagerImplTest {
} }
app.onTrimMemory(pair.first); app.onTrimMemory(pair.first);
// Verify that some of moderate bindings drop. // Verify that some of the moderate bindings have been dropped.
for (int i = 0; i < connections.length; i++) { for (int i = 0; i < connections.length; i++) {
Assert.assertEquals( Assert.assertEquals(
message, i >= pair.second, connections[i].isModerateBindingBound()); message, i >= pair.second, connections[i].isModerateBindingBound());
......
...@@ -79,13 +79,33 @@ public final class ChildProcessLauncherTestUtils { ...@@ -79,13 +79,33 @@ public final class ChildProcessLauncherTestUtils {
}); });
} }
// Retrieves the service number of the passed in connection from its service name, or -1 if the
// service number could not be determined.
public static int getConnectionServiceNumber(final BaseChildProcessConnection connection) {
String serviceName = getConnectionServiceName(connection);
// The service name ends up with the service number.
StringBuilder numberString = new StringBuilder();
for (int i = serviceName.length() - 1; i >= 0; i--) {
char c = serviceName.charAt(i);
if (!Character.isDigit(c)) {
break;
}
numberString.append(c);
}
try {
return Integer.decode(numberString.toString());
} catch (NumberFormatException nfe) {
return -1;
}
}
// Retrieves the service number of the passed in connection on the launcher thread as to not // Retrieves the service number of the passed in connection on the launcher thread as to not
// assert. // assert.
public static int getConnectionServiceNumber(final BaseChildProcessConnection connection) { public static String getConnectionServiceName(final BaseChildProcessConnection connection) {
return runOnLauncherAndGetResult(new Callable<Integer>() { return runOnLauncherAndGetResult(new Callable<String>() {
@Override @Override
public Integer call() { public String call() {
return connection.getServiceNumber(); return connection.getServiceName().getClassName();
} }
}); });
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment