diff options
Diffstat (limited to 'ddms/libs/ddmlib/src/com')
11 files changed, 279 insertions, 255 deletions
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java index 42022fe..5f0f271 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/AdbHelper.java @@ -29,7 +29,7 @@ import java.nio.channels.SocketChannel; /** * Helper class to handle requests and connections to adb. * <p/>{@link DebugBridgeServer} is the public API to connection to adb, while {@link AdbHelper} - * does the low level stuff. + * does the low level stuff. * <p/>This currently uses spin-wait non-blocking I/O. A Selector would be more efficient, * but seems like overkill for what we're doing here. */ @@ -272,14 +272,14 @@ final class AdbHelper { try { adbChan = SocketChannel.open(adbSockAddr); adbChan.configureBlocking(false); - + // if the device is not -1, then we first tell adb we're looking to talk // to a specific device setDevice(adbChan, device); - + if (write(adbChan, request) == false) throw new IOException("failed asking for frame buffer"); - + AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (!resp.ioSuccess || !resp.okay) { Log.w("ddms", "Got timeout or unhappy response from ADB fb req: " @@ -287,7 +287,7 @@ final class AdbHelper { adbChan.close(); return null; } - + reply = new byte[16]; if (read(adbChan, reply) == false) { Log.w("ddms", "got partial reply from ADB fb:"); @@ -297,19 +297,19 @@ final class AdbHelper { } ByteBuffer buf = ByteBuffer.wrap(reply); buf.order(ByteOrder.LITTLE_ENDIAN); - + imageParams.bpp = buf.getInt(); imageParams.size = buf.getInt(); imageParams.width = buf.getInt(); imageParams.height = buf.getInt(); - + Log.d("ddms", "image params: bpp=" + imageParams.bpp + ", size=" + imageParams.size + ", width=" + imageParams.width + ", height=" + imageParams.height); - + if (write(adbChan, nudge) == false) throw new IOException("failed nudging"); - + reply = new byte[imageParams.size]; if (read(adbChan, reply) == false) { Log.w("ddms", "got truncated reply from ADB fb data"); @@ -416,34 +416,34 @@ final class AdbHelper { public static void runLogService(InetSocketAddress adbSockAddr, Device device, String logName, LogReceiver rcvr) throws IOException { SocketChannel adbChan = null; - + try { adbChan = SocketChannel.open(adbSockAddr); adbChan.configureBlocking(false); - + // if the device is not -1, then we first tell adb we're looking to talk // to a specific device setDevice(adbChan, device); - + byte[] request = formAdbRequest("log:" + logName); if (write(adbChan, request) == false) { throw new IOException("failed to submit the log command"); } - + AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (!resp.ioSuccess || !resp.okay) { throw new IOException("Device rejected log command: " + resp.message); } - + byte[] data = new byte[16384]; ByteBuffer buf = ByteBuffer.wrap(data); while (true) { int count; - + if (rcvr != null && rcvr.isCancelled()) { break; } - + count = adbChan.read(buf); if (count < 0) { break; @@ -465,7 +465,7 @@ final class AdbHelper { } } } - + /** * Creates a port forwarding between a local and a remote port. * @param adbSockAddr the socket address to connect to adb @@ -473,7 +473,7 @@ final class AdbHelper { * @param localPort the local port to forward * @param remotePort the remote port. * @return <code>true</code> if success. - * @throws IOException + * @throws IOException */ public static boolean createForward(InetSocketAddress adbSockAddr, Device device, int localPort, int remotePort) throws IOException { @@ -482,15 +482,15 @@ final class AdbHelper { try { adbChan = SocketChannel.open(adbSockAddr); adbChan.configureBlocking(false); - + byte[] request = formAdbRequest(String.format( "host-serial:%1$s:forward:tcp:%2$d;tcp:%3$d", //$NON-NLS-1$ - device.serialNumber, localPort, remotePort)); - + device.getSerialNumber(), localPort, remotePort)); + if (write(adbChan, request) == false) { throw new IOException("failed to submit the forward command."); } - + AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (!resp.ioSuccess || !resp.okay) { throw new IOException("Device rejected command: " + resp.message); @@ -500,7 +500,7 @@ final class AdbHelper { adbChan.close(); } } - + return true; } @@ -520,15 +520,15 @@ final class AdbHelper { try { adbChan = SocketChannel.open(adbSockAddr); adbChan.configureBlocking(false); - + byte[] request = formAdbRequest(String.format( "host-serial:%1$s:killforward:tcp:%2$d;tcp:%3$d", //$NON-NLS-1$ - device.serialNumber, localPort, remotePort)); - + device.getSerialNumber(), localPort, remotePort)); + if (!write(adbChan, request)) { throw new IOException("failed to submit the remove forward command."); } - + AdbResponse resp = readAdbResponse(adbChan, false /* readDiagString */); if (!resp.ioSuccess || !resp.okay) { throw new IOException("Device rejected command: " + resp.message); @@ -563,7 +563,7 @@ final class AdbHelper { } return result; } - + /** * Reads from the socket until the array is filled, or no more data is coming (because * the socket closed or the timeout expired). @@ -572,7 +572,7 @@ final class AdbHelper { * mode for timeouts to work * @param data the buffer to store the read data into. * @return "true" if all data was read. - * @throws IOException + * @throws IOException */ static boolean read(SocketChannel chan, byte[] data) { try { @@ -581,7 +581,7 @@ final class AdbHelper { Log.d("ddms", "readAll: IOException: " + e.getMessage()); return false; } - + return true; } @@ -597,7 +597,7 @@ final class AdbHelper { * @param data the buffer to store the read data into. * @param length the length to read or -1 to fill the data buffer completely * @param timeout The timeout value. A timeout of zero means "wait forever". - * @throws IOException + * @throws IOException */ static void read(SocketChannel chan, byte[] data, int length, int timeout) throws IOException { ByteBuffer buf = ByteBuffer.wrap(data, 0, length != -1 ? length : data.length); @@ -653,7 +653,7 @@ final class AdbHelper { * @param data the buffer to send. * @param length the length to write or -1 to send the whole buffer. * @param timeout The timeout value. A timeout of zero means "wait forever". - * @throws IOException + * @throws IOException */ static void write(SocketChannel chan, byte[] data, int length, int timeout) throws IOException { @@ -697,7 +697,7 @@ final class AdbHelper { // if the device is not -1, then we first tell adb we're looking to talk // to a specific device if (device != null) { - String msg = "host:transport:" + device.serialNumber; //$NON-NLS-1$ + String msg = "host:transport:" + device.getSerialNumber(); //$NON-NLS-1$ byte[] device_query = formAdbRequest(msg); if (write(adbChan, device_query) == false) diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/AndroidDebugBridge.java b/ddms/libs/ddmlib/src/com/android/ddmlib/AndroidDebugBridge.java index c587b4e..9d6294a 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/AndroidDebugBridge.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/AndroidDebugBridge.java @@ -107,7 +107,7 @@ public final class AndroidDebugBridge { /** * Classes which implement this interface provide methods that deal - * with {@link Device} addition, deletion, and changes. + * with {@link IDevice} addition, deletion, and changes. */ public interface IDeviceChangeListener { /** @@ -116,7 +116,7 @@ public final class AndroidDebugBridge { * This is sent from a non UI thread. * @param device the new device. */ - public void deviceConnected(Device device); + public void deviceConnected(IDevice device); /** * Sent when the a device is connected to the {@link AndroidDebugBridge}. @@ -124,7 +124,7 @@ public final class AndroidDebugBridge { * This is sent from a non UI thread. * @param device the new device. */ - public void deviceDisconnected(Device device); + public void deviceDisconnected(IDevice device); /** * Sent when a device data changed, or when clients are started/terminated on the device. @@ -132,10 +132,10 @@ public final class AndroidDebugBridge { * This is sent from a non UI thread. * @param device the device that was updated. * @param changeMask the mask describing what changed. It can contain any of the following - * values: {@link Device#CHANGE_BUILD_INFO}, {@link Device#CHANGE_STATE}, - * {@link Device#CHANGE_CLIENT_LIST} + * values: {@link IDevice#CHANGE_BUILD_INFO}, {@link IDevice#CHANGE_STATE}, + * {@link IDevice#CHANGE_CLIENT_LIST} */ - public void deviceChanged(Device device, int changeMask); + public void deviceChanged(IDevice device, int changeMask); } /** @@ -215,7 +215,7 @@ public final class AndroidDebugBridge { /** * Returns whether the ddmlib is setup to support monitoring and interacting with - * {@link Client}s running on the {@link Device}s. + * {@link Client}s running on the {@link IDevice}s. */ static boolean getClientSupport() { return sClientSupport; @@ -391,7 +391,7 @@ public final class AndroidDebugBridge { } /** - * Adds the listener to the collection of listeners who will be notified when a {@link Device} + * Adds the listener to the collection of listeners who will be notified when a {@link IDevice} * is connected, disconnected, or when its properties or its {@link Client} list changed, * by sending it one of the messages defined in the {@link IDeviceChangeListener} interface. * @param listener The listener which should be notified. @@ -406,7 +406,7 @@ public final class AndroidDebugBridge { /** * Removes the listener from the collection of listeners who will be notified when a - * {@link Device} is connected, disconnected, or when its properties or its {@link Client} + * {@link IDevice} is connected, disconnected, or when its properties or its {@link Client} * list changed. * @param listener The listener which should no longer be notified. */ @@ -446,23 +446,23 @@ public final class AndroidDebugBridge { * Returns the devices. * @see #hasInitialDeviceList() */ - public Device[] getDevices() { + public IDevice[] getDevices() { synchronized (sLock) { if (mDeviceMonitor != null) { return mDeviceMonitor.getDevices(); } } - return new Device[0]; + return new IDevice[0]; } /** * Returns whether the bridge has acquired the initial list from adb after being created. * <p/>Calling {@link #getDevices()} right after {@link #createBridge(String, boolean)} will * generally result in an empty list. This is due to the internal asynchronous communication - * mechanism with <code>adb</code> that does not guarantee that the {@link Device} list has been + * mechanism with <code>adb</code> that does not guarantee that the {@link IDevice} list has been * built before the call to {@link #getDevices()}. - * <p/>The recommended way to get the list of {@link Device} objects is to create a + * <p/>The recommended way to get the list of {@link IDevice} objects is to create a * {@link IDeviceChangeListener} object. */ public boolean hasInitialDeviceList() { @@ -719,19 +719,19 @@ public final class AndroidDebugBridge { } /** - * Notify the listener of a new {@link Device}. + * Notify the listener of a new {@link IDevice}. * <p/> * The notification of the listeners is done in a synchronized block. It is important to - * expect the listeners to potentially access various methods of {@link Device} as well as + * expect the listeners to potentially access various methods of {@link IDevice} as well as * {@link #getDevices()} which use internal locks. * <p/> * For this reason, any call to this method from a method of {@link DeviceMonitor}, - * {@link Device} which is also inside a synchronized block, should first synchronize on + * {@link IDevice} which is also inside a synchronized block, should first synchronize on * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}. - * @param device the new <code>Device</code>. + * @param device the new <code>IDevice</code>. * @see #getLock() */ - void deviceConnected(Device device) { + void deviceConnected(IDevice device) { // because the listeners could remove themselves from the list while processing // their event callback, we make a copy of the list and iterate on it instead of // the main list. @@ -755,19 +755,19 @@ public final class AndroidDebugBridge { } /** - * Notify the listener of a disconnected {@link Device}. + * Notify the listener of a disconnected {@link IDevice}. * <p/> * The notification of the listeners is done in a synchronized block. It is important to - * expect the listeners to potentially access various methods of {@link Device} as well as + * expect the listeners to potentially access various methods of {@link IDevice} as well as * {@link #getDevices()} which use internal locks. * <p/> * For this reason, any call to this method from a method of {@link DeviceMonitor}, - * {@link Device} which is also inside a synchronized block, should first synchronize on + * {@link IDevice} which is also inside a synchronized block, should first synchronize on * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}. - * @param device the disconnected <code>Device</code>. + * @param device the disconnected <code>IDevice</code>. * @see #getLock() */ - void deviceDisconnected(Device device) { + void deviceDisconnected(IDevice device) { // because the listeners could remove themselves from the list while processing // their event callback, we make a copy of the list and iterate on it instead of // the main list. @@ -791,19 +791,19 @@ public final class AndroidDebugBridge { } /** - * Notify the listener of a modified {@link Device}. + * Notify the listener of a modified {@link IDevice}. * <p/> * The notification of the listeners is done in a synchronized block. It is important to - * expect the listeners to potentially access various methods of {@link Device} as well as + * expect the listeners to potentially access various methods of {@link IDevice} as well as * {@link #getDevices()} which use internal locks. * <p/> * For this reason, any call to this method from a method of {@link DeviceMonitor}, - * {@link Device} which is also inside a synchronized block, should first synchronize on + * {@link IDevice} which is also inside a synchronized block, should first synchronize on * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}. - * @param device the modified <code>Device</code>. + * @param device the modified <code>IDevice</code>. * @see #getLock() */ - void deviceChanged(Device device, int changeMask) { + void deviceChanged(IDevice device, int changeMask) { // because the listeners could remove themselves from the list while processing // their event callback, we make a copy of the list and iterate on it instead of // the main list. @@ -830,11 +830,11 @@ public final class AndroidDebugBridge { * Notify the listener of a modified {@link Client}. * <p/> * The notification of the listeners is done in a synchronized block. It is important to - * expect the listeners to potentially access various methods of {@link Device} as well as + * expect the listeners to potentially access various methods of {@link IDevice} as well as * {@link #getDevices()} which use internal locks. * <p/> * For this reason, any call to this method from a method of {@link DeviceMonitor}, - * {@link Device} which is also inside a synchronized block, should first synchronize on + * {@link IDevice} which is also inside a synchronized block, should first synchronize on * the {@link AndroidDebugBridge} lock. Access to this lock is done through {@link #getLock()}. * @param device the modified <code>Client</code>. * @param changeMask the mask indicating what changed in the <code>Client</code> diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/ChunkHandler.java b/ddms/libs/ddmlib/src/com/android/ddmlib/ChunkHandler.java index 441b024..74fa318 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/ChunkHandler.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/ChunkHandler.java @@ -199,7 +199,7 @@ abstract class ChunkHandler { protected static Client checkDebuggerPortForAppName(Client client, String appName) { IDebugPortProvider provider = DebugPortManager.getProvider(); if (provider != null) { - Device device = client.getDevice(); + Device device = client.getDeviceImpl(); int newPort = provider.getPort(device, appName); if (newPort != IDebugPortProvider.NO_STATIC_PORT && diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java b/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java index 866d578..64fbef6 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/Client.java @@ -133,7 +133,7 @@ public class Client { mConnState = ST_INIT; mClientData = new ClientData(pid); - + mThreadUpdateEnabled = DdmPreferences.getInitialThreadUpdate(); mHeapUpdateEnabled = DdmPreferences.getInitialHeapUpdate(); } @@ -147,9 +147,15 @@ public class Client { } /** - * Returns the {@link Device} on which this Client is running. + * Returns the {@link IDevice} on which this Client is running. */ - public Device getDevice() { + public IDevice getDevice() { + return mDevice; + } + + /** Returns the {@link Device} on which this Client is running. + */ + Device getDeviceImpl() { return mDevice; } @@ -238,7 +244,7 @@ public class Client { update(CHANGE_THREAD_MODE); } - + /** * Returns whether the thread update is enabled. */ @@ -268,7 +274,7 @@ public class Client { public void requestThreadStackTrace(int threadId) { HandleThread.requestThreadStackCallRefresh(this, threadId); } - + /** * Enables or disables the heap update. * <p/>If <code>true</code>, any GC will cause the client to send its heap information. @@ -320,7 +326,7 @@ public class Client { return false; } - + /** * Enables or disables the Allocation tracker for this client. * <p/>If enabled, the VM will start tracking allocation informations. A call to @@ -336,7 +342,7 @@ public class Client { Log.e("ddmlib", e); } } - + /** * Sends a request to the VM to send the enable status of the allocation tracking. * This is asynchronous. @@ -350,9 +356,9 @@ public class Client { HandleHeap.sendREAQ(this); } catch (IOException e) { Log.e("ddmlib", e); - } + } } - + /** * Sends a request to the VM to send the information about all the allocations that have * happened since the call to {@link #enableAllocationTracker(boolean)} with <var>enable</var> @@ -457,7 +463,7 @@ public class Client { } mConnState = ST_AWAIT_SHAKE; - + return true; } @@ -638,7 +644,7 @@ public class Client { */ Log.e("ddms", "Receiving data in state = " + mConnState); } - + return null; } @@ -753,7 +759,7 @@ public class Client { mDevice.removeClient(this, notify); } - + /** * Returns whether this {@link Client} has a valid connection to the application VM. */ diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/DebugPortManager.java b/ddms/libs/ddmlib/src/com/android/ddmlib/DebugPortManager.java index 9392127..defdc0e 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/DebugPortManager.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/DebugPortManager.java @@ -19,12 +19,12 @@ package com.android.ddmlib; import com.android.ddmlib.Device; /** - * Centralized point to provide a {@link IDebugPortProvider} to ddmlib. - * + * Centralized point to provide a {@link IDebugPortProvider} to ddmlib. + * * <p/>When {@link Client} objects are created, they start listening for debuggers on a specific - * port. The default behavior is to start with {@link DdmPreferences#getDebugPortBase()} and + * port. The default behavior is to start with {@link DdmPreferences#getDebugPortBase()} and * increment this value for each new <code>Client</code>. - * + * * <p/>This {@link DebugPortManager} allows applications using ddmlib to provide a custom * port provider on a per-<code>Client</code> basis, depending on the device/emulator they are * running on, and/or their names. @@ -48,7 +48,7 @@ public class DebugPortManager { * @return The non-random debugger port or {@link #NO_STATIC_PORT} if the {@link Client} * should use the automatic debugger port provider. */ - public int getPort(Device device, String appName); + public int getPort(IDevice device, String appName); } private static IDebugPortProvider sProvider = null; @@ -63,7 +63,7 @@ public class DebugPortManager { } /** - * Returns the + * Returns the * @return */ static IDebugPortProvider getProvider() { diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java b/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java index 37b33cf..d9d1275 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/Device.java @@ -16,7 +16,6 @@ package com.android.ddmlib; -import com.android.ddmlib.Client; import com.android.ddmlib.log.LogReceiver; import java.io.IOException; @@ -30,50 +29,20 @@ import java.util.Map; /** * A Device. It can be a physical device or an emulator. - * - * TODO: make this class package-protected, and shift all callers to use IDevice */ -public final class Device implements IDevice { - /** - * The state of a device. - */ - public static enum DeviceState { - BOOTLOADER("bootloader"), //$NON-NLS-1$ - OFFLINE("offline"), //$NON-NLS-1$ - ONLINE("device"); //$NON-NLS-1$ - - private String mState; - - DeviceState(String state) { - mState = state; - } - - /** - * Returns a {@link DeviceState} from the string returned by <code>adb devices</code>. - * @param state the device state. - * @return a {@link DeviceState} object or <code>null</code> if the state is unknown. - */ - public static DeviceState getState(String state) { - for (DeviceState deviceState : values()) { - if (deviceState.mState.equals(state)) { - return deviceState; - } - } - return null; - } - } +final class Device implements IDevice { /** Emulator Serial Number regexp. */ final static String RE_EMULATOR_SN = "emulator-(\\d+)"; //$NON-NLS-1$ /** Serial number of the device */ - String serialNumber = null; + private String mSerialNumber = null; /** Name of the AVD */ - String mAvdName = null; + private String mAvdName = null; /** State of the device. */ - DeviceState state = null; + private DeviceState mState = null; /** Device properties. */ private final Map<String, String> mProperties = new HashMap<String, String>(); @@ -91,22 +60,42 @@ public final class Device implements IDevice { * @see com.android.ddmlib.IDevice#getSerialNumber() */ public String getSerialNumber() { - return serialNumber; + return mSerialNumber; } + /** {@inheritDoc} */ public String getAvdName() { return mAvdName; } + /** + * Sets the name of the AVD + */ + void setAvdName(String avdName) { + if (isEmulator() == false) { + throw new IllegalArgumentException( + "Cannot set the AVD name of the device is not an emulator"); + } + + mAvdName = avdName; + } /* * (non-Javadoc) * @see com.android.ddmlib.IDevice#getState() */ public DeviceState getState() { - return state; + return mState; } + /** + * Changes the state of the device. + */ + void setState(DeviceState state) { + mState = state; + } + + /* * (non-Javadoc) * @see com.android.ddmlib.IDevice#getProperties() @@ -134,7 +123,7 @@ public final class Device implements IDevice { @Override public String toString() { - return serialNumber; + return mSerialNumber; } /* @@ -142,7 +131,7 @@ public final class Device implements IDevice { * @see com.android.ddmlib.IDevice#isOnline() */ public boolean isOnline() { - return state == DeviceState.ONLINE; + return mState == DeviceState.ONLINE; } /* @@ -150,7 +139,7 @@ public final class Device implements IDevice { * @see com.android.ddmlib.IDevice#isEmulator() */ public boolean isEmulator() { - return serialNumber.matches(RE_EMULATOR_SN); + return mSerialNumber.matches(RE_EMULATOR_SN); } /* @@ -158,7 +147,7 @@ public final class Device implements IDevice { * @see com.android.ddmlib.IDevice#isOffline() */ public boolean isOffline() { - return state == DeviceState.OFFLINE; + return mState == DeviceState.OFFLINE; } /* @@ -166,7 +155,7 @@ public final class Device implements IDevice { * @see com.android.ddmlib.IDevice#isBootLoader() */ public boolean isBootLoader() { - return state == DeviceState.BOOTLOADER; + return mState == DeviceState.BOOTLOADER; } /* @@ -305,8 +294,10 @@ public final class Device implements IDevice { } - Device(DeviceMonitor monitor) { + Device(DeviceMonitor monitor, String serialNumber, DeviceState deviceState) { mMonitor = monitor; + mSerialNumber = serialNumber; + mState = deviceState; } DeviceMonitor getMonitor() { diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/DeviceMonitor.java b/ddms/libs/ddmlib/src/com/android/ddmlib/DeviceMonitor.java index 87e023a..3382067 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/DeviceMonitor.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/DeviceMonitor.java @@ -18,7 +18,7 @@ package com.android.ddmlib; import com.android.ddmlib.AdbHelper.AdbResponse; import com.android.ddmlib.DebugPortManager.IDebugPortProvider; -import com.android.ddmlib.Device.DeviceState; +import com.android.ddmlib.IDevice.DeviceState; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -112,11 +112,11 @@ final class DeviceMonitor { boolean isMonitoring() { return mMonitoring; } - + int getConnectionAttemptCount() { return mConnectionAttempt; } - + int getRestartAttemptCount() { return mRestartAttemptCount; } @@ -129,7 +129,7 @@ final class DeviceMonitor { return mDevices.toArray(new Device[mDevices.size()]); } } - + boolean hasInitialDeviceList() { return mInitialDeviceListDone; } @@ -184,11 +184,11 @@ final class DeviceMonitor { if (mMonitoring) { // read the length of the incoming message int length = readLength(mMainAdbConnection, mLengthBuffer); - + if (length >= 0) { // read the incoming message processIncomingDeviceData(length); - + // flag the fact that we have build the list at least once. mInitialDeviceListDone = true; } @@ -278,20 +278,19 @@ final class DeviceMonitor { */ private void processIncomingDeviceData(int length) throws IOException { ArrayList<Device> list = new ArrayList<Device>(); - + if (length > 0) { byte[] buffer = new byte[length]; String result = read(mMainAdbConnection, buffer); - + String[] devices = result.split("\n"); // $NON-NLS-1$ for (String d : devices) { String[] param = d.split("\t"); // $NON-NLS-1$ if (param.length == 2) { // new adb uses only serial numbers to identify devices - Device device = new Device(this); - device.serialNumber = param[0]; - device.state = DeviceState.getState(param[1]); + Device device = new Device(this, param[0] /*serialnumber*/, + DeviceState.getState(param[1])); //add the device to the list list.add(device); @@ -319,24 +318,24 @@ final class DeviceMonitor { // * if we do not find it, we remove it from the current list. // Once this is done, the new list contains device we aren't monitoring yet, so we // add them to the list, and start monitoring them. - + for (int d = 0 ; d < mDevices.size() ;) { Device device = mDevices.get(d); - + // look for a similar device in the new list. int count = newList.size(); boolean foundMatch = false; for (int dd = 0 ; dd < count ; dd++) { Device newDevice = newList.get(dd); // see if it matches in id and serial number. - if (newDevice.serialNumber.equals(device.serialNumber)) { + if (newDevice.getSerialNumber().equals(device.getSerialNumber())) { foundMatch = true; - + // update the state if needed. - if (device.state != newDevice.state) { - device.state = newDevice.state; + if (device.getState() != newDevice.getState()) { + device.setState(newDevice.getState()); device.update(Device.CHANGE_STATE); - + // if the device just got ready/online, we need to start // monitoring it. if (device.isOnline()) { @@ -344,7 +343,7 @@ final class DeviceMonitor { if (startMonitoringDevice(device) == false) { Log.e("DeviceMonitor", "Failed to start monitoring " - + device.serialNumber); + + device.getSerialNumber()); } } @@ -353,13 +352,13 @@ final class DeviceMonitor { } } } - + // remove the new device from the list since it's been used newList.remove(dd); break; } } - + if (foundMatch == false) { // the device is gone, we need to remove it, and keep current index // to process the next one. @@ -370,21 +369,21 @@ final class DeviceMonitor { d++; } } - + // at this point we should still have some new devices in newList, so we // process them. for (Device newDevice : newList) { // add them to the list mDevices.add(newDevice); mServer.deviceConnected(newDevice); - + // start monitoring them. if (AndroidDebugBridge.getClientSupport() == true) { if (newDevice.isOnline()) { startMonitoringDevice(newDevice); } } - + // look for their build info. if (newDevice.isOnline()) { queryNewDeviceForInfo(newDevice); @@ -398,7 +397,7 @@ final class DeviceMonitor { private void removeDevice(Device device) { device.clearClientList(); mDevices.remove(device); - + SocketChannel channel = device.getClientMonitoringSocket(); if (channel != null) { try { @@ -419,12 +418,12 @@ final class DeviceMonitor { // first get the list of properties. device.executeShellCommand(GetPropReceiver.GETPROP_COMMAND, new GetPropReceiver(device)); - + // now get the emulator Virtual Device name (if applicable). if (device.isEmulator()) { EmulatorConsole console = EmulatorConsole.getConsole(device); if (console != null) { - device.mAvdName = console.getAvdName(); + device.setAvdName(console.getAvdName()); } } } catch (IOException e) { @@ -510,7 +509,7 @@ final class DeviceMonitor { MonitorThread monitorThread = MonitorThread.getInstance(); for (Client client : clients) { - Device device = client.getDevice(); + Device device = client.getDeviceImpl(); int pid = client.getClientData().getPid(); monitorThread.dropClient(client, false /* notify */); @@ -623,10 +622,10 @@ final class DeviceMonitor { if (length > 0) { byte[] buffer = new byte[length]; String result = read(monitorSocket, buffer); - + // split each line in its own list and create an array of integer pid String[] pids = result.split("\n"); //$NON-NLS-1$ - + for (String pid : pids) { try { pidList.add(Integer.valueOf(pid)); @@ -662,7 +661,7 @@ final class DeviceMonitor { for (int c = 0 ; c < clients.size() ;) { Client client = clients.get(c); int pid = client.getClientData().getPid(); - + // look for a matching pid Integer match = null; for (Integer matchingPid : pidList) { @@ -671,7 +670,7 @@ final class DeviceMonitor { break; } } - + if (match != null) { pidList.remove(match); c++; // move on to the next client. @@ -705,7 +704,7 @@ final class DeviceMonitor { * @return */ private void openClient(Device device, int pid, int port, MonitorThread monitorThread) { - + SocketChannel clientSocket; try { clientSocket = AdbHelper.createPassThroughConnection( @@ -721,7 +720,7 @@ final class DeviceMonitor { "Failed to connect to client '" + pid + "': " + ioe.getMessage()); return ; } - + createClient(device, pid, clientSocket, port, monitorThread); } @@ -814,7 +813,7 @@ final class DeviceMonitor { } } } - + /** * Reads the length of the next message from a socket. * @param socket The {@link SocketChannel} to read from. diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java b/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java index f3986ed..75347c6 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java @@ -41,7 +41,7 @@ import java.util.regex.Pattern; * code removes <code>\r</code> and waits for <code>\n</code>. * <p/>However this means you <i>may</i> receive <code>\r\n</code> when reading from the console. * <p/> - * <b>This API will change in the near future.</b> + * <b>This API will change in the near future.</b> */ public final class EmulatorConsole { @@ -65,7 +65,7 @@ public final class EmulatorConsole { private final static String COMMAND_NETWORK_STATUS = "network status\r\n"; //$NON-NLS-1$ private final static String COMMAND_NETWORK_SPEED = "network speed %1$s\r\n"; //$NON-NLS-1$ private final static String COMMAND_NETWORK_LATENCY = "network delay %1$s\r\n"; //$NON-NLS-1$ - private final static String COMMAND_GPS = + private final static String COMMAND_GPS = "geo nmea $GPGGA,%1$02d%2$02d%3$02d.%4$03d," + //$NON-NLS-1$ "%5$03d%6$09.6f,%7$c,%8$03d%9$09.6f,%10$c," + //$NON-NLS-1$ "1,10,0.0,0.0,0,0.0,0,0.0,0000\r\n"; //$NON-NLS-1$ @@ -202,9 +202,9 @@ public final class EmulatorConsole { * @param d The device that the console links to. * @return an <code>EmulatorConsole</code> object or <code>null</code> if the connection failed. */ - public static synchronized EmulatorConsole getConsole(Device d) { + public static synchronized EmulatorConsole getConsole(IDevice d) { // we need to make sure that the device is an emulator - Matcher m = sEmulatorRegexp.matcher(d.serialNumber); + Matcher m = sEmulatorRegexp.matcher(d.getSerialNumber()); if (m.matches()) { // get the port number. This is the console port. int port; @@ -308,7 +308,7 @@ public final class EmulatorConsole { RemoveConsole(mPort); } } - + public synchronized String getAvdName() { if (sendCommand(COMMAND_AVD_NAME)) { String[] result = readLines(); @@ -323,7 +323,7 @@ public final class EmulatorConsole { } } } - + return null; } @@ -517,18 +517,18 @@ public final class EmulatorConsole { String command = String.format(COMMAND_NETWORK_LATENCY, NETWORK_LATENCIES[selectionIndex]); return processCommand(command); } - + public synchronized String sendLocation(double longitude, double latitude, double elevation) { - + Calendar c = Calendar.getInstance(); - + double absLong = Math.abs(longitude); int longDegree = (int)Math.floor(absLong); char longDirection = 'E'; if (longitude < 0) { longDirection = 'W'; } - + double longMinute = (absLong - Math.floor(absLong)) * 60; double absLat = Math.abs(latitude); @@ -537,15 +537,15 @@ public final class EmulatorConsole { if (latitude < 0) { latDirection = 'S'; } - + double latMinute = (absLat - Math.floor(absLat)) * 60; - + String command = String.format(COMMAND_GPS, c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE), c.get(Calendar.SECOND), c.get(Calendar.MILLISECOND), latDegree, latMinute, latDirection, longDegree, longMinute, longDirection); - + return processCommand(command); } @@ -617,7 +617,7 @@ public final class EmulatorConsole { ByteBuffer buf = ByteBuffer.wrap(mBuffer, 0, mBuffer.length); int numWaits = 0; boolean stop = false; - + while (buf.position() != buf.limit() && stop == false) { int count; diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java b/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java index a54af8a..3a2bd55 100755 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java @@ -16,7 +16,6 @@ package com.android.ddmlib; -import com.android.ddmlib.Device.DeviceState; import com.android.ddmlib.log.LogReceiver; import java.io.IOException; @@ -41,6 +40,35 @@ public interface IDevice { public static final int CHANGE_BUILD_INFO = 0x0004; /** + * The state of a device. + */ + public static enum DeviceState { + BOOTLOADER("bootloader"), //$NON-NLS-1$ + OFFLINE("offline"), //$NON-NLS-1$ + ONLINE("device"); //$NON-NLS-1$ + + private String mState; + + DeviceState(String state) { + mState = state; + } + + /** + * Returns a {@link DeviceState} from the string returned by <code>adb devices</code>. + * @param state the device state. + * @return a {@link DeviceState} object or <code>null</code> if the state is unknown. + */ + public static DeviceState getState(String state) { + for (DeviceState deviceState : values()) { + if (deviceState.mState.equals(state)) { + return deviceState; + } + } + return null; + } + } + + /** * Returns the serial number of the device. */ public String getSerialNumber(); diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/MonitorThread.java b/ddms/libs/ddmlib/src/com/android/ddmlib/MonitorThread.java index 79eb5bb..3089c2e 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/MonitorThread.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/MonitorThread.java @@ -103,7 +103,7 @@ final class MonitorThread extends Thread { /** - * Sets or changes the port number for "debug selected". + * Sets or changes the port number for "debug selected". */ synchronized void setDebugSelectedPort(int port) throws IllegalStateException { if (mInstance == null) { @@ -206,7 +206,7 @@ final class MonitorThread extends Thread { } while (!mQuit) { - + try { /* * sync with new registrations: we wait until addClient is done before going through @@ -215,7 +215,7 @@ final class MonitorThread extends Thread { */ synchronized (mClientList) { } - + // (re-)open the "debug selected" port, if it's not opened yet or // if the port changed. try { @@ -234,7 +234,7 @@ final class MonitorThread extends Thread { Log.e("ddms", ioe); mNewDebugSelectedPort = mDebugSelectedPort; // no retry } - + int count; try { count = mSelector.select(); @@ -244,20 +244,20 @@ final class MonitorThread extends Thread { } catch (CancelledKeyException cke) { continue; } - + if (count == 0) { // somebody called wakeup() ? // Log.i("ddms", "selector looping"); continue; } - + Set<SelectionKey> keys = mSelector.selectedKeys(); Iterator<SelectionKey> iter = keys.iterator(); - + while (iter.hasNext()) { SelectionKey key = iter.next(); iter.remove(); - + try { if (key.attachment() instanceof Client) { processClientActivity(key); @@ -300,7 +300,7 @@ final class MonitorThread extends Thread { */ private void processClientActivity(SelectionKey key) { Client client = (Client)key.attachment(); - + try { if (key.isReadable() == false || key.isValid() == false) { Log.d("ddms", "Invalid key from " + client + ". Dropping client."); @@ -423,7 +423,7 @@ final class MonitorThread extends Thread { * @param notify */ synchronized void dropClient(Client client, boolean notify) { - if (mInstance == null) { + if (mInstance == null) { return; } @@ -551,13 +551,13 @@ final class MonitorThread extends Thread { // we should drop the client, but also attempt to reopen it. // This is done by the DeviceMonitor. - client.getDevice().getMonitor().addClientToDropAndReopen(client, + client.getDeviceImpl().getMonitor().addClientToDropAndReopen(client, IDebugPortProvider.NO_STATIC_PORT); } else { Log.i("ddms", " (recycling client connection as well)"); // we should drop the client, but also attempt to reopen it. // This is done by the DeviceMonitor. - client.getDevice().getMonitor().addClientToDropAndReopen(client, + client.getDeviceImpl().getMonitor().addClientToDropAndReopen(client, IDebugPortProvider.NO_STATIC_PORT); } } @@ -644,7 +644,7 @@ final class MonitorThread extends Thread { } } } - + /* * Broadcast an event to all message handlers. */ @@ -719,7 +719,7 @@ final class MonitorThread extends Thread { } mDebugSelectedChan.register(mSelector, SelectionKey.OP_ACCEPT, this); - + return true; } catch (java.net.BindException e) { displayDebugSelectedBindError(mNewDebugSelectedPort); @@ -727,7 +727,7 @@ final class MonitorThread extends Thread { // do not attempt to reopen it. mDebugSelectedChan = null; mNewDebugSelectedPort = -1; - + return false; } } diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/log/EventLogParser.java b/ddms/libs/ddmlib/src/com/android/ddmlib/log/EventLogParser.java index 85e99c1..0b2ce69 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/log/EventLogParser.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/log/EventLogParser.java @@ -16,7 +16,7 @@ package com.android.ddmlib.log; -import com.android.ddmlib.Device; +import com.android.ddmlib.IDevice; import com.android.ddmlib.Log; import com.android.ddmlib.MultiLineReceiver; import com.android.ddmlib.log.EventContainer.EventValueType; @@ -55,7 +55,7 @@ public final class EventLogParser { private final static int EVENT_TYPE_LONG = 1; private final static int EVENT_TYPE_STRING = 2; private final static int EVENT_TYPE_LIST = 3; - + private final static Pattern PATTERN_SIMPLE_TAG = Pattern.compile( "^(\\d+)\\s+([A-Za-z0-9_]+)\\s*$"); //$NON-NLS-1$ private final static Pattern PATTERN_TAG_WITH_DESC = Pattern.compile( @@ -67,9 +67,9 @@ public final class EventLogParser { "(\\d\\d)-(\\d\\d)\\s(\\d\\d):(\\d\\d):(\\d\\d).(\\d{3})\\s+I/([a-zA-Z0-9_]+)\\s*\\(\\s*(\\d+)\\):\\s+(.*)"); //$NON-NLS-1$ private final TreeMap<Integer, String> mTagMap = new TreeMap<Integer, String>(); - + private final TreeMap<Integer, EventValueDescription[]> mValueDescriptionMap = - new TreeMap<Integer, EventValueDescription[]>(); + new TreeMap<Integer, EventValueDescription[]>(); public EventLogParser() { } @@ -82,7 +82,7 @@ public final class EventLogParser { * @param device The device. * @return <code>true</code> if success, <code>false</code> if failure or cancellation. */ - public boolean init(Device device) { + public boolean init(IDevice device) { // read the event tag map file on the device. try { device.executeShellCommand("cat " + EVENT_TAG_MAP_FILE, //$NON-NLS-1$ @@ -103,7 +103,7 @@ public final class EventLogParser { return true; } - + /** * Inits the parser with the content of a tag file. * @param tagFileContent the lines of a tag file. @@ -115,7 +115,7 @@ public final class EventLogParser { } return true; } - + /** * Inits the parser with a specified event-log-tags file. * @param filePath @@ -124,7 +124,7 @@ public final class EventLogParser { public boolean init(String filePath) { try { BufferedReader reader = new BufferedReader(new FileReader(filePath)); - + String line = null; do { line = reader.readLine(); @@ -132,13 +132,13 @@ public final class EventLogParser { processTagLine(line); } } while (line != null); - + return true; } catch (IOException e) { return false; } } - + /** * Processes a line from the event-log-tags file. * @param line the line to process @@ -154,7 +154,7 @@ public final class EventLogParser { if (name != null && mTagMap.get(value) == null) { mTagMap.put(value, name); } - + // special case for the GC tag. We ignore what is in the file, // and take what the custom GcEventContainer class tells us. // This is due to the event encoding several values on 2 longs. @@ -163,12 +163,12 @@ public final class EventLogParser { mValueDescriptionMap.put(value, GcEventContainer.getValueDescriptions()); } else { - + String description = m.group(3); if (description != null && description.length() > 0) { EventValueDescription[] desc = processDescription(description); - + if (desc != null) { mValueDescriptionMap.put(value, desc); } @@ -189,12 +189,12 @@ public final class EventLogParser { } } } - + private EventValueDescription[] processDescription(String description) { String[] descriptions = description.split("\\s*,\\s*"); //$NON-NLS-1$ - + ArrayList<EventValueDescription> list = new ArrayList<EventValueDescription>(); - + for (String desc : descriptions) { Matcher m = PATTERN_DESCRIPTION.matcher(desc); if (m.matches()) { @@ -208,15 +208,15 @@ public final class EventLogParser { // just ignore this description if the value is not recognized. // TODO: log the error. } - + typeString = m.group(3); if (typeString != null && typeString.length() > 0) { //skip the | typeString = typeString.substring(1); - + typeValue = Integer.parseInt(typeString); ValueType valueType = ValueType.getValueType(typeValue); - + list.add(new EventValueDescription(name, eventValueType, valueType)); } else { list.add(new EventValueDescription(name, eventValueType)); @@ -233,15 +233,15 @@ public final class EventLogParser { String.format("Can't parse %1$s", description)); //$NON-NLS-1$ } } - + if (list.size() == 0) { return null; } - + return list.toArray(new EventValueDescription[list.size()]); - + } - + public EventContainer parse(LogEntry entry) { if (entry.len < 4) { return null; @@ -251,7 +251,7 @@ public final class EventLogParser { int tagValue = ArrayHelper.swap32bitFromArray(entry.data, inOffset); inOffset += 4; - + String tag = mTagMap.get(tagValue); if (tag == null) { Log.e("EventLogParser", String.format("unknown tag number: %1$d", tagValue)); @@ -275,10 +275,10 @@ public final class EventLogParser { } else { event = new EventContainer(entry, tagValue, data); } - + return event; } - + public EventContainer parse(String textLogLine) { // line will look like // 04-29 23:16:16.691 I/dvm_gc_info( 427): <data> @@ -289,7 +289,7 @@ public final class EventLogParser { if (textLogLine.length() == 0) { return null; } - + // parse the header first Matcher m = TEXT_LOG_LINE.matcher(textLogLine); if (m.matches()) { @@ -300,7 +300,7 @@ public final class EventLogParser { int minutes = Integer.parseInt(m.group(4)); int seconds = Integer.parseInt(m.group(5)); int milliseconds = Integer.parseInt(m.group(6)); - + // convert into seconds since epoch and nano-seconds. Calendar cal = Calendar.getInstance(); cal.set(cal.get(Calendar.YEAR), month-1, day, hours, minutes, seconds); @@ -308,7 +308,7 @@ public final class EventLogParser { int nsec = milliseconds * 1000000; String tag = m.group(7); - + // get the numerical tag value int tagValue = -1; Set<Entry<Integer, String>> tagSet = mTagMap.entrySet(); @@ -318,18 +318,18 @@ public final class EventLogParser { break; } } - + if (tagValue == -1) { return null; } - + int pid = Integer.parseInt(m.group(8)); - + Object data = parseTextData(m.group(9), tagValue); if (data == null) { return null; } - + // now we can allocate and return the EventContainer EventContainer event = null; if (tagValue == GcEventContainer.GC_EVENT_TAG) { @@ -337,20 +337,20 @@ public final class EventLogParser { } else { event = new EventContainer(tagValue, pid, -1 /* tid */, sec, nsec, data); } - + return event; } catch (NumberFormatException e) { return null; } } - + return null; } - + public Map<Integer, String> getTagMap() { return mTagMap; } - + public Map<Integer, EventValueDescription[]> getEventInfoMap() { return mValueDescriptionMap; } @@ -370,7 +370,7 @@ public final class EventLogParser { if (eventData.length - dataOffset < 1) return -1; - + int offset = dataOffset; int type = eventData[offset++]; @@ -385,7 +385,7 @@ public final class EventLogParser { return -1; ival = ArrayHelper.swap32bitFromArray(eventData, offset); offset += 4; - + list.add(new Integer(ival)); } break; @@ -396,7 +396,7 @@ public final class EventLogParser { return -1; lval = ArrayHelper.swap64bitFromArray(eventData, offset); offset += 8; - + list.add(new Long(lval)); } break; @@ -410,7 +410,7 @@ public final class EventLogParser { if (eventData.length - offset < strLen) return -1; - + // get the string try { String str = new String(eventData, offset, strLen, "UTF-8"); //$NON-NLS-1$ @@ -434,7 +434,7 @@ public final class EventLogParser { if (result == -1) { return result; } - + offset += result; } @@ -446,59 +446,59 @@ public final class EventLogParser { String.format("Unknown binary event type %1$d", type)); //$NON-NLS-1$ return -1; } - + return offset - dataOffset; } - + private Object parseTextData(String data, int tagValue) { // first, get the description of what we're supposed to parse EventValueDescription[] desc = mValueDescriptionMap.get(tagValue); - + if (desc == null) { // TODO parse and create string values. return null; } - + if (desc.length == 1) { return getObjectFromString(data, desc[0].getEventValueType()); } else if (data.startsWith("[") && data.endsWith("]")) { data = data.substring(1, data.length() - 1); - + // get each individual values as String String[] values = data.split(","); - + if (tagValue == GcEventContainer.GC_EVENT_TAG) { // special case for the GC event! Object[] objects = new Object[2]; - + objects[0] = getObjectFromString(values[0], EventValueType.LONG); objects[1] = getObjectFromString(values[1], EventValueType.LONG); - + return objects; } else { // must be the same number as the number of descriptors. if (values.length != desc.length) { return null; } - + Object[] objects = new Object[values.length]; - + for (int i = 0 ; i < desc.length ; i++) { Object obj = getObjectFromString(values[i], desc[i].getEventValueType()); if (obj == null) { return null; } - objects[i] = obj; + objects[i] = obj; } - + return objects; } } - + return null; } - + private Object getObjectFromString(String value, EventValueType type) { try { switch (type) { @@ -512,14 +512,14 @@ public final class EventLogParser { } catch (NumberFormatException e) { // do nothing, we'll return null. } - + return null; } /** - * Recreates the event-log-tags at the specified file path. + * Recreates the event-log-tags at the specified file path. * @param filePath the file path to write the file. - * @throws IOException + * @throws IOException */ public void saveTags(String filePath) throws IOException { File destFile = new File(filePath); @@ -527,16 +527,16 @@ public final class EventLogParser { FileOutputStream fos = null; try { - + fos = new FileOutputStream(destFile); - + for (Integer key : mTagMap.keySet()) { // get the tag name String tagName = mTagMap.get(key); - + // get the value descriptions EventValueDescription[] descriptors = mValueDescriptionMap.get(key); - + String line = null; if (descriptors != null) { StringBuilder sb = new StringBuilder(); @@ -557,12 +557,12 @@ public final class EventLogParser { sb.append("|)"); //$NON-NLS-1$ } sb.append("\n"); //$NON-NLS-1$ - + line = sb.toString(); } else { line = String.format("%1$d %2$s\n", key, tagName); //$NON-NLS-1$ } - + byte[] buffer = line.getBytes(); fos.write(buffer); } |