1 /* 2 * Copyright (C) 2009 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 package com.android.ide.eclipse.adt.internal.launch; 17 18 import com.android.ddmlib.IDevice; 19 import com.android.ddmlib.MultiLineReceiver; 20 import com.android.ide.eclipse.adt.AdtPlugin; 21 22 import java.util.ArrayList; 23 import java.util.regex.Matcher; 24 import java.util.regex.Pattern; 25 26 27 /** 28 * Output receiver for am process (Activity Manager) 29 * 30 * Monitors adb output for am errors, and retries launch as appropriate. 31 */ 32 public class AMReceiver extends MultiLineReceiver { 33 34 private static final int MAX_ATTEMPT_COUNT = 5; 35 private static final Pattern sAmErrorType = Pattern.compile("Error type (\\d+)"); //$NON-NLS-1$ 36 37 private final DelayedLaunchInfo mLaunchInfo; 38 private final IDevice mDevice; 39 private final ILaunchController mLaunchController; 40 41 /** 42 * Basic constructor. 43 * 44 * @param launchInfo the {@link DelayedLaunchInfo} associated with the am process. 45 * @param device the Android device on which the launch is done. 46 * @param launchController the {@link ILaunchController} that is managing the launch 47 */ 48 public AMReceiver(DelayedLaunchInfo launchInfo, IDevice device, 49 ILaunchController launchController) { 50 mLaunchInfo = launchInfo; 51 mDevice = device; 52 mLaunchController = launchController; 53 } 54 55 /** 56 * Monitors the am process for error messages. If an error occurs, will reattempt launch up to 57 * <code>MAX_ATTEMPT_COUNT</code> times. 58 * 59 * @param lines a portion of the am output 60 * 61 * @see MultiLineReceiver#processNewLines(String[]) 62 */ 63 @Override 64 public void processNewLines(String[] lines) { 65 // first we check if one starts with error 66 ArrayList<String> array = new ArrayList<String>(); 67 boolean error = false; 68 boolean warning = false; 69 for (String s : lines) { 70 // ignore empty lines. 71 if (s.length() == 0) { 72 continue; 73 } 74 75 // check for errors that output an error type, if the attempt count is still 76 // valid. If not the whole text will be output in the console 77 if (mLaunchInfo.getAttemptCount() < MAX_ATTEMPT_COUNT && 78 mLaunchInfo.isCancelled() == false) { 79 Matcher m = sAmErrorType.matcher(s); 80 if (m.matches()) { 81 // get the error type 82 int type = Integer.parseInt(m.group(1)); 83 84 final int waitTime = 3; 85 String msg; 86 87 switch (type) { 88 case 1: 89 /* Intended fall through */ 90 case 2: 91 msg = String.format( 92 "Device not ready. Waiting %1$d seconds before next attempt.", 93 waitTime); 94 break; 95 case 3: 96 msg = String.format( 97 "New package not yet registered with the system. Waiting %1$d seconds before next attempt.", 98 waitTime); 99 break; 100 default: 101 msg = String.format( 102 "Device not ready (%2$d). Waiting %1$d seconds before next attempt.", 103 waitTime, type); 104 break; 105 106 } 107 108 AdtPlugin.printToConsole(mLaunchInfo.getProject(), msg); 109 110 // launch another thread, that waits a bit and attempts another launch 111 new Thread("Delayed Launch attempt") { 112 @Override 113 public void run() { 114 try { 115 sleep(waitTime * 1000); 116 } catch (InterruptedException e) { 117 // ignore 118 } 119 120 mLaunchController.launchApp(mLaunchInfo, mDevice); 121 } 122 }.start(); 123 124 // no need to parse the rest 125 return; 126 } 127 } 128 129 // check for error if needed 130 if (error == false && s.startsWith("Error:")) { //$NON-NLS-1$ 131 error = true; 132 } 133 if (warning == false && s.startsWith("Warning:")) { //$NON-NLS-1$ 134 warning = true; 135 } 136 137 // add the line to the list 138 array.add("ActivityManager: " + s); //$NON-NLS-1$ 139 } 140 141 // then we display them in the console 142 if (warning || error) { 143 AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), array.toArray()); 144 } else { 145 AdtPlugin.printToConsole(mLaunchInfo.getProject(), array.toArray()); 146 } 147 148 // if error then we cancel the launch, and remove the delayed info 149 if (error) { 150 mLaunchController.stopLaunch(mLaunchInfo); 151 } 152 } 153 154 /** 155 * Returns true if launch has been cancelled 156 */ 157 @Override 158 public boolean isCancelled() { 159 return mLaunchInfo.isCancelled(); 160 } 161 } 162