/* * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Eclipse Public License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.eclipse.org/org/documents/epl-v10.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ide.eclipse.ndk.internal.launch; import com.android.ddmlib.IDevice; import com.android.ddmlib.IShellOutputReceiver; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; /** * The {@link GdbServerTask} launches gdbserver on the given device and attaches it to * provided pid. */ public class GdbServerTask implements Runnable { private IDevice mDevice; private String mRunAs; private String mSocket; private int mPid; private CountDownLatch mAttachLatch; private GdbServerOutputReceiver mOutputReceiver; private Exception mLaunchException; private AtomicBoolean mCancelled = new AtomicBoolean(false); private AtomicBoolean mHasCompleted = new AtomicBoolean(false); /** * Construct a gdbserver task. * @param device device to run gdbserver on * @param runAsPackage name of the package in which gdbserver resides * @param socketName name of the local socket on which the server will listen * @param pid pid of task to attach to * @param attachLatch latch to notify when gdbserver gets attached to the task */ public GdbServerTask(IDevice device, String runAsPackage, String socketName, int pid, CountDownLatch attachLatch) { mDevice = device; mRunAs = runAsPackage; mSocket = socketName; mPid = pid; mAttachLatch = attachLatch; mOutputReceiver = new GdbServerOutputReceiver(); } /** * Runs gdbserver on the device and connects to the given task. If gdbserver manages to * successfully attach itself to the process, then it counts down on its attach latch. */ @Override public void run() { // Launch gdbserver on the device. String command = String.format("run-as %s lib/gdbserver +%s --attach %d", mRunAs, mSocket, mPid); try { mDevice.executeShellCommand(command, mOutputReceiver, 0); } catch (Exception e) { mLaunchException = e; } } /** Returns any exceptions that might have occurred while launching gdbserver. */ public Exception getLaunchException() { return mLaunchException; } /** Cancel gdbserver if it is running. */ public void setCancelled() { mCancelled.set(true); } public String getShellOutput() { return mOutputReceiver.getOutput(); } private class GdbServerOutputReceiver implements IShellOutputReceiver { private StringBuffer mOutput = new StringBuffer(100); @Override public synchronized void addOutput(byte[] data, int offset, int length) { mOutput.append(new String(data, offset, length)); // notify other threads that gdbserver has attached to the task if (mOutput.toString().contains("Attached")) { mAttachLatch.countDown(); } } @Override public void flush() { mHasCompleted.set(true); } @Override public boolean isCancelled() { return mCancelled.get(); } public synchronized String getOutput() { return mOutput.toString(); } } }