diff options
Diffstat (limited to 'cmds')
52 files changed, 1307 insertions, 5822 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index fddb429d5ae5..53a0186a5e0d 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -31,6 +31,7 @@ import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.ResolveInfo; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -56,14 +57,14 @@ public class Am { private int mNextArg; private String mCurArgData; - private boolean mDebugOption = false; + private int mStartFlags = 0; private boolean mWaitOption = false; private boolean mStopOption = false; private int mRepeat = 0; + private int mUserId = 0; private String mProfileFile; - private boolean mProfileAutoStop; // These are magic strings understood by the Eclipse plugin. private static final String FATAL_ERROR_CODE = "Error type 1"; @@ -135,6 +136,8 @@ public class Am { runToUri(false); } else if (op.equals("to-intent-uri")) { runToUri(true); + } else if (op.equals("switch-user")) { + runSwitchUser(); } else { throw new IllegalArgumentException("Unknown command: " + op); } @@ -145,11 +148,12 @@ public class Am { Intent baseIntent = intent; boolean hasIntentInfo = false; - mDebugOption = false; + mStartFlags = 0; mWaitOption = false; mStopOption = false; mRepeat = 0; mProfileFile = null; + mUserId = 0; Uri data = null; String type = null; @@ -212,6 +216,22 @@ public class Am { list[i] = Long.valueOf(strings[i]); } intent.putExtra(key, list); + hasIntentInfo = true; + } else if (opt.equals("--ef")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + intent.putExtra(key, Float.valueOf(value)); + hasIntentInfo = true; + } else if (opt.equals("--efa")) { + String key = nextArgRequired(); + String value = nextArgRequired(); + String[] strings = value.split(","); + float[] list = new float[strings.length]; + for (int i = 0; i < strings.length; i++) { + list[i] = Float.valueOf(strings[i]); + } + intent.putExtra(key, list); + hasIntentInfo = true; } else if (opt.equals("--ez")) { String key = nextArgRequired(); String value = nextArgRequired(); @@ -275,19 +295,23 @@ public class Am { intent.setDataAndType(data, type); intent = new Intent(); } else if (opt.equals("-D")) { - mDebugOption = true; + mStartFlags |= ActivityManager.START_FLAG_DEBUG; } else if (opt.equals("-W")) { mWaitOption = true; } else if (opt.equals("-P")) { mProfileFile = nextArgRequired(); - mProfileAutoStop = true; + mStartFlags |= ActivityManager.START_FLAG_AUTO_STOP_PROFILER; } else if (opt.equals("--start-profiler")) { mProfileFile = nextArgRequired(); - mProfileAutoStop = false; + mStartFlags &= ~ActivityManager.START_FLAG_AUTO_STOP_PROFILER; } else if (opt.equals("-R")) { mRepeat = Integer.parseInt(nextArgRequired()); } else if (opt.equals("-S")) { mStopOption = true; + } else if (opt.equals("--opengl-trace")) { + mStartFlags |= ActivityManager.START_FLAG_OPENGL_TRACES; + } else if (opt.equals("--user")) { + mUserId = Integer.parseInt(nextArgRequired()); } else { System.err.println("Error: Unknown option: " + opt); showUsage(); @@ -387,7 +411,8 @@ public class Am { System.err.println("Error: Package manager not running; aborting"); return; } - List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0); + List<ResolveInfo> activities = pm.queryIntentActivities(intent, mimeType, 0, + mUserId); if (activities == null || activities.size() <= 0) { System.err.println("Error: Intent does not match any activities: " + intent); @@ -421,67 +446,65 @@ public class Am { return; } } - + IActivityManager.WaitResult result = null; int res; if (mWaitOption) { result = mAm.startActivityAndWait(null, intent, mimeType, - null, 0, null, null, 0, false, mDebugOption, - mProfileFile, fd, mProfileAutoStop); + null, null, 0, mStartFlags, mProfileFile, fd, null); res = result.result; } else { res = mAm.startActivity(null, intent, mimeType, - null, 0, null, null, 0, false, mDebugOption, - mProfileFile, fd, mProfileAutoStop); + null, null, 0, mStartFlags, mProfileFile, fd, null); } PrintStream out = mWaitOption ? System.out : System.err; boolean launched = false; switch (res) { - case IActivityManager.START_SUCCESS: + case ActivityManager.START_SUCCESS: launched = true; break; - case IActivityManager.START_SWITCHES_CANCELED: + case ActivityManager.START_SWITCHES_CANCELED: launched = true; out.println( "Warning: Activity not started because the " + " current activity is being kept for the user."); break; - case IActivityManager.START_DELIVERED_TO_TOP: + case ActivityManager.START_DELIVERED_TO_TOP: launched = true; out.println( "Warning: Activity not started, intent has " + "been delivered to currently running " + "top-most instance."); break; - case IActivityManager.START_RETURN_INTENT_TO_CALLER: + case ActivityManager.START_RETURN_INTENT_TO_CALLER: launched = true; out.println( "Warning: Activity not started because intent " + "should be handled by the caller"); break; - case IActivityManager.START_TASK_TO_FRONT: + case ActivityManager.START_TASK_TO_FRONT: launched = true; out.println( "Warning: Activity not started, its current " + "task has been brought to the front"); break; - case IActivityManager.START_INTENT_NOT_RESOLVED: + case ActivityManager.START_INTENT_NOT_RESOLVED: out.println( "Error: Activity not started, unable to " + "resolve " + intent.toString()); break; - case IActivityManager.START_CLASS_NOT_FOUND: + case ActivityManager.START_CLASS_NOT_FOUND: out.println(NO_CLASS_ERROR_CODE); out.println("Error: Activity class " + intent.getComponent().toShortString() + " does not exist."); break; - case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: + case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: out.println( "Error: Activity not started, you requested to " + "both forward and receive its result"); break; - case IActivityManager.START_PERMISSION_DENIED: + case ActivityManager.START_PERMISSION_DENIED: out.println( "Error: Activity not started, you do not " + "have permission to access it."); @@ -531,7 +554,8 @@ public class Am { Intent intent = makeIntent(); IntentReceiver receiver = new IntentReceiver(); System.out.println("Broadcasting: " + intent); - mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false); + mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, null, true, false, + mUserId); receiver.waitForFinish(); } @@ -722,6 +746,14 @@ public class Am { mAm.setDebugApp(null, false, true); } + private void runSwitchUser() throws Exception { + if (android.os.Process.myUid() != 0) { + throw new RuntimeException("switchuser can only be run as root"); + } + String user = nextArgRequired(); + mAm.switchUser(Integer.parseInt(user)); + } + class MyActivityController extends IActivityController.Stub { final String mGdbPort; @@ -1249,7 +1281,7 @@ public class Am { System.err.println( "usage: am [subcommand] [options]\n" + "usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" + - " [--R COUNT] [-S] <INTENT>\n" + + " [--R COUNT] [-S] [--opengl-trace] <INTENT>\n" + " am startservice <INTENT>\n" + " am force-stop <PACKAGE>\n" + " am kill <PACKAGE>\n" + @@ -1267,6 +1299,7 @@ public class Am { " am display-size [reset|MxN]\n" + " am to-uri [INTENT]\n" + " am to-intent-uri [INTENT]\n" + + " am switch-user <USER_ID>\n" + "\n" + "am start: start an Activity. Options are:\n" + " -D: enable debugging\n" + @@ -1276,6 +1309,7 @@ public class Am { " -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" + "\n" + "am startservice: start a Service.\n" + "\n" + @@ -1330,9 +1364,11 @@ public class Am { " [--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" + " [--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" + diff --git a/cmds/backup/Android.mk b/cmds/backup/Android.mk index 508aec073570..73af0bc0a6ca 100644 --- a/cmds/backup/Android.mk +++ b/cmds/backup/Android.mk @@ -5,7 +5,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= backup.cpp -LOCAL_SHARED_LIBRARIES := libcutils libutils +LOCAL_SHARED_LIBRARIES := libcutils libutils libandroidfw LOCAL_MODULE:= btool diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp index d4e669b5d9e8..ea1888beea2a 100644 --- a/cmds/backup/backup.cpp +++ b/cmds/backup/backup.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <utils/BackupHelpers.h> +#include <androidfw/BackupHelpers.h> #include <utils/String8.h> #include <fcntl.h> diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk index 7d3991279770..8c46b212814a 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 \ + libandroidfw \ libutils \ libbinder \ libui \ diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 0d5b4caa91b4..0ab6aa38a47f 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -25,12 +25,12 @@ #include <cutils/properties.h> +#include <androidfw/AssetManager.h> #include <binder/IPCThreadState.h> -#include <utils/threads.h> #include <utils/Atomic.h> #include <utils/Errors.h> #include <utils/Log.h> -#include <utils/AssetManager.h> +#include <utils/threads.h> #include <ui/PixelFormat.h> #include <ui/Rect.h> @@ -38,8 +38,8 @@ #include <ui/DisplayInfo.h> #include <ui/FramebufferNativeWindow.h> -#include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/ISurfaceComposerClient.h> +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> #include <core/SkBitmap.h> #include <core/SkStream.h> diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 8e28bba2de3c..62da82f134ba 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -20,11 +20,8 @@ #include <stdint.h> #include <sys/types.h> +#include <androidfw/AssetManager.h> #include <utils/threads.h> -#include <utils/AssetManager.h> - -#include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/SurfaceComposerClient.h> #include <EGL/egl.h> #include <GLES/gl.h> @@ -33,7 +30,9 @@ class SkBitmap; namespace android { -class AssetManager; +class Surface; +class SurfaceComposerClient; +class SurfaceControl; // --------------------------------------------------------------------------- diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp index ff809d369fb3..417e138b7041 100644 --- a/cmds/bootanimation/bootanimation_main.cpp +++ b/cmds/bootanimation/bootanimation_main.cpp @@ -25,8 +25,6 @@ #include <utils/Log.h> #include <utils/threads.h> -#include <surfaceflinger/ISurfaceComposer.h> - #if defined(HAVE_PTHREADS) # include <pthread.h> # include <sys/resource.h> diff --git a/cmds/content/Android.mk b/cmds/content/Android.mk new file mode 100644 index 000000000000..88c46f2792d5 --- /dev/null +++ b/cmds/content/Android.mk @@ -0,0 +1,33 @@ +# Copyright 2012 The Android Open Source Project + +LOCAL_PATH:= $(call my-dir) +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)))) diff --git a/cmds/dumpsys/MODULE_LICENSE_APACHE2 b/cmds/content/MODULE_LICENSE_APACHE2 index e69de29bb2d1..e69de29bb2d1 100644 --- a/cmds/dumpsys/MODULE_LICENSE_APACHE2 +++ b/cmds/content/MODULE_LICENSE_APACHE2 diff --git a/cmds/content/NOTICE b/cmds/content/NOTICE new file mode 100644 index 000000000000..33ff96160b77 --- /dev/null +++ b/cmds/content/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-2012, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/cmds/content/content b/cmds/content/content new file mode 100755 index 000000000000..a8e056d04d69 --- /dev/null +++ b/cmds/content/content @@ -0,0 +1,5 @@ +# Script to start "content" on the device, which has a very rudimentary shell. +base=/system +export CLASSPATH=$base/framework/content.jar +exec app_process $base/bin com.android.commands.content.Content "$@" + diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java new file mode 100644 index 000000000000..bd9eb9a930f9 --- /dev/null +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -0,0 +1,447 @@ +/* +** Copyright 2012, 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.content; + +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.IActivityManager.ContentProviderHolder; +import android.content.ContentValues; +import android.content.IContentProvider; +import android.database.Cursor; +import android.net.Uri; +import android.os.Binder; +import android.os.IBinder; +import android.text.TextUtils; + +/** + * This class is a command line utility for manipulating content. A client + * can insert, update, and remove records in a content provider. For example, + * some settings may be configured before running the CTS tests, etc. + * <p> + * Examples: + * <ul> + * <li> + * # Add "new_setting" secure setting with value "new_value".</br> + * adb shell content insert --uri content://settings/secure --bind name:s:new_setting + * --bind value:s:new_value + * </li> + * <li> + * # Change "new_setting" secure setting to "newer_value" (You have to escape single quotes in + * the where clause).</br> + * adb shell content update --uri content://settings/secure --bind value:s:newer_value + * --where "name=\'new_setting\'" + * </li> + * <li> + * # Remove "new_setting" secure setting.</br> + * adb shell content delete --uri content://settings/secure --where "name=\'new_setting\'" + * </li> + * <li> + * # Query \"name\" and \"value\" columns from secure settings where \"name\" is 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\" + * </li> + * </ul> + * </p> + */ +public class Content { + + private static final String USAGE = + "usage: adb shell content [subcommand] [options]\n" + + "\n" + + "usage: adb shell content insert --uri <URI> --bind <BINDING> [--bind <BINDING>...]\n" + + " <URI> a content provider URI.\n" + + " <BINDING> binds a typed value to a column and is formatted:\n" + + " <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n" + + " <TYPE> specifies data type such as:\n" + + " b - boolean, s - string, i - integer, l - long, f - float, d - double\n" + + " Note: Omit the value for passing an empty string, e.g column:s:\n" + + " Example:\n" + + " # Add \"new_setting\" secure setting with value \"new_value\".\n" + + " adb shell content insert --uri content://settings/secure --bind name:s:new_setting" + + " --bind value:s:new_value\n" + + "\n" + + "usage: adb shell content update --uri <URI> [--where <WHERE>]\n" + + " <WHERE> is a SQL style where clause in quotes (You have to escape single quotes" + + " - see example below).\n" + + " Example:\n" + + " # Change \"new_setting\" secure setting to \"newer_value\".\n" + + " adb shell content update --uri content://settings/secure --bind" + + " value:s:newer_value --where \"name=\'new_setting\'\"\n" + + "\n" + + "usage: adb shell content delete --uri <URI> --bind <BINDING>" + + " [--bind <BINDING>...] [--where <WHERE>]\n" + + " Example:\n" + + " # Remove \"new_setting\" secure setting.\n" + + " adb shell content delete --uri content://settings/secure " + + "--where \"name=\'new_setting\'\"\n" + + "\n" + + "usage: adb shell content query --uri <URI> [--projection <PROJECTION>]" + + " [--where <WHERE>] [--sort <SORT_ORDER>]\n" + + " <PROJECTION> is a list of colon separated column names and is formatted:\n" + + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n" + + " <SORT_OREDER> is the order in which rows in the result should be sorted.\n" + + " Example:\n" + + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is " + + "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"; + + private static class Parser { + private static final String ARGUMENT_INSERT = "insert"; + 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_WHERE = "--where"; + private static final String ARGUMENT_BIND = "--bind"; + private static final String ARGUMENT_URI = "--uri"; + private static final String ARGUMENT_PROJECTION = "--projection"; + private static final String ARGUMENT_SORT = "--sort"; + private static final String TYPE_BOOLEAN = "b"; + private static final String TYPE_STRING = "s"; + private static final String TYPE_INTEGER = "i"; + private static final String TYPE_LONG = "l"; + private static final String TYPE_FLOAT = "f"; + private static final String TYPE_DOUBLE = "d"; + private static final String COLON = ":"; + private static final String ARGUMENT_PREFIX = "--"; + + private final Tokenizer mTokenizer; + + public Parser(String[] args) { + mTokenizer = new Tokenizer(args); + } + + public Command parseCommand() { + try { + String operation = mTokenizer.nextArg(); + if (ARGUMENT_INSERT.equals(operation)) { + return parseInsertCommand(); + } else if (ARGUMENT_DELETE.equals(operation)) { + return parseDeleteCommand(); + } else if (ARGUMENT_UPDATE.equals(operation)) { + return parseUpdateCommand(); + } else if (ARGUMENT_QUERY.equals(operation)) { + return parseQueryCommand(); + } else { + throw new IllegalArgumentException("Unsupported operation: " + operation); + } + } catch (IllegalArgumentException iae) { + System.out.println(USAGE); + System.out.println("[ERROR] " + iae.getMessage()); + return null; + } + } + + private InsertCommand parseInsertCommand() { + 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_BIND.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 (values.size() == 0) { + throw new IllegalArgumentException("Bindings not specified." + + " Did you specify --bind argument(s)?"); + } + return new InsertCommand(uri, values); + } + + private DeleteCommand parseDeleteCommand() { + Uri uri = null; + String where = null; + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + return new DeleteCommand(uri, where); + } + + private UpdateCommand parseUpdateCommand() { + Uri uri = null; + String where = 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_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else if (ARGUMENT_BIND.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 (values.size() == 0) { + throw new IllegalArgumentException("Bindings not specified." + + " Did you specify --bind argument(s)?"); + } + return new UpdateCommand(uri, values, where); + } + + public QueryCommand parseQueryCommand() { + Uri uri = null; + String[] projection = null; + String sort = null; + String where = null; + for (String argument; (argument = mTokenizer.nextArg())!= null;) { + if (ARGUMENT_URI.equals(argument)) { + uri = Uri.parse(argumentValueRequired(argument)); + } else if (ARGUMENT_WHERE.equals(argument)) { + where = argumentValueRequired(argument); + } else if (ARGUMENT_SORT.equals(argument)) { + sort = argumentValueRequired(argument); + } else if (ARGUMENT_PROJECTION.equals(argument)) { + projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*"); + } else { + throw new IllegalArgumentException("Unsupported argument: " + argument); + } + } + if (uri == null) { + throw new IllegalArgumentException("Content provider URI not specified." + + " Did you specify --uri argument?"); + } + return new QueryCommand(uri, projection, where, sort); + } + + private void parseBindValue(ContentValues values) { + String argument = mTokenizer.nextArg(); + if (TextUtils.isEmpty(argument)) { + throw new IllegalArgumentException("Binding not well formed: " + argument); + } + final int firstColonIndex = argument.indexOf(COLON); + if (firstColonIndex < 0) { + throw new IllegalArgumentException("Binding not well formed: " + argument); + } + final int secondColonIndex = argument.indexOf(COLON, firstColonIndex + 1); + if (secondColonIndex < 0) { + throw new IllegalArgumentException("Binding not well formed: " + argument); + } + String column = argument.substring(0, firstColonIndex); + String type = argument.substring(firstColonIndex + 1, secondColonIndex); + String value = argument.substring(secondColonIndex + 1); + if (TYPE_STRING.equals(type)) { + values.put(column, value); + } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) { + values.put(column, Boolean.parseBoolean(value)); + } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) { + values.put(column, Long.parseLong(value)); + } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) { + values.put(column, Double.parseDouble(value)); + } else { + throw new IllegalArgumentException("Unsupported type: " + type); + } + } + + private String argumentValueRequired(String argument) { + String value = mTokenizer.nextArg(); + if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) { + throw new IllegalArgumentException("No value for argument: " + argument); + } + return value; + } + } + + private static class Tokenizer { + private final String[] mArgs; + private int mNextArg; + + public Tokenizer(String[] args) { + mArgs = args; + } + + private String nextArg() { + if (mNextArg < mArgs.length) { + return mArgs[mNextArg++]; + } else { + return null; + } + } + } + + private static abstract class Command { + final Uri mUri; + + public Command(Uri uri) { + mUri = uri; + } + + public final void execute() { + String providerName = mUri.getAuthority(); + try { + IActivityManager activityManager = ActivityManagerNative.getDefault(); + IContentProvider provider = null; + IBinder token = new Binder(); + try { + ContentProviderHolder holder = activityManager.getContentProviderExternal( + providerName, token); + if (holder == null) { + throw new IllegalStateException("Could not find provider: " + providerName); + } + provider = holder.provider; + onExecute(provider); + } finally { + if (provider != null) { + activityManager.removeContentProviderExternal(providerName, token); + } + } + } catch (Exception e) { + System.err.println("Error while accessing provider:" + providerName); + e.printStackTrace(); + } + } + + protected abstract void onExecute(IContentProvider provider) throws Exception; + } + + private static class InsertCommand extends Command { + final ContentValues mContentValues; + + public InsertCommand(Uri uri, ContentValues contentValues) { + super(uri); + mContentValues = contentValues; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.insert(mUri, mContentValues); + } + } + + private static class DeleteCommand extends Command { + final String mWhere; + + public DeleteCommand(Uri uri, String where) { + super(uri); + mWhere = where; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.delete(mUri, mWhere, null); + } + } + + private static class QueryCommand extends DeleteCommand { + final String[] mProjection; + final String mSortOrder; + + public QueryCommand(Uri uri, String[] projection, String where, String sortOrder) { + super(uri, where); + mProjection = projection; + mSortOrder = sortOrder; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null); + if (cursor == null) { + System.out.println("No result found."); + return; + } + try { + if (cursor.moveToFirst()) { + int rowIndex = 0; + StringBuilder builder = new StringBuilder(); + do { + builder.setLength(0); + builder.append("Row: ").append(rowIndex).append(" "); + rowIndex++; + final int columnCount = cursor.getColumnCount(); + for (int i = 0; i < columnCount; i++) { + if (i > 0) { + builder.append(", "); + } + String columnName = cursor.getColumnName(i); + String columnValue = null; + final int columnIndex = cursor.getColumnIndex(columnName); + final int type = cursor.getType(columnIndex); + switch (type) { + case Cursor.FIELD_TYPE_FLOAT: + columnValue = String.valueOf(cursor.getFloat(columnIndex)); + break; + case Cursor.FIELD_TYPE_INTEGER: + columnValue = String.valueOf(cursor.getInt(columnIndex)); + break; + case Cursor.FIELD_TYPE_STRING: + columnValue = cursor.getString(columnIndex); + break; + case Cursor.FIELD_TYPE_BLOB: + columnValue = "BLOB"; + break; + case Cursor.FIELD_TYPE_NULL: + columnValue = "NULL"; + break; + } + builder.append(columnName).append("=").append(columnValue); + } + System.out.println(builder); + } while (cursor.moveToNext()); + } else { + System.out.println("No reuslt found."); + } + } finally { + cursor.close(); + } + } + } + + private static class UpdateCommand extends InsertCommand { + final String mWhere; + + public UpdateCommand(Uri uri, ContentValues contentValues, String where) { + super(uri, contentValues); + mWhere = where; + } + + @Override + public void onExecute(IContentProvider provider) throws Exception { + provider.update(mUri, mContentValues, mWhere, null); + } + } + + public static void main(String[] args) { + Parser parser = new Parser(args); + Command command = parser.parseCommand(); + if (command != null) { + command.execute(); + } + } +} diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk deleted file mode 100644 index d6025006bff8..000000000000 --- a/cmds/dumpstate/Android.mk +++ /dev/null @@ -1,19 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -ifdef BOARD_WLAN_DEVICE -LOCAL_CFLAGS := -DFWDUMP_$(BOARD_WLAN_DEVICE) -endif - -LOCAL_SRC_FILES := dumpstate.c utils.c - -LOCAL_MODULE := dumpstate - -LOCAL_SHARED_LIBRARIES := libcutils - -ifdef BOARD_LIB_DUMPSTATE -LOCAL_STATIC_LIBRARIES := $(BOARD_LIB_DUMPSTATE) -LOCAL_CFLAGS += -DBOARD_HAS_DUMPSTATE -endif - -include $(BUILD_EXECUTABLE) diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c deleted file mode 100644 index 3613101e6768..000000000000 --- a/cmds/dumpstate/dumpstate.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (C) 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 <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/resource.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <cutils/properties.h> - -#include "private/android_filesystem_config.h" - -#define LOG_TAG "dumpstate" -#include <utils/Log.h> - -#include "dumpstate.h" - -/* read before root is shed */ -static char cmdline_buf[16384] = "(unknown)"; -static const char *dump_traces_path = NULL; - -static char screenshot_path[PATH_MAX] = ""; - -/* dumps the current system state to stdout */ -static void dumpstate() { - time_t now = time(NULL); - char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX]; - char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX]; - char network[PROPERTY_VALUE_MAX], date[80]; - char build_type[PROPERTY_VALUE_MAX]; - - property_get("ro.build.display.id", build, "(unknown)"); - property_get("ro.build.fingerprint", fingerprint, "(unknown)"); - property_get("ro.build.type", build_type, "(unknown)"); - property_get("ro.baseband", radio, "(unknown)"); - property_get("ro.bootloader", bootloader, "(unknown)"); - property_get("gsm.operator.alpha", network, "(unknown)"); - strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now)); - - printf("========================================================\n"); - printf("== dumpstate: %s\n", date); - printf("========================================================\n"); - - printf("\n"); - printf("Build: %s\n", build); - printf("Bootloader: %s\n", bootloader); - printf("Radio: %s\n", radio); - printf("Network: %s\n", network); - - printf("Kernel: "); - dump_file(NULL, "/proc/version"); - printf("Command line: %s\n", strtok(cmdline_buf, "\n")); - printf("\n"); - - run_command("UPTIME", 10, "uptime", NULL); - dump_file("MEMORY INFO", "/proc/meminfo"); - run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL); - run_command("PROCRANK", 20, "procrank", NULL); - dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat"); - dump_file("VMALLOC INFO", "/proc/vmallocinfo"); - dump_file("SLAB INFO", "/proc/slabinfo"); - dump_file("ZONEINFO", "/proc/zoneinfo"); - dump_file("PAGETYPEINFO", "/proc/pagetypeinfo"); - dump_file("BUDDYINFO", "/proc/buddyinfo"); - - if (screenshot_path[0]) { - ALOGI("taking screenshot\n"); - run_command(NULL, 5, "su", "root", "screenshot", screenshot_path, NULL); - ALOGI("wrote screenshot: %s\n", screenshot_path); - } - - run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL); - - /* show the traces we collected in main(), if that was done */ - if (dump_traces_path != NULL) { - dump_file("VM TRACES JUST NOW", dump_traces_path); - } - - /* only show ANR traces if they're less than 15 minutes old */ - struct stat st; - char anr_traces_path[PATH_MAX]; - property_get("dalvik.vm.stack-trace-file", anr_traces_path, ""); - if (!anr_traces_path[0]) { - printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n"); - } else if (stat(anr_traces_path, &st)) { - printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno)); - } else { - dump_file("VM TRACES AT LAST ANR", anr_traces_path); - } - - /* slow traces for slow operations */ - if (anr_traces_path[0] != 0) { - int tail = strlen(anr_traces_path)-1; - while (tail > 0 && anr_traces_path[tail] != '/') { - tail--; - } - int i = 0; - while (1) { - sprintf(anr_traces_path+tail+1, "slow%02d.txt", i); - if (stat(anr_traces_path, &st)) { - // No traces file at this index, done with the files. - break; - } - dump_file("VM TRACES WHEN SLOW", anr_traces_path); - i++; - } - } - - // dump_file("EVENT LOG TAGS", "/etc/event-log-tags"); - run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL); - run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL); - - run_command("NETWORK INTERFACES", 10, "su", "root", "netcfg", NULL); - dump_file("NETWORK DEV INFO", "/proc/net/dev"); - dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all"); - dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl"); - run_command("QTAGUID STATS INFO", 10, "su", "root", "cat", "/proc/net/xt_qtaguid/stats", NULL); - - dump_file("NETWORK ROUTES", "/proc/net/route"); - dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route"); - run_command("IP RULES", 10, "ip", "rule", "show", NULL); - run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL); - run_command("ROUTE TABLE 60", 10, "ip", "route", "show", "table", "60", NULL); - run_command("ROUTE TABLE 61 v6", 10, "ip", "-6", "route", "show", "table", "60", NULL); - run_command("ROUTE TABLE 61", 10, "ip", "route", "show", "table", "61", NULL); - run_command("ROUTE TABLE 61 v6", 10, "ip", "-6", "route", "show", "table", "61", NULL); - dump_file("ARP CACHE", "/proc/net/arp"); - run_command("IPTABLES", 10, "su", "root", "iptables", "-L", "-nvx", NULL); - run_command("IP6TABLES", 10, "su", "root", "ip6tables", "-L", "-nvx", NULL); - run_command("IPTABLE NAT", 10, "su", "root", "iptables", "-t", "nat", "-L", "-n", NULL); - run_command("IPT6ABLE NAT", 10, "su", "root", "ip6tables", "-t", "nat", "-L", "-n", NULL); - - run_command("WIFI NETWORKS", 20, - "su", "root", "wpa_cli", "list_networks", NULL); - - property_get("dhcp.wlan0.gateway", network, ""); - if (network[0]) - run_command("PING GATEWAY", 10, "su", "root", "ping", "-c", "3", "-i", ".5", network, NULL); - property_get("dhcp.wlan0.dns1", network, ""); - if (network[0]) - run_command("PING DNS1", 10, "su", "root", "ping", "-c", "3", "-i", ".5", network, NULL); - property_get("dhcp.wlan0.dns2", network, ""); - if (network[0]) - run_command("PING DNS2", 10, "su", "root", "ping", "-c", "3", "-i", ".5", network, NULL); -#ifdef FWDUMP_bcm4329 - run_command("DUMP WIFI STATUS", 20, - "su", "root", "dhdutil", "-i", "wlan0", "dump", NULL); - run_command("DUMP WIFI INTERNAL COUNTERS", 20, - "su", "root", "wlutil", "counters", NULL); -#endif - - char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0}; - property_get("ril.dumpstate.timeout", ril_dumpstate_timeout, "30"); - if (strnlen(ril_dumpstate_timeout, PROPERTY_VALUE_MAX - 1) > 0) { - if (0 == strncmp(build_type, "user", PROPERTY_VALUE_MAX - 1)) { - // su does not exist on user builds, so try running without it. - // This way any implementations of vril-dump that do not require - // root can run on user builds. - run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout), - "vril-dump", NULL); - } else { - run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout), - "su", "root", "vril-dump", NULL); - } - } - - print_properties(); - - run_command("KERNEL LOG", 20, "dmesg", NULL); - - dump_file("KERNEL WAKELOCKS", "/proc/wakelocks"); - dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state"); - - run_command("VOLD DUMP", 10, "vdc", "dump", NULL); - run_command("SECURE CONTAINERS", 10, "vdc", "asec", "list", NULL); - - run_command("PROCESSES", 10, "ps", "-P", NULL); - run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL); - run_command("LIBRANK", 10, "librank", NULL); - - dump_file("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log"); - dump_file("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log"); - dump_file("BINDER TRANSACTIONS", "/sys/kernel/debug/binder/transactions"); - dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats"); - dump_file("BINDER STATE", "/sys/kernel/debug/binder/state"); - - run_command("FILESYSTEMS & FREE SPACE", 10, "su", "root", "df", NULL); - - dump_file("PACKAGE SETTINGS", "/data/system/packages.xml"); - dump_file("PACKAGE UID ERRORS", "/data/system/uiderrors.txt"); - - dump_file("LAST KMSG", "/proc/last_kmsg"); - run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL); - dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console"); - dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads"); - - for_each_pid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS"); - - printf("------ BACKLIGHTS ------\n"); - printf("LCD brightness="); - dump_file(NULL, "/sys/class/leds/lcd-backlight/brightness"); - printf("Button brightness="); - dump_file(NULL, "/sys/class/leds/button-backlight/brightness"); - printf("Keyboard brightness="); - dump_file(NULL, "/sys/class/leds/keyboard-backlight/brightness"); - printf("ALS mode="); - dump_file(NULL, "/sys/class/leds/lcd-backlight/als"); - printf("LCD driver registers:\n"); - dump_file(NULL, "/sys/class/leds/lcd-backlight/registers"); - printf("\n"); - - run_command("LIST OF OPEN FILES", 10, "su", "root", "lsof", NULL); - - for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES"); - -#ifdef BOARD_HAS_DUMPSTATE - printf("========================================================\n"); - printf("== Board\n"); - printf("========================================================\n"); - - dumpstate_board(); - printf("\n"); -#endif - - printf("========================================================\n"); - printf("== Android Framework Services\n"); - printf("========================================================\n"); - - /* the full dumpsys is starting to take a long time, so we need - to increase its timeout. we really need to do the timeouts in - dumpsys itself... */ - run_command("DUMPSYS", 60, "dumpsys", NULL); - - printf("========================================================\n"); - printf("== Running Application Activities\n"); - printf("========================================================\n"); - - run_command("APP ACTIVITIES", 30, "dumpsys", "activity", "all", NULL); - - printf("========================================================\n"); - printf("== Running Application Services\n"); - printf("========================================================\n"); - - run_command("APP SERVICES", 30, "dumpsys", "activity", "service", "all", NULL); - - printf("========================================================\n"); - printf("== dumpstate: done\n"); - printf("========================================================\n"); -} - -static void usage() { - fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s]\n" - " -o: write to file (instead of stdout)\n" - " -d: append date to filename (requires -o)\n" - " -z: gzip output (requires -o)\n" - " -p: capture screenshot to filename.png (requires -o)\n" - " -s: write output to control socket (for init)\n" - " -b: play sound file instead of vibrate, at beginning of job\n" - " -e: play sound file instead of vibrate, at end of job\n" - ); -} - -int main(int argc, char *argv[]) { - int do_add_date = 0; - int do_compress = 0; - char* use_outfile = 0; - char* begin_sound = 0; - char* end_sound = 0; - int use_socket = 0; - int do_fb = 0; - - ALOGI("begin\n"); - - /* set as high priority, and protect from OOM killer */ - setpriority(PRIO_PROCESS, 0, -20); - FILE *oom_adj = fopen("/proc/self/oom_adj", "w"); - if (oom_adj) { - fputs("-17", oom_adj); - fclose(oom_adj); - } - - /* very first thing, collect VM traces from Dalvik (needs root) */ - dump_traces_path = dump_vm_traces(); - - int c; - while ((c = getopt(argc, argv, "b:de:ho:svzp")) != -1) { - switch (c) { - case 'b': begin_sound = optarg; break; - case 'd': do_add_date = 1; break; - case 'e': end_sound = optarg; break; - case 'o': use_outfile = optarg; break; - case 's': use_socket = 1; break; - case 'v': break; // compatibility no-op - case 'z': do_compress = 6; break; - case 'p': do_fb = 1; break; - case '?': printf("\n"); - case 'h': - usage(); - exit(1); - } - } - - /* open the vibrator before dropping root */ - FILE *vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w"); - if (vibrator) fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC); - - /* read /proc/cmdline before dropping root */ - FILE *cmdline = fopen("/proc/cmdline", "r"); - if (cmdline != NULL) { - fgets(cmdline_buf, sizeof(cmdline_buf), cmdline); - fclose(cmdline); - } - - if (getuid() == 0) { - /* switch to non-root user and group */ - gid_t groups[] = { AID_LOG, AID_SDCARD_RW, AID_MOUNT, AID_INET }; - if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) != 0) { - ALOGE("Unable to setgroups, aborting: %s\n", strerror(errno)); - return -1; - } - if (setgid(AID_SHELL) != 0) { - ALOGE("Unable to setgid, aborting: %s\n", strerror(errno)); - return -1; - } - if (setuid(AID_SHELL) != 0) { - ALOGE("Unable to setuid, aborting: %s\n", strerror(errno)); - return -1; - } - } - - char path[PATH_MAX], tmp_path[PATH_MAX]; - pid_t gzip_pid = -1; - - if (use_socket) { - redirect_to_socket(stdout, "dumpstate"); - } else if (use_outfile) { - strlcpy(path, use_outfile, sizeof(path)); - if (do_add_date) { - char date[80]; - time_t now = time(NULL); - strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now)); - strlcat(path, date, sizeof(path)); - } - if (do_fb) { - strlcpy(screenshot_path, path, sizeof(screenshot_path)); - strlcat(screenshot_path, ".png", sizeof(screenshot_path)); - } - strlcat(path, ".txt", sizeof(path)); - if (do_compress) strlcat(path, ".gz", sizeof(path)); - strlcpy(tmp_path, path, sizeof(tmp_path)); - strlcat(tmp_path, ".tmp", sizeof(tmp_path)); - gzip_pid = redirect_to_file(stdout, tmp_path, do_compress); - } - - if (begin_sound) { - play_sound(begin_sound); - } else if (vibrator) { - fputs("150", vibrator); - fflush(vibrator); - } - - dumpstate(); - - if (end_sound) { - play_sound(end_sound); - } else if (vibrator) { - int i; - for (i = 0; i < 3; i++) { - fputs("75\n", vibrator); - fflush(vibrator); - usleep((75 + 50) * 1000); - } - fclose(vibrator); - } - - /* wait for gzip to finish, otherwise it might get killed when we exit */ - if (gzip_pid > 0) { - fclose(stdout); - waitpid(gzip_pid, NULL, 0); - } - - /* rename the (now complete) .tmp file to its final location */ - if (use_outfile && rename(tmp_path, path)) { - fprintf(stderr, "rename(%s, %s): %s\n", tmp_path, path, strerror(errno)); - } - - ALOGI("done\n"); - - return 0; -} diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h deleted file mode 100644 index 6d66b1ba6676..000000000000 --- a/cmds/dumpstate/dumpstate.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 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. - */ - -#ifndef _DUMPSTATE_H_ -#define _DUMPSTATE_H_ - -#include <time.h> -#include <unistd.h> -#include <stdio.h> - -/* prints the contents of a file */ -int dump_file(const char *title, const char* path); - -/* forks a command and waits for it to finish -- terminate args with NULL */ -int run_command(const char *title, int timeout_seconds, const char *command, ...); - -/* prints all the system properties */ -void print_properties(); - -/* redirect output to a service control socket */ -void redirect_to_socket(FILE *redirect, const char *service); - -/* redirect output to a file, optionally gzipping; returns gzip pid */ -pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level); - -/* dump Dalvik stack traces, return the trace file location (NULL if none) */ -const char *dump_vm_traces(); - -/* for each process in the system, run the specified function */ -void for_each_pid(void (*func)(int, const char *), const char *header); - -/* Displays a blocked processes in-kernel wait channel */ -void show_wchan(int pid, const char *name); - -/* Runs "showmap" for a process */ -void do_showmap(int pid, const char *name); - -/* Play a sound via Stagefright */ -void play_sound(const char* path); - -/* Implemented by libdumpstate_board to dump board-specific info */ -void dumpstate_board(); - -#endif /* _DUMPSTATE_H_ */ diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c deleted file mode 100644 index 14984ecf40a9..000000000000 --- a/cmds/dumpstate/utils.c +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright (C) 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 <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <poll.h> -#include <signal.h> -#include <stdarg.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/inotify.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <sys/wait.h> -#include <time.h> -#include <unistd.h> - -#include <cutils/properties.h> -#include <cutils/sockets.h> -#include <private/android_filesystem_config.h> - -#include "dumpstate.h" - -void for_each_pid(void (*func)(int, const char *), const char *header) { - DIR *d; - struct dirent *de; - - if (!(d = opendir("/proc"))) { - printf("Failed to open /proc (%s)\n", strerror(errno)); - return; - } - - printf("\n------ %s ------\n", header); - while ((de = readdir(d))) { - int pid; - int fd; - char cmdpath[255]; - char cmdline[255]; - - if (!(pid = atoi(de->d_name))) { - continue; - } - - sprintf(cmdpath,"/proc/%d/cmdline", pid); - memset(cmdline, 0, sizeof(cmdline)); - if ((fd = open(cmdpath, O_RDONLY)) < 0) { - strcpy(cmdline, "N/A"); - } else { - read(fd, cmdline, sizeof(cmdline)); - close(fd); - } - func(pid, cmdline); - } - - closedir(d); -} - -void show_wchan(int pid, const char *name) { - char path[255]; - char buffer[255]; - int fd; - - memset(buffer, 0, sizeof(buffer)); - - sprintf(path, "/proc/%d/wchan", pid); - if ((fd = open(path, O_RDONLY)) < 0) { - printf("Failed to open '%s' (%s)\n", path, strerror(errno)); - return; - } - - if (read(fd, buffer, sizeof(buffer)) < 0) { - printf("Failed to read '%s' (%s)\n", path, strerror(errno)); - goto out_close; - } - - printf("%-7d %-32s %s\n", pid, name, buffer); - -out_close: - close(fd); - return; -} - -void do_showmap(int pid, const char *name) { - char title[255]; - char arg[255]; - - sprintf(title, "SHOW MAP %d (%s)", pid, name); - sprintf(arg, "%d", pid); - run_command(title, 10, "su", "root", "showmap", arg, NULL); -} - -/* prints the contents of a file */ -int dump_file(const char *title, const char* path) { - char buffer[32768]; - int fd = open(path, O_RDONLY); - if (fd < 0) { - int err = errno; - if (title) printf("------ %s (%s) ------\n", title, path); - printf("*** %s: %s\n", path, strerror(err)); - if (title) printf("\n"); - return -1; - } - - if (title) printf("------ %s (%s", title, path); - - if (title) { - struct stat st; - if (memcmp(path, "/proc/", 6) && memcmp(path, "/sys/", 5) && !fstat(fd, &st)) { - char stamp[80]; - time_t mtime = st.st_mtime; - strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime)); - printf(": %s", stamp); - } - printf(") ------\n"); - } - - int newline = 0; - for (;;) { - int ret = read(fd, buffer, sizeof(buffer)); - if (ret > 0) { - newline = (buffer[ret - 1] == '\n'); - ret = fwrite(buffer, ret, 1, stdout); - } - if (ret <= 0) break; - } - - close(fd); - if (!newline) printf("\n"); - if (title) printf("\n"); - return 0; -} - -/* forks a command and waits for it to finish */ -int run_command(const char *title, int timeout_seconds, const char *command, ...) { - fflush(stdout); - clock_t start = clock(); - pid_t pid = fork(); - - /* handle error case */ - if (pid < 0) { - printf("*** fork: %s\n", strerror(errno)); - return pid; - } - - /* handle child case */ - if (pid == 0) { - const char *args[1024] = {command}; - size_t arg; - - va_list ap; - va_start(ap, command); - if (title) printf("------ %s (%s", title, command); - for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) { - args[arg] = va_arg(ap, const char *); - if (args[arg] == NULL) break; - if (title) printf(" %s", args[arg]); - } - if (title) printf(") ------\n"); - fflush(stdout); - - execvp(command, (char**) args); - printf("*** exec(%s): %s\n", command, strerror(errno)); - fflush(stdout); - _exit(-1); - } - - /* handle parent case */ - for (;;) { - int status; - pid_t p = waitpid(pid, &status, WNOHANG); - float elapsed = (float) (clock() - start) / CLOCKS_PER_SEC; - if (p == pid) { - if (WIFSIGNALED(status)) { - printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status)); - } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) { - printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status)); - } - if (title) printf("[%s: %.1fs elapsed]\n\n", command, elapsed); - return status; - } - - if (timeout_seconds && elapsed > timeout_seconds) { - printf("*** %s: Timed out after %.1fs (killing pid %d)\n", command, elapsed, pid); - kill(pid, SIGTERM); - return -1; - } - - usleep(100000); // poll every 0.1 sec - } -} - -size_t num_props = 0; -static char* props[2000]; - -static void print_prop(const char *key, const char *name, void *user) { - (void) user; - if (num_props < sizeof(props) / sizeof(props[0])) { - char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10]; - snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name); - props[num_props++] = strdup(buf); - } -} - -static int compare_prop(const void *a, const void *b) { - return strcmp(*(char * const *) a, *(char * const *) b); -} - -/* prints all the system properties */ -void print_properties() { - size_t i; - num_props = 0; - property_list(print_prop, NULL); - qsort(&props, num_props, sizeof(props[0]), compare_prop); - - printf("------ SYSTEM PROPERTIES ------\n"); - for (i = 0; i < num_props; ++i) { - fputs(props[i], stdout); - free(props[i]); - } - printf("\n"); -} - -/* redirect output to a service control socket */ -void redirect_to_socket(FILE *redirect, const char *service) { - int s = android_get_control_socket(service); - if (s < 0) { - fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno)); - exit(1); - } - if (listen(s, 4) < 0) { - fprintf(stderr, "listen(control socket): %s\n", strerror(errno)); - exit(1); - } - - struct sockaddr addr; - socklen_t alen = sizeof(addr); - int fd = accept(s, &addr, &alen); - if (fd < 0) { - fprintf(stderr, "accept(control socket): %s\n", strerror(errno)); - exit(1); - } - - fflush(redirect); - dup2(fd, fileno(redirect)); - close(fd); -} - -/* redirect output to a file, optionally gzipping; returns gzip pid (or -1) */ -pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) { - char *chp = path; - - /* skip initial slash */ - if (chp[0] == '/') - chp++; - - /* create leading directories, if necessary */ - while (chp && chp[0]) { - chp = strchr(chp, '/'); - if (chp) { - *chp = 0; - mkdir(path, 0775); /* drwxrwxr-x */ - *chp++ = '/'; - } - } - - int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); - if (fd < 0) { - fprintf(stderr, "%s: %s\n", path, strerror(errno)); - exit(1); - } - - pid_t gzip_pid = -1; - if (gzip_level > 0) { - int fds[2]; - if (pipe(fds)) { - fprintf(stderr, "pipe: %s\n", strerror(errno)); - exit(1); - } - - fflush(redirect); - fflush(stdout); - - gzip_pid = fork(); - if (gzip_pid < 0) { - fprintf(stderr, "fork: %s\n", strerror(errno)); - exit(1); - } - - if (gzip_pid == 0) { - dup2(fds[0], STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - - close(fd); - close(fds[0]); - close(fds[1]); - - char level[10]; - snprintf(level, sizeof(level), "-%d", gzip_level); - execlp("gzip", "gzip", level, NULL); - fprintf(stderr, "exec(gzip): %s\n", strerror(errno)); - _exit(-1); - } - - close(fd); - close(fds[0]); - fd = fds[1]; - } - - dup2(fd, fileno(redirect)); - close(fd); - return gzip_pid; -} - -/* dump Dalvik stack traces, return the trace file location (NULL if none) */ -const char *dump_vm_traces() { - char traces_path[PROPERTY_VALUE_MAX] = ""; - property_get("dalvik.vm.stack-trace-file", traces_path, ""); - if (!traces_path[0]) return NULL; - - /* move the old traces.txt (if any) out of the way temporarily */ - char anr_traces_path[PATH_MAX]; - strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path)); - strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path)); - if (rename(traces_path, anr_traces_path) && errno != ENOENT) { - fprintf(stderr, "rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno)); - return NULL; // Can't rename old traces.txt -- no permission? -- leave it alone instead - } - - /* make the directory if necessary */ - char anr_traces_dir[PATH_MAX]; - strlcpy(anr_traces_dir, traces_path, sizeof(anr_traces_dir)); - char *slash = strrchr(anr_traces_dir, '/'); - if (slash != NULL) { - *slash = '\0'; - if (!mkdir(anr_traces_dir, 0775)) { - chown(anr_traces_dir, AID_SYSTEM, AID_SYSTEM); - } else if (errno != EEXIST) { - fprintf(stderr, "mkdir(%s): %s\n", anr_traces_dir, strerror(errno)); - return NULL; - } - } - - /* create a new, empty traces.txt file to receive stack dumps */ - int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC, 0666); /* -rw-rw-rw- */ - if (fd < 0) { - fprintf(stderr, "%s: %s\n", traces_path, strerror(errno)); - return NULL; - } - close(fd); - - /* walk /proc and kill -QUIT all Dalvik processes */ - DIR *proc = opendir("/proc"); - if (proc == NULL) { - fprintf(stderr, "/proc: %s\n", strerror(errno)); - return NULL; - } - - /* use inotify to find when processes are done dumping */ - int ifd = inotify_init(); - if (ifd < 0) { - fprintf(stderr, "inotify_init: %s\n", strerror(errno)); - return NULL; - } - - int wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE); - if (wfd < 0) { - fprintf(stderr, "inotify_add_watch(%s): %s\n", traces_path, strerror(errno)); - return NULL; - } - - struct dirent *d; - int dalvik_found = 0; - while ((d = readdir(proc))) { - int pid = atoi(d->d_name); - if (pid <= 0) continue; - - /* identify Dalvik: /proc/(pid)/exe = /system/bin/app_process */ - char path[PATH_MAX], data[PATH_MAX]; - snprintf(path, sizeof(path), "/proc/%d/exe", pid); - size_t len = readlink(path, data, sizeof(data) - 1); - if (len <= 0 || memcmp(data, "/system/bin/app_process", 23)) continue; - - /* skip zygote -- it won't dump its stack anyway */ - snprintf(path, sizeof(path), "/proc/%d/cmdline", pid); - int fd = open(path, O_RDONLY); - len = read(fd, data, sizeof(data) - 1); - close(fd); - if (len <= 0 || !memcmp(data, "zygote", 6)) continue; - - ++dalvik_found; - if (kill(pid, SIGQUIT)) { - fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno)); - continue; - } - - /* wait for the writable-close notification from inotify */ - struct pollfd pfd = { ifd, POLLIN, 0 }; - int ret = poll(&pfd, 1, 200); /* 200 msec timeout */ - if (ret < 0) { - fprintf(stderr, "poll: %s\n", strerror(errno)); - } else if (ret == 0) { - fprintf(stderr, "warning: timed out dumping pid %d\n", pid); - } else { - struct inotify_event ie; - read(ifd, &ie, sizeof(ie)); - } - } - - close(ifd); - if (dalvik_found == 0) { - fprintf(stderr, "Warning: no Dalvik processes found to dump stacks\n"); - } - - static char dump_traces_path[PATH_MAX]; - strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path)); - strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path)); - if (rename(traces_path, dump_traces_path)) { - fprintf(stderr, "rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno)); - return NULL; - } - - /* replace the saved [ANR] traces.txt file */ - rename(anr_traces_path, traces_path); - return dump_traces_path; -} - -void play_sound(const char* path) { - run_command(NULL, 5, "/system/bin/stagefright", "-o", "-a", path, NULL); -} diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk deleted file mode 100644 index 42b1b7365b1b..000000000000 --- a/cmds/dumpsys/Android.mk +++ /dev/null @@ -1,19 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - dumpsys.cpp - -LOCAL_SHARED_LIBRARIES := \ - libutils \ - libbinder - - -ifeq ($(TARGET_OS),linux) - LOCAL_CFLAGS += -DXP_UNIX - #LOCAL_SHARED_LIBRARIES += librt -endif - -LOCAL_MODULE:= dumpsys - -include $(BUILD_EXECUTABLE) diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp deleted file mode 100644 index 7dad6b625b6a..000000000000 --- a/cmds/dumpsys/dumpsys.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Command that dumps interesting system state to the log. - * - */ - -#define LOG_TAG "dumpsys" - -#include <utils/Log.h> -#include <binder/Parcel.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> -#include <utils/TextOutput.h> -#include <utils/Vector.h> - -#include <getopt.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <sys/time.h> - -using namespace android; - -static int sort_func(const String16* lhs, const String16* rhs) -{ - return lhs->compare(*rhs); -} - -int main(int argc, char* const argv[]) -{ - sp<IServiceManager> sm = defaultServiceManager(); - fflush(stdout); - if (sm == NULL) { - ALOGE("Unable to get default service manager!"); - aerr << "dumpsys: Unable to get default service manager!" << endl; - return 20; - } - - Vector<String16> services; - Vector<String16> args; - if (argc == 1) { - services = sm->listServices(); - services.sort(sort_func); - args.add(String16("-a")); - } else { - services.add(String16(argv[1])); - for (int i=2; i<argc; i++) { - args.add(String16(argv[i])); - } - } - - const size_t N = services.size(); - - if (N > 1) { - // first print a list of the current services - aout << "Currently running services:" << endl; - - for (size_t i=0; i<N; i++) { - sp<IBinder> service = sm->checkService(services[i]); - if (service != NULL) { - aout << " " << services[i] << endl; - } - } - } - - for (size_t i=0; i<N; i++) { - sp<IBinder> service = sm->checkService(services[i]); - if (service != NULL) { - if (N > 1) { - aout << "------------------------------------------------------------" - "-------------------" << endl; - aout << "DUMP OF SERVICE " << services[i] << ":" << endl; - } - int err = service->dump(STDOUT_FILENO, args); - if (err != 0) { - aerr << "Error dumping service info: (" << strerror(err) - << ") " << services[i] << endl; - } - } else { - aerr << "Can't find service: " << services[i] << endl; - } - } - - return 0; -} diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java index df1d0bf98a62..c4c3b8a9bcac 100755 --- a/cmds/input/src/com/android/commands/input/Input.java +++ b/cmds/input/src/com/android/commands/input/Input.java @@ -23,6 +23,7 @@ import android.util.Log; import android.view.IWindowManager; import android.view.KeyCharacterMap; import android.view.KeyEvent; +import android.view.MotionEvent; /** * Command that sends key events to the device, either by their keycode, or by @@ -30,6 +31,9 @@ import android.view.KeyEvent; */ public class Input { + private static final String TAG = "Input"; + + private IWindowManager mWindowManager; /** * Command-line entry point. @@ -40,6 +44,13 @@ public class Input { (new Input()).run(args); } + private IWindowManager getWindowManager() { + if (mWindowManager == null) { + mWindowManager = (IWindowManager.Stub.asInterface(ServiceManager.getService("window"))); + } + return mWindowManager; + } + private void run(String[] args) { if (args.length < 1) { showUsage(); @@ -48,19 +59,37 @@ public class Input { String command = args[0]; - if (command.equals("text")) { - sendText(args[1]); - } else if (command.equals("keyevent")) { - sendKeyEvent(args[1]); - } else if (command.equals("motionevent")) { - System.err.println("Error: motionevent not yet supported."); - return; - } - else { - System.err.println("Error: Unknown command: " + command); - showUsage(); - return; + try { + if (command.equals("text")) { + if (args.length == 2) { + sendText(args[1]); + return; + } + } else if (command.equals("keyevent")) { + if (args.length == 2) { + sendKeyEvent(Integer.parseInt(args[1])); + return; + } + } else if (command.equals("tap")) { + if (args.length == 3) { + sendTap(Float.parseFloat(args[1]), Float.parseFloat(args[2])); + return; + } + } else if (command.equals("swipe")) { + if (args.length == 5) { + sendSwipe(Float.parseFloat(args[1]), Float.parseFloat(args[2]), + Float.parseFloat(args[3]), Float.parseFloat(args[4])); + return; + } + } else { + System.err.println("Error: Unknown command: " + command); + showUsage(); + return; + } + } catch (NumberFormatException ex) { } + System.err.println("Error: Invalid arguments for command: " + command); + showUsage(); } /** @@ -69,7 +98,6 @@ public class Input { * * @param text is a string of characters you want to input to the device. */ - private void sendText(String text) { StringBuffer buff = new StringBuffer(text); @@ -90,55 +118,66 @@ public class Input { char[] chars = buff.toString().toCharArray(); - KeyCharacterMap mKeyCharacterMap = KeyCharacterMap. - load(KeyCharacterMap.VIRTUAL_KEYBOARD); - - KeyEvent[] events = mKeyCharacterMap.getEvents(chars); - + KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); + KeyEvent[] events = kcm.getEvents(chars); for(int i = 0; i < events.length; i++) { - KeyEvent event = events[i]; - Log.i("SendKeyEvent", Integer.toString(event.getKeyCode())); - try { - (IWindowManager.Stub - .asInterface(ServiceManager.getService("window"))) - .injectKeyEvent(event, true); - } catch (RemoteException e) { - Log.i("Input", "DeadOjbectException"); - } + injectKeyEvent(events[i]); } } - /** - * Send a single key event. - * - * @param event is a string representing the keycode of the key event you - * want to execute. - */ - private void sendKeyEvent(String event) { - int eventCode = Integer.parseInt(event); + private void sendKeyEvent(int keyCode) { long now = SystemClock.uptimeMillis(); - Log.i("SendKeyEvent", event); + injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0)); + injectKeyEvent(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0)); + } + + private void sendTap(float x, float y) { + long now = SystemClock.uptimeMillis(); + injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x, y, 0)); + injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x, y, 0)); + } + + private void sendSwipe(float x1, float y1, float x2, float y2) { + final int NUM_STEPS = 11; + long now = SystemClock.uptimeMillis(); + injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN, x1, y1, 0)); + for (int i = 1; i < NUM_STEPS; i++) { + float alpha = (float)i / NUM_STEPS; + injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_MOVE, + lerp(x1, x2, alpha), lerp(y1, y2, alpha), 0)); + } + injectPointerEvent(MotionEvent.obtain(now, now, MotionEvent.ACTION_UP, x2, y2, 0)); + } + + private void injectKeyEvent(KeyEvent event) { + try { + Log.i(TAG, "InjectKeyEvent: " + event); + getWindowManager().injectKeyEvent(event, true); + } catch (RemoteException ex) { + Log.i(TAG, "RemoteException", ex); + } + } + + private void injectPointerEvent(MotionEvent event) { try { - KeyEvent down = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, eventCode, 0); - KeyEvent up = new KeyEvent(now, now, KeyEvent.ACTION_UP, eventCode, 0); - (IWindowManager.Stub - .asInterface(ServiceManager.getService("window"))) - .injectKeyEvent(down, true); - (IWindowManager.Stub - .asInterface(ServiceManager.getService("window"))) - .injectKeyEvent(up, true); - } catch (RemoteException e) { - Log.i("Input", "DeadOjbectException"); + Log.i("Input", "InjectPointerEvent: " + event); + getWindowManager().injectPointerEvent(event, true); + } catch (RemoteException ex) { + Log.i(TAG, "RemoteException", ex); + } finally { + event.recycle(); } } - private void sendMotionEvent(long downTime, int action, float x, float y, - float pressure, float size) { + private static final float lerp(float a, float b, float alpha) { + return (b - a) * alpha + a; } private void showUsage() { System.err.println("usage: input [text|keyevent]"); System.err.println(" input text <string>"); - System.err.println(" input keyevent <event_code>"); + System.err.println(" input keyevent <key code>"); + System.err.println(" input tap <x> <y>"); + System.err.println(" input swipe <x1> <y1> <x2> <y2>"); } } diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index dd92bbe499bc..203d180a6439 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -148,6 +148,48 @@ int delete_persona(uid_t persona) return delete_dir_contents(pkgdir, 1, NULL); } +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 = %d\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); + } + } + closedir(d); + } + return 0; +} + int delete_cache(const char *pkgname) { char cachedir[PKG_PATH_MAX]; diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index 569b491be012..c2c749ace793 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -107,6 +107,11 @@ 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(); @@ -146,6 +151,7 @@ struct cmdinfo cmds[] = { { "unlinklib", 1, do_unlinklib }, { "mkuserdata", 3, do_mk_user_data }, { "rmuser", 1, do_rm_user }, + { "cloneuserdata", 3, do_clone_user_data }, }; static int readx(int s, void *_buf, int count) @@ -326,12 +332,15 @@ int initialize_directories() { ret = 0; // Make the /data/user directory if necessary if (access(user_data_dir, R_OK) < 0) { - if (mkdir(user_data_dir, 0755) < 0) { + if (mkdir(user_data_dir, 0711) < 0) { return -1; } if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) { return -1; } + if (chmod(user_data_dir, 0711) < 0) { + return -1; + } } // Make the /data/user/0 symlink to /data/data if necessary if (access(primary_data_dir, R_OK) < 0) { diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index 173cabfb77a7..78342bb6ac09 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -72,6 +72,9 @@ #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 { @@ -143,6 +146,7 @@ int renamepkg(const char *oldpkgname, const char *newpkgname); int delete_user_data(const char *pkgname, uid_t persona); int make_user_data(const char *pkgname, uid_t uid, uid_t persona); 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); int move_dex(const char *src, const char *dst); int rm_dex(const char *path); diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk deleted file mode 100644 index 5a9b979c6406..000000000000 --- a/cmds/keystore/Android.mk +++ /dev/null @@ -1,32 +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. -# - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := keystore.cpp -LOCAL_C_INCLUDES := external/openssl/include -LOCAL_SHARED_LIBRARIES := libcutils libcrypto -LOCAL_MODULE:= keystore -include $(BUILD_EXECUTABLE) - -include $(CLEAR_VARS) -LOCAL_SRC_FILES := keystore_cli.cpp -LOCAL_C_INCLUDES := external/openssl/include -LOCAL_SHARED_LIBRARIES := libcutils libcrypto -LOCAL_MODULE:= keystore_cli -LOCAL_MODULE_TAGS := debug -include $(BUILD_EXECUTABLE) diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp deleted file mode 100644 index 05f77e5326d9..000000000000 --- a/cmds/keystore/keystore.cpp +++ /dev/null @@ -1,810 +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 <stdint.h> -#include <string.h> -#include <unistd.h> -#include <signal.h> -#include <errno.h> -#include <dirent.h> -#include <fcntl.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <arpa/inet.h> - -#include <openssl/aes.h> -#include <openssl/evp.h> -#include <openssl/md5.h> - -#define LOG_TAG "keystore" -#include <cutils/log.h> -#include <cutils/sockets.h> -#include <private/android_filesystem_config.h> - -#include "keystore.h" - -/* KeyStore is a secured storage for key-value pairs. In this implementation, - * each file stores one key-value pair. Keys are encoded in file names, and - * values are encrypted with checksums. The encryption key is protected by a - * user-defined password. To keep things simple, buffers are always larger than - * the maximum space we needed, so boundary checks on buffers are omitted. */ - -#define KEY_SIZE ((NAME_MAX - 15) / 2) -#define VALUE_SIZE 32768 -#define PASSWORD_SIZE VALUE_SIZE - -struct Value { - int length; - uint8_t value[VALUE_SIZE]; -}; - -/* Here is the encoding of keys. This is necessary in order to allow arbitrary - * characters in keys. Characters in [0-~] are not encoded. Others are encoded - * into two bytes. The first byte is one of [+-.] which represents the first - * two bits of the character. The second byte encodes the rest of the bits into - * [0-o]. Therefore in the worst case the length of a key gets doubled. Note - * that Base64 cannot be used here due to the need of prefix match on keys. */ - -static int encode_key(char* out, uid_t uid, const Value* key) { - int n = snprintf(out, NAME_MAX, "%u_", uid); - out += n; - const uint8_t* in = key->value; - int length = key->length; - for (int i = length; i > 0; --i, ++in, ++out) { - if (*in >= '0' && *in <= '~') { - *out = *in; - } else { - *out = '+' + (*in >> 6); - *++out = '0' + (*in & 0x3F); - ++length; - } - } - *out = '\0'; - return n + length; -} - -static int decode_key(uint8_t* out, char* in, int length) { - for (int i = 0; i < length; ++i, ++in, ++out) { - if (*in >= '0' && *in <= '~') { - *out = *in; - } else { - *out = (*in - '+') << 6; - *out |= (*++in - '0') & 0x3F; - --length; - } - } - *out = '\0'; - return length; -} - -static size_t readFully(int fd, uint8_t* data, size_t size) { - size_t remaining = size; - while (remaining > 0) { - ssize_t n = TEMP_FAILURE_RETRY(read(fd, data, size)); - if (n == -1 || n == 0) { - return size-remaining; - } - data += n; - remaining -= n; - } - return size; -} - -static size_t writeFully(int fd, uint8_t* data, size_t size) { - size_t remaining = size; - while (remaining > 0) { - ssize_t n = TEMP_FAILURE_RETRY(write(fd, data, size)); - if (n == -1 || n == 0) { - return size-remaining; - } - data += n; - remaining -= n; - } - return size; -} - -class Entropy { -public: - Entropy() : mRandom(-1) {} - ~Entropy() { - if (mRandom != -1) { - close(mRandom); - } - } - - bool open() { - const char* randomDevice = "/dev/urandom"; - mRandom = ::open(randomDevice, O_RDONLY); - if (mRandom == -1) { - ALOGE("open: %s: %s", randomDevice, strerror(errno)); - return false; - } - return true; - } - - bool generate_random_data(uint8_t* data, size_t size) { - return (readFully(mRandom, data, size) == size); - } - -private: - int mRandom; -}; - -/* Here is the file format. There are two parts in blob.value, the secret and - * the description. The secret is stored in ciphertext, and its original size - * can be found in blob.length. The description is stored after the secret in - * plaintext, and its size is specified in blob.info. The total size of the two - * parts must be no more than VALUE_SIZE bytes. The first three bytes of the - * file are reserved for future use and are always set to zero. Fields other - * than blob.info, blob.length, and blob.value are modified by encryptBlob() - * and decryptBlob(). Thus they should not be accessed from outside. */ - -struct __attribute__((packed)) blob { - uint8_t reserved[3]; - uint8_t info; - uint8_t vector[AES_BLOCK_SIZE]; - uint8_t encrypted[0]; - uint8_t digest[MD5_DIGEST_LENGTH]; - uint8_t digested[0]; - int32_t length; // in network byte order when encrypted - uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE]; -}; - -class Blob { -public: - Blob(uint8_t* value, int32_t valueLength, uint8_t* info, uint8_t infoLength) { - mBlob.length = valueLength; - memcpy(mBlob.value, value, valueLength); - - mBlob.info = infoLength; - memcpy(mBlob.value + valueLength, info, infoLength); - } - - Blob(blob b) { - mBlob = b; - } - - Blob() {} - - uint8_t* getValue() { - return mBlob.value; - } - - int32_t getLength() { - return mBlob.length; - } - - uint8_t getInfo() { - return mBlob.info; - } - - ResponseCode encryptBlob(const char* filename, AES_KEY *aes_key, Entropy* entropy) { - if (!entropy->generate_random_data(mBlob.vector, AES_BLOCK_SIZE)) { - return SYSTEM_ERROR; - } - - // data includes the value and the value's length - size_t dataLength = mBlob.length + sizeof(mBlob.length); - // pad data to the AES_BLOCK_SIZE - size_t digestedLength = ((dataLength + AES_BLOCK_SIZE - 1) - / AES_BLOCK_SIZE * AES_BLOCK_SIZE); - // encrypted data includes the digest value - size_t encryptedLength = digestedLength + MD5_DIGEST_LENGTH; - // move info after space for padding - memmove(&mBlob.encrypted[encryptedLength], &mBlob.value[mBlob.length], mBlob.info); - // zero padding area - memset(mBlob.value + mBlob.length, 0, digestedLength - dataLength); - - mBlob.length = htonl(mBlob.length); - MD5(mBlob.digested, digestedLength, mBlob.digest); - - uint8_t vector[AES_BLOCK_SIZE]; - memcpy(vector, mBlob.vector, AES_BLOCK_SIZE); - AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, - aes_key, vector, AES_ENCRYPT); - - memset(mBlob.reserved, 0, sizeof(mBlob.reserved)); - size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob); - size_t fileLength = encryptedLength + headerLength + mBlob.info; - - const char* tmpFileName = ".tmp"; - int out = open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); - if (out == -1) { - return SYSTEM_ERROR; - } - size_t writtenBytes = writeFully(out, (uint8_t*) &mBlob, fileLength); - if (close(out) != 0) { - return SYSTEM_ERROR; - } - if (writtenBytes != fileLength) { - unlink(tmpFileName); - return SYSTEM_ERROR; - } - return (rename(tmpFileName, filename) == 0) ? NO_ERROR : SYSTEM_ERROR; - } - - ResponseCode decryptBlob(const char* filename, AES_KEY *aes_key) { - int in = open(filename, O_RDONLY); - if (in == -1) { - return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR; - } - // fileLength may be less than sizeof(mBlob) since the in - // memory version has extra padding to tolerate rounding up to - // the AES_BLOCK_SIZE - size_t fileLength = readFully(in, (uint8_t*) &mBlob, sizeof(mBlob)); - if (close(in) != 0) { - return SYSTEM_ERROR; - } - size_t headerLength = (mBlob.encrypted - (uint8_t*) &mBlob); - if (fileLength < headerLength) { - return VALUE_CORRUPTED; - } - - ssize_t encryptedLength = fileLength - (headerLength + mBlob.info); - if (encryptedLength < 0 || encryptedLength % AES_BLOCK_SIZE != 0) { - return VALUE_CORRUPTED; - } - AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, aes_key, - mBlob.vector, AES_DECRYPT); - size_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH; - uint8_t computedDigest[MD5_DIGEST_LENGTH]; - MD5(mBlob.digested, digestedLength, computedDigest); - if (memcmp(mBlob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) { - return VALUE_CORRUPTED; - } - - ssize_t maxValueLength = digestedLength - sizeof(mBlob.length); - mBlob.length = ntohl(mBlob.length); - if (mBlob.length < 0 || mBlob.length > maxValueLength) { - return VALUE_CORRUPTED; - } - if (mBlob.info != 0) { - // move info from after padding to after data - memmove(&mBlob.value[mBlob.length], &mBlob.value[maxValueLength], mBlob.info); - } - return NO_ERROR; - } - -private: - struct blob mBlob; -}; - -class KeyStore { -public: - KeyStore(Entropy* entropy) : mEntropy(entropy), mRetry(MAX_RETRY) { - if (access(MASTER_KEY_FILE, R_OK) == 0) { - setState(STATE_LOCKED); - } else { - setState(STATE_UNINITIALIZED); - } - } - - State getState() { - return mState; - } - - int8_t getRetry() { - return mRetry; - } - - ResponseCode initialize(Value* pw) { - if (!generateMasterKey()) { - return SYSTEM_ERROR; - } - ResponseCode response = writeMasterKey(pw); - if (response != NO_ERROR) { - return response; - } - setupMasterKeys(); - return NO_ERROR; - } - - ResponseCode writeMasterKey(Value* pw) { - uint8_t passwordKey[MASTER_KEY_SIZE_BYTES]; - generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt); - AES_KEY passwordAesKey; - AES_set_encrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey); - Blob masterKeyBlob(mMasterKey, sizeof(mMasterKey), mSalt, sizeof(mSalt)); - return masterKeyBlob.encryptBlob(MASTER_KEY_FILE, &passwordAesKey, mEntropy); - } - - ResponseCode readMasterKey(Value* pw) { - int in = open(MASTER_KEY_FILE, O_RDONLY); - if (in == -1) { - return SYSTEM_ERROR; - } - - // we read the raw blob to just to get the salt to generate - // the AES key, then we create the Blob to use with decryptBlob - blob rawBlob; - size_t length = readFully(in, (uint8_t*) &rawBlob, sizeof(rawBlob)); - if (close(in) != 0) { - return SYSTEM_ERROR; - } - // find salt at EOF if present, otherwise we have an old file - uint8_t* salt; - if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) { - salt = (uint8_t*) &rawBlob + length - SALT_SIZE; - } else { - salt = NULL; - } - uint8_t passwordKey[MASTER_KEY_SIZE_BYTES]; - generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, salt); - AES_KEY passwordAesKey; - AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey); - Blob masterKeyBlob(rawBlob); - ResponseCode response = masterKeyBlob.decryptBlob(MASTER_KEY_FILE, &passwordAesKey); - if (response == SYSTEM_ERROR) { - return SYSTEM_ERROR; - } - if (response == NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) { - // if salt was missing, generate one and write a new master key file with the salt. - if (salt == NULL) { - if (!generateSalt()) { - return SYSTEM_ERROR; - } - response = writeMasterKey(pw); - } - if (response == NO_ERROR) { - memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES); - setupMasterKeys(); - } - return response; - } - if (mRetry <= 0) { - reset(); - return UNINITIALIZED; - } - --mRetry; - switch (mRetry) { - case 0: return WRONG_PASSWORD_0; - case 1: return WRONG_PASSWORD_1; - case 2: return WRONG_PASSWORD_2; - case 3: return WRONG_PASSWORD_3; - default: return WRONG_PASSWORD_3; - } - } - - bool reset() { - clearMasterKeys(); - setState(STATE_UNINITIALIZED); - - DIR* dir = opendir("."); - struct dirent* file; - - if (!dir) { - return false; - } - while ((file = readdir(dir)) != NULL) { - unlink(file->d_name); - } - closedir(dir); - return true; - } - - bool isEmpty() { - DIR* dir = opendir("."); - struct dirent* file; - if (!dir) { - return true; - } - bool result = true; - while ((file = readdir(dir)) != NULL) { - if (isKeyFile(file->d_name)) { - result = false; - break; - } - } - closedir(dir); - return result; - } - - void lock() { - clearMasterKeys(); - setState(STATE_LOCKED); - } - - ResponseCode get(const char* filename, Blob* keyBlob) { - return keyBlob->decryptBlob(filename, &mMasterKeyDecryption); - } - - ResponseCode put(const char* filename, Blob* keyBlob) { - return keyBlob->encryptBlob(filename, &mMasterKeyEncryption, mEntropy); - } - -private: - static const char* MASTER_KEY_FILE; - static const int MASTER_KEY_SIZE_BYTES = 16; - static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8; - - static const int MAX_RETRY = 4; - static const size_t SALT_SIZE = 16; - - Entropy* mEntropy; - - State mState; - int8_t mRetry; - - uint8_t mMasterKey[MASTER_KEY_SIZE_BYTES]; - uint8_t mSalt[SALT_SIZE]; - - AES_KEY mMasterKeyEncryption; - AES_KEY mMasterKeyDecryption; - - void setState(State state) { - mState = state; - if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) { - mRetry = MAX_RETRY; - } - } - - bool generateSalt() { - return mEntropy->generate_random_data(mSalt, sizeof(mSalt)); - } - - bool generateMasterKey() { - if (!mEntropy->generate_random_data(mMasterKey, sizeof(mMasterKey))) { - return false; - } - if (!generateSalt()) { - return false; - } - return true; - } - - void setupMasterKeys() { - AES_set_encrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyEncryption); - AES_set_decrypt_key(mMasterKey, MASTER_KEY_SIZE_BITS, &mMasterKeyDecryption); - setState(STATE_NO_ERROR); - } - - void clearMasterKeys() { - memset(mMasterKey, 0, sizeof(mMasterKey)); - memset(mSalt, 0, sizeof(mSalt)); - memset(&mMasterKeyEncryption, 0, sizeof(mMasterKeyEncryption)); - memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption)); - } - - static void generateKeyFromPassword(uint8_t* key, ssize_t keySize, Value* pw, uint8_t* salt) { - size_t saltSize; - if (salt != NULL) { - saltSize = SALT_SIZE; - } else { - // pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found - salt = (uint8_t*) "keystore"; - // sizeof = 9, not strlen = 8 - saltSize = sizeof("keystore"); - } - PKCS5_PBKDF2_HMAC_SHA1((char*) pw->value, pw->length, salt, saltSize, 8192, keySize, key); - } - - static bool isKeyFile(const char* filename) { - return ((strcmp(filename, MASTER_KEY_FILE) != 0) - && (strcmp(filename, ".") != 0) - && (strcmp(filename, "..") != 0)); - } -}; - -const char* KeyStore::MASTER_KEY_FILE = ".masterkey"; - -/* Here is the protocol used in both requests and responses: - * code [length_1 message_1 ... length_n message_n] end-of-file - * where code is one byte long and lengths are unsigned 16-bit integers in - * network order. Thus the maximum length of a message is 65535 bytes. */ - -static int recv_code(int sock, int8_t* code) { - return recv(sock, code, 1, 0) == 1; -} - -static int recv_message(int sock, uint8_t* message, int length) { - uint8_t bytes[2]; - if (recv(sock, &bytes[0], 1, 0) != 1 || - recv(sock, &bytes[1], 1, 0) != 1) { - return -1; - } else { - int offset = bytes[0] << 8 | bytes[1]; - if (length < offset) { - return -1; - } - length = offset; - offset = 0; - while (offset < length) { - int n = recv(sock, &message[offset], length - offset, 0); - if (n <= 0) { - return -1; - } - offset += n; - } - } - return length; -} - -static int recv_end_of_file(int sock) { - uint8_t byte; - return recv(sock, &byte, 1, 0) == 0; -} - -static void send_code(int sock, int8_t code) { - send(sock, &code, 1, 0); -} - -static void send_message(int sock, uint8_t* message, int length) { - uint16_t bytes = htons(length); - send(sock, &bytes, 2, 0); - send(sock, message, length, 0); -} - -/* Here are the actions. Each of them is a function without arguments. All - * information is defined in global variables, which are set properly before - * performing an action. The number of parameters required by each action is - * fixed and defined in a table. If the return value of an action is positive, - * it will be treated as a response code and transmitted to the client. Note - * that the lengths of parameters are checked when they are received, so - * boundary checks on parameters are omitted. */ - -static const ResponseCode NO_ERROR_RESPONSE_CODE_SENT = (ResponseCode) 0; - -static ResponseCode test(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) { - return (ResponseCode) keyStore->getState(); -} - -static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) { - char filename[NAME_MAX]; - encode_key(filename, uid, keyName); - Blob keyBlob; - ResponseCode responseCode = keyStore->get(filename, &keyBlob); - if (responseCode != NO_ERROR) { - return responseCode; - } - send_code(sock, NO_ERROR); - send_message(sock, keyBlob.getValue(), keyBlob.getLength()); - return NO_ERROR_RESPONSE_CODE_SENT; -} - -static ResponseCode insert(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* val) { - char filename[NAME_MAX]; - encode_key(filename, uid, keyName); - Blob keyBlob(val->value, val->length, 0, NULL); - return keyStore->put(filename, &keyBlob); -} - -static ResponseCode del(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) { - char filename[NAME_MAX]; - encode_key(filename, uid, keyName); - return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR; -} - -static ResponseCode exist(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*) { - char filename[NAME_MAX]; - encode_key(filename, uid, keyName); - if (access(filename, R_OK) == -1) { - return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND; - } - return NO_ERROR; -} - -static ResponseCode saw(KeyStore* keyStore, int sock, uid_t uid, Value* keyPrefix, Value*) { - DIR* dir = opendir("."); - if (!dir) { - return SYSTEM_ERROR; - } - char filename[NAME_MAX]; - int n = encode_key(filename, uid, keyPrefix); - send_code(sock, NO_ERROR); - - struct dirent* file; - while ((file = readdir(dir)) != NULL) { - if (!strncmp(filename, file->d_name, n)) { - char* p = &file->d_name[n]; - keyPrefix->length = decode_key(keyPrefix->value, p, strlen(p)); - send_message(sock, keyPrefix->value, keyPrefix->length); - } - } - closedir(dir); - return NO_ERROR_RESPONSE_CODE_SENT; -} - -static ResponseCode reset(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) { - return keyStore->reset() ? NO_ERROR : SYSTEM_ERROR; -} - -/* Here is the history. To improve the security, the parameters to generate the - * master key has been changed. To make a seamless transition, we update the - * file using the same password when the user unlock it for the first time. If - * any thing goes wrong during the transition, the new file will not overwrite - * the old one. This avoids permanent damages of the existing data. */ - -static ResponseCode password(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value*) { - switch (keyStore->getState()) { - case STATE_UNINITIALIZED: { - // generate master key, encrypt with password, write to file, initialize mMasterKey*. - return keyStore->initialize(pw); - } - case STATE_NO_ERROR: { - // rewrite master key with new password. - return keyStore->writeMasterKey(pw); - } - case STATE_LOCKED: { - // read master key, decrypt with password, initialize mMasterKey*. - return keyStore->readMasterKey(pw); - } - } - return SYSTEM_ERROR; -} - -static ResponseCode lock(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) { - keyStore->lock(); - return NO_ERROR; -} - -static ResponseCode unlock(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value* unused) { - return password(keyStore, sock, uid, pw, unused); -} - -static ResponseCode zero(KeyStore* keyStore, int sock, uid_t uid, Value*, Value*) { - return keyStore->isEmpty() ? KEY_NOT_FOUND : NO_ERROR; -} - -/* Here are the permissions, actions, users, and the main function. */ - -enum perm { - TEST = 1, - GET = 2, - INSERT = 4, - DELETE = 8, - EXIST = 16, - SAW = 32, - RESET = 64, - PASSWORD = 128, - LOCK = 256, - UNLOCK = 512, - ZERO = 1024, -}; - -static const int MAX_PARAM = 2; - -static const State STATE_ANY = (State) 0; - -static struct action { - ResponseCode (*run)(KeyStore* keyStore, int sock, uid_t uid, Value* param1, Value* param2); - int8_t code; - State state; - uint32_t perm; - int lengths[MAX_PARAM]; -} actions[] = { - {test, 't', STATE_ANY, TEST, {0, 0}}, - {get, 'g', STATE_NO_ERROR, GET, {KEY_SIZE, 0}}, - {insert, 'i', STATE_NO_ERROR, INSERT, {KEY_SIZE, VALUE_SIZE}}, - {del, 'd', STATE_ANY, DELETE, {KEY_SIZE, 0}}, - {exist, 'e', STATE_ANY, EXIST, {KEY_SIZE, 0}}, - {saw, 's', STATE_ANY, SAW, {KEY_SIZE, 0}}, - {reset, 'r', STATE_ANY, RESET, {0, 0}}, - {password, 'p', STATE_ANY, PASSWORD, {PASSWORD_SIZE, 0}}, - {lock, 'l', STATE_NO_ERROR, LOCK, {0, 0}}, - {unlock, 'u', STATE_LOCKED, UNLOCK, {PASSWORD_SIZE, 0}}, - {zero, 'z', STATE_ANY, ZERO, {0, 0}}, - {NULL, 0 , STATE_ANY, 0, {0, 0}}, -}; - -static struct user { - uid_t uid; - uid_t euid; - uint32_t perms; -} users[] = { - {AID_SYSTEM, ~0, ~0}, - {AID_VPN, AID_SYSTEM, GET}, - {AID_WIFI, AID_SYSTEM, GET}, - {AID_ROOT, AID_SYSTEM, GET}, - {~0, ~0, TEST | GET | INSERT | DELETE | EXIST | SAW}, -}; - -static ResponseCode process(KeyStore* keyStore, int sock, uid_t uid, int8_t code) { - struct user* user = users; - struct action* action = actions; - int i; - - while (~user->uid && user->uid != uid) { - ++user; - } - while (action->code && action->code != code) { - ++action; - } - if (!action->code) { - return UNDEFINED_ACTION; - } - if (!(action->perm & user->perms)) { - return PERMISSION_DENIED; - } - if (action->state != STATE_ANY && action->state != keyStore->getState()) { - return (ResponseCode) keyStore->getState(); - } - if (~user->euid) { - uid = user->euid; - } - Value params[MAX_PARAM]; - for (i = 0; i < MAX_PARAM && action->lengths[i] != 0; ++i) { - params[i].length = recv_message(sock, params[i].value, action->lengths[i]); - if (params[i].length < 0) { - return PROTOCOL_ERROR; - } - } - if (!recv_end_of_file(sock)) { - return PROTOCOL_ERROR; - } - return action->run(keyStore, sock, uid, ¶ms[0], ¶ms[1]); -} - -int main(int argc, char* argv[]) { - int controlSocket = android_get_control_socket("keystore"); - if (argc < 2) { - ALOGE("A directory must be specified!"); - return 1; - } - if (chdir(argv[1]) == -1) { - ALOGE("chdir: %s: %s", argv[1], strerror(errno)); - return 1; - } - - Entropy entropy; - if (!entropy.open()) { - return 1; - } - if (listen(controlSocket, 3) == -1) { - ALOGE("listen: %s", strerror(errno)); - return 1; - } - - signal(SIGPIPE, SIG_IGN); - - KeyStore keyStore(&entropy); - int sock; - while ((sock = accept(controlSocket, NULL, 0)) != -1) { - struct timeval tv; - tv.tv_sec = 3; - setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); - - struct ucred cred; - socklen_t size = sizeof(cred); - int credResult = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &size); - if (credResult != 0) { - ALOGW("getsockopt: %s", strerror(errno)); - } else { - int8_t request; - if (recv_code(sock, &request)) { - State old_state = keyStore.getState(); - ResponseCode response = process(&keyStore, sock, cred.uid, request); - if (response == NO_ERROR_RESPONSE_CODE_SENT) { - response = NO_ERROR; - } else { - send_code(sock, response); - } - ALOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d", - cred.uid, - request, response, - old_state, keyStore.getState(), - keyStore.getRetry()); - } - } - close(sock); - } - ALOGE("accept: %s", strerror(errno)); - return 1; -} diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h deleted file mode 100644 index 5ae3d24acee0..000000000000 --- a/cmds/keystore/keystore.h +++ /dev/null @@ -1,43 +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. - */ - -#ifndef __KEYSTORE_H__ -#define __KEYSTORE_H__ - -// note state values overlap with ResponseCode for the purposes of the state() API -enum State { - STATE_NO_ERROR = 1, - STATE_LOCKED = 2, - STATE_UNINITIALIZED = 3, -}; - -enum ResponseCode { - NO_ERROR = STATE_NO_ERROR, // 1 - LOCKED = STATE_LOCKED, // 2 - UNINITIALIZED = STATE_UNINITIALIZED, // 3 - SYSTEM_ERROR = 4, - PROTOCOL_ERROR = 5, - PERMISSION_DENIED = 6, - KEY_NOT_FOUND = 7, - VALUE_CORRUPTED = 8, - UNDEFINED_ACTION = 9, - WRONG_PASSWORD_0 = 10, - WRONG_PASSWORD_1 = 11, - WRONG_PASSWORD_2 = 12, - WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4 -}; - -#endif diff --git a/cmds/keystore/keystore_cli.cpp b/cmds/keystore/keystore_cli.cpp deleted file mode 100644 index dcd3bcb8fc01..000000000000 --- a/cmds/keystore/keystore_cli.cpp +++ /dev/null @@ -1,95 +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 <stdint.h> -#include <string.h> -#include <sys/types.h> -#include <sys/socket.h> - -#include <cutils/sockets.h> - -#include "keystore.h" - -static const char* responses[] = { - NULL, - /* [NO_ERROR] = */ "No error", - /* [LOCKED] = */ "Locked", - /* [UNINITIALIZED] = */ "Uninitialized", - /* [SYSTEM_ERROR] = */ "System error", - /* [PROTOCOL_ERROR] = */ "Protocol error", - /* [PERMISSION_DENIED] = */ "Permission denied", - /* [KEY_NOT_FOUND] = */ "Key not found", - /* [VALUE_CORRUPTED] = */ "Value corrupted", - /* [UNDEFINED_ACTION] = */ "Undefined action", - /* [WRONG_PASSWORD] = */ "Wrong password (last chance)", - /* [WRONG_PASSWORD + 1] = */ "Wrong password (2 tries left)", - /* [WRONG_PASSWORD + 2] = */ "Wrong password (3 tries left)", - /* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)", -}; - -int main(int argc, char* argv[]) -{ - if (argc < 2) { - printf("Usage: %s action [parameter ...]\n", argv[0]); - return 0; - } - - int sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (sock == -1) { - puts("Failed to connect"); - return 1; - } - - send(sock, argv[1], 1, 0); - uint8_t bytes[65536]; - for (int i = 2; i < argc; ++i) { - uint16_t length = strlen(argv[i]); - bytes[0] = length >> 8; - bytes[1] = length; - send(sock, &bytes, 2, 0); - send(sock, argv[i], length, 0); - } - shutdown(sock, SHUT_WR); - - uint8_t code; - if (recv(sock, &code, 1, 0) != 1) { - puts("Failed to receive"); - return 1; - } - printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown"); - int i; - while ((i = recv(sock, &bytes[0], 1, 0)) == 1) { - int length; - int offset; - if ((i = recv(sock, &bytes[1], 1, 0)) != 1) { - puts("Failed to receive"); - return 1; - } - length = bytes[0] << 8 | bytes[1]; - for (offset = 0; offset < length; offset += i) { - i = recv(sock, &bytes[offset], length - offset, 0); - if (i <= 0) { - puts("Failed to receive"); - return 1; - } - } - fwrite(bytes, 1, length, stdout); - puts(""); - } - return 0; -} diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h deleted file mode 100644 index 4b4923e5c736..000000000000 --- a/cmds/keystore/keystore_get.h +++ /dev/null @@ -1,80 +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. - */ - -#ifndef __KEYSTORE_GET_H__ -#define __KEYSTORE_GET_H__ - -#include <stdio.h> -#include <stdint.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> - -#include <cutils/sockets.h> - -#define KEYSTORE_MESSAGE_SIZE 65535 - -#ifdef __cplusplus -extern "C" { -#endif - -/* This function is provided for native components to get values from keystore. - * Users are required to link against libcutils. Keys and values are 8-bit safe. - * The first two arguments are the key and its length. The third argument - * specifies the buffer to store the retrieved value, which must be an array of - * KEYSTORE_MESSAGE_SIZE bytes. This function returns the length of the value or - * -1 if an error happens. */ -static int keystore_get(const char *key, int length, char *value) -{ - uint8_t bytes[2] = {length >> 8, length}; - uint8_t code = 'g'; - int sock; - - if (length < 0 || length > KEYSTORE_MESSAGE_SIZE) { - return -1; - } - sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM); - if (sock == -1) { - return -1; - } - if (send(sock, &code, 1, 0) == 1 && send(sock, bytes, 2, 0) == 2 && - send(sock, key, length, 0) == length && shutdown(sock, SHUT_WR) == 0 && - recv(sock, &code, 1, 0) == 1 && code == /* NO_ERROR */ 1 && - recv(sock, &bytes[0], 1, 0) == 1 && recv(sock, &bytes[1], 1, 0) == 1) { - int offset = 0; - length = bytes[0] << 8 | bytes[1]; - while (offset < length) { - int n = recv(sock, &value[offset], length - offset, 0); - if (n <= 0) { - length = -1; - break; - } - offset += n; - } - } else { - length = -1; - } - - close(sock); - return length; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/cmds/keystore/test-keystore b/cmds/keystore/test-keystore deleted file mode 100755 index 3be51b3e7bfb..000000000000 --- a/cmds/keystore/test-keystore +++ /dev/null @@ -1,273 +0,0 @@ -#!/bin/bash -# -# Copyright 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. - -set -e - -prefix=$0 -log_file=$prefix.log -baseline_file=$prefix.baseline - -function cleanup_output() { - rm -f $log_file - rm -f $baseline_file -} - -function log() { - echo "$@" - append $log_file \# "$@" - append $baseline_file \# "$@" -} - -function expect() { - append $baseline_file "$@" -} - -function append() { - declare -r file=$1 - shift - echo "$@" >> $file -} - -function run() { - # strip out carriage returns from adb - # strip out date/time from ls -l - "$@" | tr --delete '\r' | sed -E 's/[0-9]{4}-[0-9]{2}-[0-9]{2} +[0-9]{1,2}:[0-9]{2} //' >> $log_file -} - -function keystore() { - declare -r user=$1 - shift - run adb shell su $user keystore_cli "$@" -} - -function list_keystore_directory() { - run adb shell ls -al /data/misc/keystore -} - -function compare() { - log "comparing $baseline_file and $log_file" - diff $baseline_file $log_file || (log $tag FAILED && exit 1) -} - -function test_basic() { - - # - # reset - # - log "reset keystore as system user" - keystore system r - expect "1 No error" - list_keystore_directory - - # - # basic tests as system/root - # - log "root does not have permission to run test" - keystore root t - expect "6 Permission denied" - - log "but system user does" - keystore system t - expect "3 Uninitialized" - list_keystore_directory - - log "password is now bar" - keystore system p bar - expect "1 No error" - list_keystore_directory - expect "-rw------- keystore keystore 84 .masterkey" - - log "no error implies initialized and unlocked" - keystore system t - expect "1 No error" - - log "saw with no argument" - keystore system s - expect "5 Protocol error" - - log "saw nothing" - keystore system s "" - expect "1 No error" - - log "add key baz" - keystore system i baz quux - expect "1 No error" - - log "1000 is uid of system" - list_keystore_directory - expect "-rw------- keystore keystore 84 .masterkey" - expect "-rw------- keystore keystore 52 1000_baz" - - log "saw baz" - keystore system s "" - expect "1 No error" - expect "baz" - - log "get baz" - keystore system g baz - expect "1 No error" - expect "quux" - - log "root can read system user keys (as can wifi or vpn users)" - keystore root g baz - expect "1 No error" - expect "quux" - - # - # app user tests - # - - # app_0 has uid 10000, as seen below - log "other uses cannot see the system keys" - keystore app_0 g baz - expect "7 Key not found" - - log "app user cannot use reset, password, lock, unlock" - keystore app_0 r - expect "6 Permission denied" - keystore app_0 p - expect "6 Permission denied" - keystore app_0 l - expect "6 Permission denied" - keystore app_0 u - expect "6 Permission denied" - - log "install app_0 key" - keystore app_0 i 0x deadbeef - expect 1 No error - list_keystore_directory - expect "-rw------- keystore keystore 84 .masterkey" - expect "-rw------- keystore keystore 52 10000_0x" - expect "-rw------- keystore keystore 52 1000_baz" - - log "get with no argument" - keystore app_0 g - expect "5 Protocol error" - - keystore app_0 g 0x - expect "1 No error" - expect "deadbeef" - - keystore app_0 i fred barney - expect "1 No error" - - keystore app_0 s "" - expect "1 No error" - expect "0x" - expect "fred" - - log "note that saw returns the suffix of prefix matches" - keystore app_0 s fr # fred - expect "1 No error" - expect "ed" # fred - - # - # lock tests - # - log "lock the store as system" - keystore system l - expect "1 No error" - keystore system t - expect "2 Locked" - - log "saw works while locked" - keystore app_0 s "" - expect "1 No error" - expect "0x" - expect "fred" - - log "...but cannot read keys..." - keystore app_0 g 0x - expect "2 Locked" - - log "...but they can be deleted." - keystore app_0 e 0x - expect "1 No error" - keystore app_0 d 0x - expect "1 No error" - keystore app_0 e 0x - expect "7 Key not found" - - # - # password - # - log "wrong password" - keystore system u foo - expect "13 Wrong password (4 tries left)" - log "right password" - keystore system u bar - expect "1 No error" - - log "make the password foo" - keystore system p foo - expect "1 No error" - - # - # final reset - # - log "reset wipes everything for all users" - keystore system r - expect "1 No error" - list_keystore_directory - - keystore system t - expect "3 Uninitialized" - -} - -function test_4599735() { - # http://b/4599735 - log "start regression test for b/4599735" - keystore system r - expect "1 No error" - - keystore system p foo - expect "1 No error" - - keystore system i baz quux - expect "1 No error" - - keystore root g baz - expect "1 No error" - expect "quux" - - keystore system l - expect "1 No error" - - keystore system p foo - expect "1 No error" - - log "after unlock, regression led to result of '8 Value corrupted'" - keystore root g baz - expect "1 No error" - expect "quux" - - keystore system r - expect "1 No error" - log "end regression test for b/4599735" -} - -function main() { - cleanup_output - log $tag START - test_basic - test_4599735 - compare - log $tag PASSED - cleanup_output -} - -main diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 0ec007cf9daa..4d638d00f025 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -16,8 +16,6 @@ package com.android.commands.pm; -import com.android.internal.content.PackageHelper; - import android.app.ActivityManagerNative; import android.content.ComponentName; import android.content.pm.ApplicationInfo; @@ -33,14 +31,17 @@ import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; +import android.content.pm.UserInfo; import android.content.res.AssetManager; import android.content.res.Resources; import android.net.Uri; -import android.os.Parcel; +import android.os.Binder; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import com.android.internal.content.PackageHelper; + import java.io.File; import java.lang.reflect.Field; import java.lang.reflect.Modifier; @@ -125,6 +126,16 @@ public final class Pm { return; } + if ("grant".equals(op)) { + runGrantRevokePermission(true); + return; + } + + if ("revoke".equals(op)) { + runGrantRevokePermission(false); + return; + } + if ("set-install-location".equals(op)) { runSetInstallLocation(); return; @@ -135,16 +146,21 @@ public final class Pm { return; } - if ("createUser".equals(op)) { + if ("create-user".equals(op)) { runCreateUser(); return; } - if ("removeUser".equals(op)) { + if ("remove-user".equals(op)) { runRemoveUser(); return; } + if ("list-users".equals(op)) { + runListUsers(); + return; + } + try { if (args.length == 1) { if (args[0].equalsIgnoreCase("-l")) { @@ -199,6 +215,8 @@ public final class Pm { runListLibraries(); } else if ("instrumentation".equals(type)) { runListInstrumentation(); + } else if ("users".equals(type)) { + runListUsers(); } else { System.err.println("Error: unknown list type '" + type + "'"); showUsage(); @@ -212,6 +230,7 @@ public final class Pm { int getFlags = 0; boolean listDisabled = false, listEnabled = false; boolean listSystem = false, listThirdParty = false; + boolean listInstaller = false; try { String opt; while ((opt=nextOption()) != null) { @@ -229,6 +248,8 @@ public final class Pm { listSystem = true; } else if (opt.equals("-3")) { listThirdParty = true; + } else if (opt.equals("-i")) { + listInstaller = true; } else if (opt.equals("-u")) { getFlags |= PackageManager.GET_UNINSTALLED_PACKAGES; } else { @@ -265,7 +286,12 @@ public final class Pm { System.out.print(info.applicationInfo.sourceDir); System.out.print("="); } - System.out.println(info.packageName); + System.out.print(info.packageName); + if (listInstaller) { + System.out.print(" installer="); + System.out.print(mPm.getInstallerPackageName(info.packageName)); + } + System.out.println(); } } } catch (RemoteException e) { @@ -582,8 +608,9 @@ public final class Pm { if (groups && groupName == null && pi.group != null) { continue; } - if (pi.protectionLevel < startProtectionLevel - || pi.protectionLevel > endProtectionLevel) { + final int base = pi.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE; + if (base < startProtectionLevel + || base > endProtectionLevel) { continue; } if (summary) { @@ -613,22 +640,8 @@ public final class Pm { + loadText(pi, pi.descriptionRes, pi.nonLocalizedDescription)); } - String protLevel = "unknown"; - switch(pi.protectionLevel) { - case PermissionInfo.PROTECTION_DANGEROUS: - protLevel = "dangerous"; - break; - case PermissionInfo.PROTECTION_NORMAL: - protLevel = "normal"; - break; - case PermissionInfo.PROTECTION_SIGNATURE: - protLevel = "signature"; - break; - case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM: - protLevel = "signatureOrSystem"; - break; - } - System.out.println(prefix + " protectionLevel:" + protLevel); + System.out.println(prefix + " protectionLevel:" + + PermissionInfo.protectionToString(pi.protectionLevel)); } } } @@ -824,7 +837,7 @@ public final class Pm { public void runCreateUser() { // Need to be run as root if (Process.myUid() != ROOT_UID) { - System.err.println("Error: createUser must be run as root"); + System.err.println("Error: create-user must be run as root"); return; } String name; @@ -837,7 +850,7 @@ public final class Pm { name = arg; try { if (mPm.createUser(name, 0) == null) { - System.err.println("Error: couldn't create user."); + System.err.println("Error: couldn't create User."); showUsage(); } } catch (RemoteException e) { @@ -850,7 +863,7 @@ public final class Pm { public void runRemoveUser() { // Need to be run as root if (Process.myUid() != ROOT_UID) { - System.err.println("Error: removeUser must be run as root"); + System.err.println("Error: remove-user must be run as root"); return; } int userId; @@ -878,6 +891,27 @@ public final class Pm { } } + public void runListUsers() { + // Need to be run as root + if (Process.myUid() != ROOT_UID) { + System.err.println("Error: list-users must be run as root"); + return; + } + try { + List<UserInfo> users = mPm.getUsers(); + if (users == null) { + System.err.println("Error: couldn't get users"); + } else { + System.out.println("Users:"); + for (int i = 0; i < users.size(); i++) { + System.out.println("\t" + users.get(i).toString()); + } + } + } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); + } + } class PackageDeleteObserver extends IPackageDeleteObserver.Stub { boolean finished; boolean result; @@ -958,7 +992,8 @@ public final class Pm { ClearDataObserver obs = new ClearDataObserver(); try { - if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs)) { + if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs, + Binder.getOrigCallingUser())) { System.err.println("Failed"); } @@ -996,7 +1031,29 @@ public final class Pm { return "unknown"; } + private boolean isNumber(String s) { + try { + Integer.parseInt(s); + } catch (NumberFormatException nfe) { + return false; + } + return true; + } + private void runSetEnabledSetting(int state) { + int userId = 0; + String option = nextOption(); + if (option != null && option.equals("--user")) { + String optionData = nextOptionData(); + if (optionData == null || !isNumber(optionData)) { + System.err.println("Error: no USER_ID specified"); + showUsage(); + return; + } else { + userId = Integer.parseInt(optionData); + } + } + String pkg = nextArg(); if (pkg == null) { System.err.println("Error: no package or component specified"); @@ -1006,20 +1063,20 @@ public final class Pm { ComponentName cn = ComponentName.unflattenFromString(pkg); if (cn == null) { try { - mPm.setApplicationEnabledSetting(pkg, state, 0); + mPm.setApplicationEnabledSetting(pkg, state, 0, userId); System.err.println("Package " + pkg + " new state: " + enabledSettingToString( - mPm.getApplicationEnabledSetting(pkg))); + mPm.getApplicationEnabledSetting(pkg, userId))); } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); } } else { try { - mPm.setComponentEnabledSetting(cn, state, 0); + mPm.setComponentEnabledSetting(cn, state, 0, userId); System.err.println("Component " + cn.toShortString() + " new state: " + enabledSettingToString( - mPm.getComponentEnabledSetting(cn))); + mPm.getComponentEnabledSetting(cn, userId))); } catch (RemoteException e) { System.err.println(e.toString()); System.err.println(PM_NOT_RUNNING_ERR); @@ -1027,13 +1084,43 @@ public final class Pm { } } + private void runGrantRevokePermission(boolean grant) { + String pkg = nextArg(); + if (pkg == null) { + System.err.println("Error: no package specified"); + showUsage(); + return; + } + String perm = nextArg(); + if (perm == null) { + System.err.println("Error: no permission specified"); + showUsage(); + return; + } + try { + if (grant) { + mPm.grantPermission(pkg, perm); + } else { + mPm.revokePermission(pkg, perm); + } + } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); + } catch (IllegalArgumentException e) { + System.err.println("Bad argument: " + e.toString()); + showUsage(); + } catch (SecurityException e) { + System.err.println("Operation not allowed: " + e.toString()); + } + } + /** * Displays the package file for a package. * @param pckg */ private void displayPackageFilePath(String pckg) { try { - PackageInfo info = mPm.getPackageInfo(pckg, 0); + PackageInfo info = mPm.getPackageInfo(pckg, 0, 0); if (info != null && info.applicationInfo != null) { System.out.print("package:"); System.out.println(info.applicationInfo.sourceDir); @@ -1049,7 +1136,7 @@ public final class Pm { if (res != null) return res; try { - ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0); + ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0, 0); AssetManager am = new AssetManager(); am.addAssetPath(ai.publicSourceDir); res = new Resources(am, null, null); @@ -1109,23 +1196,26 @@ public final class Pm { } private static void showUsage() { - System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-e] [-u] [FILTER]"); + System.err.println("usage: pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [FILTER]"); System.err.println(" pm list permission-groups"); System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); System.err.println(" pm list instrumentation [-f] [TARGET-PACKAGE]"); System.err.println(" pm list features"); System.err.println(" pm list libraries"); + System.err.println(" pm list users"); System.err.println(" pm path PACKAGE"); System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH"); System.err.println(" pm uninstall [-k] PACKAGE"); System.err.println(" pm clear PACKAGE"); - System.err.println(" pm enable PACKAGE_OR_COMPONENT"); - System.err.println(" pm disable PACKAGE_OR_COMPONENT"); - System.err.println(" pm disable-user PACKAGE_OR_COMPONENT"); + 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 grant PACKAGE PERMISSION"); + System.err.println(" pm revoke PACKAGE PERMISSION"); System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]"); System.err.println(" pm get-install-location"); - System.err.println(" pm createUser USER_NAME"); - System.err.println(" pm removeUser USER_ID"); + System.err.println(" pm create-user USER_NAME"); + System.err.println(" pm remove-user USER_ID"); System.err.println(""); System.err.println("pm list packages: prints all packages, optionally only"); System.err.println(" those whose package name contains the text in FILTER. Options:"); @@ -1134,6 +1224,7 @@ public final class Pm { System.err.println(" -e: filter to only show enabled packages."); System.err.println(" -s: filter to only show system packages."); System.err.println(" -3: filter to only show third party packages."); + System.err.println(" -i: see the installer for the packages."); System.err.println(" -u: also include uninstalled packages."); System.err.println(""); System.err.println("pm list permission-groups: prints all known permission groups."); @@ -1171,6 +1262,10 @@ public final class Pm { 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(""); + System.err.println("pm grant, revoke: these commands either grant or revoke permissions"); + System.err.println(" to applications. Only optional permissions the application has"); + System.err.println(" declared can be granted or revoked."); + System.err.println(""); System.err.println("pm get-install-location: returns the current install location."); System.err.println(" 0 [auto]: Let system decide the best location"); System.err.println(" 1 [internal]: Install on internal device storage"); diff --git a/cmds/requestsync/Android.mk b/cmds/requestsync/Android.mk new file mode 100644 index 000000000000..fe2ffd8de4dc --- /dev/null +++ b/cmds/requestsync/Android.mk @@ -0,0 +1,16 @@ +# Copyright 2012 The Android Open Source Project +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := requestsync +LOCAL_MODULE_TAGS := optional +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := requestsync +LOCAL_SRC_FILES := requestsync +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE_TAGS := optional +include $(BUILD_PREBUILT) diff --git a/cmds/requestsync/MODULE_LICENSE_APACHE2 b/cmds/requestsync/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/cmds/requestsync/MODULE_LICENSE_APACHE2 diff --git a/cmds/dumpsys/NOTICE b/cmds/requestsync/NOTICE index c5b1efa7aac7..c5b1efa7aac7 100644 --- a/cmds/dumpsys/NOTICE +++ b/cmds/requestsync/NOTICE diff --git a/cmds/requestsync/requestsync b/cmds/requestsync/requestsync new file mode 100755 index 000000000000..931567583e90 --- /dev/null +++ b/cmds/requestsync/requestsync @@ -0,0 +1,6 @@ +# Script to start "requestsync" on the device +# +base=/system +export CLASSPATH=$base/framework/requestsync.jar +exec app_process $base/bin com.android.commands.requestsync.RequestSync "$@" + diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java new file mode 100644 index 000000000000..808618f28666 --- /dev/null +++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java @@ -0,0 +1,237 @@ +/* +** +** Copyright 2012, 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.requestsync; + +import android.accounts.Account; +import android.content.ContentResolver; +import android.os.Bundle; + +import java.net.URISyntaxException; + +public class RequestSync { + // agr parsing fields + private String[] mArgs; + private int mNextArg; + private String mCurArgData; + + // account & authority + private String mAccountName = null; + private String mAccountType = null; + private String mAuthority = null; + + // extras + private Bundle mExtras = new Bundle(); + + /** + * Command-line entry point. + * + * @param args The command-line arguments + */ + public static void main(String[] args) { + try { + (new RequestSync()).run(args); + } catch (IllegalArgumentException e) { + showUsage(); + System.err.println("Error: " + e); + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(System.err); + System.exit(1); + } + } + + private void run(String[] args) throws Exception { + mArgs = args; + mNextArg = 0; + + final boolean ok = parseArgs(); + if (ok) { + final Account account = mAccountName != null && mAccountType != null + ? new Account(mAccountName, mAccountType) : null; + + System.out.printf("Requesting sync for: \n"); + if (account != null) { + System.out.printf(" Account: %s (%s)\n", account.name, account.type); + } else { + System.out.printf(" Account: all\n"); + } + + System.out.printf(" Authority: %s\n", mAuthority != null ? mAuthority : "All"); + + if (mExtras.size() > 0) { + System.out.printf(" Extras:\n"); + for (String key : mExtras.keySet()) { + System.out.printf(" %s: %s\n", key, mExtras.get(key)); + } + } + + ContentResolver.requestSync(account, mAuthority, mExtras); + } + } + + private boolean parseArgs() throws URISyntaxException { + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-h") || opt.equals("--help")) { + showUsage(); + return false; + } else if (opt.equals("-n") || opt.equals("--account-name")) { + mAccountName = nextArgRequired(); + } else if (opt.equals("-t") || opt.equals("--account-type")) { + mAccountType = nextArgRequired(); + } else if (opt.equals("-a") || opt.equals("--authority")) { + mAuthority = nextArgRequired(); + } else if (opt.equals("--is") || opt.equals("--ignore-settings")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, true); + } else if (opt.equals("--ib") || opt.equals("--ignore-backoff")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, true); + } else if (opt.equals("--dd") || opt.equals("--discard-deletions")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS, true); + } else if (opt.equals("--nr") || opt.equals("--no-retry")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, true); + } else if (opt.equals("--ex") || opt.equals("--expedited")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true); + } else if (opt.equals("-i") || opt.equals("--initialize")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, true); + } else if (opt.equals("-m") || opt.equals("--manual")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); + } else if (opt.equals("--od") || opt.equals("--override-deletions")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS, true); + } else if (opt.equals("-u") || opt.equals("--upload-only")) { + mExtras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true); + } else if (opt.equals("-e") || opt.equals("--es") || opt.equals("--extra-string")) { + final String key = nextArgRequired(); + final String value = nextArgRequired(); + mExtras.putString(key, value); + } else if (opt.equals("--esn") || opt.equals("--extra-string-null")) { + final String key = nextArgRequired(); + mExtras.putString(key, null); + } else if (opt.equals("--ei") || opt.equals("--extra-int")) { + final String key = nextArgRequired(); + final String value = nextArgRequired(); + mExtras.putInt(key, Integer.valueOf(value)); + } else if (opt.equals("--el") || opt.equals("--extra-long")) { + final String key = nextArgRequired(); + final String value = nextArgRequired(); + mExtras.putLong(key, Long.valueOf(value)); + } else if (opt.equals("--ef") || opt.equals("--extra-float")) { + final String key = nextArgRequired(); + final String value = nextArgRequired(); + mExtras.putFloat(key, Long.valueOf(value)); + } else if (opt.equals("--ed") || opt.equals("--extra-double")) { + final String key = nextArgRequired(); + final String value = nextArgRequired(); + mExtras.putFloat(key, Long.valueOf(value)); + } else if (opt.equals("--ez") || opt.equals("--extra-bool")) { + final String key = nextArgRequired(); + final String value = nextArgRequired(); + mExtras.putBoolean(key, Boolean.valueOf(value)); + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return false; + } + } + + if (mNextArg < mArgs.length) { + showUsage(); + return false; + } + 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: requestsync [options]\n" + + "With no options, a sync will be requested for all account and all sync\n" + + "authorities with no extras. Options can be:\n" + + " -h|--help: Display this message\n" + + " -n|--account-name <ACCOUNT-NAME>\n" + + " -t|--account-type <ACCOUNT-TYPE>\n" + + " -a|--authority <AUTHORITY>\n" + + " Add ContentResolver extras:\n" + + " --is|--ignore-settings: Add SYNC_EXTRAS_IGNORE_SETTINGS\n" + + " --ib|--ignore-backoff: Add SYNC_EXTRAS_IGNORE_BACKOFF\n" + + " --dd|--discard-deletions: Add SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS\n" + + " --nr|--no-retry: Add SYNC_EXTRAS_DO_NOT_RETRY\n" + + " --ex|--expedited: Add SYNC_EXTRAS_EXPEDITED\n" + + " --i|--initialize: Add SYNC_EXTRAS_INITIALIZE\n" + + " --m|--manual: Add SYNC_EXTRAS_MANUAL\n" + + " --od|--override-deletions: Add SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS\n" + + " --u|--upload-only: Add SYNC_EXTRAS_UPLOAD\n" + + " Add custom extras:\n" + + " -e|--es|--extra-string <KEY> <VALUE>\n" + + " --esn|--extra-string-null <KEY>\n" + + " --ei|--extra-int <KEY> <VALUE>\n" + + " --el|--extra-long <KEY> <VALUE>\n" + + " --ef|--extra-float <KEY> <VALUE>\n" + + " --ed|--extra-double <KEY> <VALUE>\n" + + " --ez|--extra-bool <KEY> <VALUE>\n" + ); + } +} diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index bee5880ac4cc..46e41e3d476e 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -24,7 +24,7 @@ #include <sys/mman.h> #include <binder/IMemory.h> -#include <surfaceflinger/SurfaceComposerClient.h> +#include <gui/SurfaceComposerClient.h> #include <SkImageEncoder.h> #include <SkBitmap.h> @@ -49,7 +49,6 @@ static SkBitmap::Config flinger2skia(PixelFormat f) { switch (f) { case PIXEL_FORMAT_A_8: - case PIXEL_FORMAT_L_8: return SkBitmap::kA8_Config; case PIXEL_FORMAT_RGB_565: return SkBitmap::kRGB_565_Config; diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk index ea80c7d85dc8..8840867a9dfa 100644 --- a/cmds/servicemanager/Android.mk +++ b/cmds/servicemanager/Android.mk @@ -9,7 +9,4 @@ include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES := liblog LOCAL_SRC_FILES := service_manager.c binder.c LOCAL_MODULE := servicemanager -ifeq ($(BOARD_USE_LVMX),true) - LOCAL_CFLAGS += -DLVMX -endif include $(BUILD_EXECUTABLE) diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c index 918d4d4e9633..1985756a669f 100644 --- a/cmds/servicemanager/binder.c +++ b/cmds/servicemanager/binder.c @@ -412,7 +412,7 @@ void bio_init(struct binder_io *bio, void *data, return; } - bio->data = bio->data0 = data + n; + bio->data = bio->data0 = (char *) data + n; bio->offs = bio->offs0 = data; bio->data_avail = maxdata - n; bio->offs_avail = maxoffs; diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c index 42d8977339ee..71c5622ec382 100644 --- a/cmds/servicemanager/service_manager.c +++ b/cmds/servicemanager/service_manager.c @@ -27,9 +27,6 @@ static struct { unsigned uid; const char *name; } allowed[] = { -#ifdef LVMX - { AID_MEDIA, "com.lifevibes.mx.ipc" }, -#endif { AID_MEDIA, "media.audio_flinger" }, { AID_MEDIA, "media.player" }, { AID_MEDIA, "media.camera" }, @@ -46,6 +43,8 @@ static struct { { AID_RADIO, "isms" }, { AID_RADIO, "iphonesubinfo" }, { AID_RADIO, "simphonebook" }, + { AID_MEDIA, "common_time.clock" }, + { AID_MEDIA, "common_time.config" }, }; void *svcmgr_handle; @@ -93,6 +92,7 @@ struct svcinfo struct svcinfo *next; void *ptr; struct binder_death death; + int allow_isolated; unsigned len; uint16_t name[0]; }; @@ -128,13 +128,21 @@ uint16_t svcmgr_id[] = { }; -void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len) +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; @@ -143,10 +151,11 @@ void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len) int do_add_service(struct binder_state *bs, uint16_t *s, unsigned len, - void *ptr, unsigned uid) + void *ptr, unsigned uid, int allow_isolated) { struct svcinfo *si; -// ALOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid); + //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; @@ -178,6 +187,7 @@ int do_add_service(struct binder_state *bs, si->name[len] = '\0'; si->death.func = svcinfo_death; si->death.ptr = si; + si->allow_isolated = allow_isolated; si->next = svclist; svclist = si; } @@ -197,6 +207,7 @@ int svcmgr_handler(struct binder_state *bs, 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); @@ -220,7 +231,7 @@ int svcmgr_handler(struct binder_state *bs, case SVC_MGR_GET_SERVICE: case SVC_MGR_CHECK_SERVICE: s = bio_get_string16(msg, &len); - ptr = do_find_service(bs, s, len); + ptr = do_find_service(bs, s, len, txn->sender_euid); if (!ptr) break; bio_put_ref(reply, ptr); @@ -229,7 +240,8 @@ int svcmgr_handler(struct binder_state *bs, case SVC_MGR_ADD_SERVICE: s = bio_get_string16(msg, &len); ptr = bio_get_ref(msg); - if (do_add_service(bs, s, len, ptr, txn->sender_euid)) + allow_isolated = bio_get_uint32(msg) ? 1 : 0; + if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated)) return -1; break; diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk deleted file mode 100644 index e9642f7cc8c5..000000000000 --- a/cmds/stagefright/Android.mk +++ /dev/null @@ -1,150 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - stagefright.cpp \ - SineSource.cpp - -LOCAL_SHARED_LIBRARIES := \ - libstagefright libmedia libutils libbinder libstagefright_foundation \ - libskia libgui - -LOCAL_C_INCLUDES:= \ - $(JNI_H_INCLUDE) \ - frameworks/base/media/libstagefright \ - frameworks/base/media/libstagefright/include \ - $(TOP)/frameworks/base/include/media/stagefright/openmax \ - external/skia/include/core \ - external/skia/include/images \ - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_MODULE_TAGS := debug - -LOCAL_MODULE:= stagefright - -include $(BUILD_EXECUTABLE) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - SineSource.cpp \ - record.cpp - -LOCAL_SHARED_LIBRARIES := \ - libstagefright liblog libutils libbinder - -LOCAL_C_INCLUDES:= \ - $(JNI_H_INCLUDE) \ - frameworks/base/media/libstagefright \ - $(TOP)/frameworks/base/include/media/stagefright/openmax - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_MODULE_TAGS := debug - -LOCAL_MODULE:= record - -include $(BUILD_EXECUTABLE) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - SineSource.cpp \ - recordvideo.cpp - -LOCAL_SHARED_LIBRARIES := \ - libstagefright liblog libutils libbinder - -LOCAL_C_INCLUDES:= \ - $(JNI_H_INCLUDE) \ - frameworks/base/media/libstagefright \ - $(TOP)/frameworks/base/include/media/stagefright/openmax - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_MODULE_TAGS := debug - -LOCAL_MODULE:= recordvideo - -include $(BUILD_EXECUTABLE) - - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - SineSource.cpp \ - audioloop.cpp - -LOCAL_SHARED_LIBRARIES := \ - libstagefright liblog libutils libbinder - -LOCAL_C_INCLUDES:= \ - $(JNI_H_INCLUDE) \ - frameworks/base/media/libstagefright \ - $(TOP)/frameworks/base/include/media/stagefright/openmax - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_MODULE_TAGS := debug - -LOCAL_MODULE:= audioloop - -include $(BUILD_EXECUTABLE) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - stream.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libstagefright liblog libutils libbinder libgui \ - libstagefright_foundation libmedia - -LOCAL_C_INCLUDES:= \ - $(JNI_H_INCLUDE) \ - frameworks/base/media/libstagefright \ - $(TOP)/frameworks/base/include/media/stagefright/openmax - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_MODULE_TAGS := debug - -LOCAL_MODULE:= stream - -include $(BUILD_EXECUTABLE) - -################################################################################ - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - sf2.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libstagefright liblog libutils libbinder libstagefright_foundation \ - libmedia libgui libcutils libui - -LOCAL_C_INCLUDES:= \ - $(JNI_H_INCLUDE) \ - frameworks/base/media/libstagefright \ - $(TOP)/frameworks/base/include/media/stagefright/openmax - -LOCAL_CFLAGS += -Wno-multichar - -LOCAL_MODULE_TAGS := debug - -LOCAL_MODULE:= sf2 - -include $(BUILD_EXECUTABLE) - - diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp deleted file mode 100644 index 021f636e2eb0..000000000000 --- a/cmds/stagefright/SineSource.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "SineSource.h" - -#include <math.h> - -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> - -namespace android { - -SineSource::SineSource(int32_t sampleRate, int32_t numChannels) - : mStarted(false), - mSampleRate(sampleRate), - mNumChannels(numChannels), - mPhase(0), - mGroup(NULL) { - CHECK(numChannels == 1 || numChannels == 2); -} - -SineSource::~SineSource() { - if (mStarted) { - stop(); - } -} - -status_t SineSource::start(MetaData *params) { - CHECK(!mStarted); - - mGroup = new MediaBufferGroup; - mGroup->add_buffer(new MediaBuffer(kBufferSize)); - - mPhase = 0; - mStarted = true; - - return OK; -} - -status_t SineSource::stop() { - CHECK(mStarted); - - delete mGroup; - mGroup = NULL; - - mStarted = false; - - return OK; -} - -sp<MetaData> SineSource::getFormat() { - sp<MetaData> meta = new MetaData; - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW); - meta->setInt32(kKeyChannelCount, mNumChannels); - meta->setInt32(kKeySampleRate, mSampleRate); - meta->setInt32(kKeyMaxInputSize, kBufferSize); - - return meta; -} - -status_t SineSource::read( - MediaBuffer **out, const ReadOptions *options) { - *out = NULL; - - MediaBuffer *buffer; - status_t err = mGroup->acquire_buffer(&buffer); - - if (err != OK) { - return err; - } - - size_t frameSize = mNumChannels * sizeof(int16_t); - size_t numFramesPerBuffer = buffer->size() / frameSize; - - int16_t *ptr = (int16_t *)buffer->data(); - - const double k = kFrequency / mSampleRate * (2.0 * M_PI); - - double x = mPhase * k; - for (size_t i = 0; i < numFramesPerBuffer; ++i) { - int16_t amplitude = (int16_t)(32767.0 * sin(x)); - - *ptr++ = amplitude; - if (mNumChannels == 2) { - *ptr++ = amplitude; - } - - x += k; - } - - buffer->meta_data()->setInt64( - kKeyTime, ((int64_t)mPhase * 1000000) / mSampleRate); - - mPhase += numFramesPerBuffer; - - buffer->set_range(0, numFramesPerBuffer * frameSize); - - *out = buffer; - - return OK; -} - -} // namespace android diff --git a/cmds/stagefright/SineSource.h b/cmds/stagefright/SineSource.h deleted file mode 100644 index 76ab669fbfc6..000000000000 --- a/cmds/stagefright/SineSource.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SINE_SOURCE_H_ - -#define SINE_SOURCE_H_ - -#include <media/stagefright/MediaSource.h> - -namespace android { - -struct MediaBufferGroup; - -struct SineSource : public MediaSource { - SineSource(int32_t sampleRate, int32_t numChannels); - - virtual status_t start(MetaData *params); - virtual status_t stop(); - - virtual sp<MetaData> getFormat(); - - virtual status_t read( - MediaBuffer **out, const ReadOptions *options = NULL); - -protected: - virtual ~SineSource(); - -private: - enum { kBufferSize = 8192 }; - static const double kFrequency = 500.0; - - bool mStarted; - int32_t mSampleRate; - int32_t mNumChannels; - size_t mPhase; - - MediaBufferGroup *mGroup; -}; - -} // namespace android - -#endif // SINE_SOURCE_H_ diff --git a/cmds/stagefright/WaveWriter.h b/cmds/stagefright/WaveWriter.h deleted file mode 100644 index a0eb66e2b9bc..000000000000 --- a/cmds/stagefright/WaveWriter.h +++ /dev/null @@ -1,71 +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. - */ - -#ifndef ANDROID_WAVEWRITER_H_ - -#define ANDROID_WAVEWRITER_H_ - -namespace android { - -class WaveWriter { -public: - WaveWriter(const char *filename, - uint16_t num_channels, uint32_t sampling_rate) - : mFile(fopen(filename, "wb")), - mTotalBytes(0) { - fwrite("RIFFxxxxWAVEfmt \x10\x00\x00\x00\x01\x00", 1, 22, mFile); - write_u16(num_channels); - write_u32(sampling_rate); - write_u32(sampling_rate * num_channels * 2); - write_u16(num_channels * 2); - write_u16(16); - fwrite("dataxxxx", 1, 8, mFile); - } - - ~WaveWriter() { - fseek(mFile, 40, SEEK_SET); - write_u32(mTotalBytes); - - fseek(mFile, 4, SEEK_SET); - write_u32(36 + mTotalBytes); - - fclose(mFile); - mFile = NULL; - } - - void Append(const void *data, size_t size) { - fwrite(data, 1, size, mFile); - mTotalBytes += size; - } - -private: - void write_u16(uint16_t x) { - fputc(x & 0xff, mFile); - fputc(x >> 8, mFile); - } - - void write_u32(uint32_t x) { - write_u16(x & 0xffff); - write_u16(x >> 16); - } - - FILE *mFile; - size_t mTotalBytes; -}; - -} // namespace android - -#endif // ANDROID_WAVEWRITER_H_ diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp deleted file mode 100644 index 858681f6ce45..000000000000 --- a/cmds/stagefright/audioloop.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "SineSource.h" - -#include <binder/ProcessState.h> -#include <media/mediarecorder.h> -#include <media/stagefright/AMRWriter.h> -#include <media/stagefright/AudioPlayer.h> -#include <media/stagefright/AudioSource.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/OMXClient.h> -#include <media/stagefright/OMXCodec.h> - -#include <system/audio.h> - -using namespace android; - -int main() { - // We only have an AMR-WB encoder on sholes... - static bool outputWBAMR = false; - static const int32_t kSampleRate = outputWBAMR ? 16000 : 8000; - static const int32_t kNumChannels = 1; - - android::ProcessState::self()->startThreadPool(); - - OMXClient client; - CHECK_EQ(client.connect(), OK); - -#if 0 - sp<MediaSource> source = new SineSource(kSampleRate, kNumChannels); -#else - sp<MediaSource> source = new AudioSource( - AUDIO_SOURCE_DEFAULT, - kSampleRate, - kNumChannels == 1 - ? AUDIO_CHANNEL_IN_MONO - : AUDIO_CHANNEL_IN_STEREO); -#endif - - sp<MetaData> meta = new MetaData; - - meta->setCString( - kKeyMIMEType, - outputWBAMR ? MEDIA_MIMETYPE_AUDIO_AMR_WB - : MEDIA_MIMETYPE_AUDIO_AMR_NB); - - meta->setInt32(kKeyChannelCount, kNumChannels); - meta->setInt32(kKeySampleRate, kSampleRate); - - int32_t maxInputSize; - if (source->getFormat()->findInt32(kKeyMaxInputSize, &maxInputSize)) { - meta->setInt32(kKeyMaxInputSize, maxInputSize); - } - - sp<MediaSource> encoder = OMXCodec::Create( - client.interface(), - meta, true /* createEncoder */, - source); - -#if 1 - sp<AMRWriter> writer = new AMRWriter("/sdcard/out.amr"); - writer->addSource(encoder); - writer->start(); - sleep(10); - writer->stop(); -#else - sp<MediaSource> decoder = OMXCodec::Create( - client.interface(), - meta, false /* createEncoder */, - encoder); - -#if 0 - AudioPlayer *player = new AudioPlayer(NULL); - player->setSource(decoder); - - player->start(); - - sleep(10); - - player->stop(); - - delete player; - player = NULL; -#elif 0 - CHECK_EQ(decoder->start(), OK); - - MediaBuffer *buffer; - while (decoder->read(&buffer) == OK) { - // do something with buffer - - putchar('.'); - fflush(stdout); - - buffer->release(); - buffer = NULL; - } - - CHECK_EQ(decoder->stop(), OK); -#endif -#endif - - return 0; -} diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp deleted file mode 100644 index 613435df15e8..000000000000 --- a/cmds/stagefright/record.cpp +++ /dev/null @@ -1,354 +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 "SineSource.h" - -#include <binder/ProcessState.h> -#include <media/stagefright/AudioPlayer.h> -#include <media/stagefright/CameraSource.h> -#include <media/stagefright/FileSource.h> -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/MediaExtractor.h> -#include <media/stagefright/MPEG4Writer.h> -#include <media/stagefright/OMXClient.h> -#include <media/stagefright/OMXCodec.h> -#include <media/MediaPlayerInterface.h> - -using namespace android; - -static const int32_t kFramerate = 24; // fps -static const int32_t kIFramesIntervalSec = 1; -static const int32_t kVideoBitRate = 512 * 1024; -static const int32_t kAudioBitRate = 12200; -static const int64_t kDurationUs = 10000000LL; // 10 seconds - -#if 1 -class DummySource : public MediaSource { - -public: - DummySource(int width, int height, int colorFormat) - : mWidth(width), - mHeight(height), - mColorFormat(colorFormat), - mSize((width * height * 3) / 2) { - mGroup.add_buffer(new MediaBuffer(mSize)); - - // Check the color format to make sure - // that the buffer size mSize it set correctly above. - CHECK(colorFormat == OMX_COLOR_FormatYUV420SemiPlanar || - colorFormat == OMX_COLOR_FormatYUV420Planar); - } - - virtual sp<MetaData> getFormat() { - sp<MetaData> meta = new MetaData; - meta->setInt32(kKeyWidth, mWidth); - meta->setInt32(kKeyHeight, mHeight); - meta->setInt32(kKeyColorFormat, mColorFormat); - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - - return meta; - } - - virtual status_t start(MetaData *params) { - mNumFramesOutput = 0; - return OK; - } - - virtual status_t stop() { - return OK; - } - - virtual status_t read( - MediaBuffer **buffer, const MediaSource::ReadOptions *options) { - if (mNumFramesOutput == kFramerate * 10) { - // Stop returning data after 10 secs. - return ERROR_END_OF_STREAM; - } - - // printf("DummySource::read\n"); - status_t err = mGroup.acquire_buffer(buffer); - if (err != OK) { - return err; - } - - char x = (char)((double)rand() / RAND_MAX * 255); - memset((*buffer)->data(), x, mSize); - (*buffer)->set_range(0, mSize); - (*buffer)->meta_data()->clear(); - (*buffer)->meta_data()->setInt64( - kKeyTime, (mNumFramesOutput * 1000000) / kFramerate); - ++mNumFramesOutput; - - // printf("DummySource::read - returning buffer\n"); - // ALOGI("DummySource::read - returning buffer"); - return OK; - } - -protected: - virtual ~DummySource() {} - -private: - MediaBufferGroup mGroup; - int mWidth, mHeight; - int mColorFormat; - size_t mSize; - int64_t mNumFramesOutput;; - - DummySource(const DummySource &); - DummySource &operator=(const DummySource &); -}; - -sp<MediaSource> createSource(const char *filename) { - sp<MediaSource> source; - - sp<MediaExtractor> extractor = - MediaExtractor::Create(new FileSource(filename)); - if (extractor == NULL) { - return NULL; - } - - size_t num_tracks = extractor->countTracks(); - - sp<MetaData> meta; - for (size_t i = 0; i < num_tracks; ++i) { - meta = extractor->getTrackMetaData(i); - CHECK(meta.get() != NULL); - - const char *mime; - if (!meta->findCString(kKeyMIMEType, &mime)) { - continue; - } - - if (strncasecmp(mime, "video/", 6)) { - continue; - } - - source = extractor->getTrack(i); - break; - } - - return source; -} - -enum { - kYUV420SP = 0, - kYUV420P = 1, -}; - -// returns -1 if mapping of the given color is unsuccessful -// returns an omx color enum value otherwise -static int translateColorToOmxEnumValue(int color) { - switch (color) { - case kYUV420SP: - return OMX_COLOR_FormatYUV420SemiPlanar; - case kYUV420P: - return OMX_COLOR_FormatYUV420Planar; - default: - fprintf(stderr, "Unsupported color: %d\n", color); - return -1; - } -} - -int main(int argc, char **argv) { - android::ProcessState::self()->startThreadPool(); - - DataSource::RegisterDefaultSniffers(); - -#if 1 - if (argc != 3) { - fprintf(stderr, "usage: %s <filename> <input_color_format>\n", argv[0]); - fprintf(stderr, " <input_color_format>: 0 (YUV420SP) or 1 (YUV420P)\n"); - return 1; - } - - int colorFormat = translateColorToOmxEnumValue(atoi(argv[2])); - if (colorFormat == -1) { - fprintf(stderr, "input color format must be 0 (YUV420SP) or 1 (YUV420P)\n"); - return 1; - } - OMXClient client; - CHECK_EQ(client.connect(), OK); - - status_t err = OK; - -#if 0 - sp<MediaSource> source = createSource(argv[1]); - - if (source == NULL) { - fprintf(stderr, "Unable to find a suitable video track.\n"); - return 1; - } - - sp<MetaData> meta = source->getFormat(); - - sp<MediaSource> decoder = OMXCodec::Create( - client.interface(), meta, false /* createEncoder */, source); - - int width, height; - bool success = meta->findInt32(kKeyWidth, &width); - success = success && meta->findInt32(kKeyHeight, &height); - CHECK(success); -#else - int width = 720; - int height = 480; - sp<MediaSource> decoder = new DummySource(width, height, colorFormat); -#endif - - sp<MetaData> enc_meta = new MetaData; - // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); - // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); - enc_meta->setInt32(kKeyWidth, width); - enc_meta->setInt32(kKeyHeight, height); - enc_meta->setInt32(kKeySampleRate, kFramerate); - enc_meta->setInt32(kKeyBitRate, kVideoBitRate); - enc_meta->setInt32(kKeyStride, width); - enc_meta->setInt32(kKeySliceHeight, height); - enc_meta->setInt32(kKeyIFramesInterval, kIFramesIntervalSec); - enc_meta->setInt32(kKeyColorFormat, colorFormat); - - sp<MediaSource> encoder = - OMXCodec::Create( - client.interface(), enc_meta, true /* createEncoder */, decoder); - -#if 1 - sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4"); - writer->addSource(encoder); - writer->setMaxFileDuration(kDurationUs); - CHECK_EQ(OK, writer->start()); - while (!writer->reachedEOS()) { - fprintf(stderr, "."); - usleep(100000); - } - err = writer->stop(); -#else - CHECK_EQ(OK, encoder->start()); - - MediaBuffer *buffer; - while (encoder->read(&buffer) == OK) { - printf("."); - fflush(stdout); - int32_t isSync; - if (!buffer->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)) { - isSync = false; - } - - printf("got an output frame of size %d%s\n", buffer->range_length(), - isSync ? " (SYNC)" : ""); - - buffer->release(); - buffer = NULL; - } - - err = encoder->stop(); -#endif - - printf("$\n"); - client.disconnect(); -#endif - -#if 0 - CameraSource *source = CameraSource::Create(); - source->start(); - - printf("source = %p\n", source); - - for (int i = 0; i < 100; ++i) { - MediaBuffer *buffer; - status_t err = source->read(&buffer); - CHECK_EQ(err, OK); - - printf("got a frame, data=%p, size=%d\n", - buffer->data(), buffer->range_length()); - - buffer->release(); - buffer = NULL; - } - - err = source->stop(); - - delete source; - source = NULL; -#endif - - if (err != OK && err != ERROR_END_OF_STREAM) { - fprintf(stderr, "record failed: %d\n", err); - return 1; - } - return 0; -} -#else - -int main(int argc, char **argv) { - android::ProcessState::self()->startThreadPool(); - - OMXClient client; - CHECK_EQ(client.connect(), OK); - - const int32_t kSampleRate = 22050; - const int32_t kNumChannels = 2; - sp<MediaSource> audioSource = new SineSource(kSampleRate, kNumChannels); - -#if 0 - sp<MediaPlayerBase::AudioSink> audioSink; - AudioPlayer *player = new AudioPlayer(audioSink); - player->setSource(audioSource); - player->start(); - - sleep(10); - - player->stop(); -#endif - - sp<MetaData> encMeta = new MetaData; - encMeta->setCString(kKeyMIMEType, - 1 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC); - encMeta->setInt32(kKeySampleRate, kSampleRate); - encMeta->setInt32(kKeyChannelCount, kNumChannels); - encMeta->setInt32(kKeyMaxInputSize, 8192); - encMeta->setInt32(kKeyBitRate, kAudioBitRate); - - sp<MediaSource> encoder = - OMXCodec::Create(client.interface(), encMeta, true, audioSource); - - encoder->start(); - - int32_t n = 0; - status_t err; - MediaBuffer *buffer; - while ((err = encoder->read(&buffer)) == OK) { - printf("."); - fflush(stdout); - - buffer->release(); - buffer = NULL; - - if (++n == 100) { - break; - } - } - printf("$\n"); - - encoder->stop(); - - client.disconnect(); - - return 0; -} -#endif diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp deleted file mode 100644 index c40228631ae2..000000000000 --- a/cmds/stagefright/recordvideo.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "SineSource.h" - -#include <binder/ProcessState.h> -#include <media/stagefright/AudioPlayer.h> -#include <media/stagefright/MediaBufferGroup.h> -#include <media/stagefright/MediaDebug.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/MPEG4Writer.h> -#include <media/stagefright/OMXClient.h> -#include <media/stagefright/OMXCodec.h> -#include <media/MediaPlayerInterface.h> - -using namespace android; - -// Print usage showing how to use this utility to record videos -static void usage(const char *me) { - fprintf(stderr, "usage: %s\n", me); - fprintf(stderr, " -h(elp)\n"); - fprintf(stderr, " -b bit rate in bits per second (default: 300000)\n"); - fprintf(stderr, " -c YUV420 color format: [0] semi planar or [1] planar or other omx YUV420 color format (default: 1)\n"); - fprintf(stderr, " -f frame rate in frames per second (default: 30)\n"); - fprintf(stderr, " -i I frame interval in seconds (default: 1)\n"); - fprintf(stderr, " -n number of frames to be recorded (default: 300)\n"); - fprintf(stderr, " -w width in pixels (default: 176)\n"); - fprintf(stderr, " -t height in pixels (default: 144)\n"); - fprintf(stderr, " -l encoder level. see omx il header (default: encoder specific)\n"); - fprintf(stderr, " -p encoder profile. see omx il header (default: encoder specific)\n"); - fprintf(stderr, " -v video codec: [0] AVC [1] M4V [2] H263 (default: 0)\n"); - fprintf(stderr, "The output file is /sdcard/output.mp4\n"); - exit(1); -} - -class DummySource : public MediaSource { - -public: - DummySource(int width, int height, int nFrames, int fps, int colorFormat) - : mWidth(width), - mHeight(height), - mMaxNumFrames(nFrames), - mFrameRate(fps), - mColorFormat(colorFormat), - mSize((width * height * 3) / 2) { - - mGroup.add_buffer(new MediaBuffer(mSize)); - } - - virtual sp<MetaData> getFormat() { - sp<MetaData> meta = new MetaData; - meta->setInt32(kKeyWidth, mWidth); - meta->setInt32(kKeyHeight, mHeight); - meta->setInt32(kKeyColorFormat, mColorFormat); - meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); - - return meta; - } - - virtual status_t start(MetaData *params) { - mNumFramesOutput = 0; - return OK; - } - - virtual status_t stop() { - return OK; - } - - virtual status_t read( - MediaBuffer **buffer, const MediaSource::ReadOptions *options) { - - if (mNumFramesOutput % 10 == 0) { - fprintf(stderr, "."); - } - if (mNumFramesOutput == mMaxNumFrames) { - return ERROR_END_OF_STREAM; - } - - status_t err = mGroup.acquire_buffer(buffer); - if (err != OK) { - return err; - } - - // We don't care about the contents. we just test video encoder - // Also, by skipping the content generation, we can return from - // read() much faster. - //char x = (char)((double)rand() / RAND_MAX * 255); - //memset((*buffer)->data(), x, mSize); - (*buffer)->set_range(0, mSize); - (*buffer)->meta_data()->clear(); - (*buffer)->meta_data()->setInt64( - kKeyTime, (mNumFramesOutput * 1000000) / mFrameRate); - ++mNumFramesOutput; - - return OK; - } - -protected: - virtual ~DummySource() {} - -private: - MediaBufferGroup mGroup; - int mWidth, mHeight; - int mMaxNumFrames; - int mFrameRate; - int mColorFormat; - size_t mSize; - int64_t mNumFramesOutput;; - - DummySource(const DummySource &); - DummySource &operator=(const DummySource &); -}; - -enum { - kYUV420SP = 0, - kYUV420P = 1, -}; - -// returns -1 if mapping of the given color is unsuccessful -// returns an omx color enum value otherwise -static int translateColorToOmxEnumValue(int color) { - switch (color) { - case kYUV420SP: - return OMX_COLOR_FormatYUV420SemiPlanar; - case kYUV420P: - return OMX_COLOR_FormatYUV420Planar; - default: - fprintf(stderr, "Custom OMX color format: %d\n", color); - if (color == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar || - color == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) { - return color; - } - } - return -1; -} - -int main(int argc, char **argv) { - - // Default values for the program if not overwritten - int frameRateFps = 30; - int width = 176; - int height = 144; - int bitRateBps = 300000; - int iFramesIntervalSeconds = 1; - int colorFormat = OMX_COLOR_FormatYUV420Planar; - int nFrames = 300; - int level = -1; // Encoder specific default - int profile = -1; // Encoder specific default - int codec = 0; - const char *fileName = "/sdcard/output.mp4"; - - android::ProcessState::self()->startThreadPool(); - int res; - while ((res = getopt(argc, argv, "b:c:f:i:n:w:t:l:p:v:h")) >= 0) { - switch (res) { - case 'b': - { - bitRateBps = atoi(optarg); - break; - } - - case 'c': - { - colorFormat = translateColorToOmxEnumValue(atoi(optarg)); - if (colorFormat == -1) { - usage(argv[0]); - } - break; - } - - case 'f': - { - frameRateFps = atoi(optarg); - break; - } - - case 'i': - { - iFramesIntervalSeconds = atoi(optarg); - break; - } - - case 'n': - { - nFrames = atoi(optarg); - break; - } - - case 'w': - { - width = atoi(optarg); - break; - } - - case 't': - { - height = atoi(optarg); - break; - } - - case 'l': - { - level = atoi(optarg); - break; - } - - case 'p': - { - profile = atoi(optarg); - break; - } - - case 'v': - { - codec = atoi(optarg); - if (codec < 0 || codec > 2) { - usage(argv[0]); - } - break; - } - - case 'h': - default: - { - usage(argv[0]); - break; - } - } - } - - OMXClient client; - CHECK_EQ(client.connect(), OK); - - status_t err = OK; - sp<MediaSource> source = - new DummySource(width, height, nFrames, frameRateFps, colorFormat); - - sp<MetaData> enc_meta = new MetaData; - switch (codec) { - case 1: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); - break; - case 2: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263); - break; - default: - enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); - break; - } - enc_meta->setInt32(kKeyWidth, width); - enc_meta->setInt32(kKeyHeight, height); - enc_meta->setInt32(kKeyFrameRate, frameRateFps); - enc_meta->setInt32(kKeyBitRate, bitRateBps); - enc_meta->setInt32(kKeyStride, width); - enc_meta->setInt32(kKeySliceHeight, height); - enc_meta->setInt32(kKeyIFramesInterval, iFramesIntervalSeconds); - enc_meta->setInt32(kKeyColorFormat, colorFormat); - if (level != -1) { - enc_meta->setInt32(kKeyVideoLevel, level); - } - if (profile != -1) { - enc_meta->setInt32(kKeyVideoProfile, profile); - } - - sp<MediaSource> encoder = - OMXCodec::Create( - client.interface(), enc_meta, true /* createEncoder */, source); - - sp<MPEG4Writer> writer = new MPEG4Writer(fileName); - writer->addSource(encoder); - int64_t start = systemTime(); - CHECK_EQ(OK, writer->start()); - while (!writer->reachedEOS()) { - } - err = writer->stop(); - int64_t end = systemTime(); - - fprintf(stderr, "$\n"); - client.disconnect(); - - if (err != OK && err != ERROR_END_OF_STREAM) { - fprintf(stderr, "record failed: %d\n", err); - return 1; - } - fprintf(stderr, "encoding %d frames in %lld us\n", nFrames, (end-start)/1000); - fprintf(stderr, "encoding speed is: %.2f fps\n", (nFrames * 1E9) / (end-start)); - return 0; -} diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp deleted file mode 100644 index ae80f8804992..000000000000 --- a/cmds/stagefright/sf2.cpp +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Copyright (C) 2010 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 <binder/ProcessState.h> - -#include <media/stagefright/foundation/hexdump.h> -#include <media/stagefright/foundation/ABuffer.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/ALooper.h> -#include <media/stagefright/foundation/AMessage.h> - -#include <media/stagefright/ACodec.h> -#include <media/stagefright/DataSource.h> -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaExtractor.h> -#include <media/stagefright/MediaSource.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/NativeWindowWrapper.h> -#include <media/stagefright/Utils.h> - -#include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/SurfaceComposerClient.h> - -#include "include/ESDS.h" - -using namespace android; - -struct Controller : public AHandler { - Controller(const char *uri, bool decodeAudio, - const sp<Surface> &surface, bool renderToSurface) - : mURI(uri), - mDecodeAudio(decodeAudio), - mSurface(surface), - mRenderToSurface(renderToSurface), - mCodec(new ACodec), - mIsVorbis(false) { - CHECK(!mDecodeAudio || mSurface == NULL); - } - - void startAsync() { - (new AMessage(kWhatStart, id()))->post(); - } - -protected: - virtual ~Controller() { - } - - virtual void onMessageReceived(const sp<AMessage> &msg) { - switch (msg->what()) { - case kWhatStart: - { -#if 1 - mDecodeLooper = looper(); -#else - mDecodeLooper = new ALooper; - mDecodeLooper->setName("sf2 decode looper"); - mDecodeLooper->start(); -#endif - - sp<DataSource> dataSource = - DataSource::CreateFromURI(mURI.c_str()); - - sp<MediaExtractor> extractor = - MediaExtractor::Create(dataSource); - - for (size_t i = 0; i < extractor->countTracks(); ++i) { - sp<MetaData> meta = extractor->getTrackMetaData(i); - - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - if (!strncasecmp(mDecodeAudio ? "audio/" : "video/", - mime, 6)) { - mSource = extractor->getTrack(i); - - if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) { - mIsVorbis = true; - } else { - mIsVorbis = false; - } - break; - } - } - CHECK(mSource != NULL); - - CHECK_EQ(mSource->start(), (status_t)OK); - - mDecodeLooper->registerHandler(mCodec); - - mCodec->setNotificationMessage( - new AMessage(kWhatCodecNotify, id())); - - sp<AMessage> format = makeFormat(mSource->getFormat()); - - if (mSurface != NULL) { - format->setObject( - "native-window", new NativeWindowWrapper(mSurface)); - } - - mCodec->initiateSetup(format); - - mCSDIndex = 0; - mStartTimeUs = ALooper::GetNowUs(); - mNumOutputBuffersReceived = 0; - mTotalBytesReceived = 0; - mLeftOverBuffer = NULL; - mFinalResult = OK; - mSeekState = SEEK_NONE; - - // (new AMessage(kWhatSeek, id()))->post(5000000ll); - break; - } - - case kWhatSeek: - { - printf("+"); - fflush(stdout); - - CHECK(mSeekState == SEEK_NONE - || mSeekState == SEEK_FLUSH_COMPLETED); - - if (mLeftOverBuffer != NULL) { - mLeftOverBuffer->release(); - mLeftOverBuffer = NULL; - } - - mSeekState = SEEK_FLUSHING; - mSeekTimeUs = 30000000ll; - - mCodec->signalFlush(); - break; - } - - case kWhatStop: - { - if (mLeftOverBuffer != NULL) { - mLeftOverBuffer->release(); - mLeftOverBuffer = NULL; - } - - CHECK_EQ(mSource->stop(), (status_t)OK); - mSource.clear(); - - mCodec->initiateShutdown(); - break; - } - - case kWhatCodecNotify: - { - int32_t what; - CHECK(msg->findInt32("what", &what)); - - if (what == ACodec::kWhatFillThisBuffer) { - onFillThisBuffer(msg); - } else if (what == ACodec::kWhatDrainThisBuffer) { - if ((mNumOutputBuffersReceived++ % 16) == 0) { - printf("."); - fflush(stdout); - } - - onDrainThisBuffer(msg); - } else if (what == ACodec::kWhatEOS) { - printf("$\n"); - - int64_t delayUs = ALooper::GetNowUs() - mStartTimeUs; - - if (mDecodeAudio) { - printf("%lld bytes received. %.2f KB/sec\n", - mTotalBytesReceived, - mTotalBytesReceived * 1E6 / 1024 / delayUs); - } else { - printf("%d frames decoded, %.2f fps. %lld bytes " - "received. %.2f KB/sec\n", - mNumOutputBuffersReceived, - mNumOutputBuffersReceived * 1E6 / delayUs, - mTotalBytesReceived, - mTotalBytesReceived * 1E6 / 1024 / delayUs); - } - - (new AMessage(kWhatStop, id()))->post(); - } else if (what == ACodec::kWhatFlushCompleted) { - mSeekState = SEEK_FLUSH_COMPLETED; - mCodec->signalResume(); - - (new AMessage(kWhatSeek, id()))->post(5000000ll); - } else if (what == ACodec::kWhatOutputFormatChanged) { - } else { - CHECK_EQ(what, (int32_t)ACodec::kWhatShutdownCompleted); - - mDecodeLooper->unregisterHandler(mCodec->id()); - - if (mDecodeLooper != looper()) { - mDecodeLooper->stop(); - } - - looper()->stop(); - } - break; - } - - default: - TRESPASS(); - break; - } - } - -private: - enum { - kWhatStart = 'strt', - kWhatStop = 'stop', - kWhatCodecNotify = 'noti', - kWhatSeek = 'seek', - }; - - sp<ALooper> mDecodeLooper; - - AString mURI; - bool mDecodeAudio; - sp<Surface> mSurface; - bool mRenderToSurface; - sp<ACodec> mCodec; - sp<MediaSource> mSource; - bool mIsVorbis; - - Vector<sp<ABuffer> > mCSD; - size_t mCSDIndex; - - MediaBuffer *mLeftOverBuffer; - status_t mFinalResult; - - int64_t mStartTimeUs; - int32_t mNumOutputBuffersReceived; - int64_t mTotalBytesReceived; - - enum SeekState { - SEEK_NONE, - SEEK_FLUSHING, - SEEK_FLUSH_COMPLETED, - }; - SeekState mSeekState; - int64_t mSeekTimeUs; - - sp<AMessage> makeFormat(const sp<MetaData> &meta) { - CHECK(mCSD.isEmpty()); - - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - sp<AMessage> msg = new AMessage; - msg->setString("mime", mime); - - if (!strncasecmp("video/", mime, 6)) { - int32_t width, height; - CHECK(meta->findInt32(kKeyWidth, &width)); - CHECK(meta->findInt32(kKeyHeight, &height)); - - msg->setInt32("width", width); - msg->setInt32("height", height); - } else { - CHECK(!strncasecmp("audio/", mime, 6)); - - int32_t numChannels, sampleRate; - CHECK(meta->findInt32(kKeyChannelCount, &numChannels)); - CHECK(meta->findInt32(kKeySampleRate, &sampleRate)); - - msg->setInt32("channel-count", numChannels); - msg->setInt32("sample-rate", sampleRate); - } - - uint32_t type; - const void *data; - size_t size; - if (meta->findData(kKeyAVCC, &type, &data, &size)) { - // Parse the AVCDecoderConfigurationRecord - - const uint8_t *ptr = (const uint8_t *)data; - - CHECK(size >= 7); - CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 - uint8_t profile = ptr[1]; - uint8_t level = ptr[3]; - - // There is decodable content out there that fails the following - // assertion, let's be lenient for now... - // CHECK((ptr[4] >> 2) == 0x3f); // reserved - - size_t lengthSize = 1 + (ptr[4] & 3); - - // commented out check below as H264_QVGA_500_NO_AUDIO.3gp - // violates it... - // CHECK((ptr[5] >> 5) == 7); // reserved - - size_t numSeqParameterSets = ptr[5] & 31; - - ptr += 6; - size -= 6; - - sp<ABuffer> buffer = new ABuffer(1024); - buffer->setRange(0, 0); - - for (size_t i = 0; i < numSeqParameterSets; ++i) { - CHECK(size >= 2); - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - CHECK(size >= length); - - memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4); - memcpy(buffer->data() + buffer->size() + 4, ptr, length); - buffer->setRange(0, buffer->size() + 4 + length); - - ptr += length; - size -= length; - } - - buffer->meta()->setInt32("csd", true); - mCSD.push(buffer); - - buffer = new ABuffer(1024); - buffer->setRange(0, 0); - - CHECK(size >= 1); - size_t numPictureParameterSets = *ptr; - ++ptr; - --size; - - for (size_t i = 0; i < numPictureParameterSets; ++i) { - CHECK(size >= 2); - size_t length = U16_AT(ptr); - - ptr += 2; - size -= 2; - - CHECK(size >= length); - - memcpy(buffer->data() + buffer->size(), "\x00\x00\x00\x01", 4); - memcpy(buffer->data() + buffer->size() + 4, ptr, length); - buffer->setRange(0, buffer->size() + 4 + length); - - ptr += length; - size -= length; - } - - buffer->meta()->setInt32("csd", true); - mCSD.push(buffer); - - msg->setObject("csd", buffer); - } else if (meta->findData(kKeyESDS, &type, &data, &size)) { - ESDS esds((const char *)data, size); - CHECK_EQ(esds.InitCheck(), (status_t)OK); - - const void *codec_specific_data; - size_t codec_specific_data_size; - esds.getCodecSpecificInfo( - &codec_specific_data, &codec_specific_data_size); - - sp<ABuffer> buffer = new ABuffer(codec_specific_data_size); - - memcpy(buffer->data(), codec_specific_data, - codec_specific_data_size); - - buffer->meta()->setInt32("csd", true); - mCSD.push(buffer); - } else if (meta->findData(kKeyVorbisInfo, &type, &data, &size)) { - sp<ABuffer> buffer = new ABuffer(size); - memcpy(buffer->data(), data, size); - - buffer->meta()->setInt32("csd", true); - mCSD.push(buffer); - - CHECK(meta->findData(kKeyVorbisBooks, &type, &data, &size)); - - buffer = new ABuffer(size); - memcpy(buffer->data(), data, size); - - buffer->meta()->setInt32("csd", true); - mCSD.push(buffer); - } - - int32_t maxInputSize; - if (meta->findInt32(kKeyMaxInputSize, &maxInputSize)) { - msg->setInt32("max-input-size", maxInputSize); - } - - return msg; - } - - void onFillThisBuffer(const sp<AMessage> &msg) { - sp<AMessage> reply; - CHECK(msg->findMessage("reply", &reply)); - - if (mSeekState == SEEK_FLUSHING) { - reply->post(); - return; - } - - sp<RefBase> obj; - CHECK(msg->findObject("buffer", &obj)); - sp<ABuffer> outBuffer = static_cast<ABuffer *>(obj.get()); - - if (mCSDIndex < mCSD.size()) { - outBuffer = mCSD.editItemAt(mCSDIndex++); - outBuffer->meta()->setInt64("timeUs", 0); - } else { - size_t sizeLeft = outBuffer->capacity(); - outBuffer->setRange(0, 0); - - int32_t n = 0; - - for (;;) { - MediaBuffer *inBuffer; - - if (mLeftOverBuffer != NULL) { - inBuffer = mLeftOverBuffer; - mLeftOverBuffer = NULL; - } else if (mFinalResult != OK) { - break; - } else { - MediaSource::ReadOptions options; - if (mSeekState == SEEK_FLUSH_COMPLETED) { - options.setSeekTo(mSeekTimeUs); - mSeekState = SEEK_NONE; - } - status_t err = mSource->read(&inBuffer, &options); - - if (err != OK) { - mFinalResult = err; - break; - } - } - - size_t sizeNeeded = inBuffer->range_length(); - if (mIsVorbis) { - // Vorbis data is suffixed with the number of - // valid samples on the page. - sizeNeeded += sizeof(int32_t); - } - - if (sizeNeeded > sizeLeft) { - if (outBuffer->size() == 0) { - ALOGE("Unable to fit even a single input buffer of size %d.", - sizeNeeded); - } - CHECK_GT(outBuffer->size(), 0u); - - mLeftOverBuffer = inBuffer; - break; - } - - ++n; - - if (outBuffer->size() == 0) { - int64_t timeUs; - CHECK(inBuffer->meta_data()->findInt64(kKeyTime, &timeUs)); - - outBuffer->meta()->setInt64("timeUs", timeUs); - } - - memcpy(outBuffer->data() + outBuffer->size(), - (const uint8_t *)inBuffer->data() - + inBuffer->range_offset(), - inBuffer->range_length()); - - if (mIsVorbis) { - int32_t numPageSamples; - if (!inBuffer->meta_data()->findInt32( - kKeyValidSamples, &numPageSamples)) { - numPageSamples = -1; - } - - memcpy(outBuffer->data() - + outBuffer->size() + inBuffer->range_length(), - &numPageSamples, sizeof(numPageSamples)); - } - - outBuffer->setRange( - 0, outBuffer->size() + sizeNeeded); - - sizeLeft -= sizeNeeded; - - inBuffer->release(); - inBuffer = NULL; - - break; // Don't coalesce - } - - ALOGV("coalesced %d input buffers", n); - - if (outBuffer->size() == 0) { - CHECK_NE(mFinalResult, (status_t)OK); - - reply->setInt32("err", mFinalResult); - reply->post(); - return; - } - } - - reply->setObject("buffer", outBuffer); - reply->post(); - } - - void onDrainThisBuffer(const sp<AMessage> &msg) { - sp<RefBase> obj; - CHECK(msg->findObject("buffer", &obj)); - - sp<ABuffer> buffer = static_cast<ABuffer *>(obj.get()); - mTotalBytesReceived += buffer->size(); - - sp<AMessage> reply; - CHECK(msg->findMessage("reply", &reply)); - - if (mRenderToSurface) { - reply->setInt32("render", 1); - } - - reply->post(); - } - - DISALLOW_EVIL_CONSTRUCTORS(Controller); -}; - -static void usage(const char *me) { - fprintf(stderr, "usage: %s\n", me); - fprintf(stderr, " -h(elp)\n"); - fprintf(stderr, " -a(udio)\n"); - - fprintf(stderr, - " -S(urface) Allocate output buffers on a surface.\n" - " -R(ender) Render surface-allocated buffers.\n"); -} - -int main(int argc, char **argv) { - android::ProcessState::self()->startThreadPool(); - - bool decodeAudio = false; - bool useSurface = false; - bool renderToSurface = false; - - int res; - while ((res = getopt(argc, argv, "haSR")) >= 0) { - switch (res) { - case 'a': - decodeAudio = true; - break; - - case 'S': - useSurface = true; - break; - - case 'R': - renderToSurface = true; - break; - - case '?': - case 'h': - default: - { - usage(argv[0]); - return 1; - } - } - } - - argc -= optind; - argv += optind; - - if (argc != 1) { - usage(argv[-optind]); - return 1; - } - - DataSource::RegisterDefaultSniffers(); - - sp<ALooper> looper = new ALooper; - looper->setName("sf2"); - - sp<SurfaceComposerClient> composerClient; - sp<SurfaceControl> control; - sp<Surface> surface; - - if (!decodeAudio && useSurface) { - composerClient = new SurfaceComposerClient; - CHECK_EQ(composerClient->initCheck(), (status_t)OK); - - control = composerClient->createSurface( - String8("A Surface"), - 0, - 1280, - 800, - PIXEL_FORMAT_RGB_565, - 0); - - CHECK(control != NULL); - CHECK(control->isValid()); - - SurfaceComposerClient::openGlobalTransaction(); - CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK); - CHECK_EQ(control->show(), (status_t)OK); - SurfaceComposerClient::closeGlobalTransaction(); - - surface = control->getSurface(); - CHECK(surface != NULL); - - CHECK_EQ((status_t)OK, - native_window_api_connect( - surface.get(), NATIVE_WINDOW_API_MEDIA)); - } - - sp<Controller> controller = - new Controller(argv[0], decodeAudio, surface, renderToSurface); - - looper->registerHandler(controller); - - controller->startAsync(); - - CHECK_EQ(looper->start(true /* runOnCallingThread */), (status_t)OK); - - looper->unregisterHandler(controller->id()); - - if (!decodeAudio && useSurface) { - CHECK_EQ((status_t)OK, - native_window_api_disconnect( - surface.get(), NATIVE_WINDOW_API_MEDIA)); - - composerClient->dispose(); - } - - return 0; -} - diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp deleted file mode 100644 index 7cb8f62e62f3..000000000000 --- a/cmds/stagefright/stagefright.cpp +++ /dev/null @@ -1,1118 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "stagefright" -#include <media/stagefright/foundation/ADebug.h> - -#include <sys/time.h> - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include "SineSource.h" - -#include <binder/IServiceManager.h> -#include <binder/ProcessState.h> -#include <media/IMediaPlayerService.h> -#include <media/stagefright/foundation/ALooper.h> -#include "include/LiveSession.h" -#include "include/NuCachedSource2.h" -#include <media/stagefright/AudioPlayer.h> -#include <media/stagefright/DataSource.h> -#include <media/stagefright/JPEGSource.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MediaExtractor.h> -#include <media/stagefright/MediaSource.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/OMXClient.h> -#include <media/stagefright/OMXCodec.h> -#include <media/mediametadataretriever.h> - -#include <media/stagefright/foundation/hexdump.h> -#include <media/stagefright/MPEG2TSWriter.h> -#include <media/stagefright/MPEG4Writer.h> - -#include <private/media/VideoFrame.h> -#include <SkBitmap.h> -#include <SkImageEncoder.h> - -#include <fcntl.h> - -#include <gui/SurfaceTextureClient.h> - -#include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/SurfaceComposerClient.h> - -using namespace android; - -static long gNumRepetitions; -static long gMaxNumFrames; // 0 means decode all available. -static long gReproduceBug; // if not -1. -static bool gPreferSoftwareCodec; -static bool gForceToUseHardwareCodec; -static bool gPlaybackAudio; -static bool gWriteMP4; -static bool gDisplayHistogram; -static String8 gWriteMP4Filename; - -static sp<ANativeWindow> gSurface; - -static int64_t getNowUs() { - struct timeval tv; - gettimeofday(&tv, NULL); - - return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll; -} - -static int CompareIncreasing(const int64_t *a, const int64_t *b) { - return (*a) < (*b) ? -1 : (*a) > (*b) ? 1 : 0; -} - -static void displayDecodeHistogram(Vector<int64_t> *decodeTimesUs) { - printf("decode times:\n"); - - decodeTimesUs->sort(CompareIncreasing); - - size_t n = decodeTimesUs->size(); - int64_t minUs = decodeTimesUs->itemAt(0); - int64_t maxUs = decodeTimesUs->itemAt(n - 1); - - printf("min decode time %lld us (%.2f secs)\n", minUs, minUs / 1E6); - printf("max decode time %lld us (%.2f secs)\n", maxUs, maxUs / 1E6); - - size_t counts[100]; - for (size_t i = 0; i < 100; ++i) { - counts[i] = 0; - } - - for (size_t i = 0; i < n; ++i) { - int64_t x = decodeTimesUs->itemAt(i); - - size_t slot = ((x - minUs) * 100) / (maxUs - minUs); - if (slot == 100) { slot = 99; } - - ++counts[slot]; - } - - for (size_t i = 0; i < 100; ++i) { - int64_t slotUs = minUs + (i * (maxUs - minUs) / 100); - - double fps = 1E6 / slotUs; - printf("[%.2f fps]: %d\n", fps, counts[i]); - } -} - -static void displayAVCProfileLevelIfPossible(const sp<MetaData>& meta) { - uint32_t type; - const void *data; - size_t size; - if (meta->findData(kKeyAVCC, &type, &data, &size)) { - const uint8_t *ptr = (const uint8_t *)data; - CHECK(size >= 7); - CHECK(ptr[0] == 1); // configurationVersion == 1 - uint8_t profile = ptr[1]; - uint8_t level = ptr[3]; - fprintf(stderr, "AVC video profile %d and level %d\n", profile, level); - } -} - -static void dumpSource(const sp<MediaSource> &source, const String8 &filename) { - FILE *out = fopen(filename.string(), "wb"); - - CHECK_EQ((status_t)OK, source->start()); - - status_t err; - for (;;) { - MediaBuffer *mbuf; - err = source->read(&mbuf); - - if (err == INFO_FORMAT_CHANGED) { - continue; - } else if (err != OK) { - break; - } - - CHECK_EQ( - fwrite((const uint8_t *)mbuf->data() + mbuf->range_offset(), - 1, - mbuf->range_length(), - out), - (ssize_t)mbuf->range_length()); - - mbuf->release(); - mbuf = NULL; - } - - CHECK_EQ((status_t)OK, source->stop()); - - fclose(out); - out = NULL; -} - -static void playSource(OMXClient *client, sp<MediaSource> &source) { - sp<MetaData> meta = source->getFormat(); - - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - sp<MediaSource> rawSource; - if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) { - rawSource = source; - } else { - int flags = 0; - if (gPreferSoftwareCodec) { - flags |= OMXCodec::kPreferSoftwareCodecs; - } - if (gForceToUseHardwareCodec) { - CHECK(!gPreferSoftwareCodec); - flags |= OMXCodec::kHardwareCodecsOnly; - } - rawSource = OMXCodec::Create( - client->interface(), meta, false /* createEncoder */, source, - NULL /* matchComponentName */, - flags, - gSurface); - - if (rawSource == NULL) { - fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime); - return; - } - displayAVCProfileLevelIfPossible(meta); - } - - source.clear(); - - status_t err = rawSource->start(); - - if (err != OK) { - fprintf(stderr, "rawSource returned error %d (0x%08x)\n", err, err); - return; - } - - if (gPlaybackAudio) { - AudioPlayer *player = new AudioPlayer(NULL); - player->setSource(rawSource); - rawSource.clear(); - - player->start(true /* sourceAlreadyStarted */); - - status_t finalStatus; - while (!player->reachedEOS(&finalStatus)) { - usleep(100000ll); - } - - delete player; - player = NULL; - - return; - } else if (gReproduceBug >= 3 && gReproduceBug <= 5) { - int64_t durationUs; - CHECK(meta->findInt64(kKeyDuration, &durationUs)); - - status_t err; - MediaBuffer *buffer; - MediaSource::ReadOptions options; - int64_t seekTimeUs = -1; - for (;;) { - err = rawSource->read(&buffer, &options); - options.clearSeekTo(); - - bool shouldSeek = false; - if (err == INFO_FORMAT_CHANGED) { - CHECK(buffer == NULL); - - printf("format changed.\n"); - continue; - } else if (err != OK) { - printf("reached EOF.\n"); - - shouldSeek = true; - } else { - int64_t timestampUs; - CHECK(buffer->meta_data()->findInt64(kKeyTime, ×tampUs)); - - bool failed = false; - - if (seekTimeUs >= 0) { - int64_t diff = timestampUs - seekTimeUs; - - if (diff < 0) { - diff = -diff; - } - - if ((gReproduceBug == 4 && diff > 500000) - || (gReproduceBug == 5 && timestampUs < 0)) { - printf("wanted: %.2f secs, got: %.2f secs\n", - seekTimeUs / 1E6, timestampUs / 1E6); - - printf("ERROR: "); - failed = true; - } - } - - printf("buffer has timestamp %lld us (%.2f secs)\n", - timestampUs, timestampUs / 1E6); - - buffer->release(); - buffer = NULL; - - if (failed) { - break; - } - - shouldSeek = ((double)rand() / RAND_MAX) < 0.1; - - if (gReproduceBug == 3) { - shouldSeek = false; - } - } - - seekTimeUs = -1; - - if (shouldSeek) { - seekTimeUs = (rand() * (float)durationUs) / RAND_MAX; - options.setSeekTo(seekTimeUs); - - printf("seeking to %lld us (%.2f secs)\n", - seekTimeUs, seekTimeUs / 1E6); - } - } - - rawSource->stop(); - - return; - } - - int n = 0; - int64_t startTime = getNowUs(); - - long numIterationsLeft = gNumRepetitions; - MediaSource::ReadOptions options; - - int64_t sumDecodeUs = 0; - int64_t totalBytes = 0; - - Vector<int64_t> decodeTimesUs; - - while (numIterationsLeft-- > 0) { - long numFrames = 0; - - MediaBuffer *buffer; - - for (;;) { - int64_t startDecodeUs = getNowUs(); - status_t err = rawSource->read(&buffer, &options); - int64_t delayDecodeUs = getNowUs() - startDecodeUs; - - options.clearSeekTo(); - - if (err != OK) { - CHECK(buffer == NULL); - - if (err == INFO_FORMAT_CHANGED) { - printf("format changed.\n"); - continue; - } - - break; - } - - if (buffer->range_length() > 0) { - if (gDisplayHistogram && n > 0) { - // Ignore the first time since it includes some setup - // cost. - decodeTimesUs.push(delayDecodeUs); - } - - if ((n++ % 16) == 0) { - printf("."); - fflush(stdout); - } - } - - sumDecodeUs += delayDecodeUs; - totalBytes += buffer->range_length(); - - buffer->release(); - buffer = NULL; - - ++numFrames; - if (gMaxNumFrames > 0 && numFrames == gMaxNumFrames) { - break; - } - - if (gReproduceBug == 1 && numFrames == 40) { - printf("seeking past the end now."); - options.setSeekTo(0x7fffffffL); - } else if (gReproduceBug == 2 && numFrames == 40) { - printf("seeking to 5 secs."); - options.setSeekTo(5000000); - } - } - - printf("$"); - fflush(stdout); - - options.setSeekTo(0); - } - - rawSource->stop(); - printf("\n"); - - int64_t delay = getNowUs() - startTime; - if (!strncasecmp("video/", mime, 6)) { - printf("avg. %.2f fps\n", n * 1E6 / delay); - - printf("avg. time to decode one buffer %.2f usecs\n", - (double)sumDecodeUs / n); - - printf("decoded a total of %d frame(s).\n", n); - - if (gDisplayHistogram) { - displayDecodeHistogram(&decodeTimesUs); - } - } else if (!strncasecmp("audio/", mime, 6)) { - // Frame count makes less sense for audio, as the output buffer - // sizes may be different across decoders. - printf("avg. %.2f KB/sec\n", totalBytes / 1024 * 1E6 / delay); - - printf("decoded a total of %lld bytes\n", totalBytes); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -struct DetectSyncSource : public MediaSource { - DetectSyncSource(const sp<MediaSource> &source); - - virtual status_t start(MetaData *params = NULL); - virtual status_t stop(); - virtual sp<MetaData> getFormat(); - - virtual status_t read( - MediaBuffer **buffer, const ReadOptions *options); - -private: - enum StreamType { - AVC, - MPEG4, - H263, - OTHER, - }; - - sp<MediaSource> mSource; - StreamType mStreamType; - bool mSawFirstIDRFrame; - - DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource); -}; - -DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source) - : mSource(source), - mStreamType(OTHER), - mSawFirstIDRFrame(false) { - const char *mime; - CHECK(mSource->getFormat()->findCString(kKeyMIMEType, &mime)); - - if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) { - mStreamType = AVC; - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) { - mStreamType = MPEG4; - CHECK(!"sync frame detection not implemented yet for MPEG4"); - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_H263)) { - mStreamType = H263; - CHECK(!"sync frame detection not implemented yet for H.263"); - } -} - -status_t DetectSyncSource::start(MetaData *params) { - mSawFirstIDRFrame = false; - - return mSource->start(params); -} - -status_t DetectSyncSource::stop() { - return mSource->stop(); -} - -sp<MetaData> DetectSyncSource::getFormat() { - return mSource->getFormat(); -} - -static bool isIDRFrame(MediaBuffer *buffer) { - const uint8_t *data = - (const uint8_t *)buffer->data() + buffer->range_offset(); - size_t size = buffer->range_length(); - for (size_t i = 0; i + 3 < size; ++i) { - if (!memcmp("\x00\x00\x01", &data[i], 3)) { - uint8_t nalType = data[i + 3] & 0x1f; - if (nalType == 5) { - return true; - } - } - } - - return false; -} - -status_t DetectSyncSource::read( - MediaBuffer **buffer, const ReadOptions *options) { - for (;;) { - status_t err = mSource->read(buffer, options); - - if (err != OK) { - return err; - } - - if (mStreamType == AVC) { - bool isIDR = isIDRFrame(*buffer); - (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, isIDR); - if (isIDR) { - mSawFirstIDRFrame = true; - } - } else { - (*buffer)->meta_data()->setInt32(kKeyIsSyncFrame, true); - } - - if (mStreamType != AVC || mSawFirstIDRFrame) { - break; - } - - // Ignore everything up to the first IDR frame. - (*buffer)->release(); - *buffer = NULL; - } - - return OK; -} - -//////////////////////////////////////////////////////////////////////////////// - -static void writeSourcesToMP4( - Vector<sp<MediaSource> > &sources, bool syncInfoPresent) { -#if 0 - sp<MPEG4Writer> writer = - new MPEG4Writer(gWriteMP4Filename.string()); -#else - sp<MPEG2TSWriter> writer = - new MPEG2TSWriter(gWriteMP4Filename.string()); -#endif - - // at most one minute. - writer->setMaxFileDuration(60000000ll); - - for (size_t i = 0; i < sources.size(); ++i) { - sp<MediaSource> source = sources.editItemAt(i); - - CHECK_EQ(writer->addSource( - syncInfoPresent ? source : new DetectSyncSource(source)), - (status_t)OK); - } - - sp<MetaData> params = new MetaData; - params->setInt32(kKeyNotRealTime, true); - CHECK_EQ(writer->start(params.get()), (status_t)OK); - - while (!writer->reachedEOS()) { - usleep(100000); - } - writer->stop(); -} - -static void performSeekTest(const sp<MediaSource> &source) { - CHECK_EQ((status_t)OK, source->start()); - - int64_t durationUs; - CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs)); - - for (int64_t seekTimeUs = 0; seekTimeUs <= durationUs; - seekTimeUs += 60000ll) { - MediaSource::ReadOptions options; - options.setSeekTo( - seekTimeUs, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); - - MediaBuffer *buffer; - status_t err; - for (;;) { - err = source->read(&buffer, &options); - - options.clearSeekTo(); - - if (err == INFO_FORMAT_CHANGED) { - CHECK(buffer == NULL); - continue; - } - - if (err != OK) { - CHECK(buffer == NULL); - break; - } - - if (buffer->range_length() > 0) { - break; - } - - CHECK(buffer != NULL); - - buffer->release(); - buffer = NULL; - } - - if (err == OK) { - int64_t timeUs; - CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs)); - - printf("%lld\t%lld\t%lld\n", seekTimeUs, timeUs, seekTimeUs - timeUs); - - buffer->release(); - buffer = NULL; - } else { - printf("ERROR\n"); - break; - } - } - - CHECK_EQ((status_t)OK, source->stop()); -} - -static void usage(const char *me) { - fprintf(stderr, "usage: %s\n", me); - fprintf(stderr, " -h(elp)\n"); - fprintf(stderr, " -a(udio)\n"); - fprintf(stderr, " -n repetitions\n"); - fprintf(stderr, " -l(ist) components\n"); - fprintf(stderr, " -m max-number-of-frames-to-decode in each pass\n"); - fprintf(stderr, " -b bug to reproduce\n"); - fprintf(stderr, " -p(rofiles) dump decoder profiles supported\n"); - fprintf(stderr, " -t(humbnail) extract video thumbnail or album art\n"); - fprintf(stderr, " -s(oftware) prefer software codec\n"); - fprintf(stderr, " -r(hardware) force to use hardware codec\n"); - fprintf(stderr, " -o playback audio\n"); - fprintf(stderr, " -w(rite) filename (write to .mp4 file)\n"); - fprintf(stderr, " -k seek test\n"); - fprintf(stderr, " -x display a histogram of decoding times/fps " - "(video only)\n"); - fprintf(stderr, " -S allocate buffers from a surface\n"); - fprintf(stderr, " -T allocate buffers from a surface texture\n"); - fprintf(stderr, " -d(ump) filename (raw stream data to a file)\n"); -} - -int main(int argc, char **argv) { - android::ProcessState::self()->startThreadPool(); - - bool audioOnly = false; - bool listComponents = false; - bool dumpProfiles = false; - bool extractThumbnail = false; - bool seekTest = false; - bool useSurfaceAlloc = false; - bool useSurfaceTexAlloc = false; - bool dumpStream = false; - String8 dumpStreamFilename; - gNumRepetitions = 1; - gMaxNumFrames = 0; - gReproduceBug = -1; - gPreferSoftwareCodec = false; - gForceToUseHardwareCodec = false; - gPlaybackAudio = false; - gWriteMP4 = false; - gDisplayHistogram = false; - - sp<ALooper> looper; - sp<LiveSession> liveSession; - - int res; - while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxSTd:")) >= 0) { - switch (res) { - case 'a': - { - audioOnly = true; - break; - } - - case 'd': - { - dumpStream = true; - dumpStreamFilename.setTo(optarg); - break; - } - - case 'l': - { - listComponents = true; - break; - } - - case 'm': - case 'n': - case 'b': - { - char *end; - long x = strtol(optarg, &end, 10); - - if (*end != '\0' || end == optarg || x <= 0) { - x = 1; - } - - if (res == 'n') { - gNumRepetitions = x; - } else if (res == 'm') { - gMaxNumFrames = x; - } else { - CHECK_EQ(res, 'b'); - gReproduceBug = x; - } - break; - } - - case 'w': - { - gWriteMP4 = true; - gWriteMP4Filename.setTo(optarg); - break; - } - - case 'p': - { - dumpProfiles = true; - break; - } - - case 't': - { - extractThumbnail = true; - break; - } - - case 's': - { - gPreferSoftwareCodec = true; - break; - } - - case 'r': - { - gForceToUseHardwareCodec = true; - break; - } - - case 'o': - { - gPlaybackAudio = true; - break; - } - - case 'k': - { - seekTest = true; - break; - } - - case 'x': - { - gDisplayHistogram = true; - break; - } - - case 'S': - { - useSurfaceAlloc = true; - break; - } - - case 'T': - { - useSurfaceTexAlloc = true; - break; - } - - case '?': - case 'h': - default: - { - usage(argv[0]); - exit(1); - break; - } - } - } - - if (gPlaybackAudio && !audioOnly) { - // This doesn't make any sense if we're decoding the video track. - gPlaybackAudio = false; - } - - argc -= optind; - argv += optind; - - if (extractThumbnail) { - sp<IServiceManager> sm = defaultServiceManager(); - sp<IBinder> binder = sm->getService(String16("media.player")); - sp<IMediaPlayerService> service = - interface_cast<IMediaPlayerService>(binder); - - CHECK(service.get() != NULL); - - sp<IMediaMetadataRetriever> retriever = - service->createMetadataRetriever(getpid()); - - CHECK(retriever != NULL); - - for (int k = 0; k < argc; ++k) { - const char *filename = argv[k]; - - bool failed = true; - CHECK_EQ(retriever->setDataSource(filename), (status_t)OK); - sp<IMemory> mem = - retriever->getFrameAtTime(-1, - MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); - - if (mem != NULL) { - failed = false; - printf("getFrameAtTime(%s) => OK\n", filename); - - VideoFrame *frame = (VideoFrame *)mem->pointer(); - - SkBitmap bitmap; - bitmap.setConfig( - SkBitmap::kRGB_565_Config, frame->mWidth, frame->mHeight); - - bitmap.setPixels((uint8_t *)frame + sizeof(VideoFrame)); - - CHECK(SkImageEncoder::EncodeFile( - "/sdcard/out.jpg", bitmap, - SkImageEncoder::kJPEG_Type, - SkImageEncoder::kDefaultQuality)); - } - - { - mem = retriever->extractAlbumArt(); - - if (mem != NULL) { - failed = false; - printf("extractAlbumArt(%s) => OK\n", filename); - } - } - - if (failed) { - printf("both getFrameAtTime and extractAlbumArt " - "failed on file '%s'.\n", filename); - } - } - - return 0; - } - - if (dumpProfiles) { - sp<IServiceManager> sm = defaultServiceManager(); - sp<IBinder> binder = sm->getService(String16("media.player")); - sp<IMediaPlayerService> service = - interface_cast<IMediaPlayerService>(binder); - - CHECK(service.get() != NULL); - - sp<IOMX> omx = service->getOMX(); - CHECK(omx.get() != NULL); - - const char *kMimeTypes[] = { - MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4, - MEDIA_MIMETYPE_VIDEO_H263, MEDIA_MIMETYPE_AUDIO_AAC, - MEDIA_MIMETYPE_AUDIO_AMR_NB, MEDIA_MIMETYPE_AUDIO_AMR_WB, - MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW, - MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS, - MEDIA_MIMETYPE_VIDEO_VPX - }; - - for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]); - ++k) { - printf("type '%s':\n", kMimeTypes[k]); - - Vector<CodecCapabilities> results; - // will retrieve hardware and software codecs - CHECK_EQ(QueryCodecs(omx, kMimeTypes[k], - true, // queryDecoders - &results), (status_t)OK); - - for (size_t i = 0; i < results.size(); ++i) { - printf(" decoder '%s' supports ", - results[i].mComponentName.string()); - - if (results[i].mProfileLevels.size() == 0) { - printf("NOTHING.\n"); - continue; - } - - for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) { - const CodecProfileLevel &profileLevel = - results[i].mProfileLevels[j]; - - printf("%s%ld/%ld", j > 0 ? ", " : "", - profileLevel.mProfile, profileLevel.mLevel); - } - - printf("\n"); - } - } - } - - if (listComponents) { - sp<IServiceManager> sm = defaultServiceManager(); - sp<IBinder> binder = sm->getService(String16("media.player")); - sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); - - CHECK(service.get() != NULL); - - sp<IOMX> omx = service->getOMX(); - CHECK(omx.get() != NULL); - - List<IOMX::ComponentInfo> list; - omx->listNodes(&list); - - for (List<IOMX::ComponentInfo>::iterator it = list.begin(); - it != list.end(); ++it) { - printf("%s\t Roles: ", (*it).mName.string()); - for (List<String8>::iterator itRoles = (*it).mRoles.begin() ; - itRoles != (*it).mRoles.end() ; ++itRoles) { - printf("%s\t", (*itRoles).string()); - } - printf("\n"); - } - } - - sp<SurfaceComposerClient> composerClient; - sp<SurfaceControl> control; - - if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) { - if (useSurfaceAlloc) { - composerClient = new SurfaceComposerClient; - CHECK_EQ(composerClient->initCheck(), (status_t)OK); - - control = composerClient->createSurface( - String8("A Surface"), - 0, - 1280, - 800, - PIXEL_FORMAT_RGB_565, - 0); - - CHECK(control != NULL); - CHECK(control->isValid()); - - SurfaceComposerClient::openGlobalTransaction(); - CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK); - CHECK_EQ(control->show(), (status_t)OK); - SurfaceComposerClient::closeGlobalTransaction(); - - gSurface = control->getSurface(); - CHECK(gSurface != NULL); - } else { - CHECK(useSurfaceTexAlloc); - - sp<SurfaceTexture> texture = new SurfaceTexture(0 /* tex */); - gSurface = new SurfaceTextureClient(texture); - } - - CHECK_EQ((status_t)OK, - native_window_api_connect( - gSurface.get(), NATIVE_WINDOW_API_MEDIA)); - } - - DataSource::RegisterDefaultSniffers(); - - OMXClient client; - status_t err = client.connect(); - - for (int k = 0; k < argc; ++k) { - bool syncInfoPresent = true; - - const char *filename = argv[k]; - - sp<DataSource> dataSource = DataSource::CreateFromURI(filename); - - if (strncasecmp(filename, "sine:", 5) - && strncasecmp(filename, "httplive://", 11) - && dataSource == NULL) { - fprintf(stderr, "Unable to create data source.\n"); - return 1; - } - - bool isJPEG = false; - - size_t len = strlen(filename); - if (len >= 4 && !strcasecmp(filename + len - 4, ".jpg")) { - isJPEG = true; - } - - Vector<sp<MediaSource> > mediaSources; - sp<MediaSource> mediaSource; - - if (isJPEG) { - mediaSource = new JPEGSource(dataSource); - if (gWriteMP4) { - mediaSources.push(mediaSource); - } - } else if (!strncasecmp("sine:", filename, 5)) { - char *end; - long sampleRate = strtol(filename + 5, &end, 10); - - if (end == filename + 5) { - sampleRate = 44100; - } - mediaSource = new SineSource(sampleRate, 1); - if (gWriteMP4) { - mediaSources.push(mediaSource); - } - } else { - sp<MediaExtractor> extractor; - - if (!strncasecmp("httplive://", filename, 11)) { - String8 uri("http://"); - uri.append(filename + 11); - - if (looper == NULL) { - looper = new ALooper; - looper->start(); - } - liveSession = new LiveSession; - looper->registerHandler(liveSession); - - liveSession->connect(uri.string()); - dataSource = liveSession->getDataSource(); - - extractor = - MediaExtractor::Create( - dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS); - - syncInfoPresent = false; - } else { - extractor = MediaExtractor::Create(dataSource); - - if (extractor == NULL) { - fprintf(stderr, "could not create extractor.\n"); - return -1; - } - - sp<MetaData> meta = extractor->getMetaData(); - - if (meta != NULL) { - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) { - syncInfoPresent = false; - } - } - } - - size_t numTracks = extractor->countTracks(); - - if (gWriteMP4) { - bool haveAudio = false; - bool haveVideo = false; - for (size_t i = 0; i < numTracks; ++i) { - sp<MediaSource> source = extractor->getTrack(i); - - const char *mime; - CHECK(source->getFormat()->findCString( - kKeyMIMEType, &mime)); - - bool useTrack = false; - if (!haveAudio && !strncasecmp("audio/", mime, 6)) { - haveAudio = true; - useTrack = true; - } else if (!haveVideo && !strncasecmp("video/", mime, 6)) { - haveVideo = true; - useTrack = true; - } - - if (useTrack) { - mediaSources.push(source); - - if (haveAudio && haveVideo) { - break; - } - } - } - } else { - sp<MetaData> meta; - size_t i; - for (i = 0; i < numTracks; ++i) { - meta = extractor->getTrackMetaData( - i, MediaExtractor::kIncludeExtensiveMetaData); - - const char *mime; - meta->findCString(kKeyMIMEType, &mime); - - if (audioOnly && !strncasecmp(mime, "audio/", 6)) { - break; - } - - if (!audioOnly && !strncasecmp(mime, "video/", 6)) { - break; - } - - meta = NULL; - } - - if (meta == NULL) { - fprintf(stderr, - "No suitable %s track found. The '-a' option will " - "target audio tracks only, the default is to target " - "video tracks only.\n", - audioOnly ? "audio" : "video"); - return -1; - } - - int64_t thumbTimeUs; - if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) { - printf("thumbnailTime: %lld us (%.2f secs)\n", - thumbTimeUs, thumbTimeUs / 1E6); - } - - mediaSource = extractor->getTrack(i); - } - } - - if (gWriteMP4) { - writeSourcesToMP4(mediaSources, syncInfoPresent); - } else if (dumpStream) { - dumpSource(mediaSource, dumpStreamFilename); - } else if (seekTest) { - performSeekTest(mediaSource); - } else { - playSource(&client, mediaSource); - } - } - - if ((useSurfaceAlloc || useSurfaceTexAlloc) && !audioOnly) { - CHECK_EQ((status_t)OK, - native_window_api_disconnect( - gSurface.get(), NATIVE_WINDOW_API_MEDIA)); - - gSurface.clear(); - - if (useSurfaceAlloc) { - composerClient->dispose(); - } - } - - client.disconnect(); - - return 0; -} diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp deleted file mode 100644 index 0d6c738292da..000000000000 --- a/cmds/stagefright/stream.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2010 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_NDEBUG 0 -#define LOG_TAG "stream" -#include "utils/Log.h" - -#include <binder/ProcessState.h> - -#include <media/IStreamSource.h> -#include <media/mediaplayer.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/AMessage.h> -#include <media/stagefright/DataSource.h> -#include <media/stagefright/MPEG2TSWriter.h> -#include <media/stagefright/MediaExtractor.h> -#include <media/stagefright/MediaSource.h> -#include <media/stagefright/MetaData.h> - -#include <binder/IServiceManager.h> -#include <media/IMediaPlayerService.h> -#include <surfaceflinger/ISurfaceComposer.h> -#include <surfaceflinger/SurfaceComposerClient.h> - -#include <fcntl.h> - -using namespace android; - -struct MyStreamSource : public BnStreamSource { - // Object assumes ownership of fd. - MyStreamSource(int fd); - - virtual void setListener(const sp<IStreamListener> &listener); - virtual void setBuffers(const Vector<sp<IMemory> > &buffers); - - virtual void onBufferAvailable(size_t index); - -protected: - virtual ~MyStreamSource(); - -private: - int mFd; - off64_t mFileSize; - uint64_t mNumPacketsSent; - - sp<IStreamListener> mListener; - Vector<sp<IMemory> > mBuffers; - - DISALLOW_EVIL_CONSTRUCTORS(MyStreamSource); -}; - -MyStreamSource::MyStreamSource(int fd) - : mFd(fd), - mFileSize(0), - mNumPacketsSent(0) { - CHECK_GE(fd, 0); - - mFileSize = lseek64(fd, 0, SEEK_END); - lseek64(fd, 0, SEEK_SET); -} - -MyStreamSource::~MyStreamSource() { - close(mFd); - mFd = -1; -} - -void MyStreamSource::setListener(const sp<IStreamListener> &listener) { - mListener = listener; -} - -void MyStreamSource::setBuffers(const Vector<sp<IMemory> > &buffers) { - mBuffers = buffers; -} - -void MyStreamSource::onBufferAvailable(size_t index) { - CHECK_LT(index, mBuffers.size()); - -#if 0 - if (mNumPacketsSent >= 20000) { - ALOGI("signalling discontinuity now"); - - off64_t offset = 0; - CHECK((offset % 188) == 0); - - lseek(mFd, offset, SEEK_SET); - - sp<AMessage> extra = new AMessage; - extra->setInt32(IStreamListener::kKeyFormatChange, 0); - - mListener->issueCommand( - IStreamListener::DISCONTINUITY, false /* synchronous */, extra); - - mNumPacketsSent = 0; - } -#endif - - sp<IMemory> mem = mBuffers.itemAt(index); - - ssize_t n = read(mFd, mem->pointer(), mem->size()); - if (n <= 0) { - mListener->issueCommand(IStreamListener::EOS, false /* synchronous */); - } else { - mListener->queueBuffer(index, n); - - mNumPacketsSent += n / 188; - } -} -//////////////////////////////////////////////////////////////////////////////// - -struct MyConvertingStreamSource : public BnStreamSource { - MyConvertingStreamSource(const char *filename); - - virtual void setListener(const sp<IStreamListener> &listener); - virtual void setBuffers(const Vector<sp<IMemory> > &buffers); - - virtual void onBufferAvailable(size_t index); - -protected: - virtual ~MyConvertingStreamSource(); - -private: - Mutex mLock; - Condition mCondition; - - sp<IStreamListener> mListener; - Vector<sp<IMemory> > mBuffers; - - sp<MPEG2TSWriter> mWriter; - - ssize_t mCurrentBufferIndex; - size_t mCurrentBufferOffset; - - List<size_t> mBufferQueue; - - static ssize_t WriteDataWrapper(void *me, const void *data, size_t size); - ssize_t writeData(const void *data, size_t size); - - DISALLOW_EVIL_CONSTRUCTORS(MyConvertingStreamSource); -}; - -//////////////////////////////////////////////////////////////////////////////// - -MyConvertingStreamSource::MyConvertingStreamSource(const char *filename) - : mCurrentBufferIndex(-1), - mCurrentBufferOffset(0) { - sp<DataSource> dataSource = DataSource::CreateFromURI(filename); - CHECK(dataSource != NULL); - - sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); - CHECK(extractor != NULL); - - mWriter = new MPEG2TSWriter( - this, &MyConvertingStreamSource::WriteDataWrapper); - - for (size_t i = 0; i < extractor->countTracks(); ++i) { - const sp<MetaData> &meta = extractor->getTrackMetaData(i); - - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - if (strncasecmp("video/", mime, 6) && strncasecmp("audio/", mime, 6)) { - continue; - } - - CHECK_EQ(mWriter->addSource(extractor->getTrack(i)), (status_t)OK); - } - - CHECK_EQ(mWriter->start(), (status_t)OK); -} - -MyConvertingStreamSource::~MyConvertingStreamSource() { -} - -void MyConvertingStreamSource::setListener( - const sp<IStreamListener> &listener) { - mListener = listener; -} - -void MyConvertingStreamSource::setBuffers( - const Vector<sp<IMemory> > &buffers) { - mBuffers = buffers; -} - -ssize_t MyConvertingStreamSource::WriteDataWrapper( - void *me, const void *data, size_t size) { - return static_cast<MyConvertingStreamSource *>(me)->writeData(data, size); -} - -ssize_t MyConvertingStreamSource::writeData(const void *data, size_t size) { - size_t totalWritten = 0; - - while (size > 0) { - Mutex::Autolock autoLock(mLock); - - if (mCurrentBufferIndex < 0) { - while (mBufferQueue.empty()) { - mCondition.wait(mLock); - } - - mCurrentBufferIndex = *mBufferQueue.begin(); - mCurrentBufferOffset = 0; - - mBufferQueue.erase(mBufferQueue.begin()); - } - - sp<IMemory> mem = mBuffers.itemAt(mCurrentBufferIndex); - - size_t copy = size; - if (copy + mCurrentBufferOffset > mem->size()) { - copy = mem->size() - mCurrentBufferOffset; - } - - memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy); - mCurrentBufferOffset += copy; - - if (mCurrentBufferOffset == mem->size()) { - mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset); - mCurrentBufferIndex = -1; - } - - data = (const uint8_t *)data + copy; - size -= copy; - - totalWritten += copy; - } - - return (ssize_t)totalWritten; -} - -void MyConvertingStreamSource::onBufferAvailable(size_t index) { - Mutex::Autolock autoLock(mLock); - - mBufferQueue.push_back(index); - mCondition.signal(); - - if (mWriter->reachedEOS()) { - if (mCurrentBufferIndex >= 0) { - mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset); - mCurrentBufferIndex = -1; - } - - mListener->issueCommand(IStreamListener::EOS, false /* synchronous */); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -struct MyClient : public BnMediaPlayerClient { - MyClient() - : mEOS(false) { - } - - virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) { - Mutex::Autolock autoLock(mLock); - - if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) { - mEOS = true; - mCondition.signal(); - } - } - - void waitForEOS() { - Mutex::Autolock autoLock(mLock); - while (!mEOS) { - mCondition.wait(mLock); - } - } - -protected: - virtual ~MyClient() { - } - -private: - Mutex mLock; - Condition mCondition; - - bool mEOS; - - DISALLOW_EVIL_CONSTRUCTORS(MyClient); -}; - -int main(int argc, char **argv) { - android::ProcessState::self()->startThreadPool(); - - DataSource::RegisterDefaultSniffers(); - - if (argc != 2) { - fprintf(stderr, "Usage: %s filename\n", argv[0]); - return 1; - } - - sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient; - CHECK_EQ(composerClient->initCheck(), (status_t)OK); - - ssize_t displayWidth = composerClient->getDisplayWidth(0); - ssize_t displayHeight = composerClient->getDisplayHeight(0); - - ALOGV("display is %d x %d\n", displayWidth, displayHeight); - - sp<SurfaceControl> control = - composerClient->createSurface( - String8("A Surface"), - 0, - displayWidth, - displayHeight, - PIXEL_FORMAT_RGB_565, - 0); - - CHECK(control != NULL); - CHECK(control->isValid()); - - SurfaceComposerClient::openGlobalTransaction(); - CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK); - CHECK_EQ(control->show(), (status_t)OK); - SurfaceComposerClient::closeGlobalTransaction(); - - sp<Surface> surface = control->getSurface(); - CHECK(surface != NULL); - - sp<IServiceManager> sm = defaultServiceManager(); - sp<IBinder> binder = sm->getService(String16("media.player")); - sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); - - CHECK(service.get() != NULL); - - sp<MyClient> client = new MyClient; - - sp<IStreamSource> source; - - size_t len = strlen(argv[1]); - if (len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) { - int fd = open(argv[1], O_RDONLY); - - if (fd < 0) { - fprintf(stderr, "Failed to open file '%s'.", argv[1]); - return 1; - } - - source = new MyStreamSource(fd); - } else { - printf("Converting file to transport stream for streaming...\n"); - - source = new MyConvertingStreamSource(argv[1]); - } - - sp<IMediaPlayer> player = - service->create(getpid(), client, 0); - - if (player != NULL && player->setDataSource(source) == NO_ERROR) { - player->setVideoSurfaceTexture(surface->getSurfaceTexture()); - player->start(); - - client->waitForEOS(); - - player->stop(); - } else { - fprintf(stderr, "failed to instantiate player.\n"); - } - - composerClient->dispose(); - - return 0; -} diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk deleted file mode 100644 index 1df32bbc272d..000000000000 --- a/cmds/surfaceflinger/Android.mk +++ /dev/null @@ -1,17 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - main_surfaceflinger.cpp - -LOCAL_SHARED_LIBRARIES := \ - libsurfaceflinger \ - libbinder \ - libutils - -LOCAL_C_INCLUDES := \ - $(LOCAL_PATH)/../../services/surfaceflinger - -LOCAL_MODULE:= surfaceflinger - -include $(BUILD_EXECUTABLE) diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp deleted file mode 100644 index 78b1007f5e3c..000000000000 --- a/cmds/surfaceflinger/main_surfaceflinger.cpp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2010 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 <binder/BinderService.h> -#include <SurfaceFlinger.h> - -using namespace android; - -int main(int argc, char** argv) { - SurfaceFlinger::publishAndJoinThreadPool(); - return 0; -} diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk index e8afce39f5f1..9f92330aec84 100644 --- a/cmds/system_server/library/Android.mk +++ b/cmds/system_server/library/Android.mk @@ -5,22 +5,17 @@ LOCAL_SRC_FILES:= \ system_init.cpp base = $(LOCAL_PATH)/../../.. +native = $(LOCAL_PATH)/../../../../native LOCAL_C_INCLUDES := \ - $(base)/services/camera/libcameraservice \ - $(base)/services/audioflinger \ - $(base)/services/surfaceflinger \ $(base)/services/sensorservice \ - $(base)/media/libmediaplayerservice \ + $(native)/services/surfaceflinger \ $(JNI_H_INCLUDE) LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ libsensorservice \ libsurfaceflinger \ - libaudioflinger \ - libcameraservice \ - libmediaplayerservice \ libinput \ libutils \ libbinder \ diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp index bfbc13870717..745c34a0478c 100644 --- a/cmds/system_server/library/system_init.cpp +++ b/cmds/system_server/library/system_init.cpp @@ -15,10 +15,6 @@ #include <utils/Log.h> #include <SurfaceFlinger.h> -#include <AudioFlinger.h> -#include <CameraService.h> -#include <AudioPolicyService.h> -#include <MediaPlayerService.h> #include <SensorService.h> #include <android_runtime/AndroidRuntime.h> |