1 package compiler.abcc; 2 3 import android.app.IntentService; 4 import android.app.Service; 5 import android.content.Intent; 6 import android.content.res.AssetManager; 7 import android.content.pm.ApplicationInfo; 8 import android.content.pm.PackageManager; 9 import android.os.Binder; 10 import android.os.Bundle; 11 import android.os.IBinder; 12 import android.os.Parcel; 13 import android.os.ResultReceiver; 14 import android.os.RemoteException; 15 import android.util.Log; 16 import java.io.File; 17 import java.io.FilenameFilter; 18 import java.io.FileOutputStream; 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.io.OutputStream; 22 23 public class AbccService extends IntentService { 24 private static final String TAG = "AbccService"; 25 26 String mWorkingDir = null; 27 String mSysroot = null; 28 29 // For onBind() 30 private IBinder mBinder = new LocalBinder(); 31 private int mCurrentStatus = AbccService.STATUS_OKAY; 32 private Object mStatusLock = new Object(); 33 34 private static int STATUS_OKAY = 0; 35 private static int STATUS_WORKING = 1; 36 private static int STATUS_ERROR = 2; 37 38 class WorkingThread extends Thread { 39 @Override run()40 public void run() { 41 Log.i(TAG, "WorkingThread run"); 42 43 44 synchronized (mStatusLock) { 45 mCurrentStatus = AbccService.STATUS_WORKING; 46 if (mWorkingDir == null) { 47 mCurrentStatus = AbccService.STATUS_ERROR; 48 mStatusLock.notifyAll(); 49 return; 50 } 51 } 52 53 Log.i(TAG, "mWorkingDir for genLibs: " + mWorkingDir); 54 if (genLibs(mWorkingDir, mSysroot) != 0) { 55 synchronized (mStatusLock) { 56 mCurrentStatus = AbccService.STATUS_ERROR; 57 mStatusLock.notifyAll(); 58 return; 59 } 60 } 61 62 Log.i(TAG, "WorkingThread run okay"); 63 synchronized (mStatusLock) { 64 mCurrentStatus = AbccService.STATUS_OKAY; 65 mStatusLock.notifyAll(); 66 Log.i(TAG, "WorkingThread run done"); 67 return; 68 } 69 } 70 } 71 72 class LocalBinder extends Binder { 73 @Override onTransact(int code, Parcel data, Parcel reply, int flags)74 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { 75 if (!pingBinder()) { 76 Log.e(TAG, "Process doesn't exist. Error!"); 77 throw new RemoteException("AbccLocalBinder pingBinder return false!"); 78 } 79 80 // The code is not important now. This is just a communication way 81 // and what we really need is the information from @data 82 Bundle real_data = data.readBundle(); 83 if (real_data == null) { 84 Log.e(TAG, "Should get some information from the Parcel."); 85 return false; 86 } 87 String path = real_data.getString("working_dir"); 88 if (path == null ) { 89 Log.e(TAG, "onTransact but no working_dir provided?"); 90 return false; 91 } 92 93 mWorkingDir = path; 94 compileForBinder(); 95 return queryStatusForBinder(); 96 } 97 } 98 compileForBinder()99 private boolean compileForBinder() { 100 Log.i(TAG, "compileForBinder"); 101 new WorkingThread().start(); 102 synchronized (mStatusLock) { 103 mCurrentStatus = AbccService.STATUS_WORKING; 104 } 105 Log.i(TAG, "compileForBinder done"); 106 return true; 107 } 108 queryStatusForBinder()109 private boolean queryStatusForBinder() { 110 Log.i(TAG, "queryStatusForBinder"); 111 Log.i(TAG, "mCurrentStatus = " + mCurrentStatus); 112 113 while (mCurrentStatus == STATUS_WORKING) { 114 try { 115 Log.i(TAG, "queryStatusForBinder wait"); 116 synchronized (mStatusLock) { 117 mStatusLock.wait(); 118 } 119 } catch (InterruptedException e) { 120 } 121 } 122 123 Log.i(TAG, "queryStatusForBinder checking result"); 124 125 if (mCurrentStatus == STATUS_OKAY) 126 return true; 127 else 128 return false; 129 } 130 extractIntentInfo(Intent intent)131 private void extractIntentInfo(Intent intent) { 132 if (intent == null) { 133 Log.e(TAG, "Intent should not be null when extractIntentInfo."); 134 return; 135 } 136 137 String path = intent.getStringExtra("working_dir"); 138 Log.i(TAG, "Got working_dir from intent: " + path); 139 if (path != null) 140 mWorkingDir = path; 141 else 142 Log.e(TAG, "Intent extra 'working_dir' cannot be null."); 143 144 path = intent.getStringExtra("toolchain_sysroot"); 145 if (path != null) 146 mSysroot = path; 147 } 148 installToolchain()149 private void installToolchain() { 150 if (mSysroot != null) { 151 // User specify a customized toolchain sysroot, so we don't need to copy. 152 return; 153 } 154 155 // The toolchain is enclosed inside assets/ 156 File sysroot = getDir("toolchain_sysroot", MODE_WORLD_READABLE); 157 mSysroot = sysroot.getAbsolutePath(); 158 File cur_file = new File(mSysroot + "/usr"); 159 cur_file.mkdirs(); 160 cur_file.setReadable(true, /*OwnerOnly=*/false); 161 cur_file.setExecutable(true, /*OwnerOnly=*/false); 162 cur_file = new File(mSysroot + "/usr/bin"); 163 cur_file.mkdirs(); 164 cur_file.setReadable(true, /*OwnerOnly=*/false); 165 cur_file.setExecutable(true, /*OwnerOnly=*/false); 166 cur_file = new File(mSysroot + "/usr/lib"); 167 cur_file.mkdirs(); 168 cur_file.setReadable(true, /*OwnerOnly=*/false); 169 cur_file.setExecutable(true, /*OwnerOnly=*/false); 170 copyAssets("usr/bin", mSysroot + "/usr/bin", /*executable=*/true); 171 copyAssets("usr/lib", mSysroot + "/usr/lib", /*executable=*/false); 172 } 173 copyAssets(String asset_dir, String out_dir, boolean executable)174 private void copyAssets(String asset_dir, String out_dir, boolean executable) { 175 AssetManager assetManager = getAssets(); 176 String[] files = null; 177 try { 178 files = assetManager.list(asset_dir); 179 } catch (IOException e) { 180 Log.e(TAG, "Failed to get asset file list.", e); 181 } 182 for(String filename : files) { 183 InputStream in = null; 184 OutputStream out = null; 185 try { 186 in = assetManager.open(asset_dir + "/" + filename); 187 out = new FileOutputStream(out_dir + "/" + filename); 188 copyFile(in, out); 189 in.close(); 190 in = null; 191 out.flush(); 192 out.close(); 193 out = null; 194 } catch(IOException e) { 195 Log.e(TAG, "Failed to copy asset file: " + filename, e); 196 } 197 198 File cur_file = new File(out_dir + "/" + filename); 199 cur_file.setReadable(true, /*OwnerOnly=*/false); 200 if (executable) { 201 cur_file.setExecutable(true, /*OwnerOnly=*/false); 202 } 203 } 204 } 205 copyFile(InputStream in, OutputStream out)206 private void copyFile(InputStream in, OutputStream out) throws IOException { 207 byte[] buffer = new byte[1024]; 208 int read; 209 while((read = in.read(buffer)) != -1){ 210 out.write(buffer, 0, read); 211 } 212 } 213 AbccService()214 public AbccService() { 215 super("AbccService"); 216 } 217 218 // Usage: adb shell am startservice -a compiler.abcc.BITCODE_COMPILE_TEST -n compiler.abcc/compiler.abcc.AbccService -e working_dir /data/local/tmp/test 219 @Override onHandleIntent(Intent intent)220 public void onHandleIntent(Intent intent) { 221 Log.i(TAG, "got onHandleIntent intent: " + intent); 222 if (intent.getAction() != "compiler.abcc.BITCODE_COMPILE_TEST") { 223 Log.e(TAG, "We don't support formal release by onHandleIntent() yet!"); 224 return; 225 } 226 227 extractIntentInfo(intent); 228 installToolchain(); 229 new WorkingThread().start(); 230 } 231 232 @Override onBind(Intent intent)233 public IBinder onBind(Intent intent) { 234 Log.i(TAG, "got onBind intent: " + intent); 235 if (intent.getAction() != "compiler.abcc.BITCODE_COMPILE") { 236 Log.e(TAG, "We don't support other intent except for BITCODE_COMPILE by onBind() yet!"); 237 return null; 238 } 239 240 installToolchain(); 241 242 if (mBinder == null) { 243 Log.e(TAG, "Why mBinder is null?"); 244 } 245 return mBinder; 246 } 247 dumpDebugInfo()248 private void dumpDebugInfo() { 249 Log.i(TAG, "AbccService field dump:"); 250 Log.i(TAG, "- mWorkingDir: " + mWorkingDir); 251 Log.i(TAG, "- mSysroot: " + mSysroot); 252 Log.i(TAG, "- mBinder: " + mBinder); 253 Log.i(TAG, "- mCurrentStatus: " + mCurrentStatus); 254 } 255 256 @Override onUnbind(Intent intent)257 public boolean onUnbind(Intent intent) { 258 Log.i(TAG, "got onUnbind intent: " + intent); 259 return false; 260 } 261 262 // If succeess, it will be 0 in file working_dir/compile_result. 263 // Otherwise, there will be error message in file working_dir/compile_error. genLibs(String working_dir, String sysroot)264 private native int genLibs(String working_dir, String sysroot); 265 266 static { 267 System.loadLibrary("jni_abcc"); 268 } 269 } 270