diff options
Diffstat (limited to 'cmds')
48 files changed, 2627 insertions, 2031 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 3782136f5c73..eca5af976d42 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -23,16 +23,19 @@ import android.app.IActivityManager; import android.app.IInstrumentationWatcher; import android.app.Instrumentation; import android.content.ComponentName; +import android.content.IIntentReceiver; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; +import android.util.AndroidException; import android.view.IWindowManager; import java.io.File; import java.io.FileNotFoundException; +import java.net.URISyntaxException; import java.util.Iterator; import java.util.Set; @@ -45,16 +48,29 @@ public class Am { private boolean mDebugOption = false; + // These are magic strings understood by the Eclipse plugin. + private static final String FATAL_ERROR_CODE = "Error type 1"; + private static final String NO_SYSTEM_ERROR_CODE = "Error type 2"; + private static final String NO_CLASS_ERROR_CODE = "Error type 3"; + /** * Command-line entry point. * * @param args The command-line arguments */ public static void main(String[] args) { - (new Am()).run(args); + try { + (new Am()).run(args); + } catch (IllegalArgumentException e) { + showUsage(); + System.err.println("Error: " + e.getMessage()); + } catch (Exception e) { + System.err.println(e.toString()); + System.exit(1); + } } - private void run(String[] args) { + private void run(String[] args) throws Exception { if (args.length < 1) { showUsage(); return; @@ -62,16 +78,14 @@ public class Am { mAm = ActivityManagerNative.getDefault(); if (mAm == null) { - System.err.println("Error type 2"); - System.err.println("Error: Unable to connect to activity manager; is the system running?"); - showUsage(); - return; + System.err.println(NO_SYSTEM_ERROR_CODE); + throw new AndroidException("Can't connect to activity manager; is the system running?"); } mArgs = args; - String op = args[0]; mNextArg = 1; + if (op.equals("start")) { runStart(); } else if (op.equals("instrument")) { @@ -81,13 +95,11 @@ public class Am { } else if (op.equals("profile")) { runProfile(); } else { - System.err.println("Error: Unknown command: " + op); - showUsage(); - return; + throw new IllegalArgumentException("Unknown command: " + op); } } - private Intent makeIntent() { + private Intent makeIntent() throws URISyntaxException { Intent intent = new Intent(); boolean hasIntentInfo = false; @@ -95,186 +107,146 @@ public class Am { Uri data = null; String type = null; - try { - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("-a")) { - intent.setAction(nextOptionData()); - hasIntentInfo = true; - } else if (opt.equals("-d")) { - data = Uri.parse(nextOptionData()); - hasIntentInfo = true; - } else if (opt.equals("-t")) { - type = nextOptionData(); - hasIntentInfo = true; - } else if (opt.equals("-c")) { - intent.addCategory(nextOptionData()); - hasIntentInfo = true; - } else if (opt.equals("-e") || opt.equals("--es")) { - String key = nextOptionData(); - String value = nextOptionData(); - intent.putExtra(key, value); - hasIntentInfo = true; - } else if (opt.equals("--ei")) { - String key = nextOptionData(); - String value = nextOptionData(); - intent.putExtra(key, Integer.valueOf(value)); - hasIntentInfo = true; - } else if (opt.equals("--ez")) { - String key = nextOptionData(); - String value = nextOptionData(); - intent.putExtra(key, Boolean.valueOf(value)); - hasIntentInfo = true; - } else if (opt.equals("-n")) { - String str = nextOptionData(); - ComponentName cn = ComponentName.unflattenFromString(str); - if (cn == null) { - System.err.println("Error: Bad component name: " + str); - showUsage(); - return null; - } - intent.setComponent(cn); - hasIntentInfo = true; - } else if (opt.equals("-f")) { - String str = nextOptionData(); - intent.setFlags(Integer.decode(str).intValue()); - } else if (opt.equals("-D")) { - mDebugOption = true; - } else { - System.err.println("Error: Unknown option: " + opt); - showUsage(); - return null; - } + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-a")) { + intent.setAction(nextArgRequired()); + hasIntentInfo = true; + } else if (opt.equals("-d")) { + data = Uri.parse(nextArgRequired()); + hasIntentInfo = true; + } else if (opt.equals("-t")) { + type = nextArgRequired(); + hasIntentInfo = true; + } else if (opt.equals("-c")) { + intent.addCategory(nextArgRequired()); + hasIntentInfo = true; + } else if (opt.equals("-e") || opt.equals("--es")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + intent.putExtra(key, value); + hasIntentInfo = true; + } else if (opt.equals("--ei")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + intent.putExtra(key, Integer.valueOf(value)); + hasIntentInfo = true; + } else if (opt.equals("--ez")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + intent.putExtra(key, Boolean.valueOf(value)); + hasIntentInfo = true; + } else if (opt.equals("-n")) { + String str = nextArgRequired(); + ComponentName cn = ComponentName.unflattenFromString(str); + if (cn == null) throw new IllegalArgumentException("Bad component name: " + str); + intent.setComponent(cn); + hasIntentInfo = true; + } else if (opt.equals("-f")) { + String str = nextArgRequired(); + intent.setFlags(Integer.decode(str).intValue()); + } else if (opt.equals("-D")) { + mDebugOption = true; + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return null; } - } catch (RuntimeException ex) { - System.err.println("Error: " + ex.toString()); - showUsage(); - return null; } intent.setDataAndType(data, type); String uri = nextArg(); if (uri != null) { - try { - Intent oldIntent = intent; - try { - intent = Intent.getIntent(uri); - } catch (java.net.URISyntaxException ex) { - System.err.println("Bad URI: " + uri); - showUsage(); - return null; - } - if (oldIntent.getAction() != null) { - intent.setAction(oldIntent.getAction()); - } - if (oldIntent.getData() != null || oldIntent.getType() != null) { - intent.setDataAndType(oldIntent.getData(), oldIntent.getType()); - } - Set cats = oldIntent.getCategories(); - if (cats != null) { - Iterator it = cats.iterator(); - while (it.hasNext()) { - intent.addCategory((String)it.next()); - } + Intent oldIntent = intent; + intent = Intent.getIntent(uri); + if (oldIntent.getAction() != null) { + intent.setAction(oldIntent.getAction()); + } + if (oldIntent.getData() != null || oldIntent.getType() != null) { + intent.setDataAndType(oldIntent.getData(), oldIntent.getType()); + } + Set cats = oldIntent.getCategories(); + if (cats != null) { + Iterator it = cats.iterator(); + while (it.hasNext()) { + intent.addCategory((String)it.next()); } - } catch (RuntimeException ex) { - System.err.println("Error creating from URI: " + ex.toString()); - showUsage(); - return null; } - } else if (!hasIntentInfo) { - System.err.println("Error: No intent supplied"); - showUsage(); - return null; + hasIntentInfo = true; } + if (!hasIntentInfo) throw new IllegalArgumentException("No intent supplied"); return intent; } - private void runStart() { + private void runStart() throws Exception { Intent intent = makeIntent(); - - if (intent != null) { - System.out.println("Starting: " + intent); - try { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - // XXX should do something to determine the MIME type. - int res = mAm.startActivity(null, intent, intent.getType(), - null, 0, null, null, 0, false, mDebugOption); - switch (res) { - case IActivityManager.START_SUCCESS: - break; - case IActivityManager.START_SWITCHES_CANCELED: - System.err.println( - "Warning: Activity not started because the " - + " current activity is being kept for the user."); - break; - case IActivityManager.START_DELIVERED_TO_TOP: - System.err.println( - "Warning: Activity not started, intent has " - + "been delivered to currently running " - + "top-most instance."); - break; - case IActivityManager.START_RETURN_INTENT_TO_CALLER: - System.err.println( - "Warning: Activity not started because intent " - + "should be handled by the caller"); - break; - case IActivityManager.START_TASK_TO_FRONT: - System.err.println( - "Warning: Activity not started, its current " - + "task has been brought to the front"); - break; - case IActivityManager.START_INTENT_NOT_RESOLVED: - System.err.println( - "Error: Activity not started, unable to " - + "resolve " + intent.toString()); - break; - case IActivityManager.START_CLASS_NOT_FOUND: - System.err.println("Error type 3"); - System.err.println("Error: Activity class " + - intent.getComponent().toShortString() - + " does not exist."); - break; - case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: - System.err.println( - "Error: Activity not started, you requested to " - + "both forward and receive its result"); - break; - case IActivityManager.START_PERMISSION_DENIED: - System.err.println( - "Error: Activity not started, you do not " - + "have permission to access it."); - break; - default: - System.err.println( - "Error: Activity not started, unknown error " - + "code " + res); - break; - } - } catch (RemoteException e) { - System.err.println("Error type 1"); + System.out.println("Starting: " + intent); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // XXX should do something to determine the MIME type. + int res = mAm.startActivity(null, intent, intent.getType(), + null, 0, null, null, 0, false, mDebugOption); + switch (res) { + case IActivityManager.START_SUCCESS: + break; + case IActivityManager.START_SWITCHES_CANCELED: + System.err.println( + "Warning: Activity not started because the " + + " current activity is being kept for the user."); + break; + case IActivityManager.START_DELIVERED_TO_TOP: + System.err.println( + "Warning: Activity not started, intent has " + + "been delivered to currently running " + + "top-most instance."); + break; + case IActivityManager.START_RETURN_INTENT_TO_CALLER: + System.err.println( + "Warning: Activity not started because intent " + + "should be handled by the caller"); + break; + case IActivityManager.START_TASK_TO_FRONT: + System.err.println( + "Warning: Activity not started, its current " + + "task has been brought to the front"); + break; + case IActivityManager.START_INTENT_NOT_RESOLVED: System.err.println( "Error: Activity not started, unable to " - + "call on to activity manager service"); - } + + "resolve " + intent.toString()); + break; + case IActivityManager.START_CLASS_NOT_FOUND: + System.err.println(NO_CLASS_ERROR_CODE); + System.err.println("Error: Activity class " + + intent.getComponent().toShortString() + + " does not exist."); + break; + case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: + System.err.println( + "Error: Activity not started, you requested to " + + "both forward and receive its result"); + break; + case IActivityManager.START_PERMISSION_DENIED: + System.err.println( + "Error: Activity not started, you do not " + + "have permission to access it."); + break; + default: + System.err.println( + "Error: Activity not started, unknown error code " + res); + break; } } - private void sendBroadcast() { + private void sendBroadcast() throws Exception { Intent intent = makeIntent(); - - if (intent != null) { - System.out.println("Broadcasting: " + intent); - try { - mAm.broadcastIntent(null, intent, null, null, 0, null, null, - null, true, false); - } catch (RemoteException e) { - } - } + IntentReceiver receiver = new IntentReceiver(); + System.out.println("Broadcasting: " + intent); + mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false); + receiver.waitForFinish(); } - private void runInstrument() { + private void runInstrument() throws Exception { String profileFile = null; boolean wait = false; boolean rawMode = false; @@ -283,46 +255,30 @@ public class Am { String argKey = null, argValue = null; IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); - try { - String opt; - while ((opt=nextOption()) != null) { - if (opt.equals("-p")) { - profileFile = nextOptionData(); - } else if (opt.equals("-w")) { - wait = true; - } else if (opt.equals("-r")) { - rawMode = true; - } else if (opt.equals("-e")) { - argKey = nextOptionData(); - argValue = nextOptionData(); - args.putString(argKey, argValue); - } else if (opt.equals("--no_window_animation")) { - no_window_animation = true; - } else { - System.err.println("Error: Unknown option: " + opt); - showUsage(); - return; - } + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-p")) { + profileFile = nextArgRequired(); + } else if (opt.equals("-w")) { + wait = true; + } else if (opt.equals("-r")) { + rawMode = true; + } else if (opt.equals("-e")) { + argKey = nextArgRequired(); + argValue = nextArgRequired(); + args.putString(argKey, argValue); + } else if (opt.equals("--no_window_animation")) { + no_window_animation = true; + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return; } - } catch (RuntimeException ex) { - System.err.println("Error: " + ex.toString()); - showUsage(); - return; } - String cnArg = nextArg(); - if (cnArg == null) { - System.err.println("Error: No instrumentation component supplied"); - showUsage(); - return; - } - + String cnArg = nextArgRequired(); ComponentName cn = ComponentName.unflattenFromString(cnArg); - if (cn == null) { - System.err.println("Error: Bad component name: " + cnArg); - showUsage(); - return; - } + if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg); InstrumentationWatcher watcher = null; if (wait) { @@ -331,22 +287,13 @@ public class Am { } float[] oldAnims = null; if (no_window_animation) { - try { - oldAnims = wm.getAnimationScales(); - wm.setAnimationScale(0, 0.0f); - wm.setAnimationScale(1, 0.0f); - } catch (RemoteException e) { - } + oldAnims = wm.getAnimationScales(); + wm.setAnimationScale(0, 0.0f); + wm.setAnimationScale(1, 0.0f); } - try { - if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) { - System.out.println("INSTRUMENTATION_FAILED: " + - cn.flattenToString()); - showUsage(); - return; - } - } catch (RemoteException e) { + if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) { + throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); } if (watcher != null) { @@ -356,9 +303,58 @@ public class Am { } if (oldAnims != null) { + wm.setAnimationScales(oldAnims); + } + } + + private void runProfile() throws Exception { + String profileFile = null; + boolean start = false; + String process = nextArgRequired(); + ParcelFileDescriptor fd = null; + + String cmd = nextArgRequired(); + if ("start".equals(cmd)) { + start = true; + profileFile = nextArgRequired(); + try { + fd = ParcelFileDescriptor.open( + new File(profileFile), + ParcelFileDescriptor.MODE_CREATE | + ParcelFileDescriptor.MODE_TRUNCATE | + ParcelFileDescriptor.MODE_READ_WRITE); + } catch (FileNotFoundException e) { + System.err.println("Error: Unable to open file: " + profileFile); + return; + } + } else if (!"stop".equals(cmd)) { + throw new IllegalArgumentException("Profile command " + cmd + " not valid"); + } + + if (!mAm.profileControl(process, start, profileFile, fd)) { + throw new AndroidException("PROFILE FAILED on process " + process); + } + } + + private class IntentReceiver extends IIntentReceiver.Stub { + private boolean mFinished = false; + + public synchronized void performReceive( + Intent intent, int rc, String data, Bundle ext, boolean ord, + boolean sticky) { + String line = "Broadcast completed: result=" + rc; + if (data != null) line = line + ", data=\"" + data + "\""; + if (ext != null) line = line + ", extras: " + ext; + System.out.println(line); + mFinished = true; + notifyAll(); + } + + public synchronized void waitForFinish() { try { - wm.setAnimationScales(oldAnims); - } catch (RemoteException e) { + while (!mFinished) wait(); + } catch (InterruptedException e) { + throw new IllegalStateException(e); } } } @@ -366,7 +362,7 @@ public class Am { private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { private boolean mFinished = false; private boolean mRawMode = false; - + /** * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. @@ -375,7 +371,7 @@ public class Am { public void setRawOutput(boolean rawMode) { mRawMode = rawMode; } - + public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { synchronized (this) { // pretty printer mode? @@ -431,6 +427,7 @@ public class Am { } wait(1000); } catch (InterruptedException e) { + throw new IllegalStateException(e); } } } @@ -438,62 +435,11 @@ public class Am { } } - private void runProfile() { - String profileFile = null; - boolean start = false; - - String process = nextArg(); - if (process == null) { - System.err.println("Error: No profile process supplied"); - showUsage(); - return; - } - - ParcelFileDescriptor fd = null; - - String cmd = nextArg(); - if ("start".equals(cmd)) { - start = true; - profileFile = nextArg(); - if (profileFile == null) { - System.err.println("Error: No profile file path supplied"); - showUsage(); - return; - } - try { - fd = ParcelFileDescriptor.open( - new File(profileFile), - ParcelFileDescriptor.MODE_CREATE | - ParcelFileDescriptor.MODE_TRUNCATE | - ParcelFileDescriptor.MODE_READ_WRITE); - } catch (FileNotFoundException e) { - System.err.println("Error: Unable to open file: " + profileFile); - return; - } - } else if (!"stop".equals(cmd)) { - System.err.println("Error: Profile command " + cmd + " not valid"); - showUsage(); - return; - } - - try { - if (!mAm.profileControl(process, start, profileFile, fd)) { - System.err.println("PROFILE FAILED on process " + process); - return; - } - } catch (IllegalArgumentException e) { - System.out.println("PROFILE FAILED: " + e.getMessage()); - return; - } catch (IllegalStateException e) { - System.out.println("PROFILE FAILED: " + e.getMessage()); - return; - } catch (RemoteException e) { - System.out.println("PROFILE FAILED: activity manager gone"); - return; - } - } - private String nextOption() { + if (mCurArgData != null) { + String prev = mArgs[mNextArg - 1]; + throw new IllegalArgumentException("No argument expected after \"" + prev + "\""); + } if (mNextArg >= mArgs.length) { return null; } @@ -518,41 +464,52 @@ public class Am { return arg; } - private String nextOptionData() { + private String nextArg() { if (mCurArgData != null) { - return mCurArgData; - } - if (mNextArg >= mArgs.length) { + String arg = mCurArgData; + mCurArgData = null; + return arg; + } else if (mNextArg < mArgs.length) { + return mArgs[mNextArg++]; + } else { return null; } - String data = mArgs[mNextArg]; - mNextArg++; - return data; } - private String nextArg() { - if (mNextArg >= mArgs.length) { - return null; + private String nextArgRequired() { + String arg = nextArg(); + if (arg == null) { + String prev = mArgs[mNextArg - 1]; + throw new IllegalArgumentException("Argument expected after \"" + prev + "\""); } - String arg = mArgs[mNextArg]; - mNextArg++; return arg; } - private void showUsage() { - System.err.println("usage: am [start|broadcast|instrument|profile]"); - System.err.println(" am start [-D] INTENT"); - System.err.println(" am broadcast INTENT"); - System.err.println(" am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]"); - System.err.println(" [-w] <COMPONENT> "); - System.err.println(" am profile <PROCESS> [start <PROF_FILE>|stop]"); - System.err.println(""); - System.err.println(" INTENT is described with:"); - System.err.println(" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]"); - System.err.println(" [-c <CATEGORY> [-c <CATEGORY>] ...]"); - System.err.println(" [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]"); - System.err.println(" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]"); - System.err.println(" [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]"); - System.err.println(" [-n <COMPONENT>] [-f <FLAGS>] [<URI>]"); + private static void showUsage() { + System.err.println( + "usage: am [subcommand] [options]\n" + + "\n" + + " start an Activity: am start [-D] <INTENT>\n" + + " -D: enable debugging\n" + + "\n" + + " send a broadcast Intent: am broadcast <INTENT>\n" + + "\n" + + " start an Instrumentation: am instrument [flags] <COMPONENT>\n" + + " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT)\n" + + " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>\n" + + " -p <FILE>: write profiling data to <FILE>\n" + + " -w: wait for instrumentation to finish before returning\n" + + "\n" + + " start profiling: am profile <PROCESS> start <FILE>\n" + + " stop profiling: am profile <PROCESS> stop\n" + + "\n" + + " <INTENT> specifications include these flags:\n" + + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + + " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + + " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + + " [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + + " [-n <COMPONENT>] [-f <FLAGS>] [<URI>]\n" + ); } } diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index d825d5a3a4dc..7decf9ae737d 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -7,8 +7,8 @@ #define LOG_TAG "appproc" -#include <utils/IPCThreadState.h> -#include <utils/ProcessState.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> #include <utils/Log.h> #include <cutils/process_name.h> #include <cutils/memory.h> diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index ee3ec1aa18fb..8c15d0b4ea13 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -268,7 +268,7 @@ public final class Bmgr { private void printRestoreSets(RestoreSet[] sets) { for (RestoreSet s : sets) { - System.out.println(" " + s.token + " : " + s.name); + System.out.println(" " + Long.toHexString(s.token) + " : " + s.name); } } @@ -294,7 +294,7 @@ public final class Bmgr { private void doRestore() { long token; try { - token = Long.parseLong(nextArg()); + token = Long.parseLong(nextArg(), 16); } catch (NumberFormatException e) { showUsage(); return; @@ -311,12 +311,13 @@ public final class Bmgr { return; } RestoreSet[] sets = mRestore.getAvailableRestoreSets(); - for (RestoreSet s : sets) { - if (s.token == token) { - System.out.println("Scheduling restore: " + s.name); - mRestore.performRestore(token, observer); - didRestore = true; - break; + if (sets != null) { + for (RestoreSet s : sets) { + if (s.token == token) { + System.out.println("Scheduling restore: " + s.name); + didRestore = (mRestore.performRestore(token, observer) == 0); + break; + } } } if (!didRestore) { @@ -327,21 +328,27 @@ public final class Bmgr { printRestoreSets(sets); } } + + // if we kicked off a restore successfully, we have to wait for it + // to complete before we can shut down the restore session safely + if (didRestore) { + synchronized (observer) { + while (!observer.done) { + try { + observer.wait(); + } catch (InterruptedException ex) { + } + } + } + } + + // once the restore has finished, close down the session and we're done mRestore.endRestoreSession(); } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(BMGR_NOT_RUNNING_ERR); } - // now wait for it to be done - synchronized (observer) { - while (!observer.done) { - try { - observer.wait(); - } catch (InterruptedException ex) { - } - } - } System.out.println("done"); } diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 9c94c2ef3cf9..3449de1fe737 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -12,12 +12,13 @@ ifeq ($(TARGET_SIMULATOR),true) endif endif +LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES + LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libui \ - libcorecg \ - libsgl \ + libskia \ libEGL \ libGLESv1_CM diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 2fb3f7994961..ce36c4b3320a 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -21,8 +21,9 @@ #include <math.h> #include <fcntl.h> #include <utils/misc.h> +#include <signal.h> -#include <utils/IPCThreadState.h> +#include <binder/IPCThreadState.h> #include <utils/threads.h> #include <utils/Atomic.h> #include <utils/Errors.h> @@ -35,7 +36,8 @@ #include <ui/DisplayInfo.h> #include <ui/ISurfaceComposer.h> #include <ui/ISurfaceFlingerClient.h> -#include <ui/EGLNativeWindowSurface.h> +#include <ui/FramebufferNativeWindow.h> +#include <ui/EGLUtils.h> #include <core/SkBitmap.h> #include <images/SkImageDecoder.h> @@ -51,7 +53,7 @@ namespace android { // --------------------------------------------------------------------------- BootAnimation::BootAnimation() : Thread(false) -{ +{ mSession = new SurfaceComposerClient(); } @@ -59,13 +61,29 @@ BootAnimation::~BootAnimation() { } void BootAnimation::onFirstRef() { - run("BootAnimation", PRIORITY_DISPLAY); + status_t err = mSession->linkToComposerDeath(this); + LOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err)); + if (err == NO_ERROR) { + run("BootAnimation", PRIORITY_DISPLAY); + } } -const sp<SurfaceComposerClient>& BootAnimation::session() const { +sp<SurfaceComposerClient> BootAnimation::session() const { return mSession; } + +void BootAnimation::binderDied(const wp<IBinder>& who) +{ + // woah, surfaceflinger died! + LOGD("SurfaceFlinger died, exiting..."); + + // calling requestExit() is not enough here because the Surface code + // might be blocked on a condition variable that will never be updated. + kill( getpid(), SIGKILL ); + requestExit(); +} + status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, const char* name) { Asset* asset = assets.open(name, Asset::ACCESS_BUFFER); @@ -121,6 +139,62 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, return NO_ERROR; } +status_t BootAnimation::initTexture(void* buffer, size_t len) +{ + //StopWatch watch("blah"); + + SkBitmap bitmap; + SkImageDecoder::DecodeMemory(buffer, len, + &bitmap, SkBitmap::kRGB_565_Config, + SkImageDecoder::kDecodePixels_Mode); + + // ensure we can call getPixels(). No need to call unlock, since the + // bitmap will go out of scope when we return from this method. + bitmap.lockPixels(); + + const int w = bitmap.width(); + const int h = bitmap.height(); + const void* p = bitmap.getPixels(); + + GLint crop[4] = { 0, h, w, -h }; + int tw = 1 << (31 - __builtin_clz(w)); + int th = 1 << (31 - __builtin_clz(h)); + if (tw < w) tw <<= 1; + if (th < h) th <<= 1; + + switch (bitmap.getConfig()) { + case SkBitmap::kARGB_8888_Config: + if (tw != w || th != h) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA, + GL_UNSIGNED_BYTE, 0); + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA, + GL_UNSIGNED_BYTE, p); + } + break; + + case SkBitmap::kRGB_565_Config: + if (tw != w || th != h) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, 0); + glTexSubImage2D(GL_TEXTURE_2D, 0, + 0, 0, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, p); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, p); + } + break; + default: + break; + } + + glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, crop); + + return NO_ERROR; +} + status_t BootAnimation::readyToRun() { mAssets.addDefaultAssets(); @@ -130,15 +204,19 @@ status_t BootAnimation::readyToRun() { return -1; // create the native surface - sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h, - PIXEL_FORMAT_RGB_565, ISurfaceComposer::eGPU); + sp<SurfaceControl> control = session()->createSurface( + getpid(), 0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565); session()->openTransaction(); - s->setLayer(0x40000000); + control->setLayer(0x40000000); session()->closeTransaction(); + sp<Surface> s = control->getSurface(); + // initialize opengl and egl - const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6, - EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE }; + const EGLint attribs[] = { + EGL_DEPTH_SIZE, 0, + EGL_NONE + }; EGLint w, h, dummy; EGLint numConfigs; EGLConfig config; @@ -148,60 +226,75 @@ status_t BootAnimation::readyToRun() { EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); eglInitialize(display, 0, 0); - eglChooseConfig(display, attribs, &config, 1, &numConfigs); - - mNativeWindowSurface = new EGLNativeWindowSurface(s); - surface = eglCreateWindowSurface(display, config, - mNativeWindowSurface.get(), NULL); - + EGLUtils::selectConfigForNativeWindow(display, attribs, s.get(), &config); + surface = eglCreateWindowSurface(display, config, s.get(), NULL); context = eglCreateContext(display, config, NULL, NULL); eglQuerySurface(display, surface, EGL_WIDTH, &w); eglQuerySurface(display, surface, EGL_HEIGHT, &h); - eglMakeCurrent(display, surface, surface, context); + + if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) + return NO_INIT; + mDisplay = display; mContext = context; mSurface = surface; mWidth = w; mHeight = h; + mFlingerSurfaceControl = control; mFlingerSurface = s; - // initialize GL - glShadeModel(GL_FLAT); - glEnable(GL_TEXTURE_2D); - glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + mAndroidAnimation = false; + status_t err = mZip.open("/data/local/bootanimation.zip"); + if (err != NO_ERROR) { + err = mZip.open("/system/media/bootanimation.zip"); + if (err != NO_ERROR) { + mAndroidAnimation = true; + } + } return NO_ERROR; } -bool BootAnimation::threadLoop() { - bool r = android(); +bool BootAnimation::threadLoop() +{ + bool r; + if (mAndroidAnimation) { + r = android(); + } else { + r = movie(); + } + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); eglDestroyContext(mDisplay, mContext); eglDestroySurface(mDisplay, mSurface); - mNativeWindowSurface.clear(); mFlingerSurface.clear(); + mFlingerSurfaceControl.clear(); eglTerminate(mDisplay); IPCThreadState::self()->stopProcess(); return r; } -bool BootAnimation::android() { +bool BootAnimation::android() +{ initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png"); initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png"); // clear screen + glShadeModel(GL_FLAT); glDisable(GL_DITHER); glDisable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT); eglSwapBuffers(mDisplay, mSurface); + glEnable(GL_TEXTURE_2D); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + const GLint xc = (mWidth - mAndroid[0].w) / 2; const GLint yc = (mHeight - mAndroid[0].h) / 2; const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h); // draw and update only what we need - mNativeWindowSurface->setSwapRectangle(updateRect.left, - updateRect.top, updateRect.width(), updateRect.height()); + mFlingerSurface->setSwapRectangle(updateRect); glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(), updateRect.height()); @@ -238,7 +331,7 @@ bool BootAnimation::android() { // 12fps: don't animate too fast to preserve CPU const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now); if (sleepTime > 0) - usleep(sleepTime); + usleep(sleepTime); } while (!exitPending()); glDeleteTextures(1, &mAndroid[0].name); @@ -246,6 +339,167 @@ bool BootAnimation::android() { return false; } + +bool BootAnimation::movie() +{ + ZipFileRO& zip(mZip); + + size_t numEntries = zip.getNumEntries(); + ZipEntryRO desc = zip.findEntryByName("desc.txt"); + FileMap* descMap = zip.createEntryFileMap(desc); + LOGE_IF(!descMap, "descMap is null"); + if (!descMap) { + return false; + } + + String8 desString((char const*)descMap->getDataPtr(), + descMap->getDataLength()); + char const* s = desString.string(); + + Animation animation; + + // Parse the description file + for (;;) { + const char* endl = strstr(s, "\n"); + if (!endl) break; + String8 line(s, endl - s); + const char* l = line.string(); + int fps, width, height, count, pause; + char path[256]; + if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) { + //LOGD("> w=%d, h=%d, fps=%d", fps, width, height); + animation.width = width; + animation.height = height; + animation.fps = fps; + } + if (sscanf(l, "p %d %d %s", &count, &pause, path) == 3) { + //LOGD("> count=%d, pause=%d, path=%s", count, pause, path); + Animation::Part part; + part.count = count; + part.pause = pause; + part.path = path; + animation.parts.add(part); + } + s = ++endl; + } + + // read all the data structures + const size_t pcount = animation.parts.size(); + for (size_t i=0 ; i<numEntries ; i++) { + char name[256]; + ZipEntryRO entry = zip.findEntryByIndex(i); + if (zip.getEntryFileName(entry, name, 256) == 0) { + const String8 entryName(name); + const String8 path(entryName.getPathDir()); + const String8 leaf(entryName.getPathLeaf()); + if (leaf.size() > 0) { + for (int j=0 ; j<pcount ; j++) { + if (path == animation.parts[j].path) { + int method; + // supports only stored png files + if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) { + if (method == ZipFileRO::kCompressStored) { + FileMap* map = zip.createEntryFileMap(entry); + if (map) { + Animation::Frame frame; + frame.name = leaf; + frame.map = map; + Animation::Part& part(animation.parts.editItemAt(j)); + part.frames.add(frame); + } + } + } + } + } + } + } + } + + // clear screen + glShadeModel(GL_FLAT); + glDisable(GL_DITHER); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glClear(GL_COLOR_BUFFER_BIT); + + eglSwapBuffers(mDisplay, mSurface); + + glBindTexture(GL_TEXTURE_2D, 0); + glEnable(GL_TEXTURE_2D); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + const int xc = (mWidth - animation.width) / 2; + const int yc = ((mHeight - animation.height) / 2); + nsecs_t lastFrame = systemTime(); + nsecs_t frameDuration = s2ns(1) / animation.fps; + + Region clearReg(Rect(mWidth, mHeight)); + clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height)); + + for (int i=0 ; i<pcount && !exitPending() ; i++) { + const Animation::Part& part(animation.parts[i]); + const size_t fcount = part.frames.size(); + glBindTexture(GL_TEXTURE_2D, 0); + + for (int r=0 ; !part.count || r<part.count ; r++) { + for (int j=0 ; j<fcount && !exitPending(); j++) { + const Animation::Frame& frame(part.frames[j]); + + if (r > 0) { + glBindTexture(GL_TEXTURE_2D, frame.tid); + } else { + if (part.count != 1) { + glGenTextures(1, &frame.tid); + glBindTexture(GL_TEXTURE_2D, frame.tid); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + initTexture( + frame.map->getDataPtr(), + frame.map->getDataLength()); + } + + if (!clearReg.isEmpty()) { + Region::const_iterator head(clearReg.begin()); + Region::const_iterator tail(clearReg.end()); + glEnable(GL_SCISSOR_TEST); + while (head != tail) { + const Rect& r(*head++); + glScissor(r.left, mHeight - r.bottom, + r.width(), r.height()); + glClear(GL_COLOR_BUFFER_BIT); + } + glDisable(GL_SCISSOR_TEST); + } + glDrawTexiOES(xc, yc, 0, animation.width, animation.height); + eglSwapBuffers(mDisplay, mSurface); + + nsecs_t now = systemTime(); + nsecs_t delay = frameDuration - (now - lastFrame); + lastFrame = now; + long wait = ns2us(frameDuration); + if (wait > 0) + usleep(wait); + } + usleep(part.pause * ns2us(frameDuration)); + } + + // free the textures for this part + if (part.count != 1) { + for (int j=0 ; j<fcount ; j++) { + const Animation::Frame& frame(part.frames[j]); + glDeleteTextures(1, &frame.tid); + } + } + } + + return false; +} + // --------------------------------------------------------------------------- } diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 42e9eed7d3eb..e53ba8b95114 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -34,22 +34,22 @@ class SkBitmap; namespace android { class AssetManager; -class EGLNativeWindowSurface; // --------------------------------------------------------------------------- -class BootAnimation : public Thread +class BootAnimation : public Thread, public IBinder::DeathRecipient { public: BootAnimation(); virtual ~BootAnimation(); - const sp<SurfaceComposerClient>& session() const; + sp<SurfaceComposerClient> session() const; private: virtual bool threadLoop(); virtual status_t readyToRun(); virtual void onFirstRef(); + virtual void binderDied(const wp<IBinder>& who); struct Texture { GLint w; @@ -57,8 +57,31 @@ private: GLuint name; }; + struct Animation { + struct Frame { + String8 name; + FileMap* map; + mutable GLuint tid; + bool operator < (const Frame& rhs) const { + return name < rhs.name; + } + }; + struct Part { + int count; + int pause; + String8 path; + SortedVector<Frame> frames; + }; + int fps; + int width; + int height; + Vector<Part> parts; + }; + status_t initTexture(Texture* texture, AssetManager& asset, const char* name); + status_t initTexture(void* buffer, size_t len); bool android(); + bool movie(); sp<SurfaceComposerClient> mSession; AssetManager mAssets; @@ -68,8 +91,10 @@ private: EGLDisplay mDisplay; EGLDisplay mContext; EGLDisplay mSurface; + sp<SurfaceControl> mFlingerSurfaceControl; sp<Surface> mFlingerSurface; - sp<EGLNativeWindowSurface> mNativeWindowSurface; + bool mAndroidAnimation; + ZipFileRO mZip; }; // --------------------------------------------------------------------------- diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp index a8359c40d0d2..3c82fe52dba9 100644 --- a/cmds/bootanimation/bootanimation_main.cpp +++ b/cmds/bootanimation/bootanimation_main.cpp @@ -18,9 +18,10 @@ #include <cutils/properties.h> -#include <utils/IPCThreadState.h> -#include <utils/ProcessState.h> -#include <utils/IServiceManager.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> + #include <utils/Log.h> #include <utils/threads.h> diff --git a/cmds/bugreport/Android.mk b/cmds/bugreport/Android.mk new file mode 100644 index 000000000000..631c2193a987 --- /dev/null +++ b/cmds/bugreport/Android.mk @@ -0,0 +1,14 @@ +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= bugreport.c + +LOCAL_MODULE:= bugreport + +LOCAL_SHARED_LIBRARIES := libcutils + +include $(BUILD_EXECUTABLE) + +endif diff --git a/cmds/bugreport/bugreport.c b/cmds/bugreport/bugreport.c new file mode 100644 index 000000000000..4a0b51147011 --- /dev/null +++ b/cmds/bugreport/bugreport.c @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include <cutils/properties.h> +#include <cutils/sockets.h> + +int main(int argc, char *argv[]) { + char buffer[65536]; + int i, s; + + /* start the dumpstate service */ + property_set("ctl.start", "dumpstate"); + + /* socket will not be available until service starts */ + for (i = 0; i < 10; i++) { + s = socket_local_client("dumpstate", + ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM); + if (s >= 0) + break; + /* try again in 1 second */ + sleep(1); + } + + if (s < 0) { + fprintf(stderr, "Failed to connect to dumpstate service\n"); + exit(1); + } + + while (1) { + int length = read(s, buffer, sizeof(buffer)); + if (length <= 0) + break; + fwrite(buffer, 1, length, stdout); + } + + close(s); + return 0; +} diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk index f61d7ecb3f5a..f8b37a812d08 100644 --- a/cmds/dumpstate/Android.mk +++ b/cmds/dumpstate/Android.mk @@ -11,7 +11,7 @@ LOCAL_SHARED_LIBRARIES := libcutils include $(BUILD_EXECUTABLE) -COMMANDS = dumpcrash bugreport +COMMANDS = dumpcrash SYMLINKS := $(addprefix $(TARGET_OUT_EXECUTABLES)/,$(COMMANDS)) $(SYMLINKS): DUMPSTATE_BINARY := dumpstate $(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index cc951c1bcbd1..642c943ffd36 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -20,12 +20,18 @@ #include <unistd.h> #include <sys/stat.h> #include <limits.h> +#include <errno.h> #include <fcntl.h> #include <sys/time.h> #include <sys/resource.h> +#include <cutils/sockets.h> #include "private/android_filesystem_config.h" +#define LOG_NDEBUG 0 +#define LOG_TAG "dumpstate" +#include <utils/Log.h> + #include "dumpstate.h" static char* const gzip_args[] = { "gzip", "-6", 0 }; @@ -34,6 +40,8 @@ static int end_pattern[] = { 75, 50, 75, 50, 75, 0 }; static struct tm now; +static void dump_kernel_log(const char *path, const char *title) ; + /* dumps the current system state to stdout */ static void dumpstate(int full) { if (full) { @@ -48,6 +56,8 @@ static void dumpstate(int full) { EXEC_XBIN("procrank"); PRINT("------ VIRTUAL MEMORY STATS ------"); DUMP("/proc/vmstat"); + PRINT("------ VMALLOC INFO ------"); + DUMP("/proc/vmallocinfo"); PRINT("------ SLAB INFO ------"); DUMP("/proc/slabinfo"); PRINT("------ ZONEINFO ------"); @@ -76,9 +86,9 @@ static void dumpstate(int full) { DUMP("/proc/wakelocks"); PRINT(""); PRINT("------ PROCESSES ------"); - EXEC("ps"); + EXEC1("ps", "-P"); PRINT("------ PROCESSES AND THREADS ------"); - EXEC2("ps", "-t", "-p"); + EXEC3("ps", "-t", "-p", "-P"); PRINT("------ LIBRANK ------"); EXEC_XBIN("librank"); PRINT("------ BINDER FAILED TRANSACTION LOG ------"); @@ -101,8 +111,19 @@ static void dumpstate(int full) { DUMP("/data/system/packages.xml"); PRINT("------ PACKAGE UID ERRORS ------"); DUMP("/data/system/uiderrors.txt"); - PRINT("------ LAST KERNEL LOG ------"); - DUMP("/proc/last_kmsg"); + + dump_kernel_log("/data/dontpanic/last_kmsg", "LAST KMSG"); + dump_kernel_log("/data/dontpanic/apanic_console", + "PANIC CONSOLE"); + dump_kernel_log("/data/dontpanic/apanic_threads", + "PANIC THREADS"); + + PRINT("------ BACKLIGHTS ------"); + DUMP_PROMPT("LCD brightness=", "/sys/class/leds/lcd-backlight/brightness"); + DUMP_PROMPT("Button brightness=", "/sys/class/leds/button-backlight/brightness"); + DUMP_PROMPT("Keyboard brightness=", "/sys/class/leds/keyboard-backlight/brightness"); + DUMP_PROMPT("ALS mode=", "/sys/class/leds/lcd-backlight/als"); + DUMP_PROMPT("LCD driver registers:\n", "/sys/class/leds/lcd-backlight/registers"); } PRINT("========================================================"); PRINT("== build.prop"); @@ -157,47 +178,50 @@ static int check_command_name(const char* name, const char* test) { int main(int argc, char *argv[]) { int dumpcrash = check_command_name(argv[0], "dumpcrash"); - int bugreport = check_command_name(argv[0], "bugreport"); int add_date = 0; char* outfile = 0; int vibrate = 0; int compress = 0; + int socket = 0; int c, fd, vibrate_fd, fds[2]; char path[PATH_MAX]; pid_t pid; gid_t groups[] = { AID_LOG, AID_SDCARD_RW }; + LOGI("begin\n"); + /* set as high priority, and protect from OOM killer */ setpriority(PRIO_PROCESS, 0, -20); protect_from_oom_killer(); get_time(&now); - if (bugreport) { - do { - c = getopt(argc, argv, "do:vz"); - if (c == EOF) + do { + c = getopt(argc, argv, "do:svz"); + if (c == EOF) + break; + switch (c) { + case 'd': + add_date = 1; break; - switch (c) { - case 'd': - add_date = 1; - break; - case 'o': - outfile = optarg; - break; - case 'v': - vibrate = 1; - break; - case 'z': - compress = 1; - break; - case '?': - fprintf(stderr, "%s: invalid option -%c\n", - argv[0], optopt); - exit(1); - } - } while (1); - } + case 'o': + outfile = optarg; + break; + case 'v': + vibrate = 1; + break; + case 'z': + compress = 1; + break; + case 's': + socket = 1; + break; + case '?': + fprintf(stderr, "%s: invalid option -%c\n", + argv[0], optopt); + exit(1); + } + } while (1); /* open vibrator before switching user */ if (vibrate) { @@ -214,7 +238,31 @@ int main(int argc, char *argv[]) { /* make it safe to use both printf and STDOUT_FILENO */ setvbuf(stdout, 0, _IONBF, 0); - if (outfile) { + if (socket) { + struct sockaddr addr; + socklen_t alen; + + int s = android_get_control_socket("dumpstate"); + if (s < 0) { + fprintf(stderr, "could not open dumpstate socket\n"); + exit(1); + } + if (listen(s, 4) < 0) { + fprintf(stderr, "could not listen on dumpstate socket\n"); + exit(1); + } + + alen = sizeof(addr); + fd = accept(s, &addr, &alen); + if (fd < 0) { + fprintf(stderr, "could not accept dumpstate socket\n"); + exit(1); + } + + /* redirect stdout to the socket */ + dup2(fd, STDOUT_FILENO); + close(fd); + } else if (outfile) { if (strlen(outfile) > sizeof(path) - 100) exit(1); @@ -292,6 +340,25 @@ int main(int argc, char *argv[]) { /* so gzip will terminate */ close(STDOUT_FILENO); + LOGI("done\n"); + return 0; } +static void dump_kernel_log(const char *path, const char *title) + +{ + printf("------ KERNEL %s LOG ------\n", title); + if (access(path, R_OK) < 0) + printf("%s: %s\n", path, strerror(errno)); + else { + struct stat sbuf; + + if (stat(path, &sbuf) < 0) + printf("%s: stat failed (%s)\n", path, strerror(errno)); + else + printf("Harvested %s", ctime(&sbuf.st_mtime)); + + DUMP(path); + } +} diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index 6862e5a3edb4..b99b6d792249 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -61,6 +61,15 @@ run_command(&c, TIMEOUT); \ } +#define EXEC1(cmd, a1) \ +{ \ + static struct Command c = { \ + "/system/bin/" cmd, \ + { cmd, a1, 0 } \ + }; \ + run_command(&c, TIMEOUT); \ +} + #define EXEC2(cmd, a1, a2) \ { \ static struct Command c = { \ @@ -70,6 +79,15 @@ run_command(&c, TIMEOUT); \ } +#define EXEC3(cmd, a1, a2, a3) \ +{ \ + static struct Command c = { \ + "/system/bin/" cmd, \ + { cmd, a1, a2, a3, 0 } \ + }; \ + run_command(&c, TIMEOUT); \ +} + #define EXEC4(cmd, a1, a2, a3, a4) \ { \ static struct Command c = { \ diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk index 0c623cc319c5..42b1b7365b1b 100644 --- a/cmds/dumpsys/Android.mk +++ b/cmds/dumpsys/Android.mk @@ -5,7 +5,9 @@ LOCAL_SRC_FILES:= \ dumpsys.cpp LOCAL_SHARED_LIBRARIES := \ - libutils + libutils \ + libbinder + ifeq ($(TARGET_OS),linux) LOCAL_CFLAGS += -DXP_UNIX diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp index a62fe55600e9..945a690ae0ab 100644 --- a/cmds/dumpsys/dumpsys.cpp +++ b/cmds/dumpsys/dumpsys.cpp @@ -6,9 +6,9 @@ #define LOG_TAG "dumpsys" #include <utils/Log.h> -#include <utils/Parcel.h> -#include <utils/ProcessState.h> -#include <utils/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> #include <utils/TextOutput.h> #include <utils/Vector.h> diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk index 3daf44e40a00..15a199f30c46 100644 --- a/cmds/keystore/Android.mk +++ b/cmds/keystore/Android.mk @@ -1,22 +1,36 @@ +# +# Copyright (C) 2009 The Android Open Source Project +# +# 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. +# + ifneq ($(TARGET_SIMULATOR),true) LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - netkeystore.c keymgmt.c - -LOCAL_C_INCLUDES := \ - $(call include-path-for, system-core)/cutils \ - external/openssl/include - -LOCAL_SHARED_LIBRARIES := \ - libcutils libssl - -LOCAL_STATIC_LIBRARIES := +include $(CLEAR_VARS) +LOCAL_SRC_FILES := keystore.c +LOCAL_C_INCLUDES := external/openssl/include +LOCAL_SHARED_LIBRARIES := libcutils libcrypto LOCAL_MODULE:= keystore +include $(BUILD_EXECUTABLE) +include $(CLEAR_VARS) +LOCAL_SRC_FILES := keystore_cli.c +LOCAL_C_INCLUDES := external/openssl/include +LOCAL_SHARED_LIBRARIES := libcutils libcrypto +LOCAL_MODULE:= keystore_cli +LOCAL_MODULE_TAGS := debug include $(BUILD_EXECUTABLE) -endif # !simulator)) +endif diff --git a/cmds/keystore/certtool.h b/cmds/keystore/certtool.h deleted file mode 100644 index aefad668d160..000000000000 --- a/cmds/keystore/certtool.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -** -** Copyright 2009, The Android Open Source Project -** -** 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. -*/ - -#ifndef __CERTTOOL_H__ -#define __CERTTOOL_H__ - -#include <stdio.h> -#include <string.h> -#include <cutils/sockets.h> -#include <cutils/log.h> - -#include "common.h" -#include "netkeystore.h" - -#define CERT_NAME_LEN (2 * MAX_KEY_NAME_LENGTH + 2) - -/* - * The specific function 'get_cert' is used in daemons to get the key value - * from keystore. Caller should allocate the buffer and the length of the buffer - * should be MAX_KEY_VALUE_LENGTH. - */ -static inline int get_cert(const char *certname, unsigned char *value, int *size) -{ - int count, fd, ret = -1; - LPC_MARSHAL cmd; - char delimiter[] = "_"; - char *namespace, *keyname; - char *context = NULL; - char cname[CERT_NAME_LEN]; - - if ((certname == NULL) || (value == NULL)) { - LOGE("get_cert: certname or value is null\n"); - return -1; - } - - if (strlcpy(cname, certname, CERT_NAME_LEN) >= CERT_NAME_LEN) { - LOGE("get_cert: keyname is too long\n"); - return -1; - } - - fd = socket_local_client(SOCKET_PATH, - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (fd == -1) { - LOGE("Keystore service is not up and running.\n"); - return -1; - } - - cmd.opcode = GET; - if (((namespace = strtok_r(cname, delimiter, &context)) == NULL) || - ((keyname = strtok_r(NULL, delimiter, &context)) == NULL)) { - goto err; - } - if ((cmd.len = snprintf((char*)cmd.data, BUFFER_MAX, "%s %s", namespace, keyname)) - > (2 * MAX_KEY_NAME_LENGTH + 1)) goto err; - - if (write_marshal(fd, &cmd)) { - LOGE("Incorrect command or command line is too long.\n"); - goto err; - } - if (read_marshal(fd, &cmd)) { - LOGE("Failed to read the result.\n"); - goto err; - } - - // copy the result if succeeded. - if (!cmd.retcode && cmd.len <= BUFFER_MAX) { - memcpy(value, cmd.data, cmd.len); - ret = 0; - *size = cmd.len; - } -err: - close(fd); - return ret; -} - -#endif diff --git a/cmds/keystore/common.h b/cmds/keystore/common.h deleted file mode 100644 index a18114e91abc..000000000000 --- a/cmds/keystore/common.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -** -** Copyright 2009, The Android Open Source Project -** -** 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. -*/ - -#ifndef __COMMON_H__ -#define __COMMON_H__ - -#define SOCKET_PATH "keystore" -#define KEYSTORE_DIR "/data/misc/keystore/" - -#define READ_TIMEOUT 3 -#define MAX_KEY_NAME_LENGTH 64 -#define MAX_NAMESPACE_LENGTH MAX_KEY_NAME_LENGTH -#define MAX_KEY_VALUE_LENGTH 4096 - -#define BUFFER_MAX MAX_KEY_VALUE_LENGTH - -typedef enum { - BOOTUP, - UNINITIALIZED, - LOCKED, - UNLOCKED, -} KEYSTORE_STATE; - -typedef enum { - LOCK, - UNLOCK, - PASSWD, - GETSTATE, - LISTKEYS, - GET, - PUT, - REMOVE, - RESET, - MAX_OPCODE -} KEYSTORE_OPCODE; - -typedef struct { - uint32_t len; - union { - uint32_t opcode; - uint32_t retcode; - }; - unsigned char data[BUFFER_MAX + 1]; -} LPC_MARSHAL; - -#endif diff --git a/cmds/keystore/keymgmt.c b/cmds/keystore/keymgmt.c deleted file mode 100644 index 9a1f8457d224..000000000000 --- a/cmds/keystore/keymgmt.c +++ /dev/null @@ -1,426 +0,0 @@ -/* -** Copyright 2009, The Android Open Source Project -** -** 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. -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <ctype.h> -#include <fcntl.h> -#include <dirent.h> -#include <errno.h> -#include <openssl/aes.h> -#include <openssl/evp.h> -#include <cutils/log.h> - -#include "common.h" -#include "keymgmt.h" - -static int retry_count = 0; -static unsigned char iv[IV_LEN]; -static KEYSTORE_STATE state = BOOTUP; -static AES_KEY encryptKey, decryptKey; - -inline void unlock_keystore(unsigned char *master_key) -{ - AES_set_encrypt_key(master_key, AES_KEY_LEN, &encryptKey); - AES_set_decrypt_key(master_key, AES_KEY_LEN, &decryptKey); - memset(master_key, 0, sizeof(master_key)); - state = UNLOCKED; -} - -inline void lock_keystore() -{ - memset(&encryptKey, 0 , sizeof(AES_KEY)); - memset(&decryptKey, 0 , sizeof(AES_KEY)); - state = LOCKED; -} - -inline void get_encrypt_key(char *passwd, AES_KEY *key) -{ - unsigned char user_key[USER_KEY_LEN]; - gen_key(passwd, user_key, USER_KEY_LEN); - AES_set_encrypt_key(user_key, AES_KEY_LEN, key); -} - -inline void get_decrypt_key(char *passwd, AES_KEY *key) -{ - unsigned char user_key[USER_KEY_LEN]; - gen_key(passwd, user_key, USER_KEY_LEN); - AES_set_decrypt_key(user_key, AES_KEY_LEN, key); -} - -static int gen_random_blob(unsigned char *key, int size) -{ - int ret = 0; - int fd = open("/dev/urandom", O_RDONLY); - if (fd == -1) return -1; - if (read(fd, key, size) != size) ret = -1; - close(fd); - return ret; -} - -static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob, - const char *keyfile) -{ - int size, fd, ret = -1; - unsigned char enc_blob[MAX_BLOB_LEN]; - char tmpfile[KEYFILE_LEN]; - - if ((keyfile == NULL) || (strlen(keyfile) >= (KEYFILE_LEN - 4))) { - LOGE("keyfile name is too long or null"); - return -1; - } - strcpy(tmpfile, keyfile); - strcat(tmpfile, ".tmp"); - - // prepare the blob - if (IV_LEN > USER_KEY_LEN) { - LOGE("iv length is too long."); - return -1; - } - memcpy(blob->iv, iv, IV_LEN); - blob->blob_size = get_blob_size(blob); - if (blob->blob_size > MAX_BLOB_LEN) { - LOGE("blob data size is too large."); - return -1; - } - memcpy(enc_blob, blob->blob, blob->blob_size); - AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob, - blob->blob_size, enc_key, iv, AES_ENCRYPT); - // write to keyfile - size = data_blob_size(blob); - if ((fd = open(tmpfile, O_CREAT|O_RDWR)) == -1) return -1; - if (write(fd, blob, size) == size) ret = 0; - close(fd); - if (!ret) { - unlink(keyfile); - rename(tmpfile, keyfile); - chmod(keyfile, 0440); - } - return ret; -} - -static int load_n_decrypt(const char *keyname, const char *keyfile, - AES_KEY *key, DATA_BLOB *blob) -{ - int fd, ret = -1; - if ((fd = open(keyfile, O_RDONLY)) == -1) return -1; - // get the encrypted blob and iv - if ((read(fd, blob->iv, sizeof(blob->iv)) != sizeof(blob->iv)) || - (read(fd, &blob->blob_size, sizeof(uint32_t)) != sizeof(uint32_t)) || - (blob->blob_size > MAX_BLOB_LEN)) { - goto err; - } else { - unsigned char enc_blob[MAX_BLOB_LEN]; - if (read(fd, enc_blob, blob->blob_size) != - (int) blob->blob_size) goto err; - // decrypt the blob - AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char*)blob->blob, - blob->blob_size, key, blob->iv, AES_DECRYPT); - if (strcmp(keyname, (char*)blob->keyname) == 0) ret = 0; - } -err: - close(fd); - return ret; -} - -static int store_master_key(char *upasswd, unsigned char *master_key) -{ - AES_KEY key; - DATA_BLOB blob; - - // prepare the blob - if (strlen(MASTER_KEY_TAG) >= USER_KEY_LEN) return -1; - strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN); - blob.value_size = USER_KEY_LEN; - if (USER_KEY_LEN > MAX_KEY_VALUE_LENGTH) { - LOGE("master_key length is too long."); - return -1; - } - memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN); - - // generate the encryption key - get_encrypt_key(upasswd, &key); - return encrypt_n_save(&key, &blob, MASTER_KEY); -} - -static int get_master_key(char *upasswd, unsigned char *master_key) -{ - AES_KEY key; - int size, ret = 0; - DATA_BLOB blob; - - get_decrypt_key(upasswd, &key); - ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob); - if (blob.value_size > USER_KEY_LEN) { - LOGE("the blob's value size is too large"); - return -1; - } - if (!ret) memcpy(master_key, blob.value, blob.value_size); - return ret; -} - -static int create_master_key(char *upasswd) -{ - int ret; - unsigned char mpasswd[AES_KEY_LEN]; - unsigned char master_key[USER_KEY_LEN]; - - gen_random_blob(mpasswd, AES_KEY_LEN); - gen_key((char*)mpasswd, master_key, USER_KEY_LEN); - if ((ret = store_master_key(upasswd, master_key)) == 0) { - unlock_keystore(master_key); - } - memset(master_key, 0, USER_KEY_LEN); - memset(mpasswd, 0, AES_KEY_LEN); - - return ret; -} - -static int change_passwd(char *data) -{ - unsigned char master_key[USER_KEY_LEN]; - char *old_pass, *new_pass = NULL, *p, *delimiter=" "; - int ret, count = 0; - char *context = NULL; - - old_pass = p = strtok_r(data, delimiter, &context); - while (p != NULL) { - count++; - new_pass = p; - p = strtok_r(NULL, delimiter, &context); - } - if (count != 2) return -1; - if (strlen(new_pass) < MIN_PASSWD_LENGTH) return -1; - if ((ret = get_master_key(old_pass, master_key)) == 0) { - ret = store_master_key(new_pass, master_key); - retry_count = 0; - } else { - ret = MAX_RETRY_COUNT - ++retry_count; - if (ret == 0) { - retry_count = 0; - LOGE("passwd:reach max retry count, reset the keystore now."); - reset_keystore(); - return -1; - } - - } - return ret; -} - -int remove_key(const char *namespace, const char *keyname) -{ - char keyfile[KEYFILE_LEN]; - - if (state != UNLOCKED) return -state; - if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || - (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { - LOGE("keyname is too long."); - return -1; - } - sprintf(keyfile, KEYFILE_NAME, namespace, keyname); - return unlink(keyfile); -} - -int put_key(const char *namespace, const char *keyname, - unsigned char *data, int size) -{ - DATA_BLOB blob; - uint32_t real_size; - char keyfile[KEYFILE_LEN]; - - if (state != UNLOCKED) { - LOGE("Can not store key with current state %d\n", state); - return -state; - } - if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || - (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { - LOGE("keyname is too long."); - return -1; - } - sprintf(keyfile, KEYFILE_NAME, namespace, keyname); - strcpy(blob.keyname, keyname); - blob.value_size = size; - if (size > MAX_KEY_VALUE_LENGTH) { - LOGE("the data size is too large."); - return -1; - } - memcpy(blob.value, data, size); - return encrypt_n_save(&encryptKey, &blob, keyfile); -} - -int get_key(const char *namespace, const char *keyname, - unsigned char *data, int *size) -{ - int ret; - DATA_BLOB blob; - uint32_t blob_size; - char keyfile[KEYFILE_LEN]; - - if (state != UNLOCKED) { - LOGE("Can not retrieve key value with current state %d\n", state); - return -state; - } - if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || - (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { - LOGE("keyname is too long."); - return -1; - } - sprintf(keyfile, KEYFILE_NAME, namespace, keyname); - ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob); - if (!ret) { - if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) { - LOGE("blob value size is too large."); - ret = -1; - } else { - *size = blob.value_size; - memcpy(data, blob.value, *size); - } - } - return ret; -} - -int list_keys(const char *namespace, char reply[BUFFER_MAX]) -{ - DIR *d; - struct dirent *de; - - if (state != UNLOCKED) { - LOGE("Can not list key with current state %d\n", state); - return -1; - } - - if (!namespace || ((d = opendir("."))) == NULL) { - LOGE("cannot open keystore dir or namespace is null\n"); - return -1; - } - - if (strlen(namespace) >= MAX_KEY_NAME_LENGTH) { - LOGE("namespace is too long."); - return -1; - } - - reply[0] = 0; - while ((de = readdir(d))) { - char *prefix, *name, *keyfile = de->d_name; - char *context = NULL; - - if (de->d_type != DT_REG) continue; - if ((prefix = strtok_r(keyfile, NAME_DELIMITER, &context)) - == NULL) continue; - if (strcmp(prefix, namespace)) continue; - if ((name = strtok_r(NULL, NAME_DELIMITER, &context)) == NULL) continue; - // append the key name into reply - if (reply[0] != 0) strlcat(reply, " ", BUFFER_MAX); - if (strlcat(reply, name, BUFFER_MAX) >= BUFFER_MAX) { - LOGE("too many files under keystore directory\n"); - return -1; - } - } - closedir(d); - return 0; -} - -int passwd(char *data) -{ - if (state == UNINITIALIZED) { - if (strchr(data, ' ')) return -1; - if (strlen(data) < MIN_PASSWD_LENGTH) return -1; - return create_master_key(data); - } - return change_passwd(data); -} - -int lock() -{ - switch(state) { - case UNLOCKED: - lock_keystore(); - case LOCKED: - return 0; - default: - return -1; - } -} - -int unlock(char *passwd) -{ - unsigned char master_key[USER_KEY_LEN]; - int ret = get_master_key(passwd, master_key); - if (!ret) { - unlock_keystore(master_key); - retry_count = 0; - } else { - ret = MAX_RETRY_COUNT - ++retry_count; - if (ret == 0) { - retry_count = 0; - LOGE("unlock:reach max retry count, reset the keystore now."); - reset_keystore(); - return -1; - } - } - return ret; -} - -KEYSTORE_STATE get_state() -{ - return state; -} - -int reset_keystore() -{ - int ret = 0; - DIR *d; - struct dirent *de; - - if ((d = opendir(".")) == NULL) { - LOGE("cannot open keystore dir\n"); - return -1; - } - while ((de = readdir(d))) { - if (unlink(de->d_name) != 0) ret = -1; - } - closedir(d); - state = UNINITIALIZED; - if (ret == 0) { - LOGI("keystore is reset."); - } else { - LOGI("keystore can not be cleaned up entirely."); - } - return ret; -} - -int init_keystore(const char *dir) -{ - int fd; - - if (dir) mkdir(dir, 0770); - if (!dir || chdir(dir)) { - LOGE("Can not open/create the keystore directory %s\n", - dir ? dir : "(null)"); - return -1; - } - gen_random_blob(iv, IV_LEN); - if ((fd = open(MASTER_KEY, O_RDONLY)) == -1) { - state = UNINITIALIZED; - return 0; - } - close(fd); - state = LOCKED; - return 0; -} diff --git a/cmds/keystore/keymgmt.h b/cmds/keystore/keymgmt.h deleted file mode 100644 index 0e928db494fd..000000000000 --- a/cmds/keystore/keymgmt.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -** Copyright 2009, The Android Open Source Project -** -** 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. -*/ - -#ifndef __KEYMGMT_H__ -#define __KEYMGMT_H__ - -#define MASTER_KEY_TAG "master_key" -#define MASTER_KEY ".keymaster" -#define MAX_PATH_LEN 128 -#define SALT "Android Keystore 0.1" -#define NAME_DELIMITER "_" -#define KEYFILE_NAME "%s"NAME_DELIMITER"%s" -#define KEYGEN_ITER 1024 -#define AES_KEY_LEN 128 -#define USER_KEY_LEN (AES_KEY_LEN/8) -#define IV_LEN USER_KEY_LEN -#define MAX_RETRY_COUNT 6 -#define MIN_PASSWD_LENGTH 8 - -#define gen_key(passwd, key, len) \ - PKCS5_PBKDF2_HMAC_SHA1(passwd, strlen(passwd), \ - (unsigned char*)SALT, \ - strlen(SALT), KEYGEN_ITER, \ - len, key) - -#define KEYFILE_LEN MAX_NAMESPACE_LENGTH + MAX_KEY_NAME_LENGTH + 6 - -#define get_blob_size(blob) \ - (((blob->value_size + sizeof(uint32_t) + MAX_KEY_NAME_LENGTH \ - + USER_KEY_LEN - 1) / USER_KEY_LEN) * USER_KEY_LEN) - -#define MAX_BLOB_LEN ((MAX_KEY_VALUE_LENGTH + MAX_KEY_NAME_LENGTH + \ - sizeof(uint32_t) + USER_KEY_LEN - 1) / USER_KEY_LEN)\ - * USER_KEY_LEN - -#define data_blob_size(blob) USER_KEY_LEN + sizeof(uint32_t) + blob->blob_size - -typedef struct { - unsigned char iv[USER_KEY_LEN]; - uint32_t blob_size; - union { - unsigned char blob[1]; - struct { - uint32_t value_size; - char keyname[MAX_KEY_NAME_LENGTH]; - unsigned char value[MAX_KEY_VALUE_LENGTH]; - } __attribute__((packed)); - }; -} DATA_BLOB; - -typedef struct { - char tag[USER_KEY_LEN]; - unsigned char master_key[USER_KEY_LEN]; -} MASTER_BLOB; - -int put_key(const char *namespace, const char *keyname, - unsigned char *data, int size); -int get_key(const char *namespace, const char *keyname, - unsigned char *data, int *size); -int remove_key(const char *namespace, const char *keyname); -int list_keys(const char *namespace, char reply[BUFFER_MAX]); -int passwd(char *data); -int lock(); -int unlock(char *passwd); -KEYSTORE_STATE get_state(); -int reset_keystore(); -int init_keystore(const char *dir); - -#endif diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c new file mode 100644 index 000000000000..ba74c7814e81 --- /dev/null +++ b/cmds/keystore/keystore.c @@ -0,0 +1,542 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <errno.h> +#include <dirent.h> +#include <fcntl.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <arpa/inet.h> + +#include <openssl/aes.h> +#include <openssl/evp.h> +#include <openssl/md5.h> + +#define LOG_TAG "keystore" +#include <cutils/log.h> +#include <cutils/sockets.h> +#include <private/android_filesystem_config.h> + +#include "keystore.h" + +/* KeyStore is a secured storage for key-value pairs. In this implementation, + * each file stores one key-value pair. Keys are encoded in file names, and + * values are encrypted with checksums. The encryption key is protected by a + * user-defined password. To keep things simple, buffers are always larger than + * the maximum space we needed, so boundary checks on buffers are omitted. */ + +#define KEY_SIZE 120 +#define VALUE_SIZE 32768 +#define PASSWORD_SIZE VALUE_SIZE + +/* Here is the encoding of keys. This is necessary in order to allow arbitrary + * characters in keys. Characters in [0-~] are not encoded. Others are encoded + * into two bytes. The first byte is one of [+-.] which represents the first + * two bits of the character. The second byte encodes the rest of the bits into + * [0-o]. Therefore in the worst case the length of a key gets doubled. Note + * that Base64 cannot be used here due to the need of prefix match on keys. */ + +static int encode_key(char *out, uint8_t *in, int length) +{ + int i; + for (i = length; i > 0; --i, ++in, ++out) { + if (*in >= '0' && *in <= '~') { + *out = *in; + } else { + *out = '+' + (*in >> 6); + *++out = '0' + (*in & 0x3F); + ++length; + } + } + *out = 0; + return length; +} + +static int decode_key(uint8_t *out, char *in, int length) +{ + int i; + for (i = 0; i < length; ++i, ++in, ++out) { + if (*in >= '0' && *in <= '~') { + *out = *in; + } else { + *out = (*in - '+') << 6; + *out |= (*++in - '0') & 0x3F; + --length; + } + } + *out = 0; + return length; +} + +/* Here is the protocol used in both requests and responses: + * code [length_1 message_1 ... length_n message_n] end-of-file + * where code is one byte long and lengths are unsigned 16-bit integers in + * network order. Thus the maximum length of a message is 65535 bytes. */ + +static int the_socket = -1; + +static int recv_code(int8_t *code) +{ + return recv(the_socket, code, 1, 0) == 1; +} + +static int recv_message(uint8_t *message, int length) +{ + uint8_t bytes[2]; + if (recv(the_socket, &bytes[0], 1, 0) != 1 || + recv(the_socket, &bytes[1], 1, 0) != 1) { + return -1; + } else { + int offset = bytes[0] << 8 | bytes[1]; + if (length < offset) { + return -1; + } + length = offset; + offset = 0; + while (offset < length) { + int n = recv(the_socket, &message[offset], length - offset, 0); + if (n <= 0) { + return -1; + } + offset += n; + } + } + return length; +} + +static int recv_end_of_file() +{ + uint8_t byte; + return recv(the_socket, &byte, 1, 0) == 0; +} + +static void send_code(int8_t code) +{ + send(the_socket, &code, 1, 0); +} + +static void send_message(uint8_t *message, int length) +{ + uint16_t bytes = htons(length); + send(the_socket, &bytes, 2, 0); + send(the_socket, message, length, 0); +} + +/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to + * compute their checksums. To make the files portable, the length is stored in + * network order. Note that the first four bytes are reserved for future use and + * are always set to zero in this implementation. */ + +static int the_entropy = -1; + +static struct __attribute__((packed)) { + uint32_t reserved; + uint8_t vector[AES_BLOCK_SIZE]; + uint8_t encrypted[0]; + uint8_t digest[MD5_DIGEST_LENGTH]; + uint8_t digested[0]; + int32_t length; + uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE]; +} blob; + +static int8_t encrypt_blob(char *name, AES_KEY *aes_key) +{ + uint8_t vector[AES_BLOCK_SIZE]; + int length = blob.length; + int fd; + + if (read(the_entropy, vector, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) { + return SYSTEM_ERROR; + } + + length += blob.value - blob.digested; + blob.length = htonl(blob.length); + MD5(blob.digested, length, blob.digest); + + length += blob.digested - blob.encrypted; + length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE; + memcpy(vector, blob.vector, AES_BLOCK_SIZE); + AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector, + AES_ENCRYPT); + + blob.reserved = 0; + length += blob.encrypted - (uint8_t *)&blob; + + fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); + if (fd == -1 || write(fd, &blob, length) != length) { + return SYSTEM_ERROR; + } + close(fd); + return rename(".tmp", name) ? SYSTEM_ERROR : NO_ERROR; +} + +static int8_t decrypt_blob(char *name, AES_KEY *aes_key) +{ + int fd = open(name, O_RDONLY); + int length; + + if (fd == -1) { + return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR; + } + length = read(fd, &blob, sizeof(blob)); + close(fd); + + length -= blob.encrypted - (uint8_t *)&blob; + if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) { + return VALUE_CORRUPTED; + } + + AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, + blob.vector, AES_DECRYPT); + length -= blob.digested - blob.encrypted; + if (!memcmp(blob.digest, MD5(blob.digested, length, NULL), + MD5_DIGEST_LENGTH)) { + return VALUE_CORRUPTED; + } + + length -= blob.value - blob.digested; + blob.length = ntohl(blob.length); + return (length < blob.length) ? VALUE_CORRUPTED : NO_ERROR; +} + +/* Here are the actions. Each of them is a function without arguments. All + * information is defined in global variables, which are set properly before + * performing an action. The number of parameters required by each action is + * fixed and defined in a table. If the return value of an action is positive, + * it will be treated as a response code and transmitted to the client. Note + * that the lengths of parameters are checked when they are received, so + * boundary checks on parameters are omitted. */ + +#define MAX_PARAM 2 +#define MAX_RETRY 4 + +static uid_t uid = -1; +static int8_t state = UNINITIALIZED; +static int8_t retry = MAX_RETRY; + +static struct { + int length; + uint8_t value[VALUE_SIZE]; +} params[MAX_PARAM]; + +static AES_KEY encryption_key; +static AES_KEY decryption_key; + +static int8_t test() +{ + return state; +} + +static int8_t get() +{ + char name[NAME_MAX]; + int n = sprintf(name, "%u_", uid); + encode_key(&name[n], params[0].value, params[0].length); + n = decrypt_blob(name, &decryption_key); + if (n != NO_ERROR) { + return n; + } + send_code(NO_ERROR); + send_message(blob.value, blob.length); + return -NO_ERROR; +} + +static int8_t insert() +{ + char name[NAME_MAX]; + int n = sprintf(name, "%u_", uid); + encode_key(&name[n], params[0].value, params[0].length); + blob.length = params[1].length; + memcpy(blob.value, params[1].value, params[1].length); + return encrypt_blob(name, &encryption_key); +} + +static int8_t delete() +{ + char name[NAME_MAX]; + int n = sprintf(name, "%u_", uid); + encode_key(&name[n], params[0].value, params[0].length); + return (unlink(name) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR; +} + +static int8_t exist() +{ + char name[NAME_MAX]; + int n = sprintf(name, "%u_", uid); + encode_key(&name[n], params[0].value, params[0].length); + if (access(name, R_OK) == -1) { + return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND; + } + return NO_ERROR; +} + +static int8_t saw() +{ + DIR *dir = opendir("."); + struct dirent *file; + char name[NAME_MAX]; + int n; + + if (!dir) { + return SYSTEM_ERROR; + } + n = sprintf(name, "%u_", uid); + n += encode_key(&name[n], params[0].value, params[0].length); + send_code(NO_ERROR); + while ((file = readdir(dir)) != NULL) { + if (!strncmp(name, file->d_name, n)) { + char *p = &file->d_name[n]; + params[0].length = decode_key(params[0].value, p, strlen(p)); + send_message(params[0].value, params[0].length); + } + } + closedir(dir); + return -NO_ERROR; +} + +static int8_t reset() +{ + DIR *dir = opendir("."); + struct dirent *file; + + memset(&encryption_key, 0, sizeof(encryption_key)); + memset(&decryption_key, 0, sizeof(decryption_key)); + state = UNINITIALIZED; + retry = MAX_RETRY; + + if (!dir) { + return SYSTEM_ERROR; + } + while ((file = readdir(dir)) != NULL) { + unlink(file->d_name); + } + closedir(dir); + return NO_ERROR; +} + +#define MASTER_KEY_FILE ".masterkey" +#define MASTER_KEY_SIZE 16 + +static void generate_key(uint8_t *key, uint8_t *password, int length) +{ + PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore", + sizeof("keystore"), 1024, MASTER_KEY_SIZE, key); +} + +static int8_t password() +{ + uint8_t key[MASTER_KEY_SIZE]; + AES_KEY aes_key; + int n; + + if (state == UNINITIALIZED) { + blob.length = MASTER_KEY_SIZE; + if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) { + return SYSTEM_ERROR; + } + } else { + generate_key(key, params[0].value, params[0].length); + AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key); + n = decrypt_blob(MASTER_KEY_FILE, &aes_key); + if (n == SYSTEM_ERROR) { + return SYSTEM_ERROR; + } + if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) { + if (retry <= 0) { + reset(); + return UNINITIALIZED; + } + return WRONG_PASSWORD + --retry; + } + } + + if (params[1].length == -1) { + memcpy(key, blob.value, MASTER_KEY_SIZE); + } else { + generate_key(key, params[1].value, params[1].length); + AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key); + memcpy(key, blob.value, MASTER_KEY_SIZE); + n = encrypt_blob(MASTER_KEY_FILE, &aes_key); + } + + if (n == NO_ERROR) { + AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key); + AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key); + state = NO_ERROR; + retry = MAX_RETRY; + } + return n; +} + +static int8_t lock() +{ + memset(&encryption_key, 0, sizeof(encryption_key)); + memset(&decryption_key, 0, sizeof(decryption_key)); + state = LOCKED; + return NO_ERROR; +} + +static int8_t unlock() +{ + params[1].length = -1; + return password(); +} + +/* Here are the permissions, actions, users, and the main function. */ + +enum perm { + TEST = 1, + GET = 2, + INSERT = 4, + DELETE = 8, + EXIST = 16, + SAW = 32, + RESET = 64, + PASSWORD = 128, + LOCK = 256, + UNLOCK = 512, +}; + +static struct action { + int8_t (*run)(); + int8_t code; + int8_t state; + uint32_t perm; + int lengths[MAX_PARAM]; +} actions[] = { + {test, 't', 0, TEST, {0}}, + {get, 'g', NO_ERROR, GET, {KEY_SIZE}}, + {insert, 'i', NO_ERROR, INSERT, {KEY_SIZE, VALUE_SIZE}}, + {delete, 'd', 0, DELETE, {KEY_SIZE}}, + {exist, 'e', 0, EXIST, {KEY_SIZE}}, + {saw, 's', 0, SAW, {KEY_SIZE}}, + {reset, 'r', 0, RESET, {0}}, + {password, 'p', 0, PASSWORD, {PASSWORD_SIZE, PASSWORD_SIZE}}, + {lock, 'l', NO_ERROR, LOCK, {0}}, + {unlock, 'u', LOCKED, UNLOCK, {PASSWORD_SIZE}}, + {NULL, 0 , 0, 0, {0}}, +}; + +static struct user { + uid_t uid; + uid_t euid; + uint32_t perms; +} users[] = { + {AID_SYSTEM, 0, ~GET}, + {AID_VPN, AID_SYSTEM, GET}, + {AID_WIFI, AID_SYSTEM, GET}, + {0, 0, TEST | GET | INSERT | DELETE | EXIST | SAW}, +}; + +static int8_t process(int8_t code) { + struct user *user = users; + struct action *action = actions; + int i; + + while (user->uid && user->uid != uid) { + ++user; + } + while (action->code && action->code != code) { + ++action; + } + if (!action->code) { + return UNDEFINED_ACTION; + } + if (!(action->perm & user->perms)) { + return PERMISSION_DENIED; + } + if (action->state && action->state != state) { + return state; + } + if (user->euid) { + uid = user->euid; + } + for (i = 0; i < MAX_PARAM && action->lengths[i]; ++i) { + params[i].length = recv_message(params[i].value, action->lengths[i]); + if (params[i].length == -1) { + return PROTOCOL_ERROR; + } + } + if (!recv_end_of_file()) { + return PROTOCOL_ERROR; + } + return action->run(); +} + +#define RANDOM_DEVICE "/dev/urandom" + +int main(int argc, char **argv) +{ + int control_socket = android_get_control_socket("keystore"); + if (argc < 2) { + LOGE("A directory must be specified!"); + return 1; + } + if (chdir(argv[1]) == -1) { + LOGE("chdir: %s: %s", argv[1], strerror(errno)); + return 1; + } + if ((the_entropy = open(RANDOM_DEVICE, O_RDONLY)) == -1) { + LOGE("open: %s: %s", RANDOM_DEVICE, strerror(errno)); + return 1; + } + if (listen(control_socket, 3) == -1) { + LOGE("listen: %s", strerror(errno)); + return 1; + } + + signal(SIGPIPE, SIG_IGN); + if (access(MASTER_KEY_FILE, R_OK) == 0) { + state = LOCKED; + } + + while ((the_socket = accept(control_socket, NULL, 0)) != -1) { + struct timeval tv = {.tv_sec = 3}; + struct ucred cred; + socklen_t size = sizeof(cred); + int8_t request; + + setsockopt(the_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + setsockopt(the_socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); + + if (getsockopt(the_socket, SOL_SOCKET, SO_PEERCRED, &cred, &size)) { + LOGW("getsockopt: %s", strerror(errno)); + } else if (recv_code(&request)) { + int8_t old_state = state; + int8_t response; + uid = cred.uid; + + if ((response = process(request)) > 0) { + send_code(response); + response = -response; + } + + LOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d", + cred.uid, request, -response, old_state, state, retry); + } + close(the_socket); + } + LOGE("accept: %s", strerror(errno)); + return 1; +} diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h new file mode 100644 index 000000000000..5ef51e9cd7d0 --- /dev/null +++ b/cmds/keystore/keystore.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ + +#ifndef __KEYSTORE_H__ +#define __KEYSTORE_H__ + +enum response_code { + NO_ERROR = 1, + LOCKED = 2, + UNINITIALIZED = 3, + SYSTEM_ERROR = 4, + PROTOCOL_ERROR = 5, + PERMISSION_DENIED = 6, + KEY_NOT_FOUND = 7, + VALUE_CORRUPTED = 8, + UNDEFINED_ACTION = 9, + WRONG_PASSWORD = 10, +}; + +#endif diff --git a/cmds/keystore/keystore_cli.c b/cmds/keystore/keystore_cli.c new file mode 100644 index 000000000000..e8afb5a945b2 --- /dev/null +++ b/cmds/keystore/keystore_cli.c @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> + +#include <cutils/sockets.h> + +#include "keystore.h" + +char *responses[256] = { + [NO_ERROR] = "No error", + [LOCKED] = "Locked", + [UNINITIALIZED] = "Uninitialized", + [SYSTEM_ERROR] = "System error", + [PROTOCOL_ERROR] = "Protocol error", + [PERMISSION_DENIED] = "Permission denied", + [KEY_NOT_FOUND] = "Key not found", + [VALUE_CORRUPTED] = "Value corrupted", + [UNDEFINED_ACTION] = "Undefined action", + [WRONG_PASSWORD] = "Wrong password (last chance)", + [WRONG_PASSWORD + 1] = "Wrong password (2 tries left)", + [WRONG_PASSWORD + 2] = "Wrong password (3 tries left)", + [WRONG_PASSWORD + 3] = "Wrong password (4 tries left)", +}; + +#define MAX_RESPONSE (WRONG_PASSWORD + 3) + +int main(int argc, char **argv) +{ + uint8_t bytes[65536]; + uint8_t code; + int sock, i; + + if (argc < 2) { + printf("Usage: %s action [parameter ...]\n", argv[0]); + return 0; + } + + sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM); + if (sock == -1) { + puts("Failed to connect"); + return 1; + } + + send(sock, argv[1], 1, 0); + for (i = 2; i < argc; ++i) { + uint16_t length = strlen(argv[i]); + bytes[0] = length >> 8; + bytes[1] = length; + send(sock, &bytes, 2, 0); + send(sock, argv[i], length, 0); + } + shutdown(sock, SHUT_WR); + + if (recv(sock, &code, 1, 0) != 1) { + puts("Failed to receive"); + return 1; + } + printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown"); + while ((i = recv(sock, &bytes[0], 1, 0)) == 1) { + int length; + int offset; + if ((i = recv(sock, &bytes[1], 1, 0)) != 1) { + puts("Failed to receive"); + return 1; + } + length = bytes[0] << 8 | bytes[1]; + for (offset = 0; offset < length; offset += i) { + i = recv(sock, &bytes[offset], length - offset, 0); + if (i <= 0) { + puts("Failed to receive"); + return 1; + } + } + fwrite(bytes, 1, length, stdout); + puts(""); + } + return 0; +} diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h index 7665e81a314d..0e7e1aeabb0f 100644 --- a/cmds/keystore/keystore_get.h +++ b/cmds/keystore/keystore_get.h @@ -1,53 +1,69 @@ /* -** -** Copyright 2009, The Android Open Source Project -** -** 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. -*/ + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ #ifndef __KEYSTORE_GET_H__ #define __KEYSTORE_GET_H__ #include <stdio.h> -#include <stdlib.h> +#include <stdint.h> #include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> -#include "certtool.h" +#include <cutils/sockets.h> -/* This function is provided to native components to get values from keystore. - * Users are required to link against libcutils. If something goes wrong, NULL - * is returned. Otherwise it returns the value in dynamically allocated memory - * and sets the size if the pointer is not NULL. One can release the memory by - * calling free(). */ -static char *keystore_get(const char *key, int *size) +#define KEYSTORE_MESSAGE_SIZE 65535 + +/* This function is provided for native components to get values from keystore. + * Users are required to link against libcutils. The lengths of keys and values + * are limited to KEYSTORE_MESSAGE_SIZE. This function returns the length of + * the requested value or -1 if something goes wrong. */ +static int keystore_get(const char *key, char *value) { - char buffer[MAX_KEY_VALUE_LENGTH]; - char *value; - int length; + int length = strlen(key); + uint8_t bytes[2] = {length >> 8, length}; + uint8_t code = 'g'; + int sock; - if (get_cert(key, (unsigned char *)buffer, &length) != 0) { - return NULL; + if (length > KEYSTORE_MESSAGE_SIZE) { + return -1; } - value = malloc(length + 1); - if (!value) { - return NULL; + sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, + SOCK_STREAM); + if (sock == -1) { + return -1; } - memcpy(value, buffer, length); - value[length] = 0; - if (size) { - *size = length; + if (send(sock, &code, 1, 0) == 1 && send(sock, bytes, 2, 0) == 2 && + send(sock, key, length, 0) == length && shutdown(sock, SHUT_WR) == 0 && + recv(sock, &code, 1, 0) == 1 && code == /* NO_ERROR */ 1 && + recv(sock, &bytes[0], 1, 0) == 1 && recv(sock, &bytes[1], 1, 0) == 1) { + int offset = 0; + length = bytes[0] << 8 | bytes[1]; + while (offset < length) { + int n = recv(sock, &value[offset], length - offset, 0); + if (n <= 0) { + length = -1; + break; + } + offset += n; + } } - return value; + close(sock); + return length; } #endif diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c deleted file mode 100644 index 637e0d87600d..000000000000 --- a/cmds/keystore/netkeystore.c +++ /dev/null @@ -1,411 +0,0 @@ -/* -** Copyright 2009, The Android Open Source Project -** -** 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. -*/ - -#define LOG_TAG "keystore" - -#include <stdio.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <dirent.h> -#include <unistd.h> -#include <ctype.h> -#include <fcntl.h> -#include <errno.h> -#include <utime.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <private/android_filesystem_config.h> - -#include <cutils/sockets.h> -#include <cutils/log.h> -#include <cutils/properties.h> - -#include "netkeystore.h" -#include "keymgmt.h" - -#define DBG 1 -#define CMD_PUT_WITH_FILE "putfile" - -typedef void CMD_FUNC(LPC_MARSHAL *cmd, LPC_MARSHAL *reply); - -struct cmdinfo { - const char *name; - CMD_FUNC *func; -}; - -static CMD_FUNC do_lock; -static CMD_FUNC do_unlock; -static CMD_FUNC do_passwd; -static CMD_FUNC do_get_state;; -static CMD_FUNC do_listkeys; -static CMD_FUNC do_get_key; -static CMD_FUNC do_put_key; -static CMD_FUNC do_remove_key; -static CMD_FUNC do_reset_keystore; - -#define str(x) #x - -struct cmdinfo cmds[] = { - { str(LOCK), do_lock }, - { str(UNLOCK), do_unlock }, - { str(PASSWD), do_passwd }, - { str(GETSTATE), do_get_state }, - { str(LISTKEYS), do_listkeys }, - { str(GET), do_get_key }, - { str(PUT), do_put_key }, - { str(REMOVE), do_remove_key }, - { str(RESET), do_reset_keystore }, -}; - -static struct ucred cr; - -static int check_get_perm(int uid) -{ - if (uid == AID_WIFI || uid == AID_VPN) return 0; - return -1; -} - -static int check_reset_perm(int uid) -{ - if (uid == AID_SYSTEM) return 0; - return -1; -} - -static int parse_keyname(char *name, uint32_t len, - char *namespace, char *keyname) -{ - int count = 0; - char *c = namespace, *p = namespace, *t = name; - - if (!name || !namespace || !keyname) return -1; - while (t < name + len && (*t != 0)) { - if (*t == ' ') { - if (c == keyname) return -1; - *p = count = 0; - c = p = keyname; - t++; - } else { - if (!isalnum(*t)) return -1; - *p++ = *t++; - // also check if the keyname/namespace is too long. - if (count++ == MAX_KEY_NAME_LENGTH) return -1; - } - } - *p = 0; - return 0; -} - -// args of passwd(): -// firstPassword - for the first time -// oldPassword newPassword - for changing the password -static void do_passwd(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - reply->retcode = passwd((char*)cmd->data); -} - -// args of lock(): -// no argument -static void do_lock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - reply->retcode = lock(); -} - -// args of unlock(): -// password -static void do_unlock(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - reply->retcode = unlock((char*)cmd->data); -} - -// args of get_state(): -// no argument -static void do_get_state(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - reply->retcode = get_state(); -} - -// args of listkeys(): -// namespace -static void do_listkeys(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - reply->retcode = list_keys((const char*)cmd->data, (char*)reply->data); - if (!reply->retcode) reply->len = strlen((char*)reply->data); -} - -// args of get(): -// namespace keyname -static void do_get_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - char namespace[MAX_KEY_NAME_LENGTH]; - char keyname[MAX_KEY_NAME_LENGTH]; - - if (check_get_perm(cr.uid)) { - LOGE("uid %d doesn't have the permission to get key value\n", cr.uid); - reply->retcode = -1; - return; - } - - if (parse_keyname((char*)cmd->data, cmd->len, namespace, keyname)) { - reply->retcode = -1; - } else { - reply->retcode = get_key(namespace, keyname, reply->data, - (int*)&reply->len); - } -} - -static int get_value_index(LPC_MARSHAL *cmd) -{ - uint32_t count = 0, i; - for (i = 0 ; i < cmd->len ; ++i) { - if (cmd->data[i] == ' ') { - if (++count == 2) return ++i; - } - } - return -1; -} - -// args of put(): -// namespace keyname keyvalue -static void do_put_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - char namespace[MAX_KEY_NAME_LENGTH]; - char keyname[MAX_KEY_NAME_LENGTH]; - - int p = get_value_index(cmd); - if (p == -1) { - reply->retcode = -1; - } else { - unsigned char *value; - if (parse_keyname((char*)cmd->data, p - 1, namespace, keyname)) { - reply->retcode = -1; - return; - } - value = &cmd->data[p]; - int len = cmd->len - p; - reply->retcode = put_key(namespace, keyname, value, len); - } -} - -// args of remove_key(): -// namespace keyname -static void do_remove_key(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - char namespace[MAX_KEY_NAME_LENGTH]; - char keyname[MAX_KEY_NAME_LENGTH]; - if (parse_keyname((char*)cmd->data, cmd->len, namespace, keyname)) { - reply->retcode = -1; - return; - } - reply->retcode = remove_key(namespace, keyname); -} - -// args of reset_keystore(): -// no argument -static void do_reset_keystore(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - if (check_reset_perm(cr.uid)) { - LOGE("uid %d doesn't have the permission to reset the keystore\n", - cr.uid); - reply->retcode = -1; - return; - } - reply->retcode = reset_keystore(); -} - -static void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply) -{ - uint32_t cmd_max = sizeof(cmds)/sizeof(struct cmdinfo); - - if (cmd->opcode >= cmd_max) { - LOGE("the opcode (%d) is not valid", cmd->opcode); - reply->retcode = -1; - return; - } - cmds[cmd->opcode].func(cmd, reply); -} - -static int set_read_timeout(int socket) -{ - struct timeval tv; - tv.tv_sec = READ_TIMEOUT; - if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv)) - { - LOGE("setsockopt failed"); - return -1; - } - return 0; -} - -static int append_input_from_file(const char *filename, LPC_MARSHAL *cmd) -{ - int fd, len, ret = 0; - - // get opcode of the function put() - if ((fd = open(filename, O_RDONLY)) == -1) { - fprintf(stderr, "Can not open file %s\n", filename); - return -1; - } - cmd->data[cmd->len] = ' '; - cmd->len++; - len = read(fd, cmd->data + cmd->len, BUFFER_MAX - cmd->len); - if (len < 0 || (len == (int)(BUFFER_MAX - cmd->len))) { - ret = -1; - } else { - cmd->len += len; - } - close(fd); - return ret; -} - -static int flatten_str_args(int argc, const char **argv, LPC_MARSHAL *cmd) -{ - int i, len = 0; - char *buf = (char*)cmd->data; - buf[0] = 0; - for (i = 0 ; i < argc ; ++i) { - if (i == 0) { - len = strlcpy(buf, argv[i], BUFFER_MAX); - } else { - len += snprintf(buf + len, BUFFER_MAX - len, " %s", argv[i]); - } - if (len >= BUFFER_MAX) return -1; - } - if (len) cmd->len = len; - return 0; -} - -static int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd) -{ - uint32_t i, len = 0; - uint32_t cmd_max = sizeof(cmds)/sizeof(cmds[0]); - - for (i = 0 ; i < cmd_max ; ++i) { - if (!strcasecmp(argv[0], cmds[i].name)) break; - } - - if (i == cmd_max) { - // check if this is a command to put the key value with a file. - if (strcmp(argv[0], CMD_PUT_WITH_FILE) != 0) return -1; - cmd->opcode = PUT; - if (argc != 4) { - fprintf(stderr, "%s args\n\tnamespace keyname filename\n", - argv[0]); - return -1; - } - if (flatten_str_args(argc - 2, argv + 1, cmd)) return -1; - return append_input_from_file(argv[3], cmd); - } else { - cmd->opcode = i; - return flatten_str_args(argc - 1, argv + 1, cmd); - } -} - -static int shell_command(const int argc, const char **argv) -{ - int fd, i; - LPC_MARSHAL cmd; - - if (parse_cmd(argc, argv , &cmd)) { - fprintf(stderr, "Incorrect command or command line is too long.\n"); - exit(1); - } - fd = socket_local_client(SOCKET_PATH, - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (fd == -1) { - fprintf(stderr, "Keystore service is not up and running.\n"); - exit(1); - } - - if (write_marshal(fd, &cmd)) { - fprintf(stderr, "Incorrect command or command line is too long.\n"); - exit(1); - } - if (read_marshal(fd, &cmd)) { - fprintf(stderr, "Failed to read the result.\n"); - exit(1); - } - cmd.data[cmd.len] = 0; - fprintf(stdout, "%s\n", (cmd.retcode == 0) ? "Succeeded!" : "Failed!"); - if (cmd.len) fprintf(stdout, "\t%s\n", (char*)cmd.data); - close(fd); - return 0; -} - -int main(const int argc, const char *argv[]) -{ - struct sockaddr addr; - socklen_t alen; - int lsocket, s; - LPC_MARSHAL cmd, reply; - - if (argc > 1) { - return shell_command(argc - 1, argv + 1); - } - - if (init_keystore(KEYSTORE_DIR)) { - LOGE("Can not initialize the keystore, the directory exist?\n"); - exit(1); - } - - lsocket = android_get_control_socket(SOCKET_PATH); - if (lsocket < 0) { - LOGE("Failed to get socket from environment: %s\n", strerror(errno)); - exit(1); - } - if (listen(lsocket, 5)) { - LOGE("Listen on socket failed: %s\n", strerror(errno)); - exit(1); - } - fcntl(lsocket, F_SETFD, FD_CLOEXEC); - memset(&reply, 0, sizeof(LPC_MARSHAL)); - - for (;;) { - socklen_t cr_size = sizeof(cr); - alen = sizeof(addr); - s = accept(lsocket, &addr, &alen); - - /* retrieve the caller info here */ - if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) { - close(s); - LOGE("Unable to recieve socket options\n"); - continue; - } - - if (s < 0) { - LOGE("Accept failed: %s\n", strerror(errno)); - continue; - } - fcntl(s, F_SETFD, FD_CLOEXEC); - if (set_read_timeout(s)) { - close(s); - continue; - } - - // read the command, execute and send the result back. - if(read_marshal(s, &cmd)) goto err; - if (DBG) LOGD("new connection\n"); - execute(&cmd, &reply); - write_marshal(s, &reply); -err: - memset(&reply, 0, sizeof(LPC_MARSHAL)); - if (DBG) LOGD("closing connection\n"); - close(s); - } - - return 0; -} diff --git a/cmds/keystore/netkeystore.h b/cmds/keystore/netkeystore.h deleted file mode 100644 index a87a667e9123..000000000000 --- a/cmds/keystore/netkeystore.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -** -** Copyright 2009, The Android Open Source Project -** -** 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. -*/ - -#ifndef __NETKEYSTORE_H__ -#define __NETKEYSTORE_H__ - -#include <stdio.h> -#include <cutils/sockets.h> -#include <cutils/log.h> - -#include "common.h" - -static inline int readx(int s, void *_buf, int count) -{ - char *buf = _buf; - int n = 0, r; - if (count < 0) return -1; - while (n < count) { - r = read(s, buf + n, count - n); - if (r < 0) { - if (errno == EINTR) continue; - LOGE("read error: %s\n", strerror(errno)); - return -1; - } - if (r == 0) { - LOGE("eof\n"); - return -1; /* EOF */ - } - n += r; - } - return 0; -} - -static inline int writex(int s, const void *_buf, int count) -{ - const char *buf = _buf; - int n = 0, r; - if (count < 0) return -1; - while (n < count) { - r = write(s, buf + n, count - n); - if (r < 0) { - if (errno == EINTR) continue; - LOGE("write error: %s\n", strerror(errno)); - return -1; - } - n += r; - } - return 0; -} - -static inline int read_marshal(int s, LPC_MARSHAL *cmd) -{ - if (readx(s, cmd, 2 * sizeof(uint32_t))) { - LOGE("failed to read header\n"); - return -1; - } - if (cmd->len > BUFFER_MAX) { - LOGE("invalid size %d\n", cmd->len); - return -1; - } - if (readx(s, cmd->data, cmd->len)) { - LOGE("failed to read data\n"); - return -1; - } - cmd->data[cmd->len] = 0; - return 0; -} - -static inline int write_marshal(int s, LPC_MARSHAL *cmd) -{ - if (writex(s, cmd, 2 * sizeof(uint32_t))) { - LOGE("failed to write marshal header\n"); - return -1; - } - if (writex(s, cmd->data, cmd->len)) { - LOGE("failed to write marshal data\n"); - return -1; - } - return 0; -} - -#endif diff --git a/cmds/keystore/tests/Android.mk b/cmds/keystore/tests/Android.mk deleted file mode 100644 index 33541cc79f19..000000000000 --- a/cmds/keystore/tests/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (C) 2009 The Android Open Source Project -# -# 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. -# -# define the KEYSTORE_TESTS environment variable to build the test programs -ifdef KEYSTORE_TESTS -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) -LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c -LOCAL_SHARED_LIBRARIES := libcutils libssl -LOCAL_MODULE:= netkeystore_test -LOCAL_MODULE_TAGS := optional -LOCAL_C_INCLUDES := external/openssl/include \ - frameworks/base/cmds/keystore -EXTRA_CFLAGS := -g -O0 -DGTEST_OS_LINUX -DGTEST_HAS_STD_STRING -include $(BUILD_EXECUTABLE) - -endif #KEYSTORE_TESTS diff --git a/cmds/keystore/tests/netkeystore_test.c b/cmds/keystore/tests/netkeystore_test.c deleted file mode 100644 index e7e686bd4368..000000000000 --- a/cmds/keystore/tests/netkeystore_test.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#include "common.h" -#include "keymgmt.h" - -typedef int FUNC_PTR(); -typedef struct { - const char *name; - FUNC_PTR *func; -} TESTFUNC; - -#define FUNC_NAME(x) { #x, test_##x } -#define FUNC_BODY(x) int test_##x() - -#define TEST_PASSWD "12345678" -#define TEST_NPASSWD "11111111" -#define TEST_DIR "/data/local/tmp/keystore" -#define READONLY_DIR "/proc/keystore" -#define TEST_NAMESPACE "test" -#define TEST_KEYNAME "key" -#define TEST_KEYNAME2 "key2" -#define TEST_KEYVALUE "ANDROID" - -void setup() -{ - if (init_keystore(TEST_DIR) != 0) { - fprintf(stderr, "Can not create the test directory %s\n", TEST_DIR); - exit(-1); - } -} - -void teardown() -{ - reset_keystore(); - rmdir(TEST_DIR); -} - -FUNC_BODY(init_keystore) -{ - if (init_keystore(READONLY_DIR) == 0) return -1; - - return EXIT_SUCCESS; -} - -FUNC_BODY(reset_keystore) -{ - chdir("/procx"); - if (reset_keystore() == 0) return -1; - chdir(TEST_DIR); - return EXIT_SUCCESS; -} - -FUNC_BODY(get_state) -{ - if (get_state() != UNINITIALIZED) return -1; - passwd(TEST_PASSWD); - if (get_state() != UNLOCKED) return -1; - lock(); - if (get_state() != LOCKED) return -1; - reset_keystore(); - if (get_state() != UNINITIALIZED) return -1; - return EXIT_SUCCESS; -} - -FUNC_BODY(passwd) -{ - char buf[512]; - - if (passwd(" 23432dsfsdf") == 0) return -1; - if (passwd("dsfsdf") == 0) return -1; - passwd(TEST_PASSWD); - lock(); - if (unlock("55555555") == 0) return -1; - if (unlock(TEST_PASSWD) != 0) return -1; - - // change the password - sprintf(buf, "%s %s", "klfdjdsklfjg", "abcdefghi"); - if (passwd(buf) == 0) return -1; - - sprintf(buf, "%s %s", TEST_PASSWD, TEST_NPASSWD); - if (passwd(buf) != 0) return -1; - lock(); - - if (unlock(TEST_PASSWD) == 0) return -1; - if (unlock(TEST_NPASSWD) != 0) return -1; - - return EXIT_SUCCESS; -} - -FUNC_BODY(lock) -{ - if (lock() == 0) return -1; - passwd(TEST_PASSWD); - if (lock() != 0) return -1; - if (lock() != 0) return -1; - return EXIT_SUCCESS; -} - -FUNC_BODY(unlock) -{ - int i = MAX_RETRY_COUNT; - passwd(TEST_PASSWD); - lock(); - while (i > 1) { - if (unlock(TEST_NPASSWD) != --i) return -1; - } - if (unlock(TEST_NPASSWD) != -1) return -1; - return EXIT_SUCCESS; -} - -FUNC_BODY(put_key) -{ - int i = 0; - char keyname[512]; - - if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)) == 0) return -1; - passwd(TEST_PASSWD); - if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)) != 0) return -1; - - for(i = 0; i < 500; i++) keyname[i] = 'K'; - keyname[i] = 0; - if (put_key(TEST_NAMESPACE, keyname, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)) == 0) return -1; - if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - MAX_KEY_VALUE_LENGTH + 1) == 0) return -1; - return EXIT_SUCCESS; -} - -FUNC_BODY(get_key) -{ - int size; - unsigned char data[MAX_KEY_VALUE_LENGTH]; - - if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) == 0) return -1; - - passwd(TEST_PASSWD); - put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)); - if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) != 0) return -1; - if (memcmp(data, TEST_KEYVALUE, size) != 0) return -1; - - return EXIT_SUCCESS; -} - -FUNC_BODY(remove_key) -{ - if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1; - - passwd(TEST_PASSWD); - if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1; - - put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)); - if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) != 0) return -1; - - return EXIT_SUCCESS; -} - -FUNC_BODY(list_keys) -{ - int i; - char buf[128]; - char reply[BUFFER_MAX]; - - for(i = 0; i < 100; i++) buf[i] = 'K'; - buf[i] = 0; - - if (list_keys(TEST_NAMESPACE, reply) == 0) return -1; - - passwd(TEST_PASSWD); - if (list_keys(buf, reply) == 0) return -1; - - if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; - if (strcmp(reply, "") != 0) return -1; - - put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)); - if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; - if (strcmp(reply, TEST_KEYNAME) != 0) return -1; - - put_key(TEST_NAMESPACE, TEST_KEYNAME2, (unsigned char *)TEST_KEYVALUE, - strlen(TEST_KEYVALUE)); - - if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; - sprintf(buf, "%s %s", TEST_KEYNAME2, TEST_KEYNAME); - if (strcmp(reply, buf) != 0) return -1; - - return EXIT_SUCCESS; -} - -TESTFUNC all_tests[] = { - FUNC_NAME(init_keystore), - FUNC_NAME(reset_keystore), - FUNC_NAME(get_state), - FUNC_NAME(passwd), - FUNC_NAME(lock), - FUNC_NAME(unlock), - FUNC_NAME(put_key), - FUNC_NAME(get_key), - FUNC_NAME(remove_key), - FUNC_NAME(list_keys), -}; - -int main(int argc, char **argv) { - int i, ret; - for (i = 0 ; i < (int)(sizeof(all_tests)/sizeof(TESTFUNC)) ; ++i) { - setup(); - if ((ret = all_tests[i].func()) != EXIT_SUCCESS) { - fprintf(stderr, "ERROR in function %s\n", all_tests[i].name); - return ret; - } else { - fprintf(stderr, "function %s PASSED!\n", all_tests[i].name); - } - teardown(); - } - return EXIT_SUCCESS; -} diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index fd9e70884e68..79eb310bb0e5 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -18,6 +18,7 @@ package com.android.commands.pm; import android.content.ComponentName; import android.content.pm.ApplicationInfo; +import android.content.pm.FeatureInfo; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; @@ -34,6 +35,8 @@ import android.os.RemoteException; import android.os.ServiceManager; import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -42,21 +45,21 @@ import java.util.WeakHashMap; public final class Pm { IPackageManager mPm; - + private WeakHashMap<String, Resources> mResourceCache = new WeakHashMap<String, Resources>(); - + private String[] mArgs; private int mNextArg; private String mCurArgData; - - private static final String PM_NOT_RUNNING_ERR = + + private static final String PM_NOT_RUNNING_ERR = "Error: Could not access the Package Manager. Is the system running?"; - + public static void main(String[] args) { new Pm().run(args); } - + public void run(String[] args) { boolean validCommand = false; if (args.length < 1) { @@ -73,37 +76,37 @@ public final class Pm { mArgs = args; String op = args[0]; mNextArg = 1; - + if ("list".equals(op)) { runList(); return; } - + if ("path".equals(op)) { runPath(); return; } - + if ("install".equals(op)) { runInstall(); return; } - + if ("uninstall".equals(op)) { runUninstall(); return; } - + if ("enable".equals(op)) { runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); return; } - + if ("disable".equals(op)) { runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); return; } - + try { if (args.length == 1) { if (args[0].equalsIgnoreCase("-l")) { @@ -128,13 +131,14 @@ public final class Pm { } } } - + /** * Execute the list sub-command. - * + * * pm list [package | packages] * pm list permission-groups * pm list permissions + * pm list features * pm list instrumentation */ private void runList() { @@ -150,6 +154,8 @@ public final class Pm { runListPermissionGroups(); } else if ("permissions".equals(type)) { runListPermissions(); + } else if ("features".equals(type)) { + runListFeatures(); } else if ("instrumentation".equals(type)) { runListInstrumentation(); } else { @@ -157,7 +163,7 @@ public final class Pm { showUsage(); } } - + /** * Lists all the installed packages. */ @@ -182,10 +188,10 @@ public final class Pm { showUsage(); return; } - + try { List<PackageInfo> packages = mPm.getInstalledPackages(0 /* all */); - + int count = packages.size(); for (int p = 0 ; p < count ; p++) { PackageInfo info = packages.get(p); @@ -201,10 +207,48 @@ public final class Pm { System.err.println(PM_NOT_RUNNING_ERR); } } - + + /** + * Lists all of the features supported by the current device. + * + * pm list features + */ + private void runListFeatures() { + try { + List<FeatureInfo> list = new ArrayList<FeatureInfo>(); + FeatureInfo[] rawList = mPm.getSystemAvailableFeatures(); + for (int i=0; i<rawList.length; i++) { + list.add(rawList[i]); + } + + + // Sort by name + Collections.sort(list, new Comparator<FeatureInfo>() { + public int compare(FeatureInfo o1, FeatureInfo o2) { + if (o1.name == o2.name) return 0; + if (o1.name == null) return -1; + if (o2.name == null) return 1; + return o1.name.compareTo(o2.name); + } + }); + + int count = (list != null) ? list.size() : 0; + for (int p = 0; p < count; p++) { + FeatureInfo fi = list.get(p); + System.out.print("feature:"); + if (fi.name != null) System.out.println(fi.name); + else System.out.println("reqGlEsVersion=0x" + + Integer.toHexString(fi.reqGlEsVersion)); + } + } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); + } + } + /** * Lists all of the installed instrumentation, or all for a given package - * + * * pm list instrumentation [package] [-f] */ private void runListInstrumentation() { @@ -260,14 +304,14 @@ public final class Pm { System.err.println(PM_NOT_RUNNING_ERR); } } - + /** * Lists all the known permission groups. */ private void runListPermissionGroups() { try { List<PermissionGroupInfo> pgs = mPm.getAllPermissionGroups(0); - + int count = pgs.size(); for (int p = 0 ; p < count ; p++) { PermissionGroupInfo pgi = pgs.get(p); @@ -279,7 +323,7 @@ public final class Pm { System.err.println(PM_NOT_RUNNING_ERR); } } - + private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized) { if (nonLocalized != null) { return nonLocalized.toString(); @@ -290,7 +334,7 @@ public final class Pm { } return null; } - + /** * Lists all the permissions in a group. */ @@ -321,7 +365,7 @@ public final class Pm { return; } } - + String grp = nextOption(); ArrayList<String> groupList = new ArrayList<String>(); if (groups) { @@ -334,7 +378,7 @@ public final class Pm { } else { groupList.add(grp); } - + if (dangerousOnly) { System.out.println("Dangerous Permissions:"); System.out.println(""); @@ -365,7 +409,7 @@ public final class Pm { System.err.println(PM_NOT_RUNNING_ERR); } } - + private void doListPermissions(ArrayList<String> groupList, boolean groups, boolean labels, boolean summary, int startProtectionLevel, int endProtectionLevel) @@ -385,7 +429,7 @@ public final class Pm { pgi.nonLocalizedLabel) + ": "); } else { System.out.print(pgi.name + ": "); - + } } else { System.out.println((labels ? "+ " : "") @@ -468,13 +512,13 @@ public final class Pm { } } } - + if (summary) { System.out.println(""); } } } - + private void runPath() { String pkg = nextArg(); if (pkg == null) { @@ -484,7 +528,7 @@ public final class Pm { } displayPackageFilePath(pkg); } - + class PackageInstallObserver extends IPackageInstallObserver.Stub { boolean finished; int result; @@ -497,92 +541,40 @@ public final class Pm { } } } - + + /** + * Converts a failure code into a string by using reflection to find a matching constant + * in PackageManager. + */ private String installFailureToString(int result) { - String s; - switch (result) { - case PackageManager.INSTALL_FAILED_ALREADY_EXISTS: - s = "INSTALL_FAILED_ALREADY_EXISTS"; - break; - case PackageManager.INSTALL_FAILED_INVALID_APK: - s = "INSTALL_FAILED_INVALID_APK"; - break; - case PackageManager.INSTALL_FAILED_INVALID_URI: - s = "INSTALL_FAILED_INVALID_URI"; - break; - case PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE: - s = "INSTALL_FAILED_INSUFFICIENT_STORAGE"; - break; - case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE: - s = "INSTALL_FAILED_DUPLICATE_PACKAGE"; - break; - case PackageManager.INSTALL_FAILED_NO_SHARED_USER: - s = "INSTALL_FAILED_NO_SHARED_USER"; - break; - case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE: - s = "INSTALL_FAILED_UPDATE_INCOMPATIBLE"; - break; - case PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: - s = "INSTALL_FAILED_SHARED_USER_INCOMPATIBLE"; - break; - case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY: - s = "INSTALL_FAILED_MISSING_SHARED_LIBRARY"; - break; - case PackageManager.INSTALL_FAILED_DEXOPT: - s = "INSTALL_FAILED_DEXOPT"; - break; - case PackageManager.INSTALL_FAILED_OLDER_SDK: - s = "INSTALL_FAILED_OLDER_SDK"; - break; - case PackageManager.INSTALL_FAILED_CONFLICTING_PROVIDER: - s = "INSTALL_FAILED_CONFLICTING_PROVIDER"; - break; - case PackageManager.INSTALL_FAILED_NEWER_SDK: - s = "INSTALL_FAILED_NEWER_SDK"; - break; - case PackageManager.INSTALL_FAILED_TEST_ONLY: - s = "INSTALL_FAILED_TEST_ONLY"; - break; - case PackageManager.INSTALL_FAILED_CPU_ABI_INCOMPATIBLE: - s = "INSTALL_FAILED_CPU_ABI_INCOMPATIBLE"; - break; - case PackageManager.INSTALL_PARSE_FAILED_NOT_APK: - s = "INSTALL_PARSE_FAILED_NOT_APK"; - break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST: - s = "INSTALL_PARSE_FAILED_BAD_MANIFEST"; - break; - case PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: - s = "INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION"; - break; - case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES: - s = "INSTALL_PARSE_FAILED_NO_CERTIFICATES"; - break; - case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: - s = "INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES"; - break; - case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: - s = "INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING"; - break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: - s = "INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME"; - break; - case PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: - s = "INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID"; - break; - case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: - s = "INSTALL_PARSE_FAILED_MANIFEST_MALFORMED"; - break; - case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY: - s = "INSTALL_PARSE_FAILED_MANIFEST_EMPTY"; - break; - default: - s = Integer.toString(result); - break; - } - return s; + Field[] fields = PackageManager.class.getFields(); + for (Field f: fields) { + if (f.getType() == int.class) { + int modifiers = f.getModifiers(); + // only look at public final static fields. + if (((modifiers & Modifier.FINAL) != 0) && + ((modifiers & Modifier.PUBLIC) != 0) && + ((modifiers & Modifier.STATIC) != 0)) { + String fieldName = f.getName(); + if (fieldName.startsWith("INSTALL_FAILED_") || + fieldName.startsWith("INSTALL_PARSE_FAILED_")) { + // get the int value and compare it to result. + try { + if (result == f.getInt(null)) { + return fieldName; + } + } catch (IllegalAccessException e) { + // this shouldn't happen since we only look for public static fields. + } + } + } + } + } + + // couldn't find a matching constant? return the value + return Integer.toString(result); } - + private void runInstall() { int installFlags = 0; String installerPackageName = null; @@ -621,7 +613,7 @@ public final class Pm { try { mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags, installerPackageName); - + synchronized (obs) { while (!obs.finished) { try { @@ -642,11 +634,11 @@ public final class Pm { System.err.println(PM_NOT_RUNNING_ERR); } } - + class PackageDeleteObserver extends IPackageDeleteObserver.Stub { boolean finished; boolean result; - + public void packageDeleted(boolean succeeded) { synchronized (this) { finished = true; @@ -655,7 +647,7 @@ public final class Pm { } } } - + private void runUninstall() { int unInstallFlags = 0; @@ -709,7 +701,7 @@ public final class Pm { } return "unknown"; } - + private void runSetEnabledSetting(int state) { String pkg = nextArg(); if (pkg == null) { @@ -757,11 +749,11 @@ public final class Pm { System.err.println(PM_NOT_RUNNING_ERR); } } - + private Resources getResources(PackageItemInfo pii) { Resources res = mResourceCache.get(pii.packageName); if (res != null) return res; - + try { ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0); AssetManager am = new AssetManager(); @@ -775,7 +767,7 @@ public final class Pm { return null; } } - + private String nextOption() { if (mNextArg >= mArgs.length) { return null; @@ -827,7 +819,8 @@ public final class Pm { System.err.println(" pm list packages [-f]"); System.err.println(" pm list permission-groups"); System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); - System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); + System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); + System.err.println(" pm list features"); System.err.println(" pm path PACKAGE"); System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] PATH"); System.err.println(" pm uninstall [-k] PACKAGE"); @@ -852,6 +845,8 @@ public final class Pm { System.err.println("or only those that target a specified package. Options:"); System.err.println(" -f: see their associated file."); System.err.println(""); + System.err.println("The list features command prints all features of the system."); + System.err.println(""); System.err.println("The path command prints the path to the .apk of a package."); System.err.println(""); System.err.println("The install command installs a package to the system. Options:"); diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk index 521eb2b2863e..6a72d1070850 100644 --- a/cmds/runtime/Android.mk +++ b/cmds/runtime/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libutils \ + libbinder \ libandroid_runtime \ libcutils \ libui \ diff --git a/cmds/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp index 758a95c07d56..b2bef07ff70e 100644 --- a/cmds/runtime/ServiceManager.cpp +++ b/cmds/runtime/ServiceManager.cpp @@ -9,9 +9,9 @@ #include <utils/Debug.h> #include <utils/Log.h> -#include <utils/Parcel.h> +#include <binder/Parcel.h> #include <utils/String8.h> -#include <utils/ProcessState.h> +#include <binder/ProcessState.h> #include <private/utils/Static.h> diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h index d09cec8ddad8..090ca6de648b 100644 --- a/cmds/runtime/ServiceManager.h +++ b/cmds/runtime/ServiceManager.h @@ -4,7 +4,7 @@ #ifndef ANDROID_SERVICE_MANAGER_H #define ANDROID_SERVICE_MANAGER_H -#include <utils/IServiceManager.h> +#include <binder/IServiceManager.h> #include <utils/KeyedVector.h> #include <utils/threads.h> diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp index 476f38a4d073..21e0e4d02662 100644 --- a/cmds/runtime/main_runtime.cpp +++ b/cmds/runtime/main_runtime.cpp @@ -7,9 +7,11 @@ #include "ServiceManager.h" #include "SignalHandler.h" -#include <utils.h> -#include <utils/IPCThreadState.h> -#include <utils/ProcessState.h> +#include <utils/threads.h> +#include <utils/Errors.h> + +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> #include <utils/Log.h> #include <cutils/zygote.h> diff --git a/cmds/service/Android.mk b/cmds/service/Android.mk index 8c5005c1fbb1..275bbb2e17be 100644 --- a/cmds/service/Android.mk +++ b/cmds/service/Android.mk @@ -4,8 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ service.cpp -LOCAL_SHARED_LIBRARIES := \ - libutils +LOCAL_SHARED_LIBRARIES := libutils libbinder ifeq ($(TARGET_OS),linux) LOCAL_CFLAGS += -DXP_UNIX diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp index 859a9bf9f93c..32db83ba1dcb 100644 --- a/cmds/service/service.cpp +++ b/cmds/service/service.cpp @@ -3,9 +3,9 @@ * */ -#include <utils/Parcel.h> -#include <utils/ProcessState.h> -#include <utils/IServiceManager.h> +#include <binder/Parcel.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> #include <utils/TextOutput.h> #include <getopt.h> diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index e4aa8b51cf2a..f3a471394b6a 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -30,6 +30,7 @@ static struct { { AID_MEDIA, "media.audio_flinger" }, { AID_MEDIA, "media.player" }, { AID_MEDIA, "media.camera" }, + { AID_MEDIA, "media.audio_policy" }, { AID_RADIO, "radio.phone" }, { AID_RADIO, "radio.sms" }, { AID_RADIO, "radio.phonesubinfo" }, diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk new file mode 100644 index 000000000000..5b5525240f02 --- /dev/null +++ b/cmds/stagefright/Android.mk @@ -0,0 +1,46 @@ +ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true) + +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + stagefright.cpp + +LOCAL_SHARED_LIBRARIES := \ + libstagefright + +LOCAL_C_INCLUDES:= \ + $(JNI_H_INCLUDE) \ + frameworks/base/media/libstagefright \ + $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include + +LOCAL_CFLAGS += -Wno-multichar + +LOCAL_MODULE:= stagefright + +include $(BUILD_EXECUTABLE) + +################################################################################ + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + SineSource.cpp \ + record.cpp + +LOCAL_SHARED_LIBRARIES := \ + libstagefright + +LOCAL_C_INCLUDES:= \ + $(JNI_H_INCLUDE) \ + frameworks/base/media/libstagefright \ + $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include + +LOCAL_CFLAGS += -Wno-multichar + +LOCAL_MODULE:= record + +include $(BUILD_EXECUTABLE) + +endif diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp new file mode 100644 index 000000000000..e5a6ccb6b32a --- /dev/null +++ b/cmds/stagefright/SineSource.cpp @@ -0,0 +1,101 @@ +#include "SineSource.h" + +#include <math.h> + +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MetaData.h> + +namespace android { + +SineSource::SineSource(int32_t sampleRate, int32_t numChannels) + : mStarted(false), + mSampleRate(sampleRate), + mNumChannels(numChannels), + mPhase(0), + mGroup(NULL) { + CHECK(numChannels == 1 || numChannels == 2); +} + +SineSource::~SineSource() { + if (mStarted) { + stop(); + } +} + +status_t SineSource::start(MetaData *params) { + CHECK(!mStarted); + + mGroup = new MediaBufferGroup; + mGroup->add_buffer(new MediaBuffer(kBufferSize)); + + mPhase = 0; + mStarted = true; + + return OK; +} + +status_t SineSource::stop() { + CHECK(mStarted); + + delete mGroup; + mGroup = NULL; + + mStarted = false; + + return OK; +} + +sp<MetaData> SineSource::getFormat() { + sp<MetaData> meta = new MetaData; + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); + meta->setInt32(kKeyChannelCount, mNumChannels); + meta->setInt32(kKeySampleRate, mSampleRate); + + return meta; +} + +status_t SineSource::read( + MediaBuffer **out, const ReadOptions *options) { + *out = NULL; + + MediaBuffer *buffer; + status_t err = mGroup->acquire_buffer(&buffer); + + if (err != OK) { + return err; + } + + size_t frameSize = mNumChannels * sizeof(int16_t); + size_t numFramesPerBuffer = buffer->size() / frameSize; + + int16_t *ptr = (int16_t *)buffer->data(); + + const double k = kFrequency / mSampleRate * (2.0 * M_PI); + + double x = mPhase * k; + for (size_t i = 0; i < numFramesPerBuffer; ++i) { + int16_t amplitude = (int16_t)(32767.0 * sin(x)); + + *ptr++ = amplitude; + if (mNumChannels == 2) { + *ptr++ = amplitude; + } + + x += k; + } + + buffer->meta_data()->setInt32(kKeyTimeUnits, mPhase); + buffer->meta_data()->setInt32(kKeyTimeScale, mSampleRate); + + mPhase += numFramesPerBuffer; + + buffer->set_range(0, numFramesPerBuffer * frameSize); + + *out = buffer; + + return OK; +} + +} // namespace android diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h new file mode 100644 index 000000000000..76ab669fbfc6 --- /dev/null +++ b/cmds/stagefright/SineSource.h @@ -0,0 +1,39 @@ +#ifndef SINE_SOURCE_H_ + +#define SINE_SOURCE_H_ + +#include <media/stagefright/MediaSource.h> + +namespace android { + +struct MediaBufferGroup; + +struct SineSource : public MediaSource { + SineSource(int32_t sampleRate, int32_t numChannels); + + virtual status_t start(MetaData *params); + virtual status_t stop(); + + virtual sp<MetaData> getFormat(); + + virtual status_t read( + MediaBuffer **out, const ReadOptions *options = NULL); + +protected: + virtual ~SineSource(); + +private: + enum { kBufferSize = 8192 }; + static const double kFrequency = 500.0; + + bool mStarted; + int32_t mSampleRate; + int32_t mNumChannels; + size_t mPhase; + + MediaBufferGroup *mGroup; +}; + +} // namespace android + +#endif // SINE_SOURCE_H_ diff --git a/cmds/stagefright/WaveWriter.h b/cmds/stagefright/WaveWriter.h new file mode 100644 index 000000000000..a0eb66e2b9bc --- /dev/null +++ b/cmds/stagefright/WaveWriter.h @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ + +#ifndef ANDROID_WAVEWRITER_H_ + +#define ANDROID_WAVEWRITER_H_ + +namespace android { + +class WaveWriter { +public: + WaveWriter(const char *filename, + uint16_t num_channels, uint32_t sampling_rate) + : mFile(fopen(filename, "wb")), + mTotalBytes(0) { + fwrite("RIFFxxxxWAVEfmt \x10\x00\x00\x00\x01\x00", 1, 22, mFile); + write_u16(num_channels); + write_u32(sampling_rate); + write_u32(sampling_rate * num_channels * 2); + write_u16(num_channels * 2); + write_u16(16); + fwrite("dataxxxx", 1, 8, mFile); + } + + ~WaveWriter() { + fseek(mFile, 40, SEEK_SET); + write_u32(mTotalBytes); + + fseek(mFile, 4, SEEK_SET); + write_u32(36 + mTotalBytes); + + fclose(mFile); + mFile = NULL; + } + + void Append(const void *data, size_t size) { + fwrite(data, 1, size, mFile); + mTotalBytes += size; + } + +private: + void write_u16(uint16_t x) { + fputc(x & 0xff, mFile); + fputc(x >> 8, mFile); + } + + void write_u32(uint32_t x) { + write_u16(x & 0xffff); + write_u16(x >> 16); + } + + FILE *mFile; + size_t mTotalBytes; +}; + +} // namespace android + +#endif // ANDROID_WAVEWRITER_H_ diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp new file mode 100644 index 000000000000..323d448663f9 --- /dev/null +++ b/cmds/stagefright/record.cpp @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ + +#include "SineSource.h" + +#include <binder/ProcessState.h> +#include <media/stagefright/AudioPlayer.h> +#include <media/stagefright/CameraSource.h> +#include <media/stagefright/MediaBufferGroup.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/MPEG4Extractor.h> +#include <media/stagefright/MPEG4Writer.h> +#include <media/stagefright/MmapSource.h> +#include <media/stagefright/OMXClient.h> +#include <media/stagefright/OMXCodec.h> +#include <media/MediaPlayerInterface.h> + +using namespace android; + +#if 0 +class DummySource : public MediaSource { +public: + DummySource(int width, int height) + : mWidth(width), + mHeight(height), + mSize((width * height * 3) / 2) { + mGroup.add_buffer(new MediaBuffer(mSize)); + } + + virtual sp<MetaData> getFormat() { + sp<MetaData> meta = new MetaData; + meta->setInt32(kKeyWidth, mWidth); + meta->setInt32(kKeyHeight, mHeight); + meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); + + return meta; + } + + virtual status_t start(MetaData *params) { + return OK; + } + + virtual status_t stop() { + return OK; + } + + virtual status_t read( + MediaBuffer **buffer, const MediaSource::ReadOptions *options) { + status_t err = mGroup.acquire_buffer(buffer); + if (err != OK) { + return err; + } + + char x = (char)((double)rand() / RAND_MAX * 255); + memset((*buffer)->data(), x, mSize); + (*buffer)->set_range(0, mSize); + + return OK; + } + +protected: + virtual ~DummySource() {} + +private: + MediaBufferGroup mGroup; + int mWidth, mHeight; + size_t mSize; + + DummySource(const DummySource &); + DummySource &operator=(const DummySource &); +}; + +sp<MediaSource> createSource(const char *filename) { + sp<MediaSource> source; + + sp<MPEG4Extractor> extractor = + new MPEG4Extractor(new MmapSource(filename)); + + size_t num_tracks = extractor->countTracks(); + + sp<MetaData> meta; + for (size_t i = 0; i < num_tracks; ++i) { + meta = extractor->getTrackMetaData(i); + CHECK(meta.get() != NULL); + + const char *mime; + if (!meta->findCString(kKeyMIMEType, &mime)) { + continue; + } + + if (strncasecmp(mime, "video/", 6)) { + continue; + } + + source = extractor->getTrack(i); + break; + } + + return source; +} + +int main(int argc, char **argv) { + android::ProcessState::self()->startThreadPool(); + +#if 1 + if (argc != 2) { + fprintf(stderr, "usage: %s filename\n", argv[0]); + return 1; + } + + OMXClient client; + CHECK_EQ(client.connect(), OK); + +#if 0 + sp<MediaSource> source = createSource(argv[1]); + + if (source == NULL) { + fprintf(stderr, "Unable to find a suitable video track.\n"); + return 1; + } + + sp<MetaData> meta = source->getFormat(); + + sp<OMXCodec> decoder = OMXCodec::Create( + client.interface(), meta, false /* createEncoder */, source); + + int width, height; + bool success = meta->findInt32(kKeyWidth, &width); + success = success && meta->findInt32(kKeyHeight, &height); + CHECK(success); +#else + int width = 320; + int height = 240; + sp<MediaSource> decoder = new DummySource(width, height); +#endif + + sp<MetaData> enc_meta = new MetaData; + // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); + enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); + enc_meta->setInt32(kKeyWidth, width); + enc_meta->setInt32(kKeyHeight, height); + + sp<OMXCodec> encoder = + OMXCodec::Create( + client.interface(), enc_meta, true /* createEncoder */, decoder); + +#if 0 + sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4"); + writer->addSource(enc_meta, encoder); + writer->start(); + sleep(20); + printf("stopping now.\n"); + writer->stop(); +#else + encoder->start(); + + MediaBuffer *buffer; + while (encoder->read(&buffer) == OK) { + printf("got an output frame of size %d\n", buffer->range_length()); + + buffer->release(); + buffer = NULL; + } + + encoder->stop(); +#endif + + client.disconnect(); +#endif + +#if 0 + CameraSource *source = CameraSource::Create(); + printf("source = %p\n", source); + + for (int i = 0; i < 100; ++i) { + MediaBuffer *buffer; + status_t err = source->read(&buffer); + CHECK_EQ(err, OK); + + printf("got a frame, data=%p, size=%d\n", + buffer->data(), buffer->range_length()); + + buffer->release(); + buffer = NULL; + } + + delete source; + source = NULL; +#endif + + return 0; +} +#else + +int main(int argc, char **argv) { + android::ProcessState::self()->startThreadPool(); + + OMXClient client; + CHECK_EQ(client.connect(), OK); + + const int32_t kSampleRate = 22050; + const int32_t kNumChannels = 2; + sp<MediaSource> audioSource = new SineSource(kSampleRate, kNumChannels); + +#if 0 + sp<MediaPlayerBase::AudioSink> audioSink; + AudioPlayer *player = new AudioPlayer(audioSink); + player->setSource(audioSource); + player->start(); + + sleep(10); + + player->stop(); +#endif + + sp<MetaData> encMeta = new MetaData; + encMeta->setCString(kKeyMIMEType, + 1 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC); + encMeta->setInt32(kKeySampleRate, kSampleRate); + encMeta->setInt32(kKeyChannelCount, kNumChannels); + encMeta->setInt32(kKeyMaxInputSize, 8192); + + sp<MediaSource> encoder = + OMXCodec::Create(client.interface(), encMeta, true, audioSource); + + encoder->start(); + + int32_t n = 0; + status_t err; + MediaBuffer *buffer; + while ((err = encoder->read(&buffer)) == OK) { + printf("."); + fflush(stdout); + + buffer->release(); + buffer = NULL; + + if (++n == 100) { + break; + } + } + printf("$\n"); + + encoder->stop(); + + client.disconnect(); + + return 0; +} +#endif diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp new file mode 100644 index 000000000000..4ffc8e437551 --- /dev/null +++ b/cmds/stagefright/stagefright.cpp @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * 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. + */ + +#include <sys/time.h> + +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <binder/IServiceManager.h> +#include <binder/ProcessState.h> +#include <media/IMediaPlayerService.h> +#include <media/stagefright/CachingDataSource.h> +#include <media/stagefright/HTTPDataSource.h> +#include <media/stagefright/JPEGSource.h> +#include <media/stagefright/MediaDebug.h> +#include <media/stagefright/MediaDefs.h> +#include <media/stagefright/MediaPlayerImpl.h> +#include <media/stagefright/MediaExtractor.h> +#include <media/stagefright/MediaSource.h> +#include <media/stagefright/MetaData.h> +#include <media/stagefright/MmapSource.h> +#include <media/stagefright/OMXClient.h> +#include <media/stagefright/OMXCodec.h> + +using namespace android; + +static long gNumRepetitions; +static long gMaxNumFrames; // 0 means decode all available. +static long gReproduceBug; // if not -1. + +static int64_t getNowUs() { + struct timeval tv; + gettimeofday(&tv, NULL); + + return (int64_t)tv.tv_usec + tv.tv_sec * 1000000; +} + +static void playSource(OMXClient *client, const sp<MediaSource> &source) { + sp<MetaData> meta = source->getFormat(); + + int32_t durationUnits; + int32_t timeScale; + CHECK(meta->findInt32(kKeyDuration, &durationUnits)); + CHECK(meta->findInt32(kKeyTimeScale, &timeScale)); + + int64_t durationUs = ((int64_t)durationUnits * 1000000) / timeScale; + + sp<OMXCodec> decoder = OMXCodec::Create( + client->interface(), meta, false /* createEncoder */, source); + + if (decoder == NULL) { + return; + } + + decoder->start(); + + if (gReproduceBug >= 3 && gReproduceBug <= 5) { + status_t err; + MediaBuffer *buffer; + MediaSource::ReadOptions options; + int64_t seekTimeUs = -1; + for (;;) { + err = decoder->read(&buffer, &options); + options.clearSeekTo(); + + bool shouldSeek = false; + if (err != OK) { + printf("reached EOF.\n"); + + shouldSeek = true; + } else { + int32_t timestampUnits; + CHECK(buffer->meta_data()->findInt32(kKeyTimeUnits, ×tampUnits)); + + int64_t timestampUs = ((int64_t)timestampUnits * 1000000) / timeScale; + + bool failed = false; + + if (seekTimeUs >= 0) { + int64_t diff = timestampUs - seekTimeUs; + if (diff < 0) { + diff = -diff; + } + + if ((gReproduceBug == 4 && diff > 500000) + || (gReproduceBug == 5 && timestampUs < 0)) { + printf("wanted: %.2f secs, got: %.2f secs\n", + seekTimeUs / 1E6, timestampUs / 1E6); + + printf("ERROR: "); + failed = true; + } + } + + printf("buffer has timestamp %lld us (%.2f secs)\n", + timestampUs, timestampUs / 1E6); + + buffer->release(); + buffer = NULL; + + if (failed) { + break; + } + + shouldSeek = ((double)rand() / RAND_MAX) < 0.1; + + if (gReproduceBug == 3) { + shouldSeek = false; + } + } + + seekTimeUs = -1; + + if (shouldSeek) { + seekTimeUs = (rand() * (float)durationUs) / RAND_MAX; + options.setSeekTo(seekTimeUs); + + printf("seeking to %lld us (%.2f secs)\n", + seekTimeUs, seekTimeUs / 1E6); + } + } + + decoder->stop(); + + return; + } + + int n = 0; + int64_t startTime = getNowUs(); + + long numIterationsLeft = gNumRepetitions; + MediaSource::ReadOptions options; + + while (numIterationsLeft-- > 0) { + long numFrames = 0; + + MediaBuffer *buffer; + + for (;;) { + status_t err = decoder->read(&buffer, &options); + options.clearSeekTo(); + + if (err != OK) { + CHECK_EQ(buffer, NULL); + + break; + } + + if ((n++ % 16) == 0) { + printf("."); + fflush(stdout); + } + + buffer->release(); + buffer = NULL; + + ++numFrames; + if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) { + break; + } + + if (gReproduceBug == 1 && numFrames == 40) { + printf("seeking past the end now."); + options.setSeekTo(0x7fffffffL); + } else if (gReproduceBug == 2 && numFrames == 40) { + printf("seeking to 5 secs."); + options.setSeekTo(5000000); + } + } + + printf("$"); + fflush(stdout); + + options.setSeekTo(0); + } + + decoder->stop(); + printf("\n"); + + int64_t delay = getNowUs() - startTime; + printf("avg. %.2f fps\n", n * 1E6 / delay); + + printf("decoded a total of %d frame(s).\n", n); +} + +static void usage(const char *me) { + fprintf(stderr, "usage: %s\n", me); + fprintf(stderr, " -h(elp)\n"); + fprintf(stderr, " -a(udio)\n"); + fprintf(stderr, " -n repetitions\n"); + fprintf(stderr, " -l(ist) components\n"); + fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n"); + fprintf(stderr, " -b bug to reproduce\n"); + fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n"); +} + +int main(int argc, char **argv) { + android::ProcessState::self()->startThreadPool(); + + bool audioOnly = false; + bool listComponents = false; + bool dumpProfiles = false; + gNumRepetitions = 1; + gMaxNumFrames = 0; + gReproduceBug = -1; + + int res; + while ((res = getopt(argc, argv, "han:lm:b:p")) >= 0) { + switch (res) { + case 'a': + { + audioOnly = true; + break; + } + + case 'l': + { + listComponents = true; + break; + } + + case 'm': + case 'n': + case 'b': + { + char *end; + long x = strtol(optarg, &end, 10); + + if (*end != '\0' || end == optarg || x <= 0) { + x = 1; + } + + if (res == 'n') { + gNumRepetitions = x; + } else if (res == 'm') { + gMaxNumFrames = x; + } else { + CHECK_EQ(res, 'b'); + gReproduceBug = x; + } + break; + } + + case 'p': + { + dumpProfiles = true; + break; + } + + case '?': + case 'h': + default: + { + usage(argv[0]); + exit(1); + break; + } + } + } + + argc -= optind; + argv += optind; + + if (dumpProfiles) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("media.player")); + sp<IMediaPlayerService> service = + interface_cast<IMediaPlayerService>(binder); + + CHECK(service.get() != NULL); + + sp<IOMX> omx = service->getOMX(); + CHECK(omx.get() != NULL); + + const char *kMimeTypes[] = { + MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4, + MEDIA_MIMETYPE_VIDEO_H263 + }; + + for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); + ++k) { + printf("type '%s':\n", kMimeTypes[k]); + + Vector<CodecCapabilities> results; + CHECK_EQ(QueryCodecs(omx, kMimeTypes[k], + true, // queryDecoders + &results), OK); + + for (size_t i = 0; i < results.size(); ++i) { + printf(" decoder '%s' supports ", + results[i].mComponentName.string()); + + if (results[i].mProfileLevels.size() == 0) { + printf("NOTHING.\n"); + continue; + } + + for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) { + const CodecProfileLevel &profileLevel = + results[i].mProfileLevels[j]; + + printf("%s%ld/%ld", j > 0 ? ", " : "", + profileLevel.mProfile, profileLevel.mLevel); + } + + printf("\n"); + } + } + } + + if (listComponents) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("media.player")); + sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); + + CHECK(service.get() != NULL); + + sp<IOMX> omx = service->getOMX(); + CHECK(omx.get() != NULL); + + List<String8> list; + omx->listNodes(&list); + + for (List<String8>::iterator it = list.begin(); + it != list.end(); ++it) { + printf("%s\n", (*it).string()); + } + } + + DataSource::RegisterDefaultSniffers(); + + OMXClient client; + status_t err = client.connect(); + + for (int k = 0; k < argc; ++k) { + const char *filename = argv[k]; + + sp<DataSource> dataSource; + if (!strncasecmp("http://", filename, 7)) { + dataSource = new HTTPDataSource(filename); + dataSource = new CachingDataSource(dataSource, 64 * 1024, 10); + } else { + dataSource = new MmapSource(filename); + } + + bool isJPEG = false; + + size_t len = strlen(filename); + if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) { + isJPEG = true; + } + + sp<MediaSource> mediaSource; + + if (isJPEG) { + mediaSource = new JPEGSource(dataSource); + } else { + sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); + + size_t numTracks = extractor->countTracks(); + + sp<MetaData> meta; + size_t i; + for (i = 0; i < numTracks; ++i) { + meta = extractor->getTrackMetaData(i); + + const char *mime; + meta->findCString(kKeyMIMEType, &mime); + + if (audioOnly && !strncasecmp(mime, "audio/", 6)) { + break; + } + + if (!audioOnly && !strncasecmp(mime, "video/", 6)) { + break; + } + } + + mediaSource = extractor->getTrack(i); + } + + playSource(&client, mediaSource); + } + + client.disconnect(); + + return 0; +} diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk index 37c3d942414a..bfa58a1cbf7f 100644 --- a/cmds/surfaceflinger/Android.mk +++ b/cmds/surfaceflinger/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libsurfaceflinger \ + libbinder \ libutils LOCAL_C_INCLUDES := \ diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp index 7c895783d762..d65072132783 100644 --- a/cmds/surfaceflinger/main_surfaceflinger.cpp +++ b/cmds/surfaceflinger/main_surfaceflinger.cpp @@ -1,6 +1,6 @@ -#include <utils/IPCThreadState.h> -#include <utils/ProcessState.h> -#include <utils/IServiceManager.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> #include <utils/Log.h> #include <SurfaceFlinger.h> diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java index 2b54f549f389..e021012268c9 100644 --- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java +++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java @@ -16,7 +16,10 @@ package com.android.commands.svc; +import android.os.Binder; +import android.os.IBinder; import android.os.IPowerManager; +import android.os.PowerManager; import android.os.ServiceManager; import android.os.RemoteException; import android.os.BatteryManager; @@ -60,7 +63,10 @@ public class PowerCommand extends Svc.Command { IPowerManager pm = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE)); try { + IBinder lock = new Binder(); + pm.acquireWakeLock(PowerManager.FULL_WAKE_LOCK, lock, "svc power"); pm.setStayOnSetting(val); + pm.releaseWakeLock(lock); } catch (RemoteException e) { System.err.println("Faild to set setting: " + e); diff --git a/cmds/system_server/Android.mk b/cmds/system_server/Android.mk index 0a684e86b1c7..ad537977d9eb 100644 --- a/cmds/system_server/Android.mk +++ b/cmds/system_server/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libutils \ + libbinder \ libsystem_server LOCAL_C_INCLUDES := \ diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk index 580331a695af..1813d3e5ab0c 100644 --- a/cmds/system_server/library/Android.mk +++ b/cmds/system_server/library/Android.mk @@ -20,6 +20,7 @@ LOCAL_SHARED_LIBRARIES := \ libcameraservice \ libmediaplayerservice \ libutils \ + libbinder \ libcutils LOCAL_MODULE:= libsystem_server diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp index 73b23e27e3bd..1d57fdcc4c77 100644 --- a/cmds/system_server/library/system_init.cpp +++ b/cmds/system_server/library/system_init.cpp @@ -8,15 +8,16 @@ #define LOG_TAG "sysproc" -#include <utils/IPCThreadState.h> -#include <utils/ProcessState.h> -#include <utils/IServiceManager.h> +#include <binder/IPCThreadState.h> +#include <binder/ProcessState.h> +#include <binder/IServiceManager.h> #include <utils/TextOutput.h> #include <utils/Log.h> #include <SurfaceFlinger.h> #include <AudioFlinger.h> #include <CameraService.h> +#include <AudioPolicyService.h> #include <MediaPlayerService.h> #include <android_runtime/AndroidRuntime.h> @@ -80,6 +81,9 @@ extern "C" status_t system_init() // Start the camera service CameraService::instantiate(); + + // Start the audio policy service + AudioPolicyService::instantiate(); } // And now start the Android runtime. We have to do this bit diff --git a/cmds/system_server/system_main.cpp b/cmds/system_server/system_main.cpp index ca16e5700622..543f650a4d22 100644 --- a/cmds/system_server/system_main.cpp +++ b/cmds/system_server/system_main.cpp @@ -9,7 +9,7 @@ #define LOG_TAG "sysproc" -#include <utils/IPCThreadState.h> +#include <binder/IPCThreadState.h> #include <utils/Log.h> #include <private/android_filesystem_config.h> |