/* * Copyright (C) 2012 Steven Luo * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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 jackpal.androidterm.sample.pathbroadcasts; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.ProcessBuilder; public class PathReceiver extends BroadcastReceiver { /** * Called when a broadcast matching the declared intent filters is * received. */ @Override public void onReceive(Context context, Intent intent) { /* Unpack our sample bin/ and sbin/ if not already done */ File binDir = setupBinDir(context); File sbinDir = setupSbinDir(context); String packageName = context.getPackageName(); String action = intent.getAction(); /** * You need to declare the permission * jackpal.androidterm.permission.APPEND_TO_PATH * to receive this broadcast. */ if (action.equals("jackpal.androidterm.broadcast.APPEND_TO_PATH")) { /* The directory we want appended goes into the result extras */ Bundle result = getResultExtras(true); /** * By convention, entries are indexed by package name. * * If you need to impose an ordering constraint for some reason, * you may prepend a number to your package name -- for example, * 50-com.example.awesomebin or 00-net.busybox.android. */ result.putString(packageName, binDir.getAbsolutePath()); setResultCode(Activity.RESULT_OK); } /** * You need to declare the permission * jackpal.androidterm.permission.PREPEND_TO_PATH * to receive this broadcast. * * This is intended for packages like BusyBox installers which need * to override existing system commands; otherwise, you should listen * for the APPEND_TO_PATH broadcast instead. */ if (action.equals("jackpal.androidterm.broadcast.PREPEND_TO_PATH")) { /* The directory we want prepended goes into the result extras */ Bundle result = getResultExtras(true); result.putString(packageName, sbinDir.getAbsolutePath()); setResultCode(Activity.RESULT_OK); } } private File setupBinDir(Context context) { String dataDir = getDataDir(context); File binDir = new File(dataDir, "bin"); if (!binDir.exists()) { try { binDir.mkdir(); chmod("755", binDir.getAbsolutePath()); } catch (Exception e) { } } File hello = new File(binDir, "hello"); if (!hello.exists()) { try { InputStream src = context.getAssets().open("hello"); FileOutputStream dst = new FileOutputStream(hello); copyStream(dst, src); chmod("755", hello.getAbsolutePath()); } catch (Exception e) { } } return binDir; } private File setupSbinDir(Context context) { String dataDir = getDataDir(context); File sbinDir = new File(dataDir, "sbin"); if (!sbinDir.exists()) { try { sbinDir.mkdir(); chmod("755", sbinDir.getAbsolutePath()); } catch (Exception e) { } } File ls = new File(sbinDir, "ls"); if (!ls.exists()) { try { InputStream src = context.getAssets().open("ls"); FileOutputStream dst = new FileOutputStream(ls); copyStream(dst, src); chmod("755", ls.getAbsolutePath()); } catch (Exception e) { } } return sbinDir; } private String getDataDir(Context context) { /* On API 4 and later, you can just do this */ // return context.getApplicationInfo().dataDir; String packageName = context.getPackageName(); PackageManager pm = context.getPackageManager(); String dataDir = null; try { dataDir = pm.getApplicationInfo(packageName, 0).dataDir; } catch (Exception e) { // Won't happen -- we know we're installed } return dataDir; } private void copyStream(OutputStream dst, InputStream src) throws IOException { byte[] buffer = new byte[4096]; int bytesRead = 0; while ((bytesRead = src.read(buffer)) >= 0) { dst.write(buffer, 0, bytesRead); } dst.close(); } private void chmod(String... args) throws IOException { String[] cmdline = new String[args.length + 1]; cmdline[0] = "/system/bin/chmod"; System.arraycopy(args, 0, cmdline, 1, args.length); new ProcessBuilder(cmdline).start(); } }