diff options
Diffstat (limited to 'cmds')
47 files changed, 835 insertions, 6465 deletions
diff --git a/cmds/am/Android.mk b/cmds/am/Android.mk index 8b321b3..f8350dc 100644 --- a/cmds/am/Android.mk +++ b/cmds/am/Android.mk @@ -1,31 +1,15 @@ # Copyright 2008 The Android Open Source Project # LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) +include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_MODULE := am include $(BUILD_JAVA_LIBRARY) include $(CLEAR_VARS) -ALL_PREBUILT += $(TARGET_OUT)/bin/am -$(TARGET_OUT)/bin/am : $(LOCAL_PATH)/am | $(ACP) - $(transform-prebuilt-to-target) - -NOTICE_FILE := NOTICE -files_noticed := bin/am - -# Generate rules for a single file. The argument is the file path relative to -# the installation root -define make-notice-file - -$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE) - @echo Notice file: $$< -- $$@ - @mkdir -p $$(dir $$@) - @cat $$< >> $$@ - -$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt - -endef - -$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file)))) +LOCAL_MODULE := am +LOCAL_SRC_FILES := am +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index add7a23..ccb9e1f 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -24,8 +24,8 @@ import android.app.IActivityController; import android.app.IActivityManager; import android.app.IInstrumentationWatcher; import android.app.Instrumentation; +import android.app.UiAutomationConnection; import android.content.ComponentName; -import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; import android.content.pm.IPackageManager; @@ -38,8 +38,8 @@ import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserHandle; import android.util.AndroidException; -import android.view.Display; import android.view.IWindowManager; +import com.android.internal.os.BaseCommand; import java.io.BufferedReader; import java.io.File; @@ -51,12 +51,9 @@ import java.net.URISyntaxException; import java.util.HashSet; import java.util.List; -public class Am { +public class Am extends BaseCommand { private IActivityManager mAm; - private String[] mArgs; - private int mNextArg; - private String mCurArgData; private int mStartFlags = 0; private boolean mWaitOption = false; @@ -64,36 +61,159 @@ public class Am { private int mRepeat = 0; private int mUserId; + private String mReceiverPermission; private String mProfileFile; - // 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) { - try { - (new Am()).run(args); - } catch (IllegalArgumentException e) { - showUsage(); - System.err.println("Error: " + e.getMessage()); - } catch (Exception e) { - e.printStackTrace(System.err); - System.exit(1); - } + (new Am()).run(args); } - private void run(String[] args) throws Exception { - if (args.length < 1) { - showUsage(); - return; - } + public void onShowUsage(PrintStream out) { + out.println( + "usage: am [subcommand] [options]\n" + + "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + + " [--R COUNT] [-S] [--opengl-trace]\n" + + " [--user <USER_ID> | current] <INTENT>\n" + + " am startservice [--user <USER_ID> | current] <INTENT>\n" + + " am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" + + " am kill [--user <USER_ID> | all | current] <PACKAGE>\n" + + " am kill-all\n" + + " am broadcast [--user <USER_ID> | all | current] <INTENT>\n" + + " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + + " [--user <USER_ID> | current]\n" + + " [--no-window-animation] <COMPONENT>\n" + + " am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" + + " am profile stop [--user <USER_ID> current] [<PROCESS>]\n" + + " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + + " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + + " am clear-debug-app\n" + + " am monitor [--gdb <port>]\n" + + " am screen-compat [on|off] <PACKAGE>\n" + + " am to-uri [INTENT]\n" + + " am to-intent-uri [INTENT]\n" + + " am switch-user <USER_ID>\n" + + " am stop-user <USER_ID>\n" + + "\n" + + "am start: start an Activity. Options are:\n" + + " -D: enable debugging\n" + + " -W: wait for launch to complete\n" + + " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + + " -P <FILE>: like above, but profiling stops when app goes idle\n" + + " -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" + + " the top activity will be finished.\n" + + " -S: force stop the target app before starting the activity\n" + + " --opengl-trace: enable tracing of OpenGL functions\n" + + " --user <USER_ID> | current: Specify which user to run as; if not\n" + + " specified then run as the current user.\n" + + "\n" + + "am startservice: start a Service. Options are:\n" + + " --user <USER_ID> | current: Specify which user to run as; if not\n" + + " specified then run as the current user.\n" + + "\n" + + "am force-stop: force stop everything associated with <PACKAGE>.\n" + + " --user <USER_ID> | all | current: Specify user to force stop;\n" + + " all users if not specified.\n" + + "\n" + + "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" + + " processes that are safe to kill -- that is, will not impact the user\n" + + " experience.\n" + + " --user <USER_ID> | all | current: Specify user whose processes to kill;\n" + + " all users if not specified.\n" + + "\n" + + "am kill-all: Kill all background processes.\n" + + "\n" + + "am broadcast: send a broadcast Intent. Options are:\n" + + " --user <USER_ID> | all | current: Specify which user to send to; if not\n" + + " specified then send to all users.\n" + + " --receiver-permission <PERMISSION>: Require receiver to hold permission.\n" + + "\n" + + "am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" + + " is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:\n" + + " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with\n" + + " [-e perf true] to generate raw output for performance measurements.\n" + + " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a\n" + + " common form is [-e <testrunner_flag> <value>[,<value>...]].\n" + + " -p <FILE>: write profiling data to <FILE>\n" + + " -w: wait for instrumentation to finish before returning. Required for\n" + + " test runners.\n" + + " --user <USER_ID> | current: Specify user instrumentation runs in;\n" + + " current user if not specified.\n" + + " --no-window-animation: turn off window animations will running.\n" + + "\n" + + "am profile: start and stop profiler on a process. The given <PROCESS> argument\n" + + " may be either a process name or pid. Options are:\n" + + " --user <USER_ID> | current: When supplying a process name,\n" + + " specify user of process to profile; uses current user if not specified.\n" + + "\n" + + "am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" + + " be either a process name or pid. Options are:\n" + + " -n: dump native heap instead of managed heap\n" + + " --user <USER_ID> | current: When supplying a process name,\n" + + " specify user of process to dump; uses current user if not specified.\n" + + "\n" + + "am set-debug-app: set application <PACKAGE> to debug. Options are:\n" + + " -w: wait for debugger when application starts\n" + + " --persistent: retain this value\n" + + "\n" + + "am clear-debug-app: clear the previously set-debug-app.\n" + + "\n" + + "am bug-report: request bug report generation; will launch UI\n" + + " when done to select where it should be delivered.\n" + + "\n" + + "am monitor: start monitoring for crashes or ANRs.\n" + + " --gdb: start gdbserv on the given port at crash/ANR\n" + + "\n" + + "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + + "\n" + + "am to-uri: print the given Intent specification as a URI.\n" + + "\n" + + "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + + "\n" + + "am switch-user: switch to put USER_ID in the foreground, starting\n" + + " execution of that user if it is currently stopped.\n" + + "\n" + + "am stop-user: stop execution of USER_ID, not allowing it to run any\n" + + " code until a later explicit switch to it.\n" + + "\n" + + "<INTENT> specifications include these flags and arguments:\n" + + " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + + " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + + " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + + " [--esn <EXTRA_KEY> ...]\n" + + " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + + " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + + " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + + " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" + + " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" + + " [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" + + " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + + " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + + " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + + " [-n <COMPONENT>] [-f <FLAGS>]\n" + + " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + + " [--debug-log-resolution] [--exclude-stopped-packages]\n" + + " [--include-stopped-packages]\n" + + " [--activity-brought-to-front] [--activity-clear-top]\n" + + " [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" + + " [--activity-launched-from-history] [--activity-multiple-task]\n" + + " [--activity-no-animation] [--activity-no-history]\n" + + " [--activity-no-user-action] [--activity-previous-is-top]\n" + + " [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" + + " [--activity-single-top] [--activity-clear-task]\n" + + " [--activity-task-on-home]\n" + + " [--receiver-registered-only] [--receiver-replace-pending]\n" + + " [--selector]\n" + + " [<URI> | <PACKAGE> | <COMPONENT>]\n" + ); + } + + public void onRun() throws Exception { mAm = ActivityManagerNative.getDefault(); if (mAm == null) { @@ -101,9 +221,7 @@ public class Am { throw new AndroidException("Can't connect to activity manager; is the system running?"); } - mArgs = args; - String op = args[0]; - mNextArg = 1; + String op = nextArgRequired(); if (op.equals("start")) { runStart(); @@ -133,10 +251,6 @@ public class Am { runMonitor(); } else if (op.equals("screen-compat")) { runScreenCompat(); - } else if (op.equals("display-size")) { - runDisplaySize(); - } else if (op.equals("display-density")) { - runDisplayDensity(); } else if (op.equals("to-uri")) { runToUri(false); } else if (op.equals("to-intent-uri")) { @@ -146,7 +260,7 @@ public class Am { } else if (op.equals("stop-user")) { runStopUser(); } else { - throw new IllegalArgumentException("Unknown command: " + op); + showError("Error: unknown command '" + op + "'"); } } @@ -337,6 +451,8 @@ public class Am { mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES; } else if (opt.equals("--user")) { mUserId = parseUserArg(nextArgRequired()); + } else if (opt.equals("--receiver-permission")) { + mReceiverPermission = nextArgRequired(); } else { System.err.println("Error: Unknown option: " + opt); return null; @@ -487,11 +603,11 @@ public class Am { IActivityManager.WaitResult result = null; int res; if (mWaitOption) { - result = mAm.startActivityAndWait(null, intent, mimeType, + result = mAm.startActivityAndWait(null, null, intent, mimeType, null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId); res = result.result; } else { - res = mAm.startActivityAsUser(null, intent, mimeType, + res = mAm.startActivityAsUser(null, null, intent, mimeType, null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId); } PrintStream out = mWaitOption ? System.out : System.err; @@ -613,8 +729,8 @@ public class Am { Intent intent = makeIntent(UserHandle.USER_ALL); IntentReceiver receiver = new IntentReceiver(); System.out.println("Broadcasting: " + intent); - mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false, - mUserId); + mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission, + android.app.AppOpsManager.OP_NONE, true, false, mUserId); receiver.waitForFinish(); } @@ -661,10 +777,13 @@ public class Am { if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg); InstrumentationWatcher watcher = null; + UiAutomationConnection connection = null; if (wait) { watcher = new InstrumentationWatcher(); watcher.setRawOutput(rawMode); + connection = new UiAutomationConnection(); } + float[] oldAnims = null; if (no_window_animation) { oldAnims = wm.getAnimationScales(); @@ -672,7 +791,7 @@ public class Am { wm.setAnimationScale(1, 0.0f); } - if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, userId)) { + if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId)) { throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString()); } @@ -1197,82 +1316,6 @@ public class Am { } while (packageName != null); } - private void runDisplaySize() throws Exception { - String size = nextArgRequired(); - int w, h; - if ("reset".equals(size)) { - w = h = -1; - } else { - int div = size.indexOf('x'); - if (div <= 0 || div >= (size.length()-1)) { - System.err.println("Error: bad size " + size); - return; - } - String wstr = size.substring(0, div); - String hstr = size.substring(div+1); - try { - w = Integer.parseInt(wstr); - h = Integer.parseInt(hstr); - } catch (NumberFormatException e) { - System.err.println("Error: bad number " + e); - return; - } - } - - IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService( - Context.WINDOW_SERVICE)); - if (wm == null) { - System.err.println(NO_SYSTEM_ERROR_CODE); - throw new AndroidException("Can't connect to window manager; is the system running?"); - } - - try { - if (w >= 0 && h >= 0) { - // TODO(multidisplay): For now Configuration only applies to main screen. - wm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h); - } else { - wm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY); - } - } catch (RemoteException e) { - } - } - - private void runDisplayDensity() throws Exception { - String densityStr = nextArgRequired(); - int density; - if ("reset".equals(densityStr)) { - density = -1; - } else { - try { - density = Integer.parseInt(densityStr); - } catch (NumberFormatException e) { - System.err.println("Error: bad number " + e); - return; - } - if (density < 72) { - System.err.println("Error: density must be >= 72"); - return; - } - } - - IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.checkService( - Context.WINDOW_SERVICE)); - if (wm == null) { - System.err.println(NO_SYSTEM_ERROR_CODE); - throw new AndroidException("Can't connect to window manager; is the system running?"); - } - - try { - if (density > 0) { - // TODO(multidisplay): For now Configuration only applies to main screen. - wm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density); - } else { - wm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY); - } - } catch (RemoteException e) { - } - } - private void runToUri(boolean intentScheme) throws Exception { Intent intent = makeIntent(UserHandle.USER_CURRENT); System.out.println(intent.toUri(intentScheme ? Intent.URI_INTENT_SCHEME : 0)); @@ -1378,198 +1421,4 @@ public class Am { return true; } } - - 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; - } - String arg = mArgs[mNextArg]; - if (!arg.startsWith("-")) { - return null; - } - mNextArg++; - if (arg.equals("--")) { - return null; - } - if (arg.length() > 1 && arg.charAt(1) != '-') { - if (arg.length() > 2) { - mCurArgData = arg.substring(2); - return arg.substring(0, 2); - } else { - mCurArgData = null; - return arg; - } - } - mCurArgData = null; - return arg; - } - - private String nextArg() { - if (mCurArgData != null) { - String arg = mCurArgData; - mCurArgData = null; - return arg; - } else if (mNextArg < mArgs.length) { - return mArgs[mNextArg++]; - } else { - return null; - } - } - - private String nextArgRequired() { - String arg = nextArg(); - if (arg == null) { - String prev = mArgs[mNextArg - 1]; - throw new IllegalArgumentException("Argument expected after \"" + prev + "\""); - } - return arg; - } - - private static void showUsage() { - System.err.println( - "usage: am [subcommand] [options]\n" + - "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + - " [--R COUNT] [-S] [--opengl-trace]\n" + - " [--user <USER_ID> | current] <INTENT>\n" + - " am startservice [--user <USER_ID> | current] <INTENT>\n" + - " am force-stop [--user <USER_ID> | all | current] <PACKAGE>\n" + - " am kill [--user <USER_ID> | all | current] <PACKAGE>\n" + - " am kill-all\n" + - " am broadcast [--user <USER_ID> | all | current] <INTENT>\n" + - " am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" + - " [--user <USER_ID> | current]\n" + - " [--no-window-animation] <COMPONENT>\n" + - " am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" + - " am profile stop [--user <USER_ID> current] [<PROCESS>]\n" + - " am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" + - " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + - " am clear-debug-app\n" + - " am monitor [--gdb <port>]\n" + - " am screen-compat [on|off] <PACKAGE>\n" + - " am display-size [reset|WxH]\n" + - " am display-density [reset|DENSITY]\n" + - " am to-uri [INTENT]\n" + - " am to-intent-uri [INTENT]\n" + - " am switch-user <USER_ID>\n" + - " am stop-user <USER_ID>\n" + - "\n" + - "am start: start an Activity. Options are:\n" + - " -D: enable debugging\n" + - " -W: wait for launch to complete\n" + - " --start-profiler <FILE>: start profiler and send results to <FILE>\n" + - " -P <FILE>: like above, but profiling stops when app goes idle\n" + - " -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" + - " the top activity will be finished.\n" + - " -S: force stop the target app before starting the activity\n" + - " --opengl-trace: enable tracing of OpenGL functions\n" + - " --user <USER_ID> | current: Specify which user to run as; if not\n" + - " specified then run as the current user.\n" + - "\n" + - "am startservice: start a Service. Options are:\n" + - " --user <USER_ID> | current: Specify which user to run as; if not\n" + - " specified then run as the current user.\n" + - "\n" + - "am force-stop: force stop everything associated with <PACKAGE>.\n" + - " --user <USER_ID> | all | current: Specify user to force stop;\n" + - " all users if not specified.\n" + - "\n" + - "am kill: Kill all processes associated with <PACKAGE>. Only kills.\n" + - " processes that are safe to kill -- that is, will not impact the user\n" + - " experience.\n" + - " --user <USER_ID> | all | current: Specify user whose processes to kill;\n" + - " all users if not specified.\n" + - "\n" + - "am kill-all: Kill all background processes.\n" + - "\n" + - "am broadcast: send a broadcast Intent. Options are:\n" + - " --user <USER_ID> | all | current: Specify which user to send to; if not\n" + - " specified then send to all users.\n" + - "\n" + - "am instrument: start an Instrumentation. Typically this target <COMPONENT>\n" + - " is the form <TEST_PACKAGE>/<RUNNER_CLASS>. Options are:\n" + - " -r: print raw results (otherwise decode REPORT_KEY_STREAMRESULT). Use with\n" + - " [-e perf true] to generate raw output for performance measurements.\n" + - " -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a\n" + - " common form is [-e <testrunner_flag> <value>[,<value>...]].\n" + - " -p <FILE>: write profiling data to <FILE>\n" + - " -w: wait for instrumentation to finish before returning. Required for\n" + - " test runners.\n" + - " --user <USER_ID> | current: Specify user instrumentation runs in;\n" + - " current user if not specified.\n" + - " --no-window-animation: turn off window animations will running.\n" + - "\n" + - "am profile: start and stop profiler on a process. The given <PROCESS> argument\n" + - " may be either a process name or pid. Options are:\n" + - " --user <USER_ID> | current: When supplying a process name,\n" + - " specify user of process to profile; uses current user if not specified.\n" + - "\n" + - "am dumpheap: dump the heap of a process. The given <PROCESS> argument may\n" + - " be either a process name or pid. Options are:\n" + - " -n: dump native heap instead of managed heap\n" + - " --user <USER_ID> | current: When supplying a process name,\n" + - " specify user of process to dump; uses current user if not specified.\n" + - "\n" + - "am set-debug-app: set application <PACKAGE> to debug. Options are:\n" + - " -w: wait for debugger when application starts\n" + - " --persistent: retain this value\n" + - "\n" + - "am clear-debug-app: clear the previously set-debug-app.\n" + - "\n" + - "am bug-report: request bug report generation; will launch UI\n" + - " when done to select where it should be delivered." + - "\n" + - "am monitor: start monitoring for crashes or ANRs.\n" + - " --gdb: start gdbserv on the given port at crash/ANR\n" + - "\n" + - "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + - "\n" + - "am display-size: override display size.\n" + - "\n" + - "am display-density: override display density.\n" + - "\n" + - "am to-uri: print the given Intent specification as a URI.\n" + - "\n" + - "am to-intent-uri: print the given Intent specification as an intent: URI.\n" + - "\n" + - "am switch-user: switch to put USER_ID in the foreground, starting\n" + - " execution of that user if it is currently stopped.\n" + - "\n" + - "am stop-user: stop execution of USER_ID, not allowing it to run any\n" + - " code until a later explicit switch to it.\n" + - "\n" + - "<INTENT> specifications include these flags and arguments:\n" + - " [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" + - " [-c <CATEGORY> [-c <CATEGORY>] ...]\n" + - " [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]\n" + - " [--esn <EXTRA_KEY> ...]\n" + - " [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]\n" + - " [--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]\n" + - " [--el <EXTRA_KEY> <EXTRA_LONG_VALUE> ...]\n" + - " [--ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE> ...]\n" + - " [--eu <EXTRA_KEY> <EXTRA_URI_VALUE> ...]\n" + - " [--ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>]\n" + - " [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" + - " [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" + - " [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" + - " [-n <COMPONENT>] [-f <FLAGS>]\n" + - " [--grant-read-uri-permission] [--grant-write-uri-permission]\n" + - " [--debug-log-resolution] [--exclude-stopped-packages]\n" + - " [--include-stopped-packages]\n" + - " [--activity-brought-to-front] [--activity-clear-top]\n" + - " [--activity-clear-when-task-reset] [--activity-exclude-from-recents]\n" + - " [--activity-launched-from-history] [--activity-multiple-task]\n" + - " [--activity-no-animation] [--activity-no-history]\n" + - " [--activity-no-user-action] [--activity-previous-is-top]\n" + - " [--activity-reorder-to-front] [--activity-reset-task-if-needed]\n" + - " [--activity-single-top] [--activity-clear-task]\n" + - " [--activity-task-on-home]\n" + - " [--receiver-registered-only] [--receiver-replace-pending]\n" + - " [--selector]\n" + - " [<URI> | <PACKAGE> | <COMPONENT>]\n" - ); - } } diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk index b39c335..b9afe40 100644 --- a/cmds/app_process/Android.mk +++ b/cmds/app_process/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ + liblog \ libbinder \ libandroid_runtime @@ -27,6 +28,7 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ + liblog \ libbinder \ libandroid_runtime diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index 6f37180..28752a5 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -13,6 +13,7 @@ #include <utils/Log.h> #include <cutils/process_name.h> #include <cutils/memory.h> +#include <cutils/trace.h> #include <android_runtime/AndroidRuntime.h> #include <sys/personality.h> @@ -96,6 +97,9 @@ public: virtual void onZygoteInit() { + // Re-enable tracing now that we're no longer in Zygote. + atrace_set_tracing_enabled(true); + sp<ProcessState> proc = ProcessState::self(); ALOGV("App process: starting thread pool.\n"); proc->startThreadPool(); diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 8c46b21..d5ff84e 100644 --- a/cmds/bootanimation/Android.mk +++ b/cmds/bootanimation/Android.mk @@ -9,6 +9,7 @@ LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES LOCAL_SHARED_LIBRARIES := \ libcutils \ + liblog \ libandroidfw \ libutils \ libbinder \ diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java index 046ccca..73fd660 100644 --- a/cmds/bu/src/com/android/commands/bu/Backup.java +++ b/cmds/bu/src/com/android/commands/bu/Backup.java @@ -22,6 +22,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import java.io.IOException; import java.util.ArrayList; public final class Backup { @@ -64,6 +65,7 @@ public final class Backup { private void doFullBackup(int socketFd) { ArrayList<String> packages = new ArrayList<String>(); boolean saveApks = false; + boolean saveObbs = false; boolean saveShared = false; boolean doEverything = false; boolean allIncludesSystem = true; @@ -75,6 +77,10 @@ public final class Backup { saveApks = true; } else if ("-noapk".equals(arg)) { saveApks = false; + } else if ("-obb".equals(arg)) { + saveObbs = true; + } else if ("-noobb".equals(arg)) { + saveObbs = false; } else if ("-shared".equals(arg)) { saveShared = true; } else if ("-noshared".equals(arg)) { @@ -104,23 +110,37 @@ public final class Backup { return; } + ParcelFileDescriptor fd = null; try { - ParcelFileDescriptor fd = ParcelFileDescriptor.adoptFd(socketFd); + fd = ParcelFileDescriptor.adoptFd(socketFd); String[] packArray = new String[packages.size()]; - mBackupManager.fullBackup(fd, saveApks, saveShared, doEverything, allIncludesSystem, - packages.toArray(packArray)); + mBackupManager.fullBackup(fd, saveApks, saveObbs, saveShared, doEverything, + allIncludesSystem, packages.toArray(packArray)); } catch (RemoteException e) { Log.e(TAG, "Unable to invoke backup manager for backup"); + } finally { + if (fd != null) { + try { + fd.close(); + } catch (IOException e) {} + } } } private void doFullRestore(int socketFd) { // No arguments to restore + ParcelFileDescriptor fd = null; try { - ParcelFileDescriptor fd = ParcelFileDescriptor.adoptFd(socketFd); + fd = ParcelFileDescriptor.adoptFd(socketFd); mBackupManager.fullRestore(fd); } catch (RemoteException e) { Log.e(TAG, "Unable to invoke backup manager for restore"); + } finally { + if (fd != null) { + try { + fd.close(); + } catch (IOException e) {} + } } } diff --git a/cmds/bugreport/Android.mk b/cmds/bugreport/Android.mk deleted file mode 100644 index f476f5e..0000000 --- a/cmds/bugreport/Android.mk +++ /dev/null @@ -1,10 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= bugreport.c - -LOCAL_MODULE:= bugreport - -LOCAL_SHARED_LIBRARIES := libcutils - -include $(BUILD_EXECUTABLE) diff --git a/cmds/bugreport/bugreport.c b/cmds/bugreport/bugreport.c deleted file mode 100644 index 4a0b511..0000000 --- a/cmds/bugreport/bugreport.c +++ /dev/null @@ -1,56 +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. - */ - -#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/content/Android.mk b/cmds/content/Android.mk index 88c46f2..9302e2f 100644 --- a/cmds/content/Android.mk +++ b/cmds/content/Android.mk @@ -1,33 +1,15 @@ # Copyright 2012 The Android Open Source Project LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) +include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) - LOCAL_MODULE := content - include $(BUILD_JAVA_LIBRARY) include $(CLEAR_VARS) -ALL_PREBUILT += $(TARGET_OUT)/bin/content -$(TARGET_OUT)/bin/content : $(LOCAL_PATH)/content | $(ACP) - $(transform-prebuilt-to-target) - -NOTICE_FILE := NOTICE -files_noticed := bin/content - -# Generate rules for a single file. The argument is the file path relative to -# the installation root -define make-notice-file - -$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE) - @echo Notice file: $$< -- $$@ - @mkdir -p $$(dir $$@) - @cat $$< >> $$@ - -$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt - -endef - -$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file)))) +LOCAL_MODULE := content +LOCAL_SRC_FILES := content +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java index ae39d24..e66bdf4 100644 --- a/cmds/content/src/com/android/commands/content/Content.java +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -24,6 +24,7 @@ import android.content.IContentProvider; import android.database.Cursor; import android.net.Uri; import android.os.Binder; +import android.os.Bundle; import android.os.IBinder; import android.os.UserHandle; import android.text.TextUtils; @@ -102,6 +103,12 @@ public class Content { + "equal to \"new_setting\" and sort the result by name in ascending order.\n" + " adb shell content query --uri content://settings/secure --projection name:value" + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n" + + "\n" + + "usage: adb shell content call --uri <URI> --method <METHOD> [--arg <ARG>]\n" + + " [--extra <BINDING> ...]\n" + + " <METHOD> is the name of a provider-defined method\n" + + " <ARG> is an optional string argument\n" + + " <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n" + "\n"; private static class Parser { @@ -109,12 +116,16 @@ public class Content { private static final String ARGUMENT_DELETE = "delete"; private static final String ARGUMENT_UPDATE = "update"; private static final String ARGUMENT_QUERY = "query"; + private static final String ARGUMENT_CALL = "call"; private static final String ARGUMENT_WHERE = "--where"; private static final String ARGUMENT_BIND = "--bind"; private static final String ARGUMENT_URI = "--uri"; private static final String ARGUMENT_USER = "--user"; private static final String ARGUMENT_PROJECTION = "--projection"; private static final String ARGUMENT_SORT = "--sort"; + private static final String ARGUMENT_METHOD = "--method"; + private static final String ARGUMENT_ARG = "--arg"; + private static final String ARGUMENT_EXTRA = "--extra"; private static final String TYPE_BOOLEAN = "b"; private static final String TYPE_STRING = "s"; private static final String TYPE_INTEGER = "i"; @@ -141,6 +152,8 @@ public class Content { return parseUpdateCommand(); } else if (ARGUMENT_QUERY.equals(operation)) { return parseQueryCommand(); + } else if (ARGUMENT_CALL.equals(operation)) { + return parseCallCommand(); } else { throw new IllegalArgumentException("Unsupported operation: " + operation); } @@ -228,6 +241,38 @@ public class Content { return new UpdateCommand(uri, userId, values, where); } + public CallCommand parseCallCommand() { + String method = null; + int userId = UserHandle.USER_OWNER; + String arg = null; + Uri uri = null; + ContentValues values = new ContentValues(); + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_USER.equals(argument)) { + userId = Integer.parseInt(argumentValueRequired(argument)); + } else if (ARGUMENT_METHOD.equals(argument)) { + method = argumentValueRequired(argument); + } else if (ARGUMENT_ARG.equals(argument)) { + arg = argumentValueRequired(argument); + } else if (ARGUMENT_EXTRA.equals(argument)) { + parseBindValue(values); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + if (method == null) { + throw new IllegalArgumentException("Content provider method not specified."); + } + return new CallCommand(uri, userId, method, arg, values); + } + public QueryCommand parseQueryCommand() { Uri uri = null; int userId = UserHandle.USER_OWNER; @@ -358,7 +403,7 @@ public class Content { @Override public void onExecute(IContentProvider provider) throws Exception { - provider.insert(mUri, mContentValues); + provider.insert(null, mUri, mContentValues); } } @@ -372,7 +417,44 @@ public class Content { @Override public void onExecute(IContentProvider provider) throws Exception { - provider.delete(mUri, mWhere, null); + provider.delete(null, mUri, mWhere, null); + } + } + + private static class CallCommand extends Command { + final String mMethod, mArg; + Bundle mExtras = null; + + public CallCommand(Uri uri, int userId, String method, String arg, ContentValues values) { + super(uri, userId); + mMethod = method; + mArg = arg; + if (values != null) { + mExtras = new Bundle(); + for (String key : values.keySet()) { + final Object val = values.get(key); + if (val instanceof String) { + mExtras.putString(key, (String) val); + } else if (val instanceof Float) { + mExtras.putFloat(key, (Float) val); + } else if (val instanceof Double) { + mExtras.putDouble(key, (Double) val); + } else if (val instanceof Boolean) { + mExtras.putBoolean(key, (Boolean) val); + } else if (val instanceof Integer) { + mExtras.putInt(key, (Integer) val); + } else if (val instanceof Long) { + mExtras.putLong(key, (Long) val); + } + } + } + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + Bundle result = provider.call(null, mMethod, mArg, mExtras); + final int size = result.size(); // unpack + System.out.println("Result: " + result); } } @@ -389,7 +471,7 @@ public class Content { @Override public void onExecute(IContentProvider provider) throws Exception { - Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null); + Cursor cursor = provider.query(null, mUri, mProjection, mWhere, null, mSortOrder, null); if (cursor == null) { System.out.println("No result found."); return; @@ -433,7 +515,7 @@ public class Content { System.out.println(builder); } while (cursor.moveToNext()); } else { - System.out.println("No reuslt found."); + System.out.println("No result found."); } } finally { cursor.close(); @@ -451,7 +533,7 @@ public class Content { @Override public void onExecute(IContentProvider provider) throws Exception { - provider.update(mUri, mContentValues, mWhere, null); + provider.update(null, mUri, mContentValues, mWhere, null); } } diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java index a21df0d..e43501c 100644 --- a/cmds/input/src/com/android/commands/input/Input.java +++ b/cmds/input/src/com/android/commands/input/Input.java @@ -72,14 +72,17 @@ public class Input { } else if (command.equals("swipe")) { if (args.length == 5) { sendSwipe(InputDevice.SOURCE_TOUCHSCREEN, Float.parseFloat(args[1]), Float.parseFloat(args[2]), - Float.parseFloat(args[3]), Float.parseFloat(args[4])); + Float.parseFloat(args[3]), Float.parseFloat(args[4]), -1); return; } - } else if (command.equals("touchscreen") || command.equals("touchpad")) { + } else if (command.equals("touchscreen") || command.equals("touchpad") + || command.equals("touchnavigation")) { // determine input source int inputSource = InputDevice.SOURCE_TOUCHSCREEN; if (command.equals("touchpad")) { inputSource = InputDevice.SOURCE_TOUCHPAD; + } else if (command.equals("touchnavigation")) { + inputSource = InputDevice.SOURCE_TOUCH_NAVIGATION; } // determine subcommand if (args.length > 1) { @@ -94,7 +97,12 @@ public class Input { if (args.length == 6) { sendSwipe(inputSource, Float.parseFloat(args[2]), Float.parseFloat(args[3]), Float.parseFloat(args[4]), - Float.parseFloat(args[5])); + Float.parseFloat(args[5]), -1); + return; + } else if (args.length == 7) { + sendSwipe(inputSource, Float.parseFloat(args[2]), + Float.parseFloat(args[3]), Float.parseFloat(args[4]), + Float.parseFloat(args[5]), Integer.parseInt(args[6])); return; } } @@ -172,14 +180,20 @@ public class Input { injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x, y, 0.0f); } - private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2) { - final int NUM_STEPS = 11; + private void sendSwipe(int inputSource, float x1, float y1, float x2, float y2, int duration) { + if (duration < 0) { + duration = 300; + } long now = SystemClock.uptimeMillis(); injectMotionEvent(inputSource, MotionEvent.ACTION_DOWN, now, x1, y1, 1.0f); - for (int i = 1; i < NUM_STEPS; i++) { - float alpha = (float) i / NUM_STEPS; + long startTime = now; + long endTime = startTime + duration; + while (now < endTime) { + long elapsedTime = now - startTime; + float alpha = (float) elapsedTime / duration; injectMotionEvent(inputSource, MotionEvent.ACTION_MOVE, now, lerp(x1, x2, alpha), lerp(y1, y2, alpha), 1.0f); + now = SystemClock.uptimeMillis(); } injectMotionEvent(inputSource, MotionEvent.ACTION_UP, now, x1, y1, 0.0f); } @@ -236,8 +250,9 @@ public class Input { System.err.println("usage: input ..."); System.err.println(" input text <string>"); System.err.println(" input keyevent <key code number or name>"); - System.err.println(" input [touchscreen|touchpad] tap <x> <y>"); - System.err.println(" input [touchscreen|touchpad] swipe <x1> <y1> <x2> <y2>"); + System.err.println(" input [touchscreen|touchpad|touchnavigation] tap <x> <y>"); + System.err.println(" input [touchscreen|touchpad|touchnavigation] swipe " + + "<x1> <y1> <x2> <y2> [duration(ms)]"); System.err.println(" input trackball press"); System.err.println(" input trackball roll <dx> <dy>"); } diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk deleted file mode 100644 index 1dd4ee5..0000000 --- a/cmds/installd/Android.mk +++ /dev/null @@ -1,42 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -common_src_files := \ - commands.c utils.c - -# -# Static library used in testing and executable -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - $(common_src_files) - -LOCAL_MODULE := libinstalld - -LOCAL_MODULE_TAGS := eng tests - -include $(BUILD_STATIC_LIBRARY) - -# -# Executable -# - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - installd.c \ - $(common_src_files) - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libselinux - -LOCAL_STATIC_LIBRARIES := \ - libdiskusage - -LOCAL_MODULE := installd - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c deleted file mode 100644 index 09d6f89..0000000 --- a/cmds/installd/commands.c +++ /dev/null @@ -1,1122 +0,0 @@ -/* -** Copyright 2008, 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/capability.h> -#include "installd.h" -#include <diskusage/dirsize.h> -#include <selinux/android.h> - -/* Directory records that are used in execution of commands. */ -dir_rec_t android_data_dir; -dir_rec_t android_asec_dir; -dir_rec_t android_app_dir; -dir_rec_t android_app_private_dir; -dir_rec_t android_app_lib_dir; -dir_rec_t android_media_dir; -dir_rec_array_t android_system_dirs; - -int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) -{ - char pkgdir[PKG_PATH_MAX]; - char libsymlink[PKG_PATH_MAX]; - char applibdir[PKG_PATH_MAX]; - struct stat libStat; - - if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { - ALOGE("invalid uid/gid: %d %d\n", uid, gid); - return -1; - } - - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) { - ALOGE("cannot create package path\n"); - return -1; - } - - if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, 0)) { - ALOGE("cannot create package lib symlink origin path\n"); - return -1; - } - - if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) { - ALOGE("cannot create package lib symlink dest path\n"); - return -1; - } - - if (mkdir(pkgdir, 0751) < 0) { - ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); - return -1; - } - if (chmod(pkgdir, 0751) < 0) { - ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(pkgdir); - return -1; - } - - if (lstat(libsymlink, &libStat) < 0) { - if (errno != ENOENT) { - ALOGE("couldn't stat lib dir: %s\n", strerror(errno)); - return -1; - } - } else { - if (S_ISDIR(libStat.st_mode)) { - if (delete_dir_contents(libsymlink, 1, 0) < 0) { - ALOGE("couldn't delete lib directory during install for: %s", libsymlink); - return -1; - } - } else if (S_ISLNK(libStat.st_mode)) { - if (unlink(libsymlink) < 0) { - ALOGE("couldn't unlink lib directory during install for: %s", libsymlink); - return -1; - } - } - } - - if (symlink(applibdir, libsymlink) < 0) { - ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir, - strerror(errno)); - unlink(pkgdir); - return -1; - } - - if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) { - ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(libsymlink); - unlink(pkgdir); - return -errno; - } - - if (chown(pkgdir, uid, gid) < 0) { - ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(libsymlink); - unlink(pkgdir); - return -1; - } - - return 0; -} - -int uninstall(const char *pkgname, uid_t persona) -{ - char pkgdir[PKG_PATH_MAX]; - - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) - return -1; - - /* delete contents AND directory, no exceptions */ - return delete_dir_contents(pkgdir, 1, NULL); -} - -int renamepkg(const char *oldpkgname, const char *newpkgname) -{ - char oldpkgdir[PKG_PATH_MAX]; - char newpkgdir[PKG_PATH_MAX]; - - if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0)) - return -1; - if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0)) - return -1; - - if (rename(oldpkgdir, newpkgdir) < 0) { - ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno)); - return -errno; - } - return 0; -} - -int fix_uid(const char *pkgname, uid_t uid, gid_t gid) -{ - char pkgdir[PKG_PATH_MAX]; - struct stat s; - int rc = 0; - - if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { - ALOGE("invalid uid/gid: %d %d\n", uid, gid); - return -1; - } - - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) { - ALOGE("cannot create package path\n"); - return -1; - } - - if (stat(pkgdir, &s) < 0) return -1; - - if (s.st_uid != 0 || s.st_gid != 0) { - ALOGE("fixing uid of non-root pkg: %s %lu %lu\n", pkgdir, s.st_uid, s.st_gid); - return -1; - } - - if (chmod(pkgdir, 0751) < 0) { - ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(pkgdir); - return -errno; - } - if (chown(pkgdir, uid, gid) < 0) { - ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(pkgdir); - return -errno; - } - - return 0; -} - -int delete_user_data(const char *pkgname, uid_t persona) -{ - char pkgdir[PKG_PATH_MAX]; - - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) - return -1; - - /* delete contents, excluding "lib", but not the directory itself */ - return delete_dir_contents(pkgdir, 0, "lib"); -} - -int make_user_data(const char *pkgname, uid_t uid, uid_t persona, const char* seinfo) -{ - char pkgdir[PKG_PATH_MAX]; - char applibdir[PKG_PATH_MAX]; - char libsymlink[PKG_PATH_MAX]; - struct stat libStat; - - // Create the data dir for the package - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) { - return -1; - } - if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, persona)) { - ALOGE("cannot create package lib symlink origin path\n"); - return -1; - } - if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) { - ALOGE("cannot create package lib symlink dest path\n"); - return -1; - } - - if (mkdir(pkgdir, 0751) < 0) { - ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); - return -errno; - } - if (chmod(pkgdir, 0751) < 0) { - ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(pkgdir); - return -errno; - } - - if (lstat(libsymlink, &libStat) < 0) { - if (errno != ENOENT) { - ALOGE("couldn't stat lib dir for non-primary: %s\n", strerror(errno)); - unlink(pkgdir); - return -1; - } - } else { - if (S_ISDIR(libStat.st_mode)) { - if (delete_dir_contents(libsymlink, 1, 0) < 0) { - ALOGE("couldn't delete lib directory during install for non-primary: %s", - libsymlink); - unlink(pkgdir); - return -1; - } - } else if (S_ISLNK(libStat.st_mode)) { - if (unlink(libsymlink) < 0) { - ALOGE("couldn't unlink lib directory during install for non-primary: %s", - libsymlink); - unlink(pkgdir); - return -1; - } - } - } - - if (symlink(applibdir, libsymlink) < 0) { - ALOGE("couldn't symlink directory for non-primary '%s' -> '%s': %s\n", libsymlink, - applibdir, strerror(errno)); - unlink(pkgdir); - return -1; - } - - if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) { - ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(libsymlink); - unlink(pkgdir); - return -errno; - } - - if (chown(pkgdir, uid, uid) < 0) { - ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); - unlink(libsymlink); - unlink(pkgdir); - return -errno; - } - - return 0; -} - -int delete_persona(uid_t persona) -{ - char data_path[PKG_PATH_MAX]; - if (create_persona_path(data_path, persona)) { - return -1; - } - if (delete_dir_contents(data_path, 1, NULL)) { - return -1; - } - - char media_path[PATH_MAX]; - if (create_persona_media_path(media_path, (userid_t) persona) == -1) { - return -1; - } - if (delete_dir_contents(media_path, 1, NULL) == -1) { - return -1; - } - - return 0; -} - -int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy) -{ - char src_data_dir[PKG_PATH_MAX]; - char pkg_path[PKG_PATH_MAX]; - DIR *d; - struct dirent *de; - struct stat s; - uid_t uid; - - if (create_persona_path(src_data_dir, src_persona)) { - return -1; - } - - d = opendir(src_data_dir); - if (d != NULL) { - while ((de = readdir(d))) { - const char *name = de->d_name; - - if (de->d_type == DT_DIR) { - int subfd; - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - /* Create the full path to the package's data dir */ - create_pkg_path(pkg_path, name, PKG_DIR_POSTFIX, src_persona); - /* Get the file stat */ - if (stat(pkg_path, &s) < 0) continue; - /* Get the uid of the package */ - ALOGI("Adding datadir for uid = %lu\n", s.st_uid); - uid = (uid_t) s.st_uid % PER_USER_RANGE; - /* Create the directory for the target */ - make_user_data(name, uid + target_persona * PER_USER_RANGE, - target_persona, NULL); - } - } - closedir(d); - } - - if (ensure_media_user_dirs((userid_t) target_persona) == -1) { - return -1; - } - - return 0; -} - -int delete_cache(const char *pkgname, uid_t persona) -{ - char cachedir[PKG_PATH_MAX]; - - if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, persona)) - return -1; - - /* delete contents, not the directory, no exceptions */ - return delete_dir_contents(cachedir, 0, 0); -} - -/* Try to ensure free_size bytes of storage are available. - * Returns 0 on success. - * This is rather simple-minded because doing a full LRU would - * be potentially memory-intensive, and without atime it would - * also require that apps constantly modify file metadata even - * when just reading from the cache, which is pretty awful. - */ -int free_cache(int64_t free_size) -{ - cache_t* cache; - int64_t avail; - DIR *d; - struct dirent *de; - char tmpdir[PATH_MAX]; - char *dirpos; - - avail = data_disk_free(); - if (avail < 0) return -1; - - ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail); - if (avail >= free_size) return 0; - - cache = start_cache_collection(); - - // Collect cache files for primary user. - if (create_persona_path(tmpdir, 0) == 0) { - //ALOGI("adding cache files from %s\n", tmpdir); - add_cache_files(cache, tmpdir, "cache"); - } - - // Search for other users and add any cache files from them. - snprintf(tmpdir, sizeof(tmpdir), "%s%s", android_data_dir.path, - SECONDARY_USER_PREFIX); - dirpos = tmpdir + strlen(tmpdir); - d = opendir(tmpdir); - if (d != NULL) { - while ((de = readdir(d))) { - if (de->d_type == DT_DIR) { - const char *name = de->d_name; - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - if ((strlen(name)+(dirpos-tmpdir)) < (sizeof(tmpdir)-1)) { - strcpy(dirpos, name); - //ALOGI("adding cache files from %s\n", tmpdir); - add_cache_files(cache, tmpdir, "cache"); - } else { - ALOGW("Path exceeds limit: %s%s", tmpdir, name); - } - } - } - closedir(d); - } - - // Collect cache files on external storage for all users (if it is mounted as part - // of the internal storage). - strcpy(tmpdir, android_media_dir.path); - dirpos = tmpdir + strlen(tmpdir); - d = opendir(tmpdir); - if (d != NULL) { - while ((de = readdir(d))) { - if (de->d_type == DT_DIR) { - const char *name = de->d_name; - /* skip any dir that doesn't start with a number, so not a user */ - if (name[0] < '0' || name[0] > '9') { - continue; - } - if ((strlen(name)+(dirpos-tmpdir)) < (sizeof(tmpdir)-1)) { - strcpy(dirpos, name); - if (lookup_media_dir(tmpdir, "Android") == 0 - && lookup_media_dir(tmpdir, "data") == 0) { - //ALOGI("adding cache files from %s\n", tmpdir); - add_cache_files(cache, tmpdir, "cache"); - } - } else { - ALOGW("Path exceeds limit: %s%s", tmpdir, name); - } - } - } - closedir(d); - } - - clear_cache_files(cache, free_size); - finish_cache_collection(cache); - - return data_disk_free() >= free_size ? 0 : -1; -} - -int move_dex(const char *src, const char *dst) -{ - char src_dex[PKG_PATH_MAX]; - char dst_dex[PKG_PATH_MAX]; - - if (validate_apk_path(src)) return -1; - if (validate_apk_path(dst)) return -1; - - if (create_cache_path(src_dex, src)) return -1; - if (create_cache_path(dst_dex, dst)) return -1; - - ALOGV("move %s -> %s\n", src_dex, dst_dex); - if (rename(src_dex, dst_dex) < 0) { - ALOGE("Couldn't move %s: %s\n", src_dex, strerror(errno)); - return -1; - } else { - return 0; - } -} - -int rm_dex(const char *path) -{ - char dex_path[PKG_PATH_MAX]; - - if (validate_apk_path(path)) return -1; - if (create_cache_path(dex_path, path)) return -1; - - ALOGV("unlink %s\n", dex_path); - if (unlink(dex_path) < 0) { - ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno)); - return -1; - } else { - return 0; - } -} - -int get_size(const char *pkgname, int persona, const char *apkpath, - const char *fwdlock_apkpath, const char *asecpath, - int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize, - int64_t* _asecsize) -{ - DIR *d; - int dfd; - struct dirent *de; - struct stat s; - char path[PKG_PATH_MAX]; - - int64_t codesize = 0; - int64_t datasize = 0; - int64_t cachesize = 0; - int64_t asecsize = 0; - - /* count the source apk as code -- but only if it's not - * on the /system partition and its not on the sdcard. - */ - if (validate_system_app_path(apkpath) && - strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) { - if (stat(apkpath, &s) == 0) { - codesize += stat_size(&s); - } - } - /* count the forward locked apk as code if it is given - */ - if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') { - if (stat(fwdlock_apkpath, &s) == 0) { - codesize += stat_size(&s); - } - } - /* count the cached dexfile as code */ - if (!create_cache_path(path, apkpath)) { - if (stat(path, &s) == 0) { - codesize += stat_size(&s); - } - } - - /* add in size of any libraries */ - if (!create_pkg_path_in_dir(path, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) { - d = opendir(path); - if (d != NULL) { - dfd = dirfd(d); - codesize += calculate_dir_size(dfd); - closedir(d); - } - } - - /* compute asec size if it is given - */ - if (asecpath != NULL && asecpath[0] != '!') { - if (stat(asecpath, &s) == 0) { - asecsize += stat_size(&s); - } - } - - if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, persona)) { - goto done; - } - - d = opendir(path); - if (d == NULL) { - goto done; - } - dfd = dirfd(d); - - /* most stuff in the pkgdir is data, except for the "cache" - * directory and below, which is cache, and the "lib" directory - * and below, which is code... - */ - while ((de = readdir(d))) { - const char *name = de->d_name; - - if (de->d_type == DT_DIR) { - int subfd; - int64_t statsize = 0; - int64_t dirsize = 0; - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { - statsize = stat_size(&s); - } - subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); - if (subfd >= 0) { - dirsize = calculate_dir_size(subfd); - } - if(!strcmp(name,"lib")) { - codesize += dirsize + statsize; - } else if(!strcmp(name,"cache")) { - cachesize += dirsize + statsize; - } else { - datasize += dirsize + statsize; - } - } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) { - // This is the symbolic link to the application's library - // code. We'll count this as code instead of data, since - // it is not something that the app creates. - if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { - codesize += stat_size(&s); - } - } else { - if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { - datasize += stat_size(&s); - } - } - } - closedir(d); -done: - *_codesize = codesize; - *_datasize = datasize; - *_cachesize = cachesize; - *_asecsize = asecsize; - return 0; -} - - -/* a simpler version of dexOptGenerateCacheFileName() */ -int create_cache_path(char path[PKG_PATH_MAX], const char *src) -{ - char *tmp; - int srclen; - int dstlen; - - srclen = strlen(src); - - /* demand that we are an absolute path */ - if ((src == 0) || (src[0] != '/') || strstr(src,"..")) { - return -1; - } - - if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX? - return -1; - } - - dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) + - strlen(DALVIK_CACHE_POSTFIX) + 1; - - if (dstlen > PKG_PATH_MAX) { - return -1; - } - - sprintf(path,"%s%s%s", - DALVIK_CACHE_PREFIX, - src + 1, /* skip the leading / */ - DALVIK_CACHE_POSTFIX); - - for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) { - if (*tmp == '/') { - *tmp = '@'; - } - } - - return 0; -} - -static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name, - const char* dexopt_flags) -{ - static const char* DEX_OPT_BIN = "/system/bin/dexopt"; - static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig - char zip_num[MAX_INT_LEN]; - char odex_num[MAX_INT_LEN]; - - sprintf(zip_num, "%d", zip_fd); - sprintf(odex_num, "%d", odex_fd); - - execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name, - dexopt_flags, (char*) NULL); - ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno)); -} - -static int wait_dexopt(pid_t pid, const char* apk_path) -{ - int status; - pid_t got_pid; - - /* - * Wait for the optimization process to finish. - */ - while (1) { - got_pid = waitpid(pid, &status, 0); - if (got_pid == -1 && errno == EINTR) { - printf("waitpid interrupted, retrying\n"); - } else { - break; - } - } - if (got_pid != pid) { - ALOGW("waitpid failed: wanted %d, got %d: %s\n", - (int) pid, (int) got_pid, strerror(errno)); - return 1; - } - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path); - return 0; - } else { - ALOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n", - apk_path, status); - return status; /* always nonzero */ - } -} - -int dexopt(const char *apk_path, uid_t uid, int is_public) -{ - struct utimbuf ut; - struct stat apk_stat, dex_stat; - char dex_path[PKG_PATH_MAX]; - char dexopt_flags[PROPERTY_VALUE_MAX]; - char *end; - int res, zip_fd=-1, odex_fd=-1; - - /* Before anything else: is there a .odex file? If so, we have - * pre-optimized the apk and there is nothing to do here. - */ - if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { - return -1; - } - - /* platform-specific flags affecting optimization and verification */ - property_get("dalvik.vm.dexopt-flags", dexopt_flags, ""); - - strcpy(dex_path, apk_path); - end = strrchr(dex_path, '.'); - if (end != NULL) { - strcpy(end, ".odex"); - if (stat(dex_path, &dex_stat) == 0) { - return 0; - } - } - - if (create_cache_path(dex_path, apk_path)) { - return -1; - } - - memset(&apk_stat, 0, sizeof(apk_stat)); - stat(apk_path, &apk_stat); - - zip_fd = open(apk_path, O_RDONLY, 0); - if (zip_fd < 0) { - ALOGE("dexopt cannot open '%s' for input\n", apk_path); - return -1; - } - - unlink(dex_path); - odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644); - if (odex_fd < 0) { - ALOGE("dexopt cannot open '%s' for output\n", dex_path); - goto fail; - } - if (fchmod(odex_fd, - S_IRUSR|S_IWUSR|S_IRGRP | - (is_public ? S_IROTH : 0)) < 0) { - ALOGE("dexopt cannot chmod '%s'\n", dex_path); - goto fail; - } - if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { - ALOGE("dexopt cannot chown '%s'\n", dex_path); - goto fail; - } - - ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path); - - pid_t pid; - pid = fork(); - if (pid == 0) { - /* child -- drop privileges before continuing */ - if (setgid(uid) != 0) { - ALOGE("setgid(%d) failed during dexopt\n", uid); - exit(64); - } - if (setuid(uid) != 0) { - ALOGE("setuid(%d) during dexopt\n", uid); - exit(65); - } - // drop capabilities - struct __user_cap_header_struct capheader; - struct __user_cap_data_struct capdata[2]; - memset(&capheader, 0, sizeof(capheader)); - memset(&capdata, 0, sizeof(capdata)); - capheader.version = _LINUX_CAPABILITY_VERSION_3; - if (capset(&capheader, &capdata[0]) < 0) { - ALOGE("capset failed: %s\n", strerror(errno)); - exit(66); - } - if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { - ALOGE("flock(%s) failed: %s\n", dex_path, strerror(errno)); - exit(67); - } - - run_dexopt(zip_fd, odex_fd, apk_path, dexopt_flags); - exit(68); /* only get here on exec failure */ - } else { - res = wait_dexopt(pid, apk_path); - if (res != 0) { - ALOGE("dexopt failed on '%s' res = %d\n", dex_path, res); - goto fail; - } - } - - ut.actime = apk_stat.st_atime; - ut.modtime = apk_stat.st_mtime; - utime(dex_path, &ut); - - close(odex_fd); - close(zip_fd); - return 0; - -fail: - if (odex_fd >= 0) { - close(odex_fd); - unlink(dex_path); - } - if (zip_fd >= 0) { - close(zip_fd); - } - return -1; -} - -void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid, - struct stat* statbuf) -{ - while (path[basepos] != 0) { - if (path[basepos] == '/') { - path[basepos] = 0; - if (lstat(path, statbuf) < 0) { - ALOGV("Making directory: %s\n", path); - if (mkdir(path, mode) == 0) { - chown(path, uid, gid); - } else { - ALOGW("Unable to make directory %s: %s\n", path, strerror(errno)); - } - } - path[basepos] = '/'; - basepos++; - } - basepos++; - } -} - -int movefileordir(char* srcpath, char* dstpath, int dstbasepos, - int dstuid, int dstgid, struct stat* statbuf) -{ - DIR *d; - struct dirent *de; - int res; - - int srcend = strlen(srcpath); - int dstend = strlen(dstpath); - - if (lstat(srcpath, statbuf) < 0) { - ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno)); - return 1; - } - - if ((statbuf->st_mode&S_IFDIR) == 0) { - mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH, - dstuid, dstgid, statbuf); - ALOGV("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid); - if (rename(srcpath, dstpath) >= 0) { - if (chown(dstpath, dstuid, dstgid) < 0) { - ALOGE("cannot chown %s: %s\n", dstpath, strerror(errno)); - unlink(dstpath); - return 1; - } - } else { - ALOGW("Unable to rename %s to %s: %s\n", - srcpath, dstpath, strerror(errno)); - return 1; - } - return 0; - } - - d = opendir(srcpath); - if (d == NULL) { - ALOGW("Unable to opendir %s: %s\n", srcpath, strerror(errno)); - return 1; - } - - res = 0; - - while ((de = readdir(d))) { - const char *name = de->d_name; - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - - if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) { - ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name); - continue; - } - - if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) { - ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name); - continue; - } - - srcpath[srcend] = dstpath[dstend] = '/'; - strcpy(srcpath+srcend+1, name); - strcpy(dstpath+dstend+1, name); - - if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) { - res = 1; - } - - // Note: we will be leaving empty directories behind in srcpath, - // but that is okay, the package manager will be erasing all of the - // data associated with .apks that disappear. - - srcpath[srcend] = dstpath[dstend] = 0; - } - - closedir(d); - return res; -} - -int movefiles() -{ - DIR *d; - int dfd, subfd; - struct dirent *de; - struct stat s; - char buf[PKG_PATH_MAX+1]; - int bufp, bufe, bufi, readlen; - - char srcpkg[PKG_NAME_MAX]; - char dstpkg[PKG_NAME_MAX]; - char srcpath[PKG_PATH_MAX]; - char dstpath[PKG_PATH_MAX]; - int dstuid=-1, dstgid=-1; - int hasspace; - - d = opendir(UPDATE_COMMANDS_DIR_PREFIX); - if (d == NULL) { - goto done; - } - dfd = dirfd(d); - - /* Iterate through all files in the directory, executing the - * file movements requested there-in. - */ - while ((de = readdir(d))) { - const char *name = de->d_name; - - if (de->d_type == DT_DIR) { - continue; - } else { - subfd = openat(dfd, name, O_RDONLY); - if (subfd < 0) { - ALOGW("Unable to open update commands at %s%s\n", - UPDATE_COMMANDS_DIR_PREFIX, name); - continue; - } - - bufp = 0; - bufe = 0; - buf[PKG_PATH_MAX] = 0; - srcpkg[0] = dstpkg[0] = 0; - while (1) { - bufi = bufp; - while (bufi < bufe && buf[bufi] != '\n') { - bufi++; - } - if (bufi < bufe) { - buf[bufi] = 0; - ALOGV("Processing line: %s\n", buf+bufp); - hasspace = 0; - while (bufp < bufi && isspace(buf[bufp])) { - hasspace = 1; - bufp++; - } - if (buf[bufp] == '#' || bufp == bufi) { - // skip comments and empty lines. - } else if (hasspace) { - if (dstpkg[0] == 0) { - ALOGW("Path before package line in %s%s: %s\n", - UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp); - } else if (srcpkg[0] == 0) { - // Skip -- source package no longer exists. - } else { - ALOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg); - if (!create_move_path(srcpath, srcpkg, buf+bufp, 0) && - !create_move_path(dstpath, dstpkg, buf+bufp, 0)) { - movefileordir(srcpath, dstpath, - strlen(dstpath)-strlen(buf+bufp), - dstuid, dstgid, &s); - } - } - } else { - char* div = strchr(buf+bufp, ':'); - if (div == NULL) { - ALOGW("Bad package spec in %s%s; no ':' sep: %s\n", - UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp); - } else { - *div = 0; - div++; - if (strlen(buf+bufp) < PKG_NAME_MAX) { - strcpy(dstpkg, buf+bufp); - } else { - srcpkg[0] = dstpkg[0] = 0; - ALOGW("Package name too long in %s%s: %s\n", - UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp); - } - if (strlen(div) < PKG_NAME_MAX) { - strcpy(srcpkg, div); - } else { - srcpkg[0] = dstpkg[0] = 0; - ALOGW("Package name too long in %s%s: %s\n", - UPDATE_COMMANDS_DIR_PREFIX, name, div); - } - if (srcpkg[0] != 0) { - if (!create_pkg_path(srcpath, srcpkg, PKG_DIR_POSTFIX, 0)) { - if (lstat(srcpath, &s) < 0) { - // Package no longer exists -- skip. - srcpkg[0] = 0; - } - } else { - srcpkg[0] = 0; - ALOGW("Can't create path %s in %s%s\n", - div, UPDATE_COMMANDS_DIR_PREFIX, name); - } - if (srcpkg[0] != 0) { - if (!create_pkg_path(dstpath, dstpkg, PKG_DIR_POSTFIX, 0)) { - if (lstat(dstpath, &s) == 0) { - dstuid = s.st_uid; - dstgid = s.st_gid; - } else { - // Destination package doesn't - // exist... due to original-package, - // this is normal, so don't be - // noisy about it. - srcpkg[0] = 0; - } - } else { - srcpkg[0] = 0; - ALOGW("Can't create path %s in %s%s\n", - div, UPDATE_COMMANDS_DIR_PREFIX, name); - } - } - ALOGV("Transfering from %s to %s: uid=%d\n", - srcpkg, dstpkg, dstuid); - } - } - } - bufp = bufi+1; - } else { - if (bufp == 0) { - if (bufp < bufe) { - ALOGW("Line too long in %s%s, skipping: %s\n", - UPDATE_COMMANDS_DIR_PREFIX, name, buf); - } - } else if (bufp < bufe) { - memcpy(buf, buf+bufp, bufe-bufp); - bufe -= bufp; - bufp = 0; - } - readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe); - if (readlen < 0) { - ALOGW("Failure reading update commands in %s%s: %s\n", - UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno)); - break; - } else if (readlen == 0) { - break; - } - bufe += readlen; - buf[bufe] = 0; - ALOGV("Read buf: %s\n", buf); - } - } - close(subfd); - } - } - closedir(d); -done: - return 0; -} - -int linklib(const char* pkgname, const char* asecLibDir, int userId) -{ - char pkgdir[PKG_PATH_MAX]; - char libsymlink[PKG_PATH_MAX]; - struct stat s, libStat; - int rc = 0; - - if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userId)) { - ALOGE("cannot create package path\n"); - return -1; - } - if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userId)) { - ALOGE("cannot create package lib symlink origin path\n"); - return -1; - } - - if (stat(pkgdir, &s) < 0) return -1; - - if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) { - ALOGE("failed to chown '%s': %s\n", pkgdir, strerror(errno)); - return -1; - } - - if (chmod(pkgdir, 0700) < 0) { - ALOGE("linklib() 1: failed to chmod '%s': %s\n", pkgdir, strerror(errno)); - rc = -1; - goto out; - } - - if (lstat(libsymlink, &libStat) < 0) { - if (errno != ENOENT) { - ALOGE("couldn't stat lib dir: %s\n", strerror(errno)); - rc = -1; - goto out; - } - } else { - if (S_ISDIR(libStat.st_mode)) { - if (delete_dir_contents(libsymlink, 1, 0) < 0) { - rc = -1; - goto out; - } - } else if (S_ISLNK(libStat.st_mode)) { - if (unlink(libsymlink) < 0) { - ALOGE("couldn't unlink lib dir: %s\n", strerror(errno)); - rc = -1; - goto out; - } - } - } - - if (symlink(asecLibDir, libsymlink) < 0) { - ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, asecLibDir, - strerror(errno)); - rc = -errno; - goto out; - } - -out: - if (chmod(pkgdir, s.st_mode) < 0) { - ALOGE("linklib() 2: failed to chmod '%s': %s\n", pkgdir, strerror(errno)); - rc = -errno; - } - - if (chown(pkgdir, s.st_uid, s.st_gid) < 0) { - ALOGE("failed to chown '%s' : %s\n", pkgdir, strerror(errno)); - return -errno; - } - - return rc; -} diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c deleted file mode 100644 index 281aaab..0000000 --- a/cmds/installd/installd.c +++ /dev/null @@ -1,593 +0,0 @@ -/* -** Copyright 2008, 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/capability.h> -#include <linux/prctl.h> - -#include "installd.h" - - -#define BUFFER_MAX 1024 /* input buffer for commands */ -#define TOKEN_MAX 8 /* max number of arguments in buffer */ -#define REPLY_MAX 256 /* largest reply allowed */ - -static int do_ping(char **arg, char reply[REPLY_MAX]) -{ - return 0; -} - -static int do_install(char **arg, char reply[REPLY_MAX]) -{ - return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */ -} - -static int do_dexopt(char **arg, char reply[REPLY_MAX]) -{ - /* apk_path, uid, is_public */ - return dexopt(arg[0], atoi(arg[1]), atoi(arg[2])); -} - -static int do_move_dex(char **arg, char reply[REPLY_MAX]) -{ - return move_dex(arg[0], arg[1]); /* src, dst */ -} - -static int do_rm_dex(char **arg, char reply[REPLY_MAX]) -{ - return rm_dex(arg[0]); /* pkgname */ -} - -static int do_remove(char **arg, char reply[REPLY_MAX]) -{ - return uninstall(arg[0], atoi(arg[1])); /* pkgname, userid */ -} - -static int do_rename(char **arg, char reply[REPLY_MAX]) -{ - return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */ -} - -static int do_fixuid(char **arg, char reply[REPLY_MAX]) -{ - return fix_uid(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */ -} - -static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */ -{ - return free_cache((int64_t)atoll(arg[0])); /* free_size */ -} - -static int do_rm_cache(char **arg, char reply[REPLY_MAX]) -{ - return delete_cache(arg[0], atoi(arg[1])); /* pkgname, userid */ -} - -static int do_get_size(char **arg, char reply[REPLY_MAX]) -{ - int64_t codesize = 0; - int64_t datasize = 0; - int64_t cachesize = 0; - int64_t asecsize = 0; - int res = 0; - - /* pkgdir, persona, apkpath */ - res = get_size(arg[0], atoi(arg[1]), arg[2], arg[3], arg[4], - &codesize, &datasize, &cachesize, &asecsize); - - /* - * Each int64_t can take up 22 characters printed out. Make sure it - * doesn't go over REPLY_MAX in the future. - */ - snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64, - codesize, datasize, cachesize, asecsize); - return res; -} - -static int do_rm_user_data(char **arg, char reply[REPLY_MAX]) -{ - return delete_user_data(arg[0], atoi(arg[1])); /* pkgname, userid */ -} - -static int do_mk_user_data(char **arg, char reply[REPLY_MAX]) -{ - return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); - /* pkgname, uid, userid, seinfo */ -} - -static int do_rm_user(char **arg, char reply[REPLY_MAX]) -{ - return delete_persona(atoi(arg[0])); /* userid */ -} - -static int do_clone_user_data(char **arg, char reply[REPLY_MAX]) -{ - return clone_persona_data(atoi(arg[0]), atoi(arg[1]), atoi(arg[2])); -} - -static int do_movefiles(char **arg, char reply[REPLY_MAX]) -{ - return movefiles(); -} - -static int do_linklib(char **arg, char reply[REPLY_MAX]) -{ - return linklib(arg[0], arg[1], atoi(arg[2])); -} - -struct cmdinfo { - const char *name; - unsigned numargs; - int (*func)(char **arg, char reply[REPLY_MAX]); -}; - -struct cmdinfo cmds[] = { - { "ping", 0, do_ping }, - { "install", 4, do_install }, - { "dexopt", 3, do_dexopt }, - { "movedex", 2, do_move_dex }, - { "rmdex", 1, do_rm_dex }, - { "remove", 2, do_remove }, - { "rename", 2, do_rename }, - { "fixuid", 3, do_fixuid }, - { "freecache", 1, do_free_cache }, - { "rmcache", 2, do_rm_cache }, - { "getsize", 5, do_get_size }, - { "rmuserdata", 2, do_rm_user_data }, - { "movefiles", 0, do_movefiles }, - { "linklib", 3, do_linklib }, - { "mkuserdata", 4, do_mk_user_data }, - { "rmuser", 1, do_rm_user }, - { "cloneuserdata", 3, do_clone_user_data }, -}; - -static 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; - ALOGE("read error: %s\n", strerror(errno)); - return -1; - } - if (r == 0) { - ALOGE("eof\n"); - return -1; /* EOF */ - } - n += r; - } - return 0; -} - -static 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; - ALOGE("write error: %s\n", strerror(errno)); - return -1; - } - n += r; - } - return 0; -} - - -/* Tokenize the command buffer, locate a matching command, - * ensure that the required number of arguments are provided, - * call the function(), return the result. - */ -static int execute(int s, char cmd[BUFFER_MAX]) -{ - char reply[REPLY_MAX]; - char *arg[TOKEN_MAX+1]; - unsigned i; - unsigned n = 0; - unsigned short count; - int ret = -1; - -// ALOGI("execute('%s')\n", cmd); - - /* default reply is "" */ - reply[0] = 0; - - /* n is number of args (not counting arg[0]) */ - arg[0] = cmd; - while (*cmd) { - if (isspace(*cmd)) { - *cmd++ = 0; - n++; - arg[n] = cmd; - if (n == TOKEN_MAX) { - ALOGE("too many arguments\n"); - goto done; - } - } - cmd++; - } - - for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) { - if (!strcmp(cmds[i].name,arg[0])) { - if (n != cmds[i].numargs) { - ALOGE("%s requires %d arguments (%d given)\n", - cmds[i].name, cmds[i].numargs, n); - } else { - ret = cmds[i].func(arg + 1, reply); - } - goto done; - } - } - ALOGE("unsupported command '%s'\n", arg[0]); - -done: - if (reply[0]) { - n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply); - } else { - n = snprintf(cmd, BUFFER_MAX, "%d", ret); - } - if (n > BUFFER_MAX) n = BUFFER_MAX; - count = n; - -// ALOGI("reply: '%s'\n", cmd); - if (writex(s, &count, sizeof(count))) return -1; - if (writex(s, cmd, count)) return -1; - return 0; -} - -/** - * Initialize all the global variables that are used elsewhere. Returns 0 upon - * success and -1 on error. - */ -void free_globals() { - size_t i; - - for (i = 0; i < android_system_dirs.count; i++) { - if (android_system_dirs.dirs[i].path != NULL) { - free(android_system_dirs.dirs[i].path); - } - } - - free(android_system_dirs.dirs); -} - -int initialize_globals() { - // Get the android data directory. - if (get_path_from_env(&android_data_dir, "ANDROID_DATA") < 0) { - return -1; - } - - // Get the android app directory. - if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) { - return -1; - } - - // Get the android protected app directory. - if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) { - return -1; - } - - // Get the android app native library directory. - if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) { - return -1; - } - - // Get the sd-card ASEC mount point. - if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) { - return -1; - } - - // Get the android media directory. - if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) { - return -1; - } - - // Take note of the system and vendor directories. - android_system_dirs.count = 2; - - android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t)); - if (android_system_dirs.dirs == NULL) { - ALOGE("Couldn't allocate array for dirs; aborting\n"); - return -1; - } - - // system - if (get_path_from_env(&android_system_dirs.dirs[0], "ANDROID_ROOT") < 0) { - free_globals(); - return -1; - } - - // append "app/" to dirs[0] - char *system_app_path = build_string2(android_system_dirs.dirs[0].path, APP_SUBDIR); - android_system_dirs.dirs[0].path = system_app_path; - android_system_dirs.dirs[0].len = strlen(system_app_path); - - // vendor - // TODO replace this with an environment variable (doesn't exist yet) - android_system_dirs.dirs[1].path = "/vendor/app/"; - android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path); - - return 0; -} - -int initialize_directories() { - int res = -1; - - // Read current filesystem layout version to handle upgrade paths - char version_path[PATH_MAX]; - snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path); - - int oldVersion; - if (fs_read_atomic_int(version_path, &oldVersion) == -1) { - oldVersion = 0; - } - int version = oldVersion; - - // /data/user - char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX); - // /data/data - char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX); - // /data/user/0 - char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0"); - if (!user_data_dir || !legacy_data_dir || !primary_data_dir) { - goto fail; - } - - // Make the /data/user directory if necessary - if (access(user_data_dir, R_OK) < 0) { - if (mkdir(user_data_dir, 0711) < 0) { - goto fail; - } - if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) { - goto fail; - } - if (chmod(user_data_dir, 0711) < 0) { - goto fail; - } - } - // Make the /data/user/0 symlink to /data/data if necessary - if (access(primary_data_dir, R_OK) < 0) { - if (symlink(legacy_data_dir, primary_data_dir)) { - goto fail; - } - } - - if (version == 0) { - // Introducing multi-user, so migrate /data/media contents into /data/media/0 - ALOGD("Upgrading /data/media for multi-user"); - - // Ensure /data/media - if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { - goto fail; - } - - // /data/media.tmp - char media_tmp_dir[PATH_MAX]; - snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path); - - // Only copy when upgrade not already in progress - if (access(media_tmp_dir, F_OK) == -1) { - if (rename(android_media_dir.path, media_tmp_dir) == -1) { - ALOGE("Failed to move legacy media path: %s", strerror(errno)); - goto fail; - } - } - - // Create /data/media again - if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { - goto fail; - } - - // /data/media/0 - char owner_media_dir[PATH_MAX]; - snprintf(owner_media_dir, PATH_MAX, "%s0", android_media_dir.path); - - // Move any owner data into place - if (access(media_tmp_dir, F_OK) == 0) { - if (rename(media_tmp_dir, owner_media_dir) == -1) { - ALOGE("Failed to move owner media path: %s", strerror(errno)); - goto fail; - } - } - - // Ensure media directories for any existing users - DIR *dir; - struct dirent *dirent; - char user_media_dir[PATH_MAX]; - - dir = opendir(user_data_dir); - if (dir != NULL) { - while ((dirent = readdir(dir))) { - if (dirent->d_type == DT_DIR) { - const char *name = dirent->d_name; - - // skip "." and ".." - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - - // /data/media/<user_id> - snprintf(user_media_dir, PATH_MAX, "%s%s", android_media_dir.path, name); - if (fs_prepare_dir(user_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { - goto fail; - } - } - } - closedir(dir); - } - - version = 1; - } - - // /data/media/obb - char media_obb_dir[PATH_MAX]; - snprintf(media_obb_dir, PATH_MAX, "%sobb", android_media_dir.path); - - if (version == 1) { - // Introducing /data/media/obb for sharing OBB across users; migrate - // any existing OBB files from owner. - ALOGD("Upgrading to shared /data/media/obb"); - - // /data/media/0/Android/obb - char owner_obb_path[PATH_MAX]; - snprintf(owner_obb_path, PATH_MAX, "%s0/Android/obb", android_media_dir.path); - - // Only move if target doesn't already exist - if (access(media_obb_dir, F_OK) != 0 && access(owner_obb_path, F_OK) == 0) { - if (rename(owner_obb_path, media_obb_dir) == -1) { - ALOGE("Failed to move OBB from owner: %s", strerror(errno)); - goto fail; - } - } - - version = 2; - } - - if (ensure_media_user_dirs(0) == -1) { - ALOGE("Failed to setup media for user 0"); - goto fail; - } - if (fs_prepare_dir(media_obb_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { - goto fail; - } - - // Persist layout version if changed - if (version != oldVersion) { - if (fs_write_atomic_int(version_path, version) == -1) { - ALOGE("Failed to save version to %s: %s", version_path, strerror(errno)); - goto fail; - } - } - - // Success! - res = 0; - -fail: - free(user_data_dir); - free(legacy_data_dir); - free(primary_data_dir); - return res; -} - -static void drop_privileges() { - if (prctl(PR_SET_KEEPCAPS, 1) < 0) { - ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno)); - exit(1); - } - - if (setgid(AID_INSTALL) < 0) { - ALOGE("setgid() can't drop privileges; exiting.\n"); - exit(1); - } - - if (setuid(AID_INSTALL) < 0) { - ALOGE("setuid() can't drop privileges; exiting.\n"); - exit(1); - } - - struct __user_cap_header_struct capheader; - struct __user_cap_data_struct capdata[2]; - memset(&capheader, 0, sizeof(capheader)); - memset(&capdata, 0, sizeof(capdata)); - capheader.version = _LINUX_CAPABILITY_VERSION_3; - capheader.pid = 0; - - capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE); - capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN); - capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID); - capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID); - - capdata[0].effective = capdata[0].permitted; - capdata[1].effective = capdata[1].permitted; - capdata[0].inheritable = 0; - capdata[1].inheritable = 0; - - if (capset(&capheader, &capdata[0]) < 0) { - ALOGE("capset failed: %s\n", strerror(errno)); - exit(1); - } -} - -int main(const int argc, const char *argv[]) { - char buf[BUFFER_MAX]; - struct sockaddr addr; - socklen_t alen; - int lsocket, s, count; - - ALOGI("installd firing up\n"); - - if (initialize_globals() < 0) { - ALOGE("Could not initialize globals; exiting.\n"); - exit(1); - } - - if (initialize_directories() < 0) { - ALOGE("Could not create directories; exiting.\n"); - exit(1); - } - - drop_privileges(); - - lsocket = android_get_control_socket(SOCKET_PATH); - if (lsocket < 0) { - ALOGE("Failed to get socket from environment: %s\n", strerror(errno)); - exit(1); - } - if (listen(lsocket, 5)) { - ALOGE("Listen on socket failed: %s\n", strerror(errno)); - exit(1); - } - fcntl(lsocket, F_SETFD, FD_CLOEXEC); - - for (;;) { - alen = sizeof(addr); - s = accept(lsocket, &addr, &alen); - if (s < 0) { - ALOGE("Accept failed: %s\n", strerror(errno)); - continue; - } - fcntl(s, F_SETFD, FD_CLOEXEC); - - ALOGI("new connection\n"); - for (;;) { - unsigned short count; - if (readx(s, &count, sizeof(count))) { - ALOGE("failed to read size\n"); - break; - } - if ((count < 1) || (count >= BUFFER_MAX)) { - ALOGE("invalid size %d\n", count); - break; - } - if (readx(s, buf, count)) { - ALOGE("failed to read command\n"); - break; - } - buf[count] = 0; - if (execute(s, buf)) break; - } - ALOGI("closing connection\n"); - close(s); - } - - return 0; -} diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h deleted file mode 100644 index 04498ef..0000000 --- a/cmds/installd/installd.h +++ /dev/null @@ -1,213 +0,0 @@ -/* -** -** Copyright 2008, 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 "installd" - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <inttypes.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 <cutils/fs.h> -#include <cutils/sockets.h> -#include <cutils/log.h> -#include <cutils/properties.h> -#include <cutils/multiuser.h> - -#include <private/android_filesystem_config.h> - -#if INCLUDE_SYS_MOUNT_FOR_STATFS -#include <sys/mount.h> -#else -#include <sys/statfs.h> -#endif - -#define SOCKET_PATH "installd" - - -/* elements combined with a valid package name to form paths */ - -#define PRIMARY_USER_PREFIX "data/" -#define SECONDARY_USER_PREFIX "user/" - -#define PKG_DIR_POSTFIX "" - -#define PKG_LIB_POSTFIX "/lib" - -#define CACHE_DIR_POSTFIX "/cache" - -#define APP_SUBDIR "app/" // sub-directory under ANDROID_DATA - -#define APP_LIB_SUBDIR "app-lib/" // sub-directory under ANDROID_DATA - -#define MEDIA_SUBDIR "media/" // sub-directory under ANDROID_DATA - -/* other handy constants */ - -#define PRIVATE_APP_SUBDIR "app-private/" // sub-directory under ANDROID_DATA - -#define DALVIK_CACHE_PREFIX "/data/dalvik-cache/" -#define DALVIK_CACHE_POSTFIX "/classes.dex" - -#define UPDATE_COMMANDS_DIR_PREFIX "/system/etc/updatecmds/" - -#define PKG_NAME_MAX 128 /* largest allowed package name */ -#define PKG_PATH_MAX 256 /* max size of any path we use */ - -#define PER_USER_RANGE ((uid_t)100000) /* range of uids per user - uid = persona * PER_USER_RANGE + appid */ - -/* data structures */ - -typedef struct { - char* path; - size_t len; -} dir_rec_t; - -typedef struct { - size_t count; - dir_rec_t* dirs; -} dir_rec_array_t; - -extern dir_rec_t android_app_dir; -extern dir_rec_t android_app_private_dir; -extern dir_rec_t android_app_lib_dir; -extern dir_rec_t android_data_dir; -extern dir_rec_t android_asec_dir; -extern dir_rec_t android_media_dir; -extern dir_rec_array_t android_system_dirs; - -typedef struct cache_dir_struct { - struct cache_dir_struct* parent; - int32_t childCount; - int32_t hiddenCount; - int32_t deleted; - char name[]; -} cache_dir_t; - -typedef struct { - cache_dir_t* dir; - time_t modTime; - char name[]; -} cache_file_t; - -typedef struct { - size_t numDirs; - size_t availDirs; - cache_dir_t** dirs; - size_t numFiles; - size_t availFiles; - cache_file_t** files; - size_t numCollected; - void* memBlocks; - int8_t* curMemBlockAvail; - int8_t* curMemBlockEnd; -} cache_t; - -/* util.c */ - -int create_pkg_path_in_dir(char path[PKG_PATH_MAX], - const dir_rec_t* dir, - const char* pkgname, - const char* postfix); - -int create_pkg_path(char path[PKG_PATH_MAX], - const char *pkgname, - const char *postfix, - uid_t persona); - -int create_persona_path(char path[PKG_PATH_MAX], - uid_t persona); - -int create_persona_media_path(char path[PKG_PATH_MAX], userid_t userid); - -int create_move_path(char path[PKG_PATH_MAX], - const char* pkgname, - const char* leaf, - uid_t persona); - -int is_valid_package_name(const char* pkgname); - -int create_cache_path(char path[PKG_PATH_MAX], const char *src); - -int delete_dir_contents(const char *pathname, - int also_delete_dir, - const char *ignore); - -int delete_dir_contents_fd(int dfd, const char *name); - -int lookup_media_dir(char basepath[PATH_MAX], const char *dir); - -int64_t data_disk_free(); - -cache_t* start_cache_collection(); - -void add_cache_files(cache_t* cache, const char *basepath, const char *cachedir); - -void clear_cache_files(cache_t* cache, int64_t free_size); - -void finish_cache_collection(cache_t* cache); - -int validate_system_app_path(const char* path); - -int get_path_from_env(dir_rec_t* rec, const char* var); - -int get_path_from_string(dir_rec_t* rec, const char* path); - -int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix); - -int validate_apk_path(const char *path); - -int append_and_increment(char** dst, const char* src, size_t* dst_size); - -char *build_string2(char *s1, char *s2); -char *build_string3(char *s1, char *s2, char *s3); - -int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid); -int ensure_media_user_dirs(userid_t userid); - -/* commands.c */ - -int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo); -int uninstall(const char *pkgname, uid_t persona); -int renamepkg(const char *oldpkgname, const char *newpkgname); -int fix_uid(const char *pkgname, uid_t uid, gid_t gid); -int delete_user_data(const char *pkgname, uid_t persona); -int make_user_data(const char *pkgname, uid_t uid, uid_t persona, const char* seinfo); -int delete_persona(uid_t persona); -int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy); -int delete_cache(const char *pkgname, uid_t persona); -int move_dex(const char *src, const char *dst); -int rm_dex(const char *path); -int protect(char *pkgname, gid_t gid); -int get_size(const char *pkgname, int persona, const char *apkpath, const char *fwdlock_apkpath, - const char *asecpath, int64_t *codesize, int64_t *datasize, int64_t *cachesize, - int64_t *asecsize); -int free_cache(int64_t free_size); -int dexopt(const char *apk_path, uid_t uid, int is_public); -int movefiles(); -int linklib(const char* target, const char* source, int userId); diff --git a/cmds/installd/tests/Android.mk b/cmds/installd/tests/Android.mk deleted file mode 100644 index c0192f4..0000000 --- a/cmds/installd/tests/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# Build the unit tests for installd -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -# Build the unit tests. -test_src_files := \ - installd_utils_test.cpp - -shared_libraries := \ - libutils \ - libcutils \ - libstlport - -static_libraries := \ - libinstalld \ - libdiskusage \ - libgtest \ - libgtest_main - -c_includes := \ - frameworks/base/cmds/installd - -$(foreach file,$(test_src_files), \ - $(eval include $(CLEAR_VARS)) \ - $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \ - $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \ - $(eval LOCAL_SRC_FILES := $(file)) \ - $(eval LOCAL_C_INCLUDES := $(c_includes)) \ - $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ - $(eval include $(BUILD_NATIVE_TEST)) \ -) diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp deleted file mode 100644 index 7cb9b37..0000000 --- a/cmds/installd/tests/installd_utils_test.cpp +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Copyright (C) 2011 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 <stdlib.h> -#include <string.h> - -#define LOG_TAG "utils_test" -#include <utils/Log.h> - -#include <gtest/gtest.h> - -extern "C" { -#include "installd.h" -} - -#define TEST_DATA_DIR "/data/" -#define TEST_APP_DIR "/data/app/" -#define TEST_APP_PRIVATE_DIR "/data/app-private/" -#define TEST_ASEC_DIR "/mnt/asec/" - -#define TEST_SYSTEM_DIR1 "/system/app/" -#define TEST_SYSTEM_DIR2 "/vendor/app/" - -#define REALLY_LONG_APP_NAME "com.example." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \ - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - -#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \ - "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" - -namespace android { - -class UtilsTest : public testing::Test { -protected: - virtual void SetUp() { - android_app_dir.path = TEST_APP_DIR; - android_app_dir.len = strlen(TEST_APP_DIR); - - android_app_private_dir.path = TEST_APP_PRIVATE_DIR; - android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR); - - android_data_dir.path = TEST_DATA_DIR; - android_data_dir.len = strlen(TEST_DATA_DIR); - - android_asec_dir.path = TEST_ASEC_DIR; - android_asec_dir.len = strlen(TEST_ASEC_DIR); - - android_system_dirs.count = 2; - - android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t)); - android_system_dirs.dirs[0].path = TEST_SYSTEM_DIR1; - android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1); - - android_system_dirs.dirs[1].path = TEST_SYSTEM_DIR2; - android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2); - } - - virtual void TearDown() { - free(android_system_dirs.dirs); - } -}; - -TEST_F(UtilsTest, IsValidApkPath_BadPrefix) { - // Bad prefixes directories - const char *badprefix1 = "/etc/passwd"; - EXPECT_EQ(-1, validate_apk_path(badprefix1)) - << badprefix1 << " should be allowed as a valid path"; - - const char *badprefix2 = "../.." TEST_APP_DIR "../../../blah"; - EXPECT_EQ(-1, validate_apk_path(badprefix2)) - << badprefix2 << " should be allowed as a valid path"; - - const char *badprefix3 = "init.rc"; - EXPECT_EQ(-1, validate_apk_path(badprefix3)) - << badprefix3 << " should be allowed as a valid path"; - - const char *badprefix4 = "/init.rc"; - EXPECT_EQ(-1, validate_apk_path(badprefix4)) - << badprefix4 << " should be allowed as a valid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_Internal) { - // Internal directories - const char *internal1 = TEST_APP_DIR "example.apk"; - EXPECT_EQ(0, validate_apk_path(internal1)) - << internal1 << " should be allowed as a valid path"; - - const char *badint1 = TEST_APP_DIR "../example.apk"; - EXPECT_EQ(-1, validate_apk_path(badint1)) - << badint1 << " should be rejected as a invalid path"; - - const char *badint2 = TEST_APP_DIR "/../example.apk"; - EXPECT_EQ(-1, validate_apk_path(badint2)) - << badint2 << " should be rejected as a invalid path"; - - const char *badint3 = TEST_APP_DIR "example.com/pkg.apk"; - EXPECT_EQ(-1, validate_apk_path(badint3)) - << badint3 << " should be rejected as a invalid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_Private) { - // Internal directories - const char *private1 = TEST_APP_PRIVATE_DIR "example.apk"; - EXPECT_EQ(0, validate_apk_path(private1)) - << private1 << " should be allowed as a valid path"; - - const char *badpriv1 = TEST_APP_PRIVATE_DIR "../example.apk"; - EXPECT_EQ(-1, validate_apk_path(badpriv1)) - << badpriv1 << " should be rejected as a invalid path"; - - const char *badpriv2 = TEST_APP_PRIVATE_DIR "/../example.apk"; - EXPECT_EQ(-1, validate_apk_path(badpriv2)) - << badpriv2 << " should be rejected as a invalid path"; - - const char *badpriv3 = TEST_APP_PRIVATE_DIR "example.com/pkg.apk"; - EXPECT_EQ(-1, validate_apk_path(badpriv3)) - << badpriv3 << " should be rejected as a invalid path"; -} - - -TEST_F(UtilsTest, IsValidApkPath_AsecGood1) { - const char *asec1 = TEST_ASEC_DIR "example.apk"; - EXPECT_EQ(0, validate_apk_path(asec1)) - << asec1 << " should be allowed as a valid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_AsecGood2) { - const char *asec2 = TEST_ASEC_DIR "com.example.asec/pkg.apk"; - EXPECT_EQ(0, validate_apk_path(asec2)) - << asec2 << " should be allowed as a valid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_EscapeFail) { - const char *badasec1 = TEST_ASEC_DIR "../example.apk"; - EXPECT_EQ(-1, validate_apk_path(badasec1)) - << badasec1 << " should be rejected as a invalid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_DoubleSlashFail) { - const char *badasec2 = TEST_ASEC_DIR "com.example.asec//pkg.apk"; - EXPECT_EQ(-1, validate_apk_path(badasec2)) - << badasec2 << " should be rejected as a invalid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeFail) { - const char *badasec3 = TEST_ASEC_DIR "com.example.asec/../../../pkg.apk"; - EXPECT_EQ(-1, validate_apk_path(badasec3)) - << badasec3 << " should be rejected as a invalid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_SlashEscapeFail) { - const char *badasec4 = TEST_ASEC_DIR "/../example.apk"; - EXPECT_EQ(-1, validate_apk_path(badasec4)) - << badasec4 << " should be rejected as a invalid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_CrazyDirFail) { - const char *badasec5 = TEST_ASEC_DIR ".//../.."; - EXPECT_EQ(-1, validate_apk_path(badasec5)) - << badasec5 << " should be rejected as a invalid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeSingleFail) { - const char *badasec6 = TEST_ASEC_DIR "com.example.asec/../pkg.apk"; - EXPECT_EQ(-1, validate_apk_path(badasec6)) - << badasec6 << " should be rejected as a invalid path"; -} - -TEST_F(UtilsTest, IsValidApkPath_TwoSubdirFail) { - const char *badasec7 = TEST_ASEC_DIR "com.example.asec/subdir1/pkg.apk"; - EXPECT_EQ(-1, validate_apk_path(badasec7)) - << badasec7 << " should be rejected as a invalid path"; -} - -TEST_F(UtilsTest, CheckSystemApp_Dir1) { - const char *sysapp1 = TEST_SYSTEM_DIR1 "Voice.apk"; - EXPECT_EQ(0, validate_system_app_path(sysapp1)) - << sysapp1 << " should be allowed as a system path"; -} - -TEST_F(UtilsTest, CheckSystemApp_Dir2) { - const char *sysapp2 = TEST_SYSTEM_DIR2 "com.example.myapp.apk"; - EXPECT_EQ(0, validate_system_app_path(sysapp2)) - << sysapp2 << " should be allowed as a system path"; -} - -TEST_F(UtilsTest, CheckSystemApp_EscapeFail) { - const char *badapp1 = TEST_SYSTEM_DIR1 "../com.example.apk"; - EXPECT_EQ(-1, validate_system_app_path(badapp1)) - << badapp1 << " should be rejected not a system path"; -} - -TEST_F(UtilsTest, CheckSystemApp_DoubleEscapeFail) { - const char *badapp2 = TEST_SYSTEM_DIR2 "/../../com.example.apk"; - EXPECT_EQ(-1, validate_system_app_path(badapp2)) - << badapp2 << " should be rejected not a system path"; -} - -TEST_F(UtilsTest, CheckSystemApp_BadPathEscapeFail) { - const char *badapp3 = TEST_APP_DIR "/../../com.example.apk"; - EXPECT_EQ(-1, validate_system_app_path(badapp3)) - << badapp3 << " should be rejected not a system path"; -} - -TEST_F(UtilsTest, GetPathFromString_NullPathFail) { - dir_rec_t test1; - EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL)) - << "Should not allow NULL as a path."; -} - -TEST_F(UtilsTest, GetPathFromString_EmptyPathFail) { - dir_rec_t test1; - EXPECT_EQ(-1, get_path_from_string(&test1, "")) - << "Should not allow empty paths."; -} - -TEST_F(UtilsTest, GetPathFromString_RelativePathFail) { - dir_rec_t test1; - EXPECT_EQ(-1, get_path_from_string(&test1, "mnt/asec")) - << "Should not allow relative paths."; -} - -TEST_F(UtilsTest, GetPathFromString_NonCanonical) { - dir_rec_t test1; - - EXPECT_EQ(0, get_path_from_string(&test1, "/mnt/asec")) - << "Should be able to canonicalize directory /mnt/asec"; - EXPECT_STREQ("/mnt/asec/", test1.path) - << "/mnt/asec should be canonicalized to /mnt/asec/"; - EXPECT_EQ(10, (ssize_t) test1.len) - << "path len should be equal to the length of /mnt/asec/ (10)"; - free(test1.path); -} - -TEST_F(UtilsTest, GetPathFromString_CanonicalPath) { - dir_rec_t test3; - EXPECT_EQ(0, get_path_from_string(&test3, "/data/app/")) - << "Should be able to canonicalize directory /data/app/"; - EXPECT_STREQ("/data/app/", test3.path) - << "/data/app/ should be canonicalized to /data/app/"; - EXPECT_EQ(10, (ssize_t) test3.len) - << "path len should be equal to the length of /data/app/ (10)"; - free(test3.path); -} - -TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) { - char path[PKG_PATH_MAX]; - - // Create long packagename of "aaaaa..." - size_t pkgnameSize = PKG_NAME_MAX; - char pkgname[pkgnameSize + 1]; - memset(pkgname, 'a', pkgnameSize); - pkgname[pkgnameSize] = '\0'; - - EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0)) - << "Should successfully be able to create package name."; - - const char *prefix = TEST_DATA_DIR PRIMARY_USER_PREFIX; - size_t offset = strlen(prefix); - EXPECT_STREQ(pkgname, path + offset) - << "Package path should be a really long string of a's"; -} - -TEST_F(UtilsTest, CreatePkgPath_LongPkgNameFail) { - char path[PKG_PATH_MAX]; - - // Create long packagename of "aaaaa..." - size_t pkgnameSize = PKG_NAME_MAX + 1; - char pkgname[pkgnameSize + 1]; - memset(pkgname, 'a', pkgnameSize); - pkgname[pkgnameSize] = '\0'; - - EXPECT_EQ(-1, create_pkg_path(path, pkgname, "", 0)) - << "Should return error because package name is too long."; -} - -TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) { - char path[PKG_PATH_MAX]; - - // Create long packagename of "aaaaa..." - size_t postfixSize = PKG_PATH_MAX; - char postfix[postfixSize + 1]; - memset(postfix, 'a', postfixSize); - postfix[postfixSize] = '\0'; - - EXPECT_EQ(-1, create_pkg_path(path, "com.example.package", postfix, 0)) - << "Should return error because postfix is too long."; -} - -TEST_F(UtilsTest, CreatePkgPath_PrimaryUser) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 0)) - << "Should return error because postfix is too long."; - - EXPECT_STREQ(TEST_DATA_DIR PRIMARY_USER_PREFIX "com.example.package", path) - << "Package path should be in /data/data/"; -} - -TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 1)) - << "Should successfully create package path."; - - EXPECT_STREQ(TEST_DATA_DIR SECONDARY_USER_PREFIX "1/com.example.package", path) - << "Package path should be in /data/user/"; -} - -TEST_F(UtilsTest, CreatePkgPathInDir_ProtectedDir) { - char path[PKG_PATH_MAX]; - - dir_rec_t dir; - dir.path = "/data/app-private/"; - dir.len = strlen(dir.path); - - EXPECT_EQ(0, create_pkg_path_in_dir(path, &dir, "com.example.package", ".apk")) - << "Should successfully create package path."; - - EXPECT_STREQ("/data/app-private/com.example.package.apk", path) - << "Package path should be in /data/app-private/"; -} - -TEST_F(UtilsTest, CreatePersonaPath_Primary) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(0, create_persona_path(path, 0)) - << "Should successfully build primary user path."; - - EXPECT_STREQ("/data/data/", path) - << "Primary user should have correct path"; -} - -TEST_F(UtilsTest, CreatePersonaPath_Secondary) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(0, create_persona_path(path, 1)) - << "Should successfully build primary user path."; - - EXPECT_STREQ("/data/user/1/", path) - << "Primary user should have correct path"; -} - -TEST_F(UtilsTest, CreateMovePath_Primary) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0)) - << "Should be able to create move path for primary user"; - - EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path) - << "Primary user package directory should be created correctly"; -} - -TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0)) - << "Should fail to create move path for primary user"; -} - -TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) { - char path[PKG_PATH_MAX]; - - EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0)) - << "Should fail to create move path for primary user"; -} - -TEST_F(UtilsTest, CopyAndAppend_Normal) { - //int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix) - dir_rec_t dst; - dir_rec_t src; - - src.path = "/data/"; - src.len = strlen(src.path); - - EXPECT_EQ(0, copy_and_append(&dst, &src, "app/")) - << "Should return error because postfix is too long."; - - EXPECT_STREQ("/data/app/", dst.path) - << "Appended path should be correct"; - - EXPECT_EQ(10, (ssize_t) dst.len) - << "Appended path should be length of '/data/app/' (10)"; -} - -TEST_F(UtilsTest, AppendAndIncrement_Normal) { - size_t dst_size = 10; - char dst[dst_size]; - char *dstp = dst; - const char* src = "FOO"; - - EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size)) - << "String should append successfully"; - - EXPECT_STREQ("FOO", dst) - << "String should append correctly"; - - EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size)) - << "String should append successfully again"; - - EXPECT_STREQ("FOOFOO", dst) - << "String should append correctly again"; -} - -TEST_F(UtilsTest, AppendAndIncrement_TooBig) { - size_t dst_size = 5; - char dst[dst_size]; - char *dstp = dst; - const char* src = "FOO"; - - EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size)) - << "String should append successfully"; - - EXPECT_STREQ("FOO", dst) - << "String should append correctly"; - - EXPECT_EQ(-1, append_and_increment(&dstp, src, &dst_size)) - << "String should fail because it's too large to fit"; -} - -} diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c deleted file mode 100644 index 625a35e..0000000 --- a/cmds/installd/utils.c +++ /dev/null @@ -1,1006 +0,0 @@ -/* -** Copyright 2008, 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 "installd.h" - -#define CACHE_NOISY(x) //x - -int create_pkg_path_in_dir(char path[PKG_PATH_MAX], - const dir_rec_t* dir, - const char* pkgname, - const char* postfix) -{ - const size_t postfix_len = strlen(postfix); - - const size_t pkgname_len = strlen(pkgname); - if (pkgname_len > PKG_NAME_MAX) { - return -1; - } - - if (is_valid_package_name(pkgname) < 0) { - return -1; - } - - if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) { - return -1; - } - - char *dst = path; - size_t dst_size = PKG_PATH_MAX; - - if (append_and_increment(&dst, dir->path, &dst_size) < 0 - || append_and_increment(&dst, pkgname, &dst_size) < 0 - || append_and_increment(&dst, postfix, &dst_size) < 0) { - ALOGE("Error building APK path"); - return -1; - } - - return 0; -} - -/** - * Create the package path name for a given package name with a postfix for - * a certain persona. Returns 0 on success, and -1 on failure. - */ -int create_pkg_path(char path[PKG_PATH_MAX], - const char *pkgname, - const char *postfix, - uid_t persona) -{ - size_t uid_len; - char* persona_prefix; - if (persona == 0) { - persona_prefix = PRIMARY_USER_PREFIX; - uid_len = 0; - } else { - persona_prefix = SECONDARY_USER_PREFIX; - uid_len = snprintf(NULL, 0, "%d", persona); - } - - const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/; - char prefix[prefix_len + 1]; - - char *dst = prefix; - size_t dst_size = sizeof(prefix); - - if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0 - || append_and_increment(&dst, persona_prefix, &dst_size) < 0) { - ALOGE("Error building prefix for APK path"); - return -1; - } - - if (persona != 0) { - int ret = snprintf(dst, dst_size, "%d/", persona); - if (ret < 0 || (size_t) ret != uid_len + 1) { - ALOGW("Error appending UID to APK path"); - return -1; - } - } - - dir_rec_t dir; - dir.path = prefix; - dir.len = prefix_len; - - return create_pkg_path_in_dir(path, &dir, pkgname, postfix); -} - -/** - * Create the path name for user data for a certain persona. - * Returns 0 on success, and -1 on failure. - */ -int create_persona_path(char path[PKG_PATH_MAX], - uid_t persona) -{ - size_t uid_len; - char* persona_prefix; - if (persona == 0) { - persona_prefix = PRIMARY_USER_PREFIX; - uid_len = 0; - } else { - persona_prefix = SECONDARY_USER_PREFIX; - uid_len = snprintf(NULL, 0, "%d/", persona); - } - - char *dst = path; - size_t dst_size = PKG_PATH_MAX; - - if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0 - || append_and_increment(&dst, persona_prefix, &dst_size) < 0) { - ALOGE("Error building prefix for user path"); - return -1; - } - - if (persona != 0) { - if (dst_size < uid_len + 1) { - ALOGE("Error building user path"); - return -1; - } - int ret = snprintf(dst, dst_size, "%d/", persona); - if (ret < 0 || (size_t) ret != uid_len) { - ALOGE("Error appending persona id to path"); - return -1; - } - } - return 0; -} - -/** - * Create the path name for media for a certain persona. - * Returns 0 on success, and -1 on failure. - */ -int create_persona_media_path(char path[PATH_MAX], userid_t userid) { - if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) { - return -1; - } - return 0; -} - -int create_move_path(char path[PKG_PATH_MAX], - const char* pkgname, - const char* leaf, - uid_t persona) -{ - if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1) - >= PKG_PATH_MAX) { - return -1; - } - - sprintf(path, "%s%s%s/%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgname, leaf); - return 0; -} - -/** - * Checks whether the package name is valid. Returns -1 on error and - * 0 on success. - */ -int is_valid_package_name(const char* pkgname) { - const char *x = pkgname; - int alpha = -1; - - while (*x) { - if (isalnum(*x) || (*x == '_')) { - /* alphanumeric or underscore are fine */ - } else if (*x == '.') { - if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) { - /* periods must not be first, last, or doubled */ - ALOGE("invalid package name '%s'\n", pkgname); - return -1; - } - } else if (*x == '-') { - /* Suffix -X is fine to let versioning of packages. - But whatever follows should be alphanumeric.*/ - alpha = 1; - } else { - /* anything not A-Z, a-z, 0-9, _, or . is invalid */ - ALOGE("invalid package name '%s'\n", pkgname); - return -1; - } - - x++; - } - - if (alpha == 1) { - // Skip current character - x++; - while (*x) { - if (!isalnum(*x)) { - ALOGE("invalid package name '%s' should include only numbers after -\n", pkgname); - return -1; - } - x++; - } - } - - return 0; -} - -static int _delete_dir_contents(DIR *d, const char *ignore) -{ - int result = 0; - struct dirent *de; - int dfd; - - dfd = dirfd(d); - - if (dfd < 0) return -1; - - while ((de = readdir(d))) { - const char *name = de->d_name; - - /* skip the ignore name if provided */ - if (ignore && !strcmp(name, ignore)) continue; - - if (de->d_type == DT_DIR) { - int r, subfd; - DIR *subdir; - - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - - subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); - if (subfd < 0) { - ALOGE("Couldn't openat %s: %s\n", name, strerror(errno)); - result = -1; - continue; - } - subdir = fdopendir(subfd); - if (subdir == NULL) { - ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); - close(subfd); - result = -1; - continue; - } - if (_delete_dir_contents(subdir, 0)) { - result = -1; - } - closedir(subdir); - if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { - ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); - result = -1; - } - } else { - if (unlinkat(dfd, name, 0) < 0) { - ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); - result = -1; - } - } - } - - return result; -} - -int delete_dir_contents(const char *pathname, - int also_delete_dir, - const char *ignore) -{ - int res = 0; - DIR *d; - - d = opendir(pathname); - if (d == NULL) { - ALOGE("Couldn't opendir %s: %s\n", pathname, strerror(errno)); - return -errno; - } - res = _delete_dir_contents(d, ignore); - closedir(d); - if (also_delete_dir) { - if (rmdir(pathname)) { - ALOGE("Couldn't rmdir %s: %s\n", pathname, strerror(errno)); - res = -1; - } - } - return res; -} - -int delete_dir_contents_fd(int dfd, const char *name) -{ - int fd, res; - DIR *d; - - fd = openat(dfd, name, O_RDONLY | O_DIRECTORY); - if (fd < 0) { - ALOGE("Couldn't openat %s: %s\n", name, strerror(errno)); - return -1; - } - d = fdopendir(fd); - if (d == NULL) { - ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); - close(fd); - return -1; - } - res = _delete_dir_contents(d, 0); - closedir(d); - return res; -} - -int lookup_media_dir(char basepath[PATH_MAX], const char *dir) -{ - DIR *d; - struct dirent *de; - struct stat s; - char* dirpos = basepath + strlen(basepath); - - if ((*(dirpos-1)) != '/') { - *dirpos = '/'; - dirpos++; - } - - CACHE_NOISY(ALOGI("Looking up %s in %s\n", dir, basepath)); - // Verify the path won't extend beyond our buffer, to avoid - // repeated checking later. - if ((dirpos-basepath+strlen(dir)) >= (PATH_MAX-1)) { - ALOGW("Path exceeds limit: %s%s", basepath, dir); - return -1; - } - - // First, can we find this directory with the case that is given? - strcpy(dirpos, dir); - if (stat(basepath, &s) >= 0) { - CACHE_NOISY(ALOGI("Found direct: %s\n", basepath)); - return 0; - } - - // Not found with that case... search through all entries to find - // one that matches regardless of case. - *dirpos = 0; - - d = opendir(basepath); - if (d == NULL) { - return -1; - } - - while ((de = readdir(d))) { - if (strcasecmp(de->d_name, dir) == 0) { - strcpy(dirpos, de->d_name); - closedir(d); - CACHE_NOISY(ALOGI("Found search: %s\n", basepath)); - return 0; - } - } - - ALOGW("Couldn't find %s in %s", dir, basepath); - closedir(d); - return -1; -} - -int64_t data_disk_free() -{ - struct statfs sfs; - if (statfs(android_data_dir.path, &sfs) == 0) { - return sfs.f_bavail * sfs.f_bsize; - } else { - ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno)); - return -1; - } -} - -cache_t* start_cache_collection() -{ - cache_t* cache = (cache_t*)calloc(1, sizeof(cache_t)); - return cache; -} - -#define CACHE_BLOCK_SIZE (512*1024) - -static void* _cache_malloc(cache_t* cache, size_t len) -{ - len = (len+3)&~3; - if (len > (CACHE_BLOCK_SIZE/2)) { - // It doesn't make sense to try to put this allocation into one - // of our blocks, because it is so big. Instead, make a new dedicated - // block for it. - int8_t* res = (int8_t*)malloc(len+sizeof(void*)); - if (res == NULL) { - return NULL; - } - CACHE_NOISY(ALOGI("Allocated large cache mem block: %p size %d", res, len)); - // Link it into our list of blocks, not disrupting the current one. - if (cache->memBlocks == NULL) { - *(void**)res = NULL; - cache->memBlocks = res; - } else { - *(void**)res = *(void**)cache->memBlocks; - *(void**)cache->memBlocks = res; - } - return res + sizeof(void*); - } - int8_t* res = cache->curMemBlockAvail; - int8_t* nextPos = res + len; - if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) { - int8_t* newBlock = malloc(CACHE_BLOCK_SIZE); - if (newBlock == NULL) { - return NULL; - } - CACHE_NOISY(ALOGI("Allocated new cache mem block: %p", newBlock)); - *(void**)newBlock = cache->memBlocks; - cache->memBlocks = newBlock; - res = cache->curMemBlockAvail = newBlock + sizeof(void*); - cache->curMemBlockEnd = newBlock + CACHE_BLOCK_SIZE; - nextPos = res + len; - } - CACHE_NOISY(ALOGI("cache_malloc: ret %p size %d, block=%p, nextPos=%p", - res, len, cache->memBlocks, nextPos)); - cache->curMemBlockAvail = nextPos; - return res; -} - -static void* _cache_realloc(cache_t* cache, void* cur, size_t origLen, size_t len) -{ - // This isn't really a realloc, but it is good enough for our purposes here. - void* alloc = _cache_malloc(cache, len); - if (alloc != NULL && cur != NULL) { - memcpy(alloc, cur, origLen < len ? origLen : len); - } - return alloc; -} - -static void _inc_num_cache_collected(cache_t* cache) -{ - cache->numCollected++; - if ((cache->numCollected%20000) == 0) { - ALOGI("Collected cache so far: %d directories, %d files", - cache->numDirs, cache->numFiles); - } -} - -static cache_dir_t* _add_cache_dir_t(cache_t* cache, cache_dir_t* parent, const char *name) -{ - size_t nameLen = strlen(name); - cache_dir_t* dir = (cache_dir_t*)_cache_malloc(cache, sizeof(cache_dir_t)+nameLen+1); - if (dir != NULL) { - dir->parent = parent; - dir->childCount = 0; - dir->hiddenCount = 0; - dir->deleted = 0; - strcpy(dir->name, name); - if (cache->numDirs >= cache->availDirs) { - size_t newAvail = cache->availDirs < 1000 ? 1000 : cache->availDirs*2; - cache_dir_t** newDirs = (cache_dir_t**)_cache_realloc(cache, cache->dirs, - cache->availDirs*sizeof(cache_dir_t*), newAvail*sizeof(cache_dir_t*)); - if (newDirs == NULL) { - ALOGE("Failure growing cache dirs array for %s\n", name); - return NULL; - } - cache->availDirs = newAvail; - cache->dirs = newDirs; - } - cache->dirs[cache->numDirs] = dir; - cache->numDirs++; - if (parent != NULL) { - parent->childCount++; - } - _inc_num_cache_collected(cache); - } else { - ALOGE("Failure allocating cache_dir_t for %s\n", name); - } - return dir; -} - -static cache_file_t* _add_cache_file_t(cache_t* cache, cache_dir_t* dir, time_t modTime, - const char *name) -{ - size_t nameLen = strlen(name); - cache_file_t* file = (cache_file_t*)_cache_malloc(cache, sizeof(cache_file_t)+nameLen+1); - if (file != NULL) { - file->dir = dir; - file->modTime = modTime; - strcpy(file->name, name); - if (cache->numFiles >= cache->availFiles) { - size_t newAvail = cache->availFiles < 1000 ? 1000 : cache->availFiles*2; - cache_file_t** newFiles = (cache_file_t**)_cache_realloc(cache, cache->files, - cache->availFiles*sizeof(cache_file_t*), newAvail*sizeof(cache_file_t*)); - if (newFiles == NULL) { - ALOGE("Failure growing cache file array for %s\n", name); - return NULL; - } - cache->availFiles = newAvail; - cache->files = newFiles; - } - CACHE_NOISY(ALOGI("Setting file %p at position %d in array %p", file, - cache->numFiles, cache->files)); - cache->files[cache->numFiles] = file; - cache->numFiles++; - dir->childCount++; - _inc_num_cache_collected(cache); - } else { - ALOGE("Failure allocating cache_file_t for %s\n", name); - } - return file; -} - -static int _add_cache_files(cache_t *cache, cache_dir_t *parentDir, const char *dirName, - DIR* dir, char *pathBase, char *pathPos, size_t pathAvailLen) -{ - struct dirent *de; - cache_dir_t* cacheDir = NULL; - int dfd; - - CACHE_NOISY(ALOGI("_add_cache_files: parent=%p dirName=%s dir=%p pathBase=%s", - parentDir, dirName, dir, pathBase)); - - dfd = dirfd(dir); - - if (dfd < 0) return 0; - - // Sub-directories always get added to the data structure, so if they - // are empty we will know about them to delete them later. - cacheDir = _add_cache_dir_t(cache, parentDir, dirName); - - while ((de = readdir(dir))) { - const char *name = de->d_name; - - if (de->d_type == DT_DIR) { - int subfd; - DIR *subdir; - - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - - subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); - if (subfd < 0) { - ALOGE("Couldn't openat %s: %s\n", name, strerror(errno)); - continue; - } - subdir = fdopendir(subfd); - if (subdir == NULL) { - ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno)); - close(subfd); - continue; - } - if (cacheDir == NULL) { - cacheDir = _add_cache_dir_t(cache, parentDir, dirName); - } - if (cacheDir != NULL) { - // Update pathBase for the new path... this may change dirName - // if that is also pointing to the path, but we are done with it - // now. - size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name); - CACHE_NOISY(ALOGI("Collecting dir %s\n", pathBase)); - if (finallen < pathAvailLen) { - _add_cache_files(cache, cacheDir, name, subdir, pathBase, - pathPos+finallen, pathAvailLen-finallen); - } else { - // Whoops, the final path is too long! We'll just delete - // this directory. - ALOGW("Cache dir %s truncated in path %s; deleting dir\n", - name, pathBase); - _delete_dir_contents(subdir, NULL); - if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { - ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); - } - } - } - closedir(subdir); - } else if (de->d_type == DT_REG) { - // Skip files that start with '.'; they will be deleted if - // their entire directory is deleted. This allows for metadata - // like ".nomedia" to remain in the directory until the entire - // directory is deleted. - if (cacheDir == NULL) { - cacheDir = _add_cache_dir_t(cache, parentDir, dirName); - } - if (name[0] == '.') { - cacheDir->hiddenCount++; - continue; - } - if (cacheDir != NULL) { - // Build final full path for file... this may change dirName - // if that is also pointing to the path, but we are done with it - // now. - size_t finallen = snprintf(pathPos, pathAvailLen, "/%s", name); - CACHE_NOISY(ALOGI("Collecting file %s\n", pathBase)); - if (finallen < pathAvailLen) { - struct stat s; - if (stat(pathBase, &s) >= 0) { - _add_cache_file_t(cache, cacheDir, s.st_mtime, name); - } else { - ALOGW("Unable to stat cache file %s; deleting\n", pathBase); - if (unlink(pathBase) < 0) { - ALOGE("Couldn't unlink %s: %s\n", pathBase, strerror(errno)); - } - } - } else { - // Whoops, the final path is too long! We'll just delete - // this file. - ALOGW("Cache file %s truncated in path %s; deleting\n", - name, pathBase); - if (unlinkat(dfd, name, 0) < 0) { - *pathPos = 0; - ALOGE("Couldn't unlinkat %s in %s: %s\n", name, pathBase, - strerror(errno)); - } - } - } - } else { - cacheDir->hiddenCount++; - } - } - return 0; -} - -void add_cache_files(cache_t* cache, const char *basepath, const char *cachedir) -{ - DIR *d; - struct dirent *de; - char dirname[PATH_MAX]; - - CACHE_NOISY(ALOGI("add_cache_files: base=%s cachedir=%s\n", basepath, cachedir)); - - d = opendir(basepath); - if (d == NULL) { - return; - } - - while ((de = readdir(d))) { - if (de->d_type == DT_DIR) { - DIR* subdir; - const char *name = de->d_name; - char* pathpos; - - /* always skip "." and ".." */ - if (name[0] == '.') { - if (name[1] == 0) continue; - if ((name[1] == '.') && (name[2] == 0)) continue; - } - - strcpy(dirname, basepath); - pathpos = dirname + strlen(dirname); - if ((*(pathpos-1)) != '/') { - *pathpos = '/'; - pathpos++; - *pathpos = 0; - } - if (cachedir != NULL) { - snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s/%s", name, cachedir); - } else { - snprintf(pathpos, sizeof(dirname)-(pathpos-dirname), "%s", name); - } - CACHE_NOISY(ALOGI("Adding cache files from dir: %s\n", dirname)); - subdir = opendir(dirname); - if (subdir != NULL) { - size_t dirnameLen = strlen(dirname); - _add_cache_files(cache, NULL, dirname, subdir, dirname, dirname+dirnameLen, - PATH_MAX - dirnameLen); - closedir(subdir); - } - } - } - - closedir(d); -} - -static char *create_dir_path(char path[PATH_MAX], cache_dir_t* dir) -{ - char *pos = path; - if (dir->parent != NULL) { - pos = create_dir_path(path, dir->parent); - } - // Note that we don't need to worry about going beyond the buffer, - // since when we were constructing the cache entries our maximum - // buffer size for full paths was PATH_MAX. - strcpy(pos, dir->name); - pos += strlen(pos); - *pos = '/'; - pos++; - *pos = 0; - return pos; -} - -static void delete_cache_dir(char path[PATH_MAX], cache_dir_t* dir) -{ - if (dir->parent != NULL) { - create_dir_path(path, dir); - ALOGI("DEL DIR %s\n", path); - if (dir->hiddenCount <= 0) { - if (rmdir(path)) { - ALOGE("Couldn't rmdir %s: %s\n", path, strerror(errno)); - return; - } - } else { - // The directory contains hidden files so we need to delete - // them along with the directory itself. - if (delete_dir_contents(path, 1, NULL)) { - return; - } - } - dir->parent->childCount--; - dir->deleted = 1; - if (dir->parent->childCount <= 0) { - delete_cache_dir(path, dir->parent); - } - } else if (dir->hiddenCount > 0) { - // This is a root directory, but it has hidden files. Get rid of - // all of those files, but not the directory itself. - create_dir_path(path, dir); - ALOGI("DEL CONTENTS %s\n", path); - delete_dir_contents(path, 0, NULL); - } -} - -static int cache_modtime_sort(const void *lhsP, const void *rhsP) -{ - const cache_file_t *lhs = *(const cache_file_t**)lhsP; - const cache_file_t *rhs = *(const cache_file_t**)rhsP; - return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0); -} - -void clear_cache_files(cache_t* cache, int64_t free_size) -{ - size_t i; - int skip = 0; - char path[PATH_MAX]; - - ALOGI("Collected cache files: %d directories, %d files", - cache->numDirs, cache->numFiles); - - CACHE_NOISY(ALOGI("Sorting files...")); - qsort(cache->files, cache->numFiles, sizeof(cache_file_t*), - cache_modtime_sort); - - CACHE_NOISY(ALOGI("Cleaning empty directories...")); - for (i=cache->numDirs; i>0; i--) { - cache_dir_t* dir = cache->dirs[i-1]; - if (dir->childCount <= 0 && !dir->deleted) { - delete_cache_dir(path, dir); - } - } - - CACHE_NOISY(ALOGI("Trimming files...")); - for (i=0; i<cache->numFiles; i++) { - skip++; - if (skip > 10) { - if (data_disk_free() > free_size) { - return; - } - skip = 0; - } - cache_file_t* file = cache->files[i]; - strcpy(create_dir_path(path, file->dir), file->name); - ALOGI("DEL (mod %d) %s\n", (int)file->modTime, path); - if (unlink(path) < 0) { - ALOGE("Couldn't unlink %s: %s\n", path, strerror(errno)); - } - file->dir->childCount--; - if (file->dir->childCount <= 0) { - delete_cache_dir(path, file->dir); - } - } -} - -void finish_cache_collection(cache_t* cache) -{ - size_t i; - - CACHE_NOISY(ALOGI("clear_cache_files: %d dirs, %d files\n", cache->numDirs, cache->numFiles)); - CACHE_NOISY( - for (i=0; i<cache->numDirs; i++) { - cache_dir_t* dir = cache->dirs[i]; - ALOGI("dir #%d: %p %s parent=%p\n", i, dir, dir->name, dir->parent); - }) - CACHE_NOISY( - for (i=0; i<cache->numFiles; i++) { - cache_file_t* file = cache->files[i]; - ALOGI("file #%d: %p %s time=%d dir=%p\n", i, file, file->name, - (int)file->modTime, file->dir); - }) - void* block = cache->memBlocks; - while (block != NULL) { - void* nextBlock = *(void**)block; - CACHE_NOISY(ALOGI("Freeing cache mem block: %p", block)); - free(block); - block = nextBlock; - } - free(cache); -} - -/** - * Checks whether a path points to a system app (.apk file). Returns 0 - * if it is a system app or -1 if it is not. - */ -int validate_system_app_path(const char* path) { - size_t i; - - for (i = 0; i < android_system_dirs.count; i++) { - const size_t dir_len = android_system_dirs.dirs[i].len; - if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) { - if (path[dir_len] == '.' || strchr(path + dir_len, '/') != NULL) { - ALOGE("invalid system apk path '%s' (trickery)\n", path); - return -1; - } - return 0; - } - } - - return -1; -} - -/** - * Get the contents of a environment variable that contains a path. Caller - * owns the string that is inserted into the directory record. Returns - * 0 on success and -1 on error. - */ -int get_path_from_env(dir_rec_t* rec, const char* var) { - const char* path = getenv(var); - int ret = get_path_from_string(rec, path); - if (ret < 0) { - ALOGW("Problem finding value for environment variable %s\n", var); - } - return ret; -} - -/** - * Puts the string into the record as a directory. Appends '/' to the end - * of all paths. Caller owns the string that is inserted into the directory - * record. A null value will result in an error. - * - * Returns 0 on success and -1 on error. - */ -int get_path_from_string(dir_rec_t* rec, const char* path) { - if (path == NULL) { - return -1; - } else { - const size_t path_len = strlen(path); - if (path_len <= 0) { - return -1; - } - - // Make sure path is absolute. - if (path[0] != '/') { - return -1; - } - - if (path[path_len - 1] == '/') { - // Path ends with a forward slash. Make our own copy. - - rec->path = strdup(path); - if (rec->path == NULL) { - return -1; - } - - rec->len = path_len; - } else { - // Path does not end with a slash. Generate a new string. - char *dst; - - // Add space for slash and terminating null. - size_t dst_size = path_len + 2; - - rec->path = malloc(dst_size); - if (rec->path == NULL) { - return -1; - } - - dst = rec->path; - - if (append_and_increment(&dst, path, &dst_size) < 0 - || append_and_increment(&dst, "/", &dst_size)) { - ALOGE("Error canonicalizing path"); - return -1; - } - - rec->len = dst - rec->path; - } - } - return 0; -} - -int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) { - dst->len = src->len + strlen(suffix); - const size_t dstSize = dst->len + 1; - dst->path = (char*) malloc(dstSize); - - if (dst->path == NULL - || snprintf(dst->path, dstSize, "%s%s", src->path, suffix) - != (ssize_t) dst->len) { - ALOGE("Could not allocate memory to hold appended path; aborting\n"); - return -1; - } - - return 0; -} - -/** - * Check whether path points to a valid path for an APK file. An ASEC - * directory is allowed to have one level of subdirectory names. Returns -1 - * when an invalid path is encountered and 0 when a valid path is encountered. - */ -int validate_apk_path(const char *path) -{ - int allowsubdir = 0; - char *subdir = NULL; - size_t dir_len; - size_t path_len; - - if (!strncmp(path, android_app_dir.path, android_app_dir.len)) { - dir_len = android_app_dir.len; - } else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) { - dir_len = android_app_private_dir.len; - } else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) { - dir_len = android_asec_dir.len; - allowsubdir = 1; - } else { - ALOGE("invalid apk path '%s' (bad prefix)\n", path); - return -1; - } - - path_len = strlen(path); - - /* - * Only allow the path to have a subdirectory if it's been marked as being allowed. - */ - if ((subdir = strchr(path + dir_len, '/')) != NULL) { - ++subdir; - if (!allowsubdir - || (path_len > (size_t) (subdir - path) && (strchr(subdir, '/') != NULL))) { - ALOGE("invalid apk path '%s' (subdir?)\n", path); - return -1; - } - } - - /* - * Directories can't have a period directly after the directory markers - * to prevent ".." - */ - if (path[dir_len] == '.' - || (subdir != NULL && ((*subdir == '.') || (strchr(subdir, '/') != NULL)))) { - ALOGE("invalid apk path '%s' (trickery)\n", path); - return -1; - } - - return 0; -} - -int append_and_increment(char** dst, const char* src, size_t* dst_size) { - ssize_t ret = strlcpy(*dst, src, *dst_size); - if (ret < 0 || (size_t) ret >= *dst_size) { - return -1; - } - *dst += ret; - *dst_size -= ret; - return 0; -} - -char *build_string2(char *s1, char *s2) { - if (s1 == NULL || s2 == NULL) return NULL; - - int len_s1 = strlen(s1); - int len_s2 = strlen(s2); - int len = len_s1 + len_s2 + 1; - char *result = malloc(len); - if (result == NULL) return NULL; - - strcpy(result, s1); - strcpy(result + len_s1, s2); - - return result; -} - -char *build_string3(char *s1, char *s2, char *s3) { - if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL; - - int len_s1 = strlen(s1); - int len_s2 = strlen(s2); - int len_s3 = strlen(s3); - int len = len_s1 + len_s2 + len_s3 + 1; - char *result = malloc(len); - if (result == NULL) return NULL; - - strcpy(result, s1); - strcpy(result + len_s1, s2); - strcpy(result + len_s1 + len_s2, s3); - - return result; -} - -/* Ensure that /data/media directories are prepared for given user. */ -int ensure_media_user_dirs(userid_t userid) { - char media_user_path[PATH_MAX]; - char path[PATH_MAX]; - - // Ensure /data/media/<userid> exists - create_persona_media_path(media_user_path, userid); - if (fs_prepare_dir(media_user_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) { - return -1; - } - - return 0; -} diff --git a/cmds/ip-up-vpn/Android.mk b/cmds/ip-up-vpn/Android.mk deleted file mode 100644 index de81889..0000000 --- a/cmds/ip-up-vpn/Android.mk +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (C) 2011 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. -# - -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := ip-up-vpn.c -LOCAL_SHARED_LIBRARIES := libcutils -LOCAL_MODULE := ip-up-vpn -LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/cmds/ip-up-vpn/ip-up-vpn.c b/cmds/ip-up-vpn/ip-up-vpn.c deleted file mode 100644 index 9fcc950..0000000 --- a/cmds/ip-up-vpn/ip-up-vpn.c +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2011 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 <errno.h> - -#include <arpa/inet.h> -#include <netinet/in.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <linux/if.h> -#include <linux/route.h> - -#define LOG_TAG "ip-up-vpn" -#include <cutils/log.h> - -#define DIR "/data/misc/vpn/" - -static const char *env(const char *name) { - const char *value = getenv(name); - return value ? value : ""; -} - -static int set_address(struct sockaddr *sa, const char *address) { - sa->sa_family = AF_INET; - errno = EINVAL; - return inet_pton(AF_INET, address, &((struct sockaddr_in *)sa)->sin_addr); -} - -/* - * The primary goal is to create a file with VPN parameters. Currently they - * are interface, addresses, routes, DNS servers, and search domains. Each - * parameter occupies one line in the file, and it can be an empty string or - * space-separated values. The order and the format must be consistent with - * com.android.server.connectivity.Vpn. Here is an example. - * - * ppp0 - * 192.168.1.100/24 - * 0.0.0.0/0 - * 192.168.1.1 192.168.1.2 - * example.org - * - * The secondary goal is to unify the outcome of VPN. The current baseline - * is to have an interface configured with the given address and netmask - * and maybe add a host route to protect the tunnel. PPP-based VPN already - * does this, but others might not. Routes, DNS servers, and search domains - * are handled by the framework since they can be overridden by the users. - */ -int main(int argc, char **argv) -{ - FILE *state = fopen(DIR ".tmp", "wb"); - if (!state) { - ALOGE("Cannot create state: %s", strerror(errno)); - return 1; - } - - if (argc >= 6) { - /* Invoked by pppd. */ - fprintf(state, "%s\n", argv[1]); - fprintf(state, "%s/32\n", argv[4]); - fprintf(state, "0.0.0.0/0\n"); - fprintf(state, "%s %s\n", env("DNS1"), env("DNS2")); - fprintf(state, "\n"); - } else if (argc == 2) { - /* Invoked by racoon. */ - const char *interface = env("INTERFACE"); - const char *address = env("INTERNAL_ADDR4"); - const char *routes = env("SPLIT_INCLUDE_CIDR"); - - int s = socket(AF_INET, SOCK_DGRAM, 0); - struct rtentry rt; - struct ifreq ifr; - - memset(&rt, 0, sizeof(rt)); - memset(&ifr, 0, sizeof(ifr)); - - /* Remove the old host route. There could be more than one. */ - rt.rt_flags |= RTF_UP | RTF_HOST; - if (set_address(&rt.rt_dst, env("REMOTE_ADDR"))) { - while (!ioctl(s, SIOCDELRT, &rt)); - } - if (errno != ESRCH) { - ALOGE("Cannot remove host route: %s", strerror(errno)); - return 1; - } - - /* Create a new host route. */ - rt.rt_flags |= RTF_GATEWAY; - if (!set_address(&rt.rt_gateway, argv[1]) || - (ioctl(s, SIOCADDRT, &rt) && errno != EEXIST)) { - ALOGE("Cannot create host route: %s", strerror(errno)); - return 1; - } - - /* Bring up the interface. */ - ifr.ifr_flags = IFF_UP; - strncpy(ifr.ifr_name, interface, IFNAMSIZ); - if (ioctl(s, SIOCSIFFLAGS, &ifr)) { - ALOGE("Cannot bring up %s: %s", interface, strerror(errno)); - return 1; - } - - /* Set the address. */ - if (!set_address(&ifr.ifr_addr, address) || - ioctl(s, SIOCSIFADDR, &ifr)) { - ALOGE("Cannot set address: %s", strerror(errno)); - return 1; - } - - /* Set the netmask. */ - if (set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4"))) { - if (ioctl(s, SIOCSIFNETMASK, &ifr)) { - ALOGE("Cannot set netmask: %s", strerror(errno)); - return 1; - } - } - - /* TODO: Send few packets to trigger phase 2? */ - - fprintf(state, "%s\n", interface); - fprintf(state, "%s/%s\n", address, env("INTERNAL_CIDR4")); - fprintf(state, "%s\n", routes[0] ? routes : "0.0.0.0/0"); - fprintf(state, "%s\n", env("INTERNAL_DNS4_LIST")); - fprintf(state, "%s\n", env("DEFAULT_DOMAIN")); - } else { - ALOGE("Cannot parse parameters"); - return 1; - } - - fclose(state); - if (chmod(DIR ".tmp", 0444) || rename(DIR ".tmp", DIR "state")) { - ALOGE("Cannot write state: %s", strerror(errno)); - return 1; - } - return 0; -} diff --git a/cmds/media/Android.mk b/cmds/media/Android.mk new file mode 100644 index 0000000..b9451c5 --- /dev/null +++ b/cmds/media/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2013 The Android Open Source Project +# +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := media_cmd +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := media +LOCAL_SRC_FILES := media +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) diff --git a/cmds/service/MODULE_LICENSE_APACHE2 b/cmds/media/MODULE_LICENSE_APACHE2 index e69de29..e69de29 100644 --- a/cmds/service/MODULE_LICENSE_APACHE2 +++ b/cmds/media/MODULE_LICENSE_APACHE2 diff --git a/cmds/rawbu/NOTICE b/cmds/media/NOTICE index c5b1efa..c5b1efa 100644 --- a/cmds/rawbu/NOTICE +++ b/cmds/media/NOTICE diff --git a/cmds/media/media b/cmds/media/media new file mode 100755 index 0000000..1194442 --- /dev/null +++ b/cmds/media/media @@ -0,0 +1,6 @@ +# Script to start "media_cmd" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/media_cmd.jar +exec app_process $base/bin com.android.commands.media.Media "$@" diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java new file mode 100644 index 0000000..56af7d6 --- /dev/null +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -0,0 +1,220 @@ +/* +** +** Copyright 2013, 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. +*/ + +package com.android.commands.media; + +import android.app.PendingIntent; +import android.content.Context; +import android.graphics.Bitmap; +import android.media.IAudioService; +import android.media.IRemoteControlDisplay; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.util.AndroidException; +import android.view.InputDevice; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import com.android.internal.os.BaseCommand; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintStream; + +public class Media extends BaseCommand { + + private IAudioService mAudioService; + + /** + * Command-line entry point. + * + * @param args The command-line arguments + */ + public static void main(String[] args) { + (new Media()).run(args); + } + + public void onShowUsage(PrintStream out) { + out.println( + "usage: media [subcommand] [options]\n" + + " media dispatch KEY\n" + + " media remote-display\n" + + "\n" + + "media dispatch: dispatch a media key to the current media client.\n" + + " KEY may be: play, pause, play-pause, mute, headsethook,\n" + + " stop, next, previous, rewind, recordm fast-forword.\n" + + "media remote-display: monitor remote display updates.\n" + ); + } + + public void onRun() throws Exception { + mAudioService = IAudioService.Stub.asInterface(ServiceManager.checkService( + Context.AUDIO_SERVICE)); + if (mAudioService == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + throw new AndroidException("Can't connect to audio service; is the system running?"); + } + + String op = nextArgRequired(); + + if (op.equals("dispatch")) { + runDispatch(); + } else if (op.equals("remote-display")) { + runRemoteDisplay(); + } else { + showError("Error: unknown command '" + op + "'"); + return; + } + } + + private void sendMediaKey(KeyEvent event) { + try { + mAudioService.dispatchMediaKeyEvent(event); + } catch (RemoteException e) { + } + } + + private void runDispatch() throws Exception { + String cmd = nextArgRequired(); + int keycode; + if ("play".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_PLAY; + } else if ("pause".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_PAUSE; + } else if ("play-pause".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE; + } else if ("mute".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MUTE; + } else if ("headsethook".equals(cmd)) { + keycode = KeyEvent.KEYCODE_HEADSETHOOK; + } else if ("stop".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_STOP; + } else if ("next".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_NEXT; + } else if ("previous".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_PREVIOUS; + } else if ("rewind".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_REWIND; + } else if ("record".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_RECORD; + } else if ("fast-forward".equals(cmd)) { + keycode = KeyEvent.KEYCODE_MEDIA_FAST_FORWARD; + } else { + showError("Error: unknown dispatch code '" + cmd + "'"); + return; + } + + final long now = SystemClock.uptimeMillis(); + sendMediaKey(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keycode, 0, 0, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); + sendMediaKey(new KeyEvent(now, now, KeyEvent.ACTION_UP, keycode, 0, 0, + KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD)); + } + + class RemoteDisplayMonitor extends IRemoteControlDisplay.Stub { + RemoteDisplayMonitor() { + } + + + @Override + public void setCurrentClientId(int clientGeneration, PendingIntent clientMediaIntent, + boolean clearing) { + System.out.println("New client: id=" + clientGeneration + + " intent=" + clientMediaIntent + " clearing=" + clearing); + } + + @Override + public void setPlaybackState(int generationId, int state, long stateChangeTimeMs, + long currentPosMs, float speed) { + System.out.println("New state: id=" + generationId + " state=" + state + + " time=" + stateChangeTimeMs + " pos=" + currentPosMs + " speed=" + speed); + } + + @Override + public void setTransportControlInfo(int generationId, int transportControlFlags, + int posCapabilities) { + System.out.println("New control info: id=" + generationId + + " flags=0x" + Integer.toHexString(transportControlFlags) + + " cap=0x" + Integer.toHexString(posCapabilities)); + } + + @Override + public void setMetadata(int generationId, Bundle metadata) { + System.out.println("New metadata: id=" + generationId + + " data=" + metadata); + } + + @Override + public void setArtwork(int generationId, Bitmap artwork) { + System.out.println("New artwork: id=" + generationId + + " art=" + artwork); + } + + @Override + public void setAllMetadata(int generationId, Bundle metadata, Bitmap artwork) { + System.out.println("New metadata+artwork: id=" + generationId + + " data=" + metadata + " art=" + artwork); + } + + void printUsageMessage() { + System.out.println("Monitoring remote control displays... available commands:"); + System.out.println("(q)uit: finish monitoring"); + } + + void run() throws RemoteException { + printUsageMessage(); + + mAudioService.registerRemoteControlDisplay(this, 0, 0); + + try { + InputStreamReader converter = new InputStreamReader(System.in); + BufferedReader in = new BufferedReader(converter); + String line; + + while ((line = in.readLine()) != null) { + boolean addNewline = true; + if (line.length() <= 0) { + addNewline = false; + } else if ("q".equals(line) || "quit".equals(line)) { + break; + } else { + System.out.println("Invalid command: " + line); + } + + synchronized (this) { + if (addNewline) { + System.out.println(""); + } + printUsageMessage(); + } + } + + } catch (IOException e) { + e.printStackTrace(); + } finally { + mAudioService.unregisterRemoteControlDisplay(this); + } + } + } + + private void runRemoteDisplay() throws Exception { + RemoteDisplayMonitor monitor = new RemoteDisplayMonitor(); + monitor.run(); + } +} diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 42c9d34..224945a 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -135,6 +135,11 @@ public final class Pm { return; } + if ("disable-until-used".equals(op)) { + runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); + return; + } + if ("grant".equals(op)) { runGrantRevokePermission(true); return; @@ -321,17 +326,8 @@ public final class Pm { @SuppressWarnings("unchecked") private List<PackageInfo> getInstalledPackages(IPackageManager pm, int flags, int userId) throws RemoteException { - final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>(); - PackageInfo lastItem = null; - ParceledListSlice<PackageInfo> slice; - - do { - final String lastKey = lastItem != null ? lastItem.packageName : null; - slice = pm.getInstalledPackages(flags, lastKey, userId); - lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR); - } while (!slice.isLastSlice()); - - return packageInfos; + ParceledListSlice<PackageInfo> slice = pm.getInstalledPackages(flags, userId); + return slice.getList(); } /** @@ -1098,7 +1094,7 @@ public final class Pm { private boolean deletePackage(String pkg, int unInstallFlags) { PackageDeleteObserver obs = new PackageDeleteObserver(); try { - mPm.deletePackage(pkg, obs, unInstallFlags); + mPm.deletePackageAsUser(pkg, obs, UserHandle.USER_OWNER, unInstallFlags); synchronized (obs) { while (!obs.finished) { @@ -1153,10 +1149,7 @@ public final class Pm { ClearDataObserver obs = new ClearDataObserver(); try { - if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId)) { - System.err.println("Failed"); - } - + ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, userId); synchronized (obs) { while (!obs.finished) { try { @@ -1187,6 +1180,8 @@ public final class Pm { return "disabled"; case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: return "disabled-user"; + case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: + return "disabled-until-used"; } return "unknown"; } @@ -1223,7 +1218,8 @@ public final class Pm { ComponentName cn = ComponentName.unflattenFromString(pkg); if (cn == null) { try { - mPm.setApplicationEnabledSetting(pkg, state, 0, userId); + mPm.setApplicationEnabledSetting(pkg, state, 0, userId, + "shell:" + android.os.Process.myUid()); System.err.println("Package " + pkg + " new state: " + enabledSettingToString( mPm.getApplicationEnabledSetting(pkg, userId))); @@ -1468,6 +1464,7 @@ public final class Pm { System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT"); + System.err.println(" pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT"); System.err.println(" pm grant PACKAGE PERMISSION"); System.err.println(" pm revoke PACKAGE PERMISSION"); System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]"); @@ -1523,8 +1520,9 @@ public final class Pm { System.err.println(""); System.err.println("pm clear: deletes all data associated with a package."); System.err.println(""); - System.err.println("pm enable, disable, disable-user: these commands change the enabled state"); - System.err.println(" of a given package or component (written as \"package/class\")."); + System.err.println("pm enable, disable, disable-user, disable-until-used: these commands"); + System.err.println(" change the enabled state of a given package or component (written"); + System.err.println(" as \"package/class\")."); System.err.println(""); System.err.println("pm grant, revoke: these commands either grant or revoke permissions"); System.err.println(" to applications. Only optional permissions the application has"); diff --git a/cmds/rawbu/Android.mk b/cmds/rawbu/Android.mk deleted file mode 100644 index b580390..0000000 --- a/cmds/rawbu/Android.mk +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2009 The Android Open Source Project - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= backup.cpp - -LOCAL_SHARED_LIBRARIES := libcutils libc - -LOCAL_MODULE:= rawbu - -LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES) -LOCAL_MODULE_TAGS := debug - -include $(BUILD_EXECUTABLE) diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp deleted file mode 100644 index 70e7b57..0000000 --- a/cmds/rawbu/backup.cpp +++ /dev/null @@ -1,746 +0,0 @@ -// Copyright 2009 The Android Open Source Project - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <time.h> -#include <dirent.h> -#include <errno.h> -#include <assert.h> -#include <ctype.h> -#include <utime.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <stdint.h> - -#include <cutils/properties.h> - -#include <private/android_filesystem_config.h> - -#ifndef PATH_MAX -#define PATH_MAX 4096 -#endif - -// First version. -#define FILE_VERSION_1 0xffff0001 - -// Introduces backup all option to header. -#define FILE_VERSION_2 0xffff0002 - -#define FILE_VERSION FILE_VERSION_2 - -namespace android { - -static char nameBuffer[PATH_MAX]; -static struct stat statBuffer; - -static char copyBuffer[8192]; -static char *backupFilePath = NULL; - -static uint32_t inputFileVersion; - -static int opt_backupAll; - -#define SPECIAL_NO_TOUCH 0 -#define SPECIAL_NO_BACKUP 1 - -struct special_dir { - const char* path; - int type; -}; - -/* Directory paths that we will not backup/restore */ -static const struct special_dir SKIP_PATHS[] = { - { "/data/misc", SPECIAL_NO_TOUCH }, - { "/data/system/batterystats.bin", SPECIAL_NO_TOUCH }, - { "/data/system/location", SPECIAL_NO_TOUCH }, - { "/data/dalvik-cache", SPECIAL_NO_BACKUP }, - { NULL, 0 }, -}; - -/* This is just copied from the shell's built-in wipe command. */ -static int wipe (const char *path) -{ - DIR *dir; - struct dirent *de; - int ret; - int i; - - dir = opendir(path); - - if (dir == NULL) { - fprintf (stderr, "Error opendir'ing %s: %s\n", - path, strerror(errno)); - return 0; - } - - char *filenameOffset; - - strcpy(nameBuffer, path); - strcat(nameBuffer, "/"); - - filenameOffset = nameBuffer + strlen(nameBuffer); - - for (;;) { - de = readdir(dir); - - if (de == NULL) { - break; - } - - if (0 == strcmp(de->d_name, ".") - || 0 == strcmp(de->d_name, "..") - || 0 == strcmp(de->d_name, "lost+found") - ) { - continue; - } - - strcpy(filenameOffset, de->d_name); - bool noBackup = false; - - /* See if this is a path we should skip. */ - for (i = 0; SKIP_PATHS[i].path; i++) { - if (strcmp(SKIP_PATHS[i].path, nameBuffer) == 0) { - if (opt_backupAll || SKIP_PATHS[i].type == SPECIAL_NO_BACKUP) { - // In this case we didn't back up the directory -- - // we do want to wipe its contents, but not the - // directory itself, since the restore file won't - // contain the directory. - noBackup = true; - } - break; - } - } - - if (!noBackup && SKIP_PATHS[i].path != NULL) { - // This is a SPECIAL_NO_TOUCH directory. - continue; - } - - ret = lstat (nameBuffer, &statBuffer); - - if (ret != 0) { - fprintf(stderr, "warning -- stat() error on '%s': %s\n", - nameBuffer, strerror(errno)); - continue; - } - - if(S_ISDIR(statBuffer.st_mode)) { - int i; - char *newpath; - - newpath = strdup(nameBuffer); - if (wipe(newpath) == 0) { - free(newpath); - closedir(dir); - return 0; - } - - if (!noBackup) { - ret = rmdir(newpath); - if (ret != 0) { - fprintf(stderr, "warning -- rmdir() error on '%s': %s\n", - newpath, strerror(errno)); - } - } - - free(newpath); - - strcpy(nameBuffer, path); - strcat(nameBuffer, "/"); - - } else { - // Don't delete the backup file - if (backupFilePath && strcmp(backupFilePath, nameBuffer) == 0) { - continue; - } - ret = unlink(nameBuffer); - - if (ret != 0) { - fprintf(stderr, "warning -- unlink() error on '%s': %s\n", - nameBuffer, strerror(errno)); - } - } - } - - closedir(dir); - - return 1; -} - -static int write_int32(FILE* fh, int32_t val) -{ - int res = fwrite(&val, 1, sizeof(val), fh); - if (res != sizeof(val)) { - fprintf(stderr, "unable to write int32 (%d bytes): %s\n", res, strerror(errno)); - return 0; - } - - return 1; -} - -static int write_int64(FILE* fh, int64_t val) -{ - int res = fwrite(&val, 1, sizeof(val), fh); - if (res != sizeof(val)) { - fprintf(stderr, "unable to write int64 (%d bytes): %s\n", res, strerror(errno)); - return 0; - } - - return 1; -} - -static int copy_file(FILE* dest, FILE* src, off_t size, const char* destName, - const char* srcName) -{ - errno = 0; - - off_t origSize = size; - - while (size > 0) { - int amt = size > (off_t)sizeof(copyBuffer) ? sizeof(copyBuffer) : (int)size; - int readLen = fread(copyBuffer, 1, amt, src); - if (readLen <= 0) { - if (srcName != NULL) { - fprintf(stderr, "unable to read source (%d of %ld bytes) file '%s': %s\n", - amt, origSize, srcName, errno != 0 ? strerror(errno) : "unexpected EOF"); - } else { - fprintf(stderr, "unable to read buffer (%d of %ld bytes): %s\n", - amt, origSize, errno != 0 ? strerror(errno) : "unexpected EOF"); - } - return 0; - } - int writeLen = fwrite(copyBuffer, 1, readLen, dest); - if (writeLen != readLen) { - if (destName != NULL) { - fprintf(stderr, "unable to write file (%d of %d bytes) '%s': '%s'\n", - writeLen, readLen, destName, strerror(errno)); - } else { - fprintf(stderr, "unable to write buffer (%d of %d bytes): '%s'\n", - writeLen, readLen, strerror(errno)); - } - return 0; - } - size -= readLen; - } - return 1; -} - -#define TYPE_END 0 -#define TYPE_DIR 1 -#define TYPE_FILE 2 - -static int write_header(FILE* fh, int type, const char* path, const struct stat* st) -{ - int pathLen = strlen(path); - if (!write_int32(fh, type)) return 0; - if (!write_int32(fh, pathLen)) return 0; - if (fwrite(path, 1, pathLen, fh) != (size_t)pathLen) { - fprintf(stderr, "unable to write: %s\n", strerror(errno)); - return 0; - } - - if (!write_int32(fh, st->st_uid)) return 0; - if (!write_int32(fh, st->st_gid)) return 0; - if (!write_int32(fh, st->st_mode)) return 0; - if (!write_int64(fh, ((int64_t)st->st_atime)*1000*1000*1000)) return 0; - if (!write_int64(fh, ((int64_t)st->st_mtime)*1000*1000*1000)) return 0; - if (!write_int64(fh, ((int64_t)st->st_ctime)*1000*1000*1000)) return 0; - - return 1; -} - -static int backup_dir(FILE* fh, const char* srcPath) -{ - DIR *dir; - struct dirent *de; - char* fullPath = NULL; - int srcLen = strlen(srcPath); - int result = 1; - int i; - - dir = opendir(srcPath); - - if (dir == NULL) { - fprintf (stderr, "error opendir'ing '%s': %s\n", - srcPath, strerror(errno)); - return 0; - } - - for (;;) { - de = readdir(dir); - - if (de == NULL) { - break; - } - - if (0 == strcmp(de->d_name, ".") - || 0 == strcmp(de->d_name, "..") - || 0 == strcmp(de->d_name, "lost+found") - ) { - continue; - } - - if (fullPath != NULL) { - free(fullPath); - } - fullPath = (char*)malloc(srcLen + strlen(de->d_name) + 2); - strcpy(fullPath, srcPath); - fullPath[srcLen] = '/'; - strcpy(fullPath+srcLen+1, de->d_name); - - /* See if this is a path we should skip. */ - if (!opt_backupAll) { - for (i = 0; SKIP_PATHS[i].path; i++) { - if (strcmp(SKIP_PATHS[i].path, fullPath) == 0) { - break; - } - } - if (SKIP_PATHS[i].path != NULL) { - continue; - } - } - - int ret = lstat(fullPath, &statBuffer); - - if (ret != 0) { - fprintf(stderr, "stat() error on '%s': %s\n", - fullPath, strerror(errno)); - result = 0; - goto done; - } - - if(S_ISDIR(statBuffer.st_mode)) { - printf("Saving dir %s...\n", fullPath); - - if (write_header(fh, TYPE_DIR, fullPath, &statBuffer) == 0) { - result = 0; - goto done; - } - if (backup_dir(fh, fullPath) == 0) { - result = 0; - goto done; - } - } else if (S_ISREG(statBuffer.st_mode)) { - // Skip the backup file - if (backupFilePath && strcmp(fullPath, backupFilePath) == 0) { - printf("Skipping backup file %s...\n", backupFilePath); - continue; - } else { - printf("Saving file %s...\n", fullPath); - } - if (write_header(fh, TYPE_FILE, fullPath, &statBuffer) == 0) { - result = 0; - goto done; - } - - off_t size = statBuffer.st_size; - if (!write_int64(fh, size)) { - result = 0; - goto done; - } - - FILE* src = fopen(fullPath, "r"); - if (src == NULL) { - fprintf(stderr, "unable to open source file '%s': %s\n", - fullPath, strerror(errno)); - result = 0; - goto done; - } - - int copyres = copy_file(fh, src, size, NULL, fullPath); - fclose(src); - if (!copyres) { - result = 0; - goto done; - } - } - } - -done: - if (fullPath != NULL) { - free(fullPath); - } - - closedir(dir); - - return result; -} - -static int backup_data(const char* destPath) -{ - int res = -1; - - FILE* fh = fopen(destPath, "w"); - if (fh == NULL) { - fprintf(stderr, "unable to open destination '%s': %s\n", - destPath, strerror(errno)); - return -1; - } - - printf("Backing up /data to %s...\n", destPath); - - // The path that shouldn't be backed up - backupFilePath = strdup(destPath); - - if (!write_int32(fh, FILE_VERSION)) goto done; - if (!write_int32(fh, opt_backupAll)) goto done; - if (!backup_dir(fh, "/data")) goto done; - if (!write_int32(fh, 0)) goto done; - - res = 0; - -done: - if (fflush(fh) != 0) { - fprintf(stderr, "error flushing destination '%s': %s\n", - destPath, strerror(errno)); - res = -1; - goto donedone; - } - if (fsync(fileno(fh)) != 0) { - fprintf(stderr, "error syncing destination '%s': %s\n", - destPath, strerror(errno)); - res = -1; - goto donedone; - } - fclose(fh); - sync(); - -donedone: - return res; -} - -static int32_t read_int32(FILE* fh, int32_t defVal) -{ - int32_t val; - if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) { - fprintf(stderr, "unable to read: %s\n", strerror(errno)); - return defVal; - } - - return val; -} - -static int64_t read_int64(FILE* fh, int64_t defVal) -{ - int64_t val; - if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) { - fprintf(stderr, "unable to read: %s\n", strerror(errno)); - return defVal; - } - - return val; -} - -static int read_header(FILE* fh, int* type, char** path, struct stat* st) -{ - *type = read_int32(fh, -1); - if (*type == TYPE_END) { - return 1; - } - - if (*type < 0) { - fprintf(stderr, "bad token %d in restore file\n", *type); - return 0; - } - - int32_t pathLen = read_int32(fh, -1); - if (pathLen <= 0) { - fprintf(stderr, "bad path length %d in restore file\n", pathLen); - return 0; - } - char* readPath = (char*)malloc(pathLen+1); - if (fread(readPath, 1, pathLen, fh) != (size_t)pathLen) { - fprintf(stderr, "truncated path in restore file\n"); - free(readPath); - return 0; - } - readPath[pathLen] = 0; - *path = readPath; - - st->st_uid = read_int32(fh, -1); - if (st->st_uid == (uid_t)-1) { - fprintf(stderr, "bad uid in restore file at '%s'\n", readPath); - return 0; - } - st->st_gid = read_int32(fh, -1); - if (st->st_gid == (gid_t)-1) { - fprintf(stderr, "bad gid in restore file at '%s'\n", readPath); - return 0; - } - st->st_mode = read_int32(fh, -1); - if (st->st_mode == (mode_t)-1) { - fprintf(stderr, "bad mode in restore file at '%s'\n", readPath); - return 0; - } - int64_t ltime = read_int64(fh, -1); - if (ltime < 0) { - fprintf(stderr, "bad atime in restore file at '%s'\n", readPath); - return 0; - } - st->st_atime = (time_t)(ltime/1000/1000/1000); - ltime = read_int64(fh, -1); - if (ltime < 0) { - fprintf(stderr, "bad mtime in restore file at '%s'\n", readPath); - return 0; - } - st->st_mtime = (time_t)(ltime/1000/1000/1000); - ltime = read_int64(fh, -1); - if (ltime < 0) { - fprintf(stderr, "bad ctime in restore file at '%s'\n", readPath); - return 0; - } - st->st_ctime = (time_t)(ltime/1000/1000/1000); - - st->st_mode &= (S_IRWXU|S_IRWXG|S_IRWXO); - - return 1; -} - -static int restore_data(const char* srcPath) -{ - int res = -1; - - FILE* fh = fopen(srcPath, "r"); - if (fh == NULL) { - fprintf(stderr, "Unable to open source '%s': %s\n", - srcPath, strerror(errno)); - return -1; - } - - inputFileVersion = read_int32(fh, 0); - if (inputFileVersion < FILE_VERSION_1 || inputFileVersion > FILE_VERSION) { - fprintf(stderr, "Restore file has bad version: 0x%x\n", inputFileVersion); - goto done; - } - - if (inputFileVersion >= FILE_VERSION_2) { - opt_backupAll = read_int32(fh, 0); - } else { - opt_backupAll = 0; - } - - // The path that shouldn't be deleted - backupFilePath = strdup(srcPath); - - printf("Wiping contents of /data...\n"); - if (!wipe("/data")) { - goto done; - } - - printf("Restoring from %s to /data...\n", srcPath); - - while (1) { - int type; - char* path = NULL; - if (read_header(fh, &type, &path, &statBuffer) == 0) { - goto done; - } - if (type == 0) { - break; - } - - const char* typeName = "?"; - - if (type == TYPE_DIR) { - typeName = "dir"; - - printf("Restoring dir %s...\n", path); - - if (mkdir(path, statBuffer.st_mode) != 0) { - if (errno != EEXIST) { - fprintf(stderr, "unable to create directory '%s': %s\n", - path, strerror(errno)); - free(path); - goto done; - } - } - - } else if (type == TYPE_FILE) { - typeName = "file"; - off_t size = read_int64(fh, -1); - if (size < 0) { - fprintf(stderr, "bad file size %ld in restore file\n", size); - free(path); - goto done; - } - - printf("Restoring file %s...\n", path); - - FILE* dest = fopen(path, "w"); - if (dest == NULL) { - fprintf(stderr, "unable to open destination file '%s': %s\n", - path, strerror(errno)); - free(path); - goto done; - } - - int copyres = copy_file(dest, fh, size, path, NULL); - fclose(dest); - if (!copyres) { - free(path); - goto done; - } - - } else { - fprintf(stderr, "unknown node type %d\n", type); - goto done; - } - - // Do this even for directories, since the dir may have already existed - // so we need to make sure it gets the correct mode. - if (chmod(path, statBuffer.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO)) != 0) { - fprintf(stderr, "unable to chmod destination %s '%s' to 0x%x: %s\n", - typeName, path, statBuffer.st_mode, strerror(errno)); - free(path); - goto done; - } - - if (chown(path, statBuffer.st_uid, statBuffer.st_gid) != 0) { - fprintf(stderr, "unable to chown destination %s '%s' to uid %d / gid %d: %s\n", - typeName, path, (int)statBuffer.st_uid, (int)statBuffer.st_gid, strerror(errno)); - free(path); - goto done; - } - - struct utimbuf timbuf; - timbuf.actime = statBuffer.st_atime; - timbuf.modtime = statBuffer.st_mtime; - if (utime(path, &timbuf) != 0) { - fprintf(stderr, "unable to utime destination %s '%s': %s\n", - typeName, path, strerror(errno)); - free(path); - goto done; - } - - - free(path); - } - - res = 0; - -done: - fclose(fh); - - return res; -} - -static void show_help(const char *cmd) -{ - fprintf(stderr,"Usage: %s COMMAND [options] [backup-file-path]\n", cmd); - - fprintf(stderr, "commands are:\n" - " help Show this help text.\n" - " backup Perform a backup of /data.\n" - " restore Perform a restore of /data.\n"); - fprintf(stderr, "options include:\n" - " -h Show this help text.\n" - " -a Backup all files.\n"); - fprintf(stderr, "\nThe %s command allows you to perform low-level\n" - "backup and restore of the /data partition. This is\n" - "where all user data is kept, allowing for a fairly\n" - "complete restore of a device's state. Note that\n" - "because this is low-level, it will only work across\n" - "builds of the same (or very similar) device software.\n", - cmd); -} - -} /* namespace android */ - -int main (int argc, char **argv) -{ - int restore = 0; - - if (getuid() != AID_ROOT) { - fprintf(stderr, "error -- %s must run as root\n", argv[0]); - exit(-1); - } - - if (argc < 2) { - fprintf(stderr, "No command specified.\n"); - android::show_help(argv[0]); - exit(-1); - } - - if (0 == strcmp(argv[1], "restore")) { - restore = 1; - } else if (0 == strcmp(argv[1], "help")) { - android::show_help(argv[0]); - exit(0); - } else if (0 != strcmp(argv[1], "backup")) { - fprintf(stderr, "Unknown command: %s\n", argv[1]); - android::show_help(argv[0]); - exit(-1); - } - - android::opt_backupAll = 0; - - optind = 2; - - for (;;) { - int ret; - - ret = getopt(argc, argv, "ah"); - - if (ret < 0) { - break; - } - - switch(ret) { - case 'a': - android::opt_backupAll = 1; - if (restore) fprintf(stderr, "Warning: -a option ignored on restore\n"); - break; - case 'h': - android::show_help(argv[0]); - exit(0); - break; - - default: - fprintf(stderr,"Unrecognized Option\n"); - android::show_help(argv[0]); - exit(-1); - break; - } - } - - const char* backupFile = "/sdcard/backup.dat"; - - if (argc > optind) { - backupFile = argv[optind]; - optind++; - if (argc != optind) { - fprintf(stderr, "Too many arguments\n"); - android::show_help(argv[0]); - exit(-1); - } - } - - printf("Stopping system...\n"); - property_set("ctl.stop", "runtime"); - property_set("ctl.stop", "zygote"); - sleep(1); - - int res; - if (restore) { - res = android::restore_data(backupFile); - if (res != 0) { - // Don't restart system, since the data partition is hosed. - return res; - } - printf("Restore complete! Restarting system, cross your fingers...\n"); - } else { - res = android::backup_data(backupFile); - if (res == 0) { - printf("Backup complete! Restarting system...\n"); - } else { - printf("Restarting system...\n"); - } - } - - property_set("ctl.start", "zygote"); - property_set("ctl.start", "runtime"); -} diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index a1ea81a..be32355 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -23,10 +23,13 @@ #include <sys/ioctl.h> #include <sys/mman.h> -#include <binder/IMemory.h> +#include <binder/ProcessState.h> + #include <gui/SurfaceComposerClient.h> #include <gui/ISurfaceComposer.h> +#include <ui/PixelFormat.h> + #include <SkImageEncoder.h> #include <SkBitmap.h> #include <SkData.h> @@ -89,6 +92,8 @@ static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo, int main(int argc, char** argv) { + ProcessState::self()->startThreadPool(); + const char* pname = argv[0]; bool png = false; int32_t displayId = DEFAULT_DISPLAY_ID; @@ -135,7 +140,7 @@ int main(int argc, char** argv) ssize_t mapsize = -1; void const* base = 0; - uint32_t w, h, f; + uint32_t w, s, h, f; size_t size = 0; ScreenshotClient screenshot; @@ -144,6 +149,7 @@ int main(int argc, char** argv) base = screenshot.getPixels(); w = screenshot.getWidth(); h = screenshot.getHeight(); + s = screenshot.getStride(); f = screenshot.getFormat(); size = screenshot.getSize(); } else { @@ -157,6 +163,7 @@ int main(int argc, char** argv) size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp; w = vinfo.xres; h = vinfo.yres; + s = vinfo.xres; size = w*h*bytespp; mapsize = offset + size; mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0); @@ -172,7 +179,7 @@ int main(int argc, char** argv) if (base) { if (png) { SkBitmap b; - b.setConfig(flinger2skia(f), w, h); + b.setConfig(flinger2skia(f), w, h, s*bytesPerPixel(f)); b.setPixels((void*)base); SkDynamicMemoryWStream stream; SkImageEncoder::EncodeStream(&stream, b, @@ -184,7 +191,11 @@ int main(int argc, char** argv) write(fd, &w, 4); write(fd, &h, 4); write(fd, &f, 4); - write(fd, base, size); + size_t Bpp = bytesPerPixel(f); + for (size_t y=0 ; y<h ; y++) { + write(fd, base, w*Bpp); + base = (void *)((char *)base + s*Bpp); + } } } close(fd); diff --git a/cmds/screenshot/Android.mk b/cmds/screenshot/Android.mk deleted file mode 100644 index 73a8e22..0000000 --- a/cmds/screenshot/Android.mk +++ /dev/null @@ -1,12 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := screenshot.c - -LOCAL_MODULE := screenshot - -LOCAL_SHARED_LIBRARIES := libcutils libz -LOCAL_STATIC_LIBRARIES := libpng -LOCAL_C_INCLUDES += external/zlib - -include $(BUILD_EXECUTABLE) diff --git a/cmds/screenshot/screenshot.c b/cmds/screenshot/screenshot.c deleted file mode 100644 index cca80c3..0000000 --- a/cmds/screenshot/screenshot.c +++ /dev/null @@ -1,171 +0,0 @@ -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> - -#include <linux/fb.h> - -#include <zlib.h> -#include <libpng/png.h> - -#include "private/android_filesystem_config.h" - -#define LOG_TAG "screenshot" -#include <utils/Log.h> - -void take_screenshot(FILE *fb_in, FILE *fb_out) { - int fb; - char imgbuf[0x10000]; - struct fb_var_screeninfo vinfo; - png_structp png; - png_infop info; - unsigned int r,c,rowlen; - unsigned int bytespp,offset; - - fb = fileno(fb_in); - if(fb < 0) { - ALOGE("failed to open framebuffer\n"); - return; - } - fb_in = fdopen(fb, "r"); - - if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) { - ALOGE("failed to get framebuffer info\n"); - return; - } - fcntl(fb, F_SETFD, FD_CLOEXEC); - - png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (png == NULL) { - ALOGE("failed png_create_write_struct\n"); - fclose(fb_in); - return; - } - - png_init_io(png, fb_out); - info = png_create_info_struct(png); - if (info == NULL) { - ALOGE("failed png_create_info_struct\n"); - png_destroy_write_struct(&png, NULL); - fclose(fb_in); - return; - } - if (setjmp(png_jmpbuf(png))) { - ALOGE("failed png setjmp\n"); - png_destroy_write_struct(&png, NULL); - fclose(fb_in); - return; - } - - bytespp = vinfo.bits_per_pixel / 8; - png_set_IHDR(png, info, - vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4, - PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - png_write_info(png, info); - - rowlen=vinfo.xres * bytespp; - if (rowlen > sizeof(imgbuf)) { - ALOGE("crazy rowlen: %d\n", rowlen); - png_destroy_write_struct(&png, NULL); - fclose(fb_in); - return; - } - - offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp; - fseek(fb_in, offset, SEEK_SET); - - for(r=0; r<vinfo.yres; r++) { - int len = fread(imgbuf, 1, rowlen, fb_in); - if (len <= 0) break; - png_write_row(png, (png_bytep)imgbuf); - } - - png_write_end(png, info); - fclose(fb_in); - png_destroy_write_struct(&png, NULL); -} - -void fork_sound(const char* path) { - pid_t pid = fork(); - if (pid == 0) { - execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL); - } -} - -void usage() { - fprintf(stderr, - "usage: screenshot [-s soundfile] filename.png\n" - " -s: play a sound effect to signal success\n" - " -i: autoincrement to avoid overwriting filename.png\n" - ); -} - -int main(int argc, char**argv) { - FILE *png = NULL; - FILE *fb_in = NULL; - char outfile[PATH_MAX] = ""; - - char * soundfile = NULL; - int do_increment = 0; - - int c; - while ((c = getopt(argc, argv, "s:i")) != -1) { - switch (c) { - case 's': soundfile = optarg; break; - case 'i': do_increment = 1; break; - case '?': - case 'h': - usage(); exit(1); - } - } - argc -= optind; - argv += optind; - - if (argc < 1) { - usage(); exit(1); - } - - strlcpy(outfile, argv[0], PATH_MAX); - if (do_increment) { - struct stat st; - char base[PATH_MAX] = ""; - int i = 0; - while (stat(outfile, &st) == 0) { - if (!base[0]) { - char *p = strrchr(outfile, '.'); - if (p) *p = '\0'; - strcpy(base, outfile); - } - snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i); - } - } - - fb_in = fopen("/dev/graphics/fb0", "r"); - if (!fb_in) { - fprintf(stderr, "error: could not read framebuffer\n"); - exit(1); - } - - /* switch to non-root user and group */ - gid_t groups[] = { AID_LOG, AID_SDCARD_RW }; - setgroups(sizeof(groups)/sizeof(groups[0]), groups); - setuid(AID_SHELL); - - png = fopen(outfile, "w"); - if (!png) { - fprintf(stderr, "error: writing file %s: %s\n", - outfile, strerror(errno)); - exit(1); - } - - take_screenshot(fb_in, png); - - if (soundfile) { - fork_sound(soundfile); - } - - exit(0); -} diff --git a/cmds/service/Android.mk b/cmds/service/Android.mk deleted file mode 100644 index 275bbb2..0000000 --- a/cmds/service/Android.mk +++ /dev/null @@ -1,16 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - service.cpp - -LOCAL_SHARED_LIBRARIES := libutils libbinder - -ifeq ($(TARGET_OS),linux) - LOCAL_CFLAGS += -DXP_UNIX - #LOCAL_SHARED_LIBRARIES += librt -endif - -LOCAL_MODULE:= service - -include $(BUILD_EXECUTABLE) diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp deleted file mode 100644 index 32db83b..0000000 --- a/cmds/service/service.cpp +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Command line access to services. - * - */ - -#include <binder/Parcel.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> -#include <utils/TextOutput.h> - -#include <getopt.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/time.h> - -using namespace android; - -void writeString16(Parcel& parcel, const char* string) -{ - if (string != NULL) - { - parcel.writeString16(String16(string)); - } - else - { - parcel.writeInt32(-1); - } -} - -// get the name of the generic interface we hold a reference to -static String16 get_interface_name(sp<IBinder> service) -{ - if (service != NULL) { - Parcel data, reply; - status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply); - if (err == NO_ERROR) { - return reply.readString16(); - } - } - return String16(); -} - -static String8 good_old_string(const String16& src) -{ - String8 name8; - char ch8[2]; - ch8[1] = 0; - for (unsigned j = 0; j < src.size(); j++) { - char16_t ch = src[j]; - if (ch < 128) ch8[0] = (char)ch; - name8.append(ch8); - } - return name8; -} - -int main(int argc, char* const argv[]) -{ - sp<IServiceManager> sm = defaultServiceManager(); - fflush(stdout); - if (sm == NULL) { - aerr << "service: Unable to get default service manager!" << endl; - return 20; - } - - bool wantsUsage = false; - int result = 0; - - while (1) { - int ic = getopt(argc, argv, "h?"); - if (ic < 0) - break; - - switch (ic) { - case 'h': - case '?': - wantsUsage = true; - break; - default: - aerr << "service: Unknown option -" << ic << endl; - wantsUsage = true; - result = 10; - break; - } - } - - if (optind >= argc) { - wantsUsage = true; - } else if (!wantsUsage) { - if (strcmp(argv[optind], "check") == 0) { - optind++; - if (optind < argc) { - sp<IBinder> service = sm->checkService(String16(argv[optind])); - aout << "Service " << argv[optind] << - (service == NULL ? ": not found" : ": found") << endl; - } else { - aerr << "service: No service specified for check" << endl; - wantsUsage = true; - result = 10; - } - } - else if (strcmp(argv[optind], "list") == 0) { - Vector<String16> services = sm->listServices(); - aout << "Found " << services.size() << " services:" << endl; - for (unsigned i = 0; i < services.size(); i++) { - String16 name = services[i]; - sp<IBinder> service = sm->checkService(name); - aout << i - << "\t" << good_old_string(name) - << ": [" << good_old_string(get_interface_name(service)) << "]" - << endl; - } - } else if (strcmp(argv[optind], "call") == 0) { - optind++; - if (optind+1 < argc) { - int serviceArg = optind; - sp<IBinder> service = sm->checkService(String16(argv[optind++])); - String16 ifName = get_interface_name(service); - int32_t code = atoi(argv[optind++]); - if (service != NULL && ifName.size() > 0) { - Parcel data, reply; - - // the interface name is first - data.writeInterfaceToken(ifName); - - // then the rest of the call arguments - while (optind < argc) { - if (strcmp(argv[optind], "i32") == 0) { - optind++; - if (optind >= argc) { - aerr << "service: no integer supplied for 'i32'" << endl; - wantsUsage = true; - result = 10; - break; - } - data.writeInt32(atoi(argv[optind++])); - } else if (strcmp(argv[optind], "s16") == 0) { - optind++; - if (optind >= argc) { - aerr << "service: no string supplied for 's16'" << endl; - wantsUsage = true; - result = 10; - break; - } - data.writeString16(String16(argv[optind++])); - } else if (strcmp(argv[optind], "null") == 0) { - optind++; - data.writeStrongBinder(NULL); - } else if (strcmp(argv[optind], "intent") == 0) { - - char* action = NULL; - char* dataArg = NULL; - char* type = NULL; - int launchFlags = 0; - char* component = NULL; - int categoryCount = 0; - char* categories[16]; - - char* context1 = NULL; - - optind++; - - while (optind < argc) - { - char* key = strtok_r(argv[optind], "=", &context1); - char* value = strtok_r(NULL, "=", &context1); - - // we have reached the end of the XXX=XXX args. - if (key == NULL) break; - - if (strcmp(key, "action") == 0) - { - action = value; - } - else if (strcmp(key, "data") == 0) - { - dataArg = value; - } - else if (strcmp(key, "type") == 0) - { - type = value; - } - else if (strcmp(key, "launchFlags") == 0) - { - launchFlags = atoi(value); - } - else if (strcmp(key, "component") == 0) - { - component = value; - } - else if (strcmp(key, "categories") == 0) - { - char* context2 = NULL; - int categoryCount = 0; - categories[categoryCount] = strtok_r(value, ",", &context2); - - while (categories[categoryCount] != NULL) - { - categoryCount++; - categories[categoryCount] = strtok_r(NULL, ",", &context2); - } - } - - optind++; - } - - writeString16(data, action); - writeString16(data, dataArg); - writeString16(data, type); - data.writeInt32(launchFlags); - writeString16(data, component); - - if (categoryCount > 0) - { - data.writeInt32(categoryCount); - for (int i = 0 ; i < categoryCount ; i++) - { - writeString16(data, categories[i]); - } - } - else - { - data.writeInt32(0); - } - - // for now just set the extra field to be null. - data.writeInt32(-1); - } else { - aerr << "service: unknown option " << argv[optind] << endl; - wantsUsage = true; - result = 10; - break; - } - } - - service->transact(code, data, &reply); - aout << "Result: " << reply << endl; - } else { - aerr << "service: Service " << argv[serviceArg] - << " does not exist" << endl; - result = 10; - } - } else { - if (optind < argc) { - aerr << "service: No service specified for call" << endl; - } else { - aerr << "service: No code specified for call" << endl; - } - wantsUsage = true; - result = 10; - } - } else { - aerr << "service: Unknown command " << argv[optind] << endl; - wantsUsage = true; - result = 10; - } - } - - if (wantsUsage) { - aout << "Usage: service [-h|-?]\n" - " service list\n" - " service check SERVICE\n" - " service call SERVICE CODE [i32 INT | s16 STR] ...\n" - "Options:\n" - " i32: Write the integer INT into the send parcel.\n" - " s16: Write the UTF-16 string STR into the send parcel.\n"; -// " intent: Write and Intent int the send parcel. ARGS can be\n" -// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; - return result; - } - - return result; -} - diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk deleted file mode 100644 index 8840867..0000000 --- a/cmds/servicemanager/Android.mk +++ /dev/null @@ -1,12 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -#include $(CLEAR_VARS) -#LOCAL_SRC_FILES := bctest.c binder.c -#LOCAL_MODULE := bctest -#include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) -LOCAL_SHARED_LIBRARIES := liblog -LOCAL_SRC_FILES := service_manager.c binder.c -LOCAL_MODULE := servicemanager -include $(BUILD_EXECUTABLE) diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c deleted file mode 100644 index ff5aced..0000000 --- a/cmds/servicemanager/bctest.c +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - -#include "binder.h" - -void *svcmgr_lookup(struct binder_state *bs, void *target, const char *name) -{ - void *ptr; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) - return 0; - - ptr = bio_get_ref(&reply); - - if (ptr) - binder_acquire(bs, ptr); - - binder_done(bs, &msg, &reply); - - return ptr; -} - -int svcmgr_publish(struct binder_state *bs, void *target, const char *name, void *ptr) -{ - unsigned status; - unsigned iodata[512/4]; - struct binder_io msg, reply; - - bio_init(&msg, iodata, sizeof(iodata), 4); - bio_put_uint32(&msg, 0); // strict mode header - bio_put_string16_x(&msg, SVC_MGR_NAME); - bio_put_string16_x(&msg, name); - bio_put_obj(&msg, ptr); - - if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) - return -1; - - status = bio_get_uint32(&reply); - - binder_done(bs, &msg, &reply); - - return status; -} - -unsigned token; - -int main(int argc, char **argv) -{ - int fd; - struct binder_state *bs; - void *svcmgr = BINDER_SERVICE_MANAGER; - - bs = binder_open(128*1024); - - argc--; - argv++; - while (argc > 0) { - if (!strcmp(argv[0],"alt")) { - void *ptr = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); - if (!ptr) { - fprintf(stderr,"cannot find alt_svc_mgr\n"); - return -1; - } - svcmgr = ptr; - fprintf(stderr,"svcmgr is via %p\n", ptr); - } else if (!strcmp(argv[0],"lookup")) { - void *ptr; - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - ptr = svcmgr_lookup(bs, svcmgr, argv[1]); - fprintf(stderr,"lookup(%s) = %p\n", argv[1], ptr); - argc--; - argv++; - } else if (!strcmp(argv[0],"publish")) { - if (argc < 2) { - fprintf(stderr,"argument required\n"); - return -1; - } - svcmgr_publish(bs, svcmgr, argv[1], &token); - argc--; - argv++; - } else { - fprintf(stderr,"unknown command %s\n", argv[0]); - return -1; - } - argc--; - argv++; - } - return 0; -} diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c deleted file mode 100644 index 1985756..0000000 --- a/cmds/servicemanager/binder.c +++ /dev/null @@ -1,616 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <unistd.h> -#include <fcntl.h> -#include <sys/mman.h> - -#include "binder.h" - -#define MAX_BIO_SIZE (1 << 30) - -#define TRACE 0 - -#define LOG_TAG "Binder" -#include <cutils/log.h> - -void bio_init_from_txn(struct binder_io *io, struct binder_txn *txn); - -#if TRACE -void hexdump(void *_data, unsigned len) -{ - unsigned char *data = _data; - unsigned count; - - for (count = 0; count < len; count++) { - if ((count & 15) == 0) - fprintf(stderr,"%04x:", count); - fprintf(stderr," %02x %c", *data, - (*data < 32) || (*data > 126) ? '.' : *data); - data++; - if ((count & 15) == 15) - fprintf(stderr,"\n"); - } - if ((count & 15) != 0) - fprintf(stderr,"\n"); -} - -void binder_dump_txn(struct binder_txn *txn) -{ - struct binder_object *obj; - unsigned *offs = txn->offs; - unsigned count = txn->offs_size / 4; - - fprintf(stderr," target %p cookie %p code %08x flags %08x\n", - txn->target, txn->cookie, txn->code, txn->flags); - fprintf(stderr," pid %8d uid %8d data %8d offs %8d\n", - txn->sender_pid, txn->sender_euid, txn->data_size, txn->offs_size); - hexdump(txn->data, txn->data_size); - while (count--) { - obj = (void*) (((char*) txn->data) + *offs++); - fprintf(stderr," - type %08x flags %08x ptr %p cookie %p\n", - obj->type, obj->flags, obj->pointer, obj->cookie); - } -} - -#define NAME(n) case n: return #n -const char *cmd_name(uint32_t cmd) -{ - switch(cmd) { - NAME(BR_NOOP); - NAME(BR_TRANSACTION_COMPLETE); - NAME(BR_INCREFS); - NAME(BR_ACQUIRE); - NAME(BR_RELEASE); - NAME(BR_DECREFS); - NAME(BR_TRANSACTION); - NAME(BR_REPLY); - NAME(BR_FAILED_REPLY); - NAME(BR_DEAD_REPLY); - NAME(BR_DEAD_BINDER); - default: return "???"; - } -} -#else -#define hexdump(a,b) do{} while (0) -#define binder_dump_txn(txn) do{} while (0) -#endif - -#define BIO_F_SHARED 0x01 /* needs to be buffer freed */ -#define BIO_F_OVERFLOW 0x02 /* ran out of space */ -#define BIO_F_IOERROR 0x04 -#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ - -struct binder_state -{ - int fd; - void *mapped; - unsigned mapsize; -}; - -struct binder_state *binder_open(unsigned mapsize) -{ - struct binder_state *bs; - - bs = malloc(sizeof(*bs)); - if (!bs) { - errno = ENOMEM; - return 0; - } - - bs->fd = open("/dev/binder", O_RDWR); - if (bs->fd < 0) { - fprintf(stderr,"binder: cannot open device (%s)\n", - strerror(errno)); - goto fail_open; - } - - bs->mapsize = mapsize; - bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); - if (bs->mapped == MAP_FAILED) { - fprintf(stderr,"binder: cannot map device (%s)\n", - strerror(errno)); - goto fail_map; - } - - /* TODO: check version */ - - return bs; - -fail_map: - close(bs->fd); -fail_open: - free(bs); - return 0; -} - -void binder_close(struct binder_state *bs) -{ - munmap(bs->mapped, bs->mapsize); - close(bs->fd); - free(bs); -} - -int binder_become_context_manager(struct binder_state *bs) -{ - return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); -} - -int binder_write(struct binder_state *bs, void *data, unsigned len) -{ - struct binder_write_read bwr; - int res; - bwr.write_size = len; - bwr.write_consumed = 0; - bwr.write_buffer = (unsigned) data; - bwr.read_size = 0; - bwr.read_consumed = 0; - bwr.read_buffer = 0; - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - if (res < 0) { - fprintf(stderr,"binder_write: ioctl failed (%s)\n", - strerror(errno)); - } - return res; -} - -void binder_send_reply(struct binder_state *bs, - struct binder_io *reply, - void *buffer_to_free, - int status) -{ - struct { - uint32_t cmd_free; - void *buffer; - uint32_t cmd_reply; - struct binder_txn txn; - } __attribute__((packed)) data; - - data.cmd_free = BC_FREE_BUFFER; - data.buffer = buffer_to_free; - data.cmd_reply = BC_REPLY; - data.txn.target = 0; - data.txn.cookie = 0; - data.txn.code = 0; - if (status) { - data.txn.flags = TF_STATUS_CODE; - data.txn.data_size = sizeof(int); - data.txn.offs_size = 0; - data.txn.data = &status; - data.txn.offs = 0; - } else { - data.txn.flags = 0; - data.txn.data_size = reply->data - reply->data0; - data.txn.offs_size = ((char*) reply->offs) - ((char*) reply->offs0); - data.txn.data = reply->data0; - data.txn.offs = reply->offs0; - } - binder_write(bs, &data, sizeof(data)); -} - -int binder_parse(struct binder_state *bs, struct binder_io *bio, - uint32_t *ptr, uint32_t size, binder_handler func) -{ - int r = 1; - uint32_t *end = ptr + (size / 4); - - while (ptr < end) { - uint32_t cmd = *ptr++; -#if TRACE - fprintf(stderr,"%s:\n", cmd_name(cmd)); -#endif - switch(cmd) { - case BR_NOOP: - break; - case BR_TRANSACTION_COMPLETE: - break; - case BR_INCREFS: - case BR_ACQUIRE: - case BR_RELEASE: - case BR_DECREFS: -#if TRACE - fprintf(stderr," %08x %08x\n", ptr[0], ptr[1]); -#endif - ptr += 2; - break; - case BR_TRANSACTION: { - struct binder_txn *txn = (void *) ptr; - if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) { - ALOGE("parse: txn too small!\n"); - return -1; - } - binder_dump_txn(txn); - if (func) { - unsigned rdata[256/4]; - struct binder_io msg; - struct binder_io reply; - int res; - - bio_init(&reply, rdata, sizeof(rdata), 4); - bio_init_from_txn(&msg, txn); - res = func(bs, txn, &msg, &reply); - binder_send_reply(bs, &reply, txn->data, res); - } - ptr += sizeof(*txn) / sizeof(uint32_t); - break; - } - case BR_REPLY: { - struct binder_txn *txn = (void*) ptr; - if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) { - ALOGE("parse: reply too small!\n"); - return -1; - } - binder_dump_txn(txn); - if (bio) { - bio_init_from_txn(bio, txn); - bio = 0; - } else { - /* todo FREE BUFFER */ - } - ptr += (sizeof(*txn) / sizeof(uint32_t)); - r = 0; - break; - } - case BR_DEAD_BINDER: { - struct binder_death *death = (void*) *ptr++; - death->func(bs, death->ptr); - break; - } - case BR_FAILED_REPLY: - r = -1; - break; - case BR_DEAD_REPLY: - r = -1; - break; - default: - ALOGE("parse: OOPS %d\n", cmd); - return -1; - } - } - - return r; -} - -void binder_acquire(struct binder_state *bs, void *ptr) -{ - uint32_t cmd[2]; - cmd[0] = BC_ACQUIRE; - cmd[1] = (uint32_t) ptr; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_release(struct binder_state *bs, void *ptr) -{ - uint32_t cmd[2]; - cmd[0] = BC_RELEASE; - cmd[1] = (uint32_t) ptr; - binder_write(bs, cmd, sizeof(cmd)); -} - -void binder_link_to_death(struct binder_state *bs, void *ptr, struct binder_death *death) -{ - uint32_t cmd[3]; - cmd[0] = BC_REQUEST_DEATH_NOTIFICATION; - cmd[1] = (uint32_t) ptr; - cmd[2] = (uint32_t) death; - binder_write(bs, cmd, sizeof(cmd)); -} - - -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - void *target, uint32_t code) -{ - int res; - struct binder_write_read bwr; - struct { - uint32_t cmd; - struct binder_txn txn; - } writebuf; - unsigned readbuf[32]; - - if (msg->flags & BIO_F_OVERFLOW) { - fprintf(stderr,"binder: txn buffer overflow\n"); - goto fail; - } - - writebuf.cmd = BC_TRANSACTION; - writebuf.txn.target = target; - writebuf.txn.code = code; - writebuf.txn.flags = 0; - writebuf.txn.data_size = msg->data - msg->data0; - writebuf.txn.offs_size = ((char*) msg->offs) - ((char*) msg->offs0); - writebuf.txn.data = msg->data0; - writebuf.txn.offs = msg->offs0; - - bwr.write_size = sizeof(writebuf); - bwr.write_consumed = 0; - bwr.write_buffer = (unsigned) &writebuf; - - hexdump(msg->data0, msg->data - msg->data0); - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (unsigned) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); - goto fail; - } - - res = binder_parse(bs, reply, readbuf, bwr.read_consumed, 0); - if (res == 0) return 0; - if (res < 0) goto fail; - } - -fail: - memset(reply, 0, sizeof(*reply)); - reply->flags |= BIO_F_IOERROR; - return -1; -} - -void binder_loop(struct binder_state *bs, binder_handler func) -{ - int res; - struct binder_write_read bwr; - unsigned readbuf[32]; - - bwr.write_size = 0; - bwr.write_consumed = 0; - bwr.write_buffer = 0; - - readbuf[0] = BC_ENTER_LOOPER; - binder_write(bs, readbuf, sizeof(unsigned)); - - for (;;) { - bwr.read_size = sizeof(readbuf); - bwr.read_consumed = 0; - bwr.read_buffer = (unsigned) readbuf; - - res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); - - if (res < 0) { - ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); - break; - } - - res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func); - if (res == 0) { - ALOGE("binder_loop: unexpected reply?!\n"); - break; - } - if (res < 0) { - ALOGE("binder_loop: io error %d %s\n", res, strerror(errno)); - break; - } - } -} - -void bio_init_from_txn(struct binder_io *bio, struct binder_txn *txn) -{ - bio->data = bio->data0 = txn->data; - bio->offs = bio->offs0 = txn->offs; - bio->data_avail = txn->data_size; - bio->offs_avail = txn->offs_size / 4; - bio->flags = BIO_F_SHARED; -} - -void bio_init(struct binder_io *bio, void *data, - uint32_t maxdata, uint32_t maxoffs) -{ - uint32_t n = maxoffs * sizeof(uint32_t); - - if (n > maxdata) { - bio->flags = BIO_F_OVERFLOW; - bio->data_avail = 0; - bio->offs_avail = 0; - return; - } - - bio->data = bio->data0 = (char *) data + n; - bio->offs = bio->offs0 = data; - bio->data_avail = maxdata - n; - bio->offs_avail = maxoffs; - bio->flags = 0; -} - -static void *bio_alloc(struct binder_io *bio, uint32_t size) -{ - size = (size + 3) & (~3); - if (size > bio->data_avail) { - bio->flags |= BIO_F_OVERFLOW; - return 0; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -void binder_done(struct binder_state *bs, - struct binder_io *msg, - struct binder_io *reply) -{ - if (reply->flags & BIO_F_SHARED) { - uint32_t cmd[2]; - cmd[0] = BC_FREE_BUFFER; - cmd[1] = (uint32_t) reply->data0; - binder_write(bs, cmd, sizeof(cmd)); - reply->flags = 0; - } -} - -static struct binder_object *bio_alloc_obj(struct binder_io *bio) -{ - struct binder_object *obj; - - obj = bio_alloc(bio, sizeof(*obj)); - - if (obj && bio->offs_avail) { - bio->offs_avail--; - *bio->offs++ = ((char*) obj) - ((char*) bio->data0); - return obj; - } - - bio->flags |= BIO_F_OVERFLOW; - return 0; -} - -void bio_put_uint32(struct binder_io *bio, uint32_t n) -{ - uint32_t *ptr = bio_alloc(bio, sizeof(n)); - if (ptr) - *ptr = n; -} - -void bio_put_obj(struct binder_io *bio, void *ptr) -{ - struct binder_object *obj; - - obj = bio_alloc_obj(bio); - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->type = BINDER_TYPE_BINDER; - obj->pointer = ptr; - obj->cookie = 0; -} - -void bio_put_ref(struct binder_io *bio, void *ptr) -{ - struct binder_object *obj; - - if (ptr) - obj = bio_alloc_obj(bio); - else - obj = bio_alloc(bio, sizeof(*obj)); - - if (!obj) - return; - - obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; - obj->type = BINDER_TYPE_HANDLE; - obj->pointer = ptr; - obj->cookie = 0; -} - -void bio_put_string16(struct binder_io *bio, const uint16_t *str) -{ - uint32_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = 0; - while (str[len]) len++; - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - bio_put_uint32(bio, len); - len = (len + 1) * sizeof(uint16_t); - ptr = bio_alloc(bio, len); - if (ptr) - memcpy(ptr, str, len); -} - -void bio_put_string16_x(struct binder_io *bio, const char *_str) -{ - unsigned char *str = (unsigned char*) _str; - uint32_t len; - uint16_t *ptr; - - if (!str) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - len = strlen(_str); - - if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { - bio_put_uint32(bio, 0xffffffff); - return; - } - - bio_put_uint32(bio, len); - ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); - if (!ptr) - return; - - while (*str) - *ptr++ = *str++; - *ptr++ = 0; -} - -static void *bio_get(struct binder_io *bio, uint32_t size) -{ - size = (size + 3) & (~3); - - if (bio->data_avail < size){ - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return 0; - } else { - void *ptr = bio->data; - bio->data += size; - bio->data_avail -= size; - return ptr; - } -} - -uint32_t bio_get_uint32(struct binder_io *bio) -{ - uint32_t *ptr = bio_get(bio, sizeof(*ptr)); - return ptr ? *ptr : 0; -} - -uint16_t *bio_get_string16(struct binder_io *bio, unsigned *sz) -{ - unsigned len; - len = bio_get_uint32(bio); - if (sz) - *sz = len; - return bio_get(bio, (len + 1) * sizeof(uint16_t)); -} - -static struct binder_object *_bio_get_obj(struct binder_io *bio) -{ - unsigned n; - unsigned off = bio->data - bio->data0; - - /* TODO: be smarter about this? */ - for (n = 0; n < bio->offs_avail; n++) { - if (bio->offs[n] == off) - return bio_get(bio, sizeof(struct binder_object)); - } - - bio->data_avail = 0; - bio->flags |= BIO_F_OVERFLOW; - return 0; -} - -void *bio_get_ref(struct binder_io *bio) -{ - struct binder_object *obj; - - obj = _bio_get_obj(bio); - if (!obj) - return 0; - - if (obj->type == BINDER_TYPE_HANDLE) - return obj->pointer; - - return 0; -} diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h deleted file mode 100644 index d8c51ef..0000000 --- a/cmds/servicemanager/binder.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#ifndef _BINDER_H_ -#define _BINDER_H_ - -#include <sys/ioctl.h> -#include <linux/binder.h> - -struct binder_state; - -struct binder_object -{ - uint32_t type; - uint32_t flags; - void *pointer; - void *cookie; -}; - -struct binder_txn -{ - void *target; - void *cookie; - uint32_t code; - uint32_t flags; - - uint32_t sender_pid; - uint32_t sender_euid; - - uint32_t data_size; - uint32_t offs_size; - void *data; - void *offs; -}; - -struct binder_io -{ - char *data; /* pointer to read/write from */ - uint32_t *offs; /* array of offsets */ - uint32_t data_avail; /* bytes available in data buffer */ - uint32_t offs_avail; /* entries available in offsets array */ - - char *data0; /* start of data buffer */ - uint32_t *offs0; /* start of offsets buffer */ - uint32_t flags; - uint32_t unused; -}; - -struct binder_death { - void (*func)(struct binder_state *bs, void *ptr); - void *ptr; -}; - -/* the one magic object */ -#define BINDER_SERVICE_MANAGER ((void*) 0) - -#define SVC_MGR_NAME "android.os.IServiceManager" - -enum { - SVC_MGR_GET_SERVICE = 1, - SVC_MGR_CHECK_SERVICE, - SVC_MGR_ADD_SERVICE, - SVC_MGR_LIST_SERVICES, -}; - -typedef int (*binder_handler)(struct binder_state *bs, - struct binder_txn *txn, - struct binder_io *msg, - struct binder_io *reply); - -struct binder_state *binder_open(unsigned mapsize); -void binder_close(struct binder_state *bs); - -/* initiate a blocking binder call - * - returns zero on success - */ -int binder_call(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply, - void *target, uint32_t code); - -/* release any state associate with the binder_io - * - call once any necessary data has been extracted from the - * binder_io after binder_call() returns - * - can safely be called even if binder_call() fails - */ -void binder_done(struct binder_state *bs, - struct binder_io *msg, struct binder_io *reply); - -/* manipulate strong references */ -void binder_acquire(struct binder_state *bs, void *ptr); -void binder_release(struct binder_state *bs, void *ptr); - -void binder_link_to_death(struct binder_state *bs, void *ptr, struct binder_death *death); - -void binder_loop(struct binder_state *bs, binder_handler func); - -int binder_become_context_manager(struct binder_state *bs); - -/* allocate a binder_io, providing a stack-allocated working - * buffer, size of the working buffer, and how many object - * offset entries to reserve from the buffer - */ -void bio_init(struct binder_io *bio, void *data, - uint32_t maxdata, uint32_t maxobjects); - -void bio_destroy(struct binder_io *bio); - -void bio_put_obj(struct binder_io *bio, void *ptr); -void bio_put_ref(struct binder_io *bio, void *ptr); -void bio_put_uint32(struct binder_io *bio, uint32_t n); -void bio_put_string16(struct binder_io *bio, const uint16_t *str); -void bio_put_string16_x(struct binder_io *bio, const char *_str); - -uint32_t bio_get_uint32(struct binder_io *bio); -uint16_t *bio_get_string16(struct binder_io *bio, uint32_t *sz); -void *bio_get_obj(struct binder_io *bio); -void *bio_get_ref(struct binder_io *bio); - -#endif diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c deleted file mode 100644 index c563a82..0000000 --- a/cmds/servicemanager/service_manager.c +++ /dev/null @@ -1,287 +0,0 @@ -/* Copyright 2008 The Android Open Source Project - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include <fcntl.h> - -#include <private/android_filesystem_config.h> - -#include "binder.h" - -#if 0 -#define ALOGI(x...) fprintf(stderr, "svcmgr: " x) -#define ALOGE(x...) fprintf(stderr, "svcmgr: " x) -#else -#define LOG_TAG "ServiceManager" -#include <cutils/log.h> -#endif - -/* TODO: - * These should come from a config file or perhaps be - * based on some namespace rules of some sort (media - * uid can register media.*, etc) - */ -static struct { - unsigned uid; - const char *name; -} allowed[] = { - { AID_MEDIA, "media.audio_flinger" }, - { AID_MEDIA, "media.player" }, - { AID_MEDIA, "media.camera" }, - { AID_MEDIA, "media.audio_policy" }, - { AID_MEDIA, "android.media.IAAHMetaDataService" }, - { AID_DRM, "drm.drmManager" }, - { AID_NFC, "nfc" }, - { AID_BLUETOOTH, "bluetooth" }, - { AID_RADIO, "radio.phone" }, - { AID_RADIO, "radio.sms" }, - { AID_RADIO, "radio.phonesubinfo" }, - { AID_RADIO, "radio.simphonebook" }, -/* TODO: remove after phone services are updated: */ - { AID_RADIO, "phone" }, - { AID_RADIO, "sip" }, - { AID_RADIO, "isms" }, - { AID_RADIO, "iphonesubinfo" }, - { AID_RADIO, "simphonebook" }, - { AID_MEDIA, "common_time.clock" }, - { AID_MEDIA, "common_time.config" }, - { AID_KEYSTORE, "android.security.keystore" }, -}; - -void *svcmgr_handle; - -const char *str8(uint16_t *x) -{ - static char buf[128]; - unsigned max = 127; - char *p = buf; - - if (x) { - while (*x && max--) { - *p++ = *x++; - } - } - *p++ = 0; - return buf; -} - -int str16eq(uint16_t *a, const char *b) -{ - while (*a && *b) - if (*a++ != *b++) return 0; - if (*a || *b) - return 0; - return 1; -} - -int svc_can_register(unsigned uid, uint16_t *name) -{ - unsigned n; - - if ((uid == 0) || (uid == AID_SYSTEM)) - return 1; - - for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++) - if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name)) - return 1; - - return 0; -} - -struct svcinfo -{ - struct svcinfo *next; - void *ptr; - struct binder_death death; - int allow_isolated; - unsigned len; - uint16_t name[0]; -}; - -struct svcinfo *svclist = 0; - -struct svcinfo *find_svc(uint16_t *s16, unsigned len) -{ - struct svcinfo *si; - - for (si = svclist; si; si = si->next) { - if ((len == si->len) && - !memcmp(s16, si->name, len * sizeof(uint16_t))) { - return si; - } - } - return 0; -} - -void svcinfo_death(struct binder_state *bs, void *ptr) -{ - struct svcinfo *si = ptr; - ALOGI("service '%s' died\n", str8(si->name)); - if (si->ptr) { - binder_release(bs, si->ptr); - si->ptr = 0; - } -} - -uint16_t svcmgr_id[] = { - 'a','n','d','r','o','i','d','.','o','s','.', - 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' -}; - - -void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid) -{ - struct svcinfo *si; - si = find_svc(s, len); - -// ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0); - if (si && si->ptr) { - if (!si->allow_isolated) { - // If this service doesn't allow access from isolated processes, - // then check the uid to see if it is isolated. - unsigned appid = uid % AID_USER; - if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) { - return 0; - } - } - return si->ptr; - } else { - return 0; - } -} - -int do_add_service(struct binder_state *bs, - uint16_t *s, unsigned len, - void *ptr, unsigned uid, int allow_isolated) -{ - struct svcinfo *si; - //ALOGI("add_service('%s',%p,%s) uid=%d\n", str8(s), ptr, - // allow_isolated ? "allow_isolated" : "!allow_isolated", uid); - - if (!ptr || (len == 0) || (len > 127)) - return -1; - - if (!svc_can_register(uid, s)) { - ALOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n", - str8(s), ptr, uid); - return -1; - } - - si = find_svc(s, len); - if (si) { - if (si->ptr) { - ALOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED, OVERRIDE\n", - str8(s), ptr, uid); - svcinfo_death(bs, si); - } - si->ptr = ptr; - } else { - si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); - if (!si) { - ALOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n", - str8(s), ptr, uid); - return -1; - } - si->ptr = ptr; - si->len = len; - memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); - si->name[len] = '\0'; - si->death.func = svcinfo_death; - si->death.ptr = si; - si->allow_isolated = allow_isolated; - si->next = svclist; - svclist = si; - } - - binder_acquire(bs, ptr); - binder_link_to_death(bs, ptr, &si->death); - return 0; -} - -int svcmgr_handler(struct binder_state *bs, - struct binder_txn *txn, - struct binder_io *msg, - struct binder_io *reply) -{ - struct svcinfo *si; - uint16_t *s; - unsigned len; - void *ptr; - uint32_t strict_policy; - int allow_isolated; - -// ALOGI("target=%p code=%d pid=%d uid=%d\n", -// txn->target, txn->code, txn->sender_pid, txn->sender_euid); - - if (txn->target != svcmgr_handle) - return -1; - - // Equivalent to Parcel::enforceInterface(), reading the RPC - // header with the strict mode policy mask and the interface name. - // Note that we ignore the strict_policy and don't propagate it - // further (since we do no outbound RPCs anyway). - strict_policy = bio_get_uint32(msg); - s = bio_get_string16(msg, &len); - if ((len != (sizeof(svcmgr_id) / 2)) || - memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { - fprintf(stderr,"invalid id %s\n", str8(s)); - return -1; - } - - switch(txn->code) { - case SVC_MGR_GET_SERVICE: - case SVC_MGR_CHECK_SERVICE: - s = bio_get_string16(msg, &len); - ptr = do_find_service(bs, s, len, txn->sender_euid); - if (!ptr) - break; - bio_put_ref(reply, ptr); - return 0; - - case SVC_MGR_ADD_SERVICE: - s = bio_get_string16(msg, &len); - ptr = bio_get_ref(msg); - allow_isolated = bio_get_uint32(msg) ? 1 : 0; - if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated)) - return -1; - break; - - case SVC_MGR_LIST_SERVICES: { - unsigned n = bio_get_uint32(msg); - - si = svclist; - while ((n-- > 0) && si) - si = si->next; - if (si) { - bio_put_string16(reply, si->name); - return 0; - } - return -1; - } - default: - ALOGE("unknown code %d\n", txn->code); - return -1; - } - - bio_put_uint32(reply, 0); - return 0; -} - -int main(int argc, char **argv) -{ - struct binder_state *bs; - void *svcmgr = BINDER_SERVICE_MANAGER; - - bs = binder_open(128*1024); - - if (binder_become_context_manager(bs)) { - ALOGE("cannot become context manager (%s)\n", strerror(errno)); - return -1; - } - - svcmgr_handle = svcmgr; - binder_loop(bs, svcmgr_handler); - return 0; -} diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java index 0c69f01..dce0a75 100644 --- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java +++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java @@ -180,7 +180,7 @@ public final class SettingsCmd { try { Bundle arg = new Bundle(); arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle); - Bundle b = provider.call(callGetCommand, key, arg); + Bundle b = provider.call(null, callGetCommand, key, arg); if (b != null) { result = b.getPairValue(); } @@ -205,7 +205,7 @@ public final class SettingsCmd { Bundle arg = new Bundle(); arg.putString(Settings.NameValueTable.VALUE, value); arg.putInt(Settings.CALL_METHOD_USER_KEY, userHandle); - provider.call(callPutCommand, key, arg); + provider.call(null, callPutCommand, key, arg); } catch (RemoteException e) { System.err.println("Can't set key " + key + " in " + table + " for user " + userHandle); } diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java index 58105fa..da8586c 100644 --- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java +++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java @@ -36,12 +36,18 @@ public class PowerCommand extends Svc.Command { return shortHelp() + "\n" + "\n" + "usage: svc power stayon [true|false|usb|ac|wireless]\n" - + " Set the 'keep awake while plugged in' setting.\n"; + + " Set the 'keep awake while plugged in' setting.\n" + + " svc power reboot [reason]\n" + + " Perform a runtime shutdown and reboot device with specified reason.\n" + + " svc power shutdown\n" + + " Perform a runtime shutdown and power off the device.\n"; } public void run(String[] args) { fail: { if (args.length >= 2) { + IPowerManager pm = IPowerManager.Stub.asInterface( + ServiceManager.getService(Context.POWER_SERVICE)); if ("stayon".equals(args[1]) && args.length == 3) { int val; if ("true".equals(args[2])) { @@ -60,8 +66,6 @@ public class PowerCommand extends Svc.Command { } else { break fail; } - IPowerManager pm - = IPowerManager.Stub.asInterface(ServiceManager.getService(Context.POWER_SERVICE)); try { if (val != 0) { // if the request is not to set it to false, wake up the screen so that @@ -74,6 +78,26 @@ public class PowerCommand extends Svc.Command { System.err.println("Faild to set setting: " + e); } return; + } else if ("reboot".equals(args[1])) { + String mode = null; + if (args.length == 3) { + mode = args[2]; + } + try { + // no confirm, wait till device is rebooted + pm.reboot(false, mode, true); + } catch (RemoteException e) { + System.err.println("Failed to reboot."); + } + return; + } else if ("shutdown".equals(args[1])) { + try { + // no confirm, wait till device is off + pm.shutdown(false, true); + } catch (RemoteException e) { + System.err.println("Failed to shutdown."); + } + return; } } } diff --git a/cmds/system_server/Android.mk b/cmds/system_server/Android.mk index ad537977..3083e31 100644 --- a/cmds/system_server/Android.mk +++ b/cmds/system_server/Android.mk @@ -7,7 +7,8 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libutils \ libbinder \ - libsystem_server + libsystem_server \ + liblog LOCAL_C_INCLUDES := \ $(JNI_H_INCLUDE) @@ -17,4 +18,3 @@ LOCAL_MODULE:= system_server include $(BUILD_EXECUTABLE) include $(LOCAL_PATH)/library/Android.mk - diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk index c42424c..d78474e 100644 --- a/cmds/system_server/library/Android.mk +++ b/cmds/system_server/library/Android.mk @@ -16,10 +16,11 @@ LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ libsensorservice \ libsurfaceflinger \ - libinput \ + libinput \ libutils \ libbinder \ - libcutils + libcutils \ + liblog LOCAL_MODULE:= libsystem_server diff --git a/cmds/wm/Android.mk b/cmds/wm/Android.mk new file mode 100644 index 0000000..3f3795f --- /dev/null +++ b/cmds/wm/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2013 The Android Open Source Project +# +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := wm +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := wm +LOCAL_SRC_FILES := wm +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) diff --git a/cmds/wm/MODULE_LICENSE_APACHE2 b/cmds/wm/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/wm/MODULE_LICENSE_APACHE2 diff --git a/cmds/service/NOTICE b/cmds/wm/NOTICE index c5b1efa..c5b1efa 100644 --- a/cmds/service/NOTICE +++ b/cmds/wm/NOTICE diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java new file mode 100644 index 0000000..815a0ac --- /dev/null +++ b/cmds/wm/src/com/android/commands/wm/Wm.java @@ -0,0 +1,196 @@ +/* +** +** Copyright 2013, 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. +*/ + + +package com.android.commands.wm; + +import android.content.Context; +import android.graphics.Point; +import android.graphics.Rect; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.AndroidException; +import android.view.Display; +import android.view.IWindowManager; +import com.android.internal.os.BaseCommand; + +import java.io.PrintStream; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class Wm extends BaseCommand { + + private IWindowManager mWm; + + /** + * Command-line entry point. + * + * @param args The command-line arguments + */ + public static void main(String[] args) { + (new Wm()).run(args); + } + + public void onShowUsage(PrintStream out) { + out.println( + "usage: wm [subcommand] [options]\n" + + " wm size [reset|WxH]\n" + + " wm density [reset|DENSITY]\n" + + " wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" + + "\n" + + "wm size: return or override display size.\n" + + "\n" + + "wm density: override display density.\n" + + "\n" + + "wm overscan: set overscan area for display.\n" + ); + } + + public void onRun() throws Exception { + mWm = IWindowManager.Stub.asInterface(ServiceManager.checkService( + Context.WINDOW_SERVICE)); + if (mWm == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + throw new AndroidException("Can't connect to window manager; is the system running?"); + } + + String op = nextArgRequired(); + + if (op.equals("size")) { + runDisplaySize(); + } else if (op.equals("density")) { + runDisplayDensity(); + } else if (op.equals("overscan")) { + runDisplayOverscan(); + } else { + showError("Error: unknown command '" + op + "'"); + return; + } + } + + private void runDisplaySize() throws Exception { + String size = nextArg(); + int w, h; + if (size == null) { + Point initialSize = new Point(); + Point baseSize = new Point(); + try { + mWm.getInitialDisplaySize(Display.DEFAULT_DISPLAY, initialSize); + mWm.getBaseDisplaySize(Display.DEFAULT_DISPLAY, baseSize); + System.out.println("Physical size: " + initialSize.x + "x" + initialSize.y); + if (!initialSize.equals(baseSize)) { + System.out.println("Override size: " + baseSize.x + "x" + baseSize.y); + } + } catch (RemoteException e) { + } + return; + } else if ("reset".equals(size)) { + w = h = -1; + } else { + int div = size.indexOf('x'); + if (div <= 0 || div >= (size.length()-1)) { + System.err.println("Error: bad size " + size); + return; + } + String wstr = size.substring(0, div); + String hstr = size.substring(div+1); + try { + w = Integer.parseInt(wstr); + h = Integer.parseInt(hstr); + } catch (NumberFormatException e) { + System.err.println("Error: bad number " + e); + return; + } + } + + try { + if (w >= 0 && h >= 0) { + // TODO(multidisplay): For now Configuration only applies to main screen. + mWm.setForcedDisplaySize(Display.DEFAULT_DISPLAY, w, h); + } else { + mWm.clearForcedDisplaySize(Display.DEFAULT_DISPLAY); + } + } catch (RemoteException e) { + } + } + + private void runDisplayDensity() throws Exception { + String densityStr = nextArg(); + int density; + if (densityStr == null) { + try { + int initialDensity = mWm.getInitialDisplayDensity(Display.DEFAULT_DISPLAY); + int baseDensity = mWm.getBaseDisplayDensity(Display.DEFAULT_DISPLAY); + System.out.println("Physical density: " + initialDensity); + if (initialDensity != baseDensity) { + System.out.println("Override density: " + baseDensity); + } + } catch (RemoteException e) { + } + return; + } else if ("reset".equals(densityStr)) { + density = -1; + } else { + try { + density = Integer.parseInt(densityStr); + } catch (NumberFormatException e) { + System.err.println("Error: bad number " + e); + return; + } + if (density < 72) { + System.err.println("Error: density must be >= 72"); + return; + } + } + + try { + if (density > 0) { + // TODO(multidisplay): For now Configuration only applies to main screen. + mWm.setForcedDisplayDensity(Display.DEFAULT_DISPLAY, density); + } else { + mWm.clearForcedDisplayDensity(Display.DEFAULT_DISPLAY); + } + } catch (RemoteException e) { + } + } + + private void runDisplayOverscan() throws Exception { + String overscanStr = nextArgRequired(); + Rect rect = new Rect(); + int density; + if ("reset".equals(overscanStr)) { + rect.set(0, 0, 0, 0); + } else { + final Pattern FLATTENED_PATTERN = Pattern.compile( + "(-?\\d+),(-?\\d+),(-?\\d+),(-?\\d+)"); + Matcher matcher = FLATTENED_PATTERN.matcher(overscanStr); + if (!matcher.matches()) { + System.err.println("Error: bad rectangle arg: " + overscanStr); + return; + } + rect.left = Integer.parseInt(matcher.group(1)); + rect.top = Integer.parseInt(matcher.group(2)); + rect.right = Integer.parseInt(matcher.group(3)); + rect.bottom = Integer.parseInt(matcher.group(4)); + } + + try { + mWm.setOverscan(Display.DEFAULT_DISPLAY, rect.left, rect.top, rect.right, rect.bottom); + } catch (RemoteException e) { + } + } +} diff --git a/cmds/wm/wm b/cmds/wm/wm new file mode 100755 index 0000000..f7a5bc7 --- /dev/null +++ b/cmds/wm/wm @@ -0,0 +1,6 @@ +# Script to start "wm" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/wm.jar +exec app_process $base/bin com.android.commands.wm.Wm "$@" |