1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Eclipse Public License, Version 1.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.eclipse.org/org/documents/epl-v10.php 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ide.eclipse.ndk.internal.launch; 18 19 import com.android.ddmlib.IDevice; 20 import com.android.ddmlib.IShellOutputReceiver; 21 22 import java.util.concurrent.CountDownLatch; 23 import java.util.concurrent.atomic.AtomicBoolean; 24 25 /** 26 * The {@link GdbServerTask} launches gdbserver on the given device and attaches it to 27 * provided pid. 28 */ 29 public class GdbServerTask implements Runnable { 30 private IDevice mDevice; 31 private String mRunAs; 32 private String mSocket; 33 private int mPid; 34 private CountDownLatch mAttachLatch; 35 36 private GdbServerOutputReceiver mOutputReceiver; 37 private Exception mLaunchException; 38 39 private AtomicBoolean mCancelled = new AtomicBoolean(false); 40 private AtomicBoolean mHasCompleted = new AtomicBoolean(false); 41 42 /** 43 * Construct a gdbserver task. 44 * @param device device to run gdbserver on 45 * @param runAsPackage name of the package in which gdbserver resides 46 * @param socketName name of the local socket on which the server will listen 47 * @param pid pid of task to attach to 48 * @param attachLatch latch to notify when gdbserver gets attached to the task 49 */ GdbServerTask(IDevice device, String runAsPackage, String socketName, int pid, CountDownLatch attachLatch)50 public GdbServerTask(IDevice device, String runAsPackage, String socketName, int pid, 51 CountDownLatch attachLatch) { 52 mDevice = device; 53 mRunAs = runAsPackage; 54 mSocket = socketName; 55 mPid = pid; 56 mAttachLatch = attachLatch; 57 58 mOutputReceiver = new GdbServerOutputReceiver(); 59 } 60 61 /** 62 * Runs gdbserver on the device and connects to the given task. If gdbserver manages to 63 * successfully attach itself to the process, then it counts down on its attach latch. 64 */ 65 @Override run()66 public void run() { 67 // Launch gdbserver on the device. 68 String command = String.format("run-as %s lib/gdbserver +%s --attach %d", 69 mRunAs, mSocket, mPid); 70 try { 71 mDevice.executeShellCommand(command, mOutputReceiver, 0); 72 } catch (Exception e) { 73 mLaunchException = e; 74 } 75 } 76 77 /** Returns any exceptions that might have occurred while launching gdbserver. */ getLaunchException()78 public Exception getLaunchException() { 79 return mLaunchException; 80 } 81 82 /** Cancel gdbserver if it is running. */ setCancelled()83 public void setCancelled() { 84 mCancelled.set(true); 85 } 86 getShellOutput()87 public String getShellOutput() { 88 return mOutputReceiver.getOutput(); 89 } 90 91 private class GdbServerOutputReceiver implements IShellOutputReceiver { 92 private StringBuffer mOutput = new StringBuffer(100); 93 94 @Override addOutput(byte[] data, int offset, int length)95 public synchronized void addOutput(byte[] data, int offset, int length) { 96 mOutput.append(new String(data, offset, length)); 97 98 // notify other threads that gdbserver has attached to the task 99 if (mOutput.toString().contains("Attached")) { 100 mAttachLatch.countDown(); 101 } 102 } 103 104 @Override flush()105 public void flush() { 106 mHasCompleted.set(true); 107 } 108 109 @Override isCancelled()110 public boolean isCancelled() { 111 return mCancelled.get(); 112 } 113 getOutput()114 public synchronized String getOutput() { 115 return mOutput.toString(); 116 } 117 } 118 } 119