diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-10-21 07:00:00 -0700 |
commit | 54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch) | |
tree | 35051494d2af230dce54d6b31c6af8fc24091316 /cmds | |
download | frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2 |
Initial Contribution
Diffstat (limited to 'cmds')
61 files changed, 7512 insertions, 0 deletions
diff --git a/cmds/am/Android.mk b/cmds/am/Android.mk new file mode 100644 index 0000000..170849d --- /dev/null +++ b/cmds/am/Android.mk @@ -0,0 +1,14 @@ +# Copyright 2008 The Android Open Source Project +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := am +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +ALL_PREBUILT += $(TARGET_OUT)/bin/am +$(TARGET_OUT)/bin/am : $(LOCAL_PATH)/am | $(ACP) + $(transform-prebuilt-to-target) + diff --git a/cmds/am/MODULE_LICENSE_APACHE2 b/cmds/am/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/am/MODULE_LICENSE_APACHE2 diff --git a/cmds/am/NOTICE b/cmds/am/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/am/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/am/am b/cmds/am/am new file mode 100755 index 0000000..a5b13f9 --- /dev/null +++ b/cmds/am/am @@ -0,0 +1,7 @@ +# Script to start "am" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/am.jar +exec app_process $base/bin com.android.commands.am.Am $* + diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java new file mode 100644 index 0000000..b86d40a --- /dev/null +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -0,0 +1,487 @@ +/* +** +** Copyright 2007, 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.am; + +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.IInstrumentationWatcher; +import android.app.Instrumentation; +import android.content.ComponentName; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.view.IWindowManager; + +import java.util.Iterator; +import java.util.Set; + +public class Am { + + private IActivityManager mAm; + private String[] mArgs; + private int mNextArg; + private String mCurArgData; + + private boolean mDebugOption = false; + + /** + * Command-line entry point. + * + * @param args The command-line arguments + */ + public static void main(String[] args) { + (new Am()).run(args); + } + + private void run(String[] args) { + if (args.length < 1) { + showUsage(); + return; + } + + mAm = ActivityManagerNative.getDefault(); + if (mAm == null) { + System.err.println("Error type 2"); + System.err.println("Error: Unable to connect to activity manager; is the system running?"); + showUsage(); + return; + } + + mArgs = args; + + String op = args[0]; + mNextArg = 1; + if (op.equals("start")) { + runStart(); + } else if (op.equals("instrument")) { + runInstrument(); + } else if (op.equals("broadcast")) { + sendBroadcast(); + } else { + System.err.println("Error: Unknown command: " + op); + showUsage(); + return; + } + } + + private Intent makeIntent() { + Intent intent = new Intent(); + boolean hasIntentInfo = false; + + mDebugOption = false; + Uri data = null; + String type = null; + + try { + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-a")) { + intent.setAction(nextOptionData()); + hasIntentInfo = true; + } else if (opt.equals("-d")) { + data = Uri.parse(nextOptionData()); + hasIntentInfo = true; + } else if (opt.equals("-t")) { + type = nextOptionData(); + hasIntentInfo = true; + } else if (opt.equals("-c")) { + intent.addCategory(nextOptionData()); + hasIntentInfo = true; + } else if (opt.equals("-e") || opt.equals("--es")) { + String key = nextOptionData(); + String value = nextOptionData(); + intent.putExtra(key, value); + hasIntentInfo = true; + } else if (opt.equals("--ei")) { + String key = nextOptionData(); + String value = nextOptionData(); + intent.putExtra(key, Integer.valueOf(value)); + hasIntentInfo = true; + } else if (opt.equals("--ez")) { + String key = nextOptionData(); + String value = nextOptionData(); + intent.putExtra(key, Boolean.valueOf(value)); + hasIntentInfo = true; + } else if (opt.equals("-n")) { + String str = nextOptionData(); + ComponentName cn = ComponentName.unflattenFromString(str); + if (cn == null) { + System.err.println("Error: Bad component name: " + str); + showUsage(); + return null; + } + intent.setComponent(cn); + hasIntentInfo = true; + } else if (opt.equals("-f")) { + String str = nextOptionData(); + intent.setFlags(Integer.decode(str).intValue()); + } else if (opt.equals("-D")) { + mDebugOption = true; + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return null; + } + } + } catch (RuntimeException ex) { + System.err.println("Error: " + ex.toString()); + showUsage(); + return null; + } + intent.setDataAndType(data, type); + + String uri = nextArg(); + if (uri != null) { + try { + Intent oldIntent = intent; + try { + intent = Intent.getIntent(uri); + } catch (java.net.URISyntaxException ex) { + System.err.println("Bad URI: " + uri); + showUsage(); + return null; + } + if (oldIntent.getAction() != null) { + intent.setAction(oldIntent.getAction()); + } + if (oldIntent.getData() != null || oldIntent.getType() != null) { + intent.setDataAndType(oldIntent.getData(), oldIntent.getType()); + } + Set cats = oldIntent.getCategories(); + if (cats != null) { + Iterator it = cats.iterator(); + while (it.hasNext()) { + intent.addCategory((String)it.next()); + } + } + } catch (RuntimeException ex) { + System.err.println("Error creating from URI: " + ex.toString()); + showUsage(); + return null; + } + } else if (!hasIntentInfo) { + System.err.println("Error: No intent supplied"); + showUsage(); + return null; + } + + return intent; + } + + private void runStart() { + Intent intent = makeIntent(); + + if (intent != null) { + System.out.println("Starting: " + intent); + try { + intent.addFlags(intent.FLAG_ACTIVITY_NEW_TASK); + // XXX should do something to determine the MIME type. + int res = mAm.startActivity(null, intent, intent.getType(), + null, 0, null, null, 0, false, mDebugOption); + switch (res) { + case IActivityManager.START_SUCCESS: + break; + case IActivityManager.START_CLASS_NOT_FOUND: + System.err.println("Error type 3"); + System.err.println("Error: Activity class " + + intent.getComponent().toShortString() + + " does not exist."); + break; + case IActivityManager.START_DELIVERED_TO_TOP: + System.err.println( + "Warning: Activity not started, intent has " + + "been delivered to currently running " + + "top-most instance."); + break; + case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: + System.err.println( + "Error: Activity not started, you requested to " + + "both forward and receive its result"); + break; + case IActivityManager.START_INTENT_NOT_RESOLVED: + System.err.println( + "Error: Activity not started, unable to " + + "resolve " + intent.toString()); + break; + case IActivityManager.START_RETURN_INTENT_TO_CALLER: + System.err.println( + "Warning: Activity not started because intent " + + "should be handled by the caller"); + break; + case IActivityManager.START_TASK_TO_FRONT: + System.err.println( + "Warning: Activity not started, its current " + + "task has been brought to the front"); + break; + default: + System.err.println( + "Error: Activity not started, unknown error " + + "code " + res); + break; + } + } catch (RemoteException e) { + System.err.println("Error type 1"); + System.err.println( + "Error: Activity not started, unable to " + + "call on to activity manager service"); + } + } + } + + private void sendBroadcast() { + Intent intent = makeIntent(); + + if (intent != null) { + System.out.println("Broadcasting: " + intent); + try { + mAm.broadcastIntent(null, intent, null, null, 0, null, null, + null, true, false); + } catch (RemoteException e) { + } + } + } + + private void runInstrument() { + String profileFile = null; + boolean wait = false; + boolean rawMode = false; + boolean no_window_animation = false; + Bundle args = new Bundle(); + String argKey = null, argValue = null; + IWindowManager wm = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); + + try { + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-p")) { + profileFile = nextOptionData(); + } else if (opt.equals("-w")) { + wait = true; + } else if (opt.equals("-r")) { + rawMode = true; + } else if (opt.equals("-e")) { + argKey = nextOptionData(); + argValue = nextOptionData(); + args.putString(argKey, argValue); + } else if (opt.equals("--no_window_animation")) { + no_window_animation = true; + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return; + } + } + } catch (RuntimeException ex) { + System.err.println("Error: " + ex.toString()); + showUsage(); + return; + } + + String cnArg = nextArg(); + if (cnArg == null) { + System.err.println("Error: No instrumentation component supplied"); + showUsage(); + return; + } + + ComponentName cn = ComponentName.unflattenFromString(cnArg); + if (cn == null) { + System.err.println("Error: Bad component name: " + cnArg); + showUsage(); + return; + } + + InstrumentationWatcher watcher = null; + if (wait) { + watcher = new InstrumentationWatcher(); + watcher.setRawOutput(rawMode); + } + float[] oldAnims = null; + if (no_window_animation) { + try { + oldAnims = wm.getAnimationScales(); + wm.setAnimationScale(0, 0.0f); + wm.setAnimationScale(1, 0.0f); + } catch (RemoteException e) { + } + } + + try { + if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher)) { + System.out.println("INSTRUMENTATION_FAILED: " + + cn.flattenToString()); + showUsage(); + return; + } + } catch (RemoteException e) { + } + + if (watcher != null) { + if (!watcher.waitForFinish()) { + System.out.println("INSTRUMENTATION_ABORTED: System has crashed."); + } + } + + if (oldAnims != null) { + try { + wm.setAnimationScales(oldAnims); + } catch (RemoteException e) { + } + } + } + + private class InstrumentationWatcher extends IInstrumentationWatcher.Stub { + private boolean mFinished = false; + private boolean mRawMode = false; + + /** + * Set or reset "raw mode". In "raw mode", all bundles are dumped. In "pretty mode", + * if a bundle includes Instrumentation.REPORT_KEY_STREAMRESULT, just print that. + * @param rawMode true for raw mode, false for pretty mode. + */ + public void setRawOutput(boolean rawMode) { + mRawMode = rawMode; + } + + public void instrumentationStatus(ComponentName name, int resultCode, Bundle results) { + synchronized (this) { + // pretty printer mode? + String pretty = null; + if (!mRawMode && results != null) { + pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); + } + if (pretty != null) { + System.out.print(pretty); + } else { + if (results != null) { + for (String key : results.keySet()) { + System.out.println( + "INSTRUMENTATION_STATUS: " + key + "=" + results.get(key)); + } + } + System.out.println("INSTRUMENTATION_STATUS_CODE: " + resultCode); + } + notifyAll(); + } + } + + public void instrumentationFinished(ComponentName name, int resultCode, + Bundle results) { + synchronized (this) { + // pretty printer mode? + String pretty = null; + if (!mRawMode && results != null) { + pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT); + } + if (pretty != null) { + System.out.println(pretty); + } else { + if (results != null) { + for (String key : results.keySet()) { + System.out.println( + "INSTRUMENTATION_RESULT: " + key + "=" + results.get(key)); + } + } + System.out.println("INSTRUMENTATION_CODE: " + resultCode); + } + mFinished = true; + notifyAll(); + } + } + + public boolean waitForFinish() { + synchronized (this) { + while (!mFinished) { + try { + if (!mAm.asBinder().pingBinder()) { + return false; + } + wait(1000); + } catch (InterruptedException e) { + } + } + } + return true; + } + } + + private String nextOption() { + 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 nextOptionData() { + if (mCurArgData != null) { + return mCurArgData; + } + if (mNextArg >= mArgs.length) { + return null; + } + String data = mArgs[mNextArg]; + mNextArg++; + return data; + } + + private String nextArg() { + if (mNextArg >= mArgs.length) { + return null; + } + String arg = mArgs[mNextArg]; + mNextArg++; + return arg; + } + + private void showUsage() { + System.err.println("usage: am [start|broadcast|instrument]"); + System.err.println(" am start -D INTENT"); + System.err.println(" am broadcast INTENT"); + System.err.println(" am instrument [-r] [-e <ARG_NAME> <ARG_VALUE>] [-p <PROF_FILE>]"); + System.err.println(" [-w] <COMPONENT> "); + System.err.println(""); + System.err.println(" INTENT is described with:"); + System.err.println(" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]"); + System.err.println(" [-c <CATEGORY> [-c <CATEGORY>] ...]"); + System.err.println(" [-e|--es <EXTRA_KEY> <EXTRA_STRING_VALUE> ...]"); + System.err.println(" [--ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE> ...]"); + System.err.println(" [-e|--ei <EXTRA_KEY> <EXTRA_INT_VALUE> ...]"); + System.err.println(" [-n <COMPONENT>] [-f <FLAGS>] [<URI>]"); + } +} diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk new file mode 100644 index 0000000..a33f5cc --- /dev/null +++ b/cmds/app_process/Android.mk @@ -0,0 +1,14 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + app_main.cpp + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libutils \ + libandroid_runtime + +LOCAL_MODULE:= app_process + +include $(BUILD_EXECUTABLE) diff --git a/cmds/app_process/MODULE_LICENSE_APACHE2 b/cmds/app_process/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/app_process/MODULE_LICENSE_APACHE2 diff --git a/cmds/app_process/NOTICE b/cmds/app_process/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/app_process/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/app_process/app_main.cpp b/cmds/app_process/app_main.cpp new file mode 100644 index 0000000..d825d5a --- /dev/null +++ b/cmds/app_process/app_main.cpp @@ -0,0 +1,180 @@ +/* + * Main entry of app process. + * + * Starts the interpreted runtime, then starts up the application. + * + */ + +#define LOG_TAG "appproc" + +#include <utils/IPCThreadState.h> +#include <utils/ProcessState.h> +#include <utils/Log.h> +#include <cutils/process_name.h> +#include <cutils/memory.h> +#include <android_runtime/AndroidRuntime.h> + +#include <stdio.h> +#include <unistd.h> + +namespace android { + +void app_usage() +{ + fprintf(stderr, + "Usage: app_process [java-options] cmd-dir start-class-name [options]\n"); +} + +status_t app_init(const char* className, int argc, const char* const argv[]) +{ + LOGV("Entered app_init()!\n"); + + AndroidRuntime* jr = AndroidRuntime::getRuntime(); + jr->callMain(className, argc, argv); + + LOGV("Exiting app_init()!\n"); + return NO_ERROR; +} + +class AppRuntime : public AndroidRuntime +{ +public: + AppRuntime() + : mParentDir(NULL) + , mClassName(NULL) + , mArgC(0) + , mArgV(NULL) + { + } + +#if 0 + // this appears to be unused + const char* getParentDir() const + { + return mParentDir; + } +#endif + + const char* getClassName() const + { + return mClassName; + } + + virtual void onStarted() + { + sp<ProcessState> proc = ProcessState::self(); + if (proc->supportsProcesses()) { + LOGV("App process: starting thread pool.\n"); + proc->startThreadPool(); + } + + app_init(mClassName, mArgC, mArgV); + + if (ProcessState::self()->supportsProcesses()) { + IPCThreadState::self()->stopProcess(); + } + } + + virtual void onZygoteInit() + { + sp<ProcessState> proc = ProcessState::self(); + if (proc->supportsProcesses()) { + LOGV("App process: starting thread pool.\n"); + proc->startThreadPool(); + } + } + + virtual void onExit(int code) + { + if (mClassName == NULL) { + // if zygote + if (ProcessState::self()->supportsProcesses()) { + IPCThreadState::self()->stopProcess(); + } + } + + AndroidRuntime::onExit(code); + } + + + const char* mParentDir; + const char* mClassName; + int mArgC; + const char* const* mArgV; +}; + +} + +using namespace android; + +/* + * sets argv0 to as much of newArgv0 as will fit + */ +static void setArgv0(const char *argv0, const char *newArgv0) +{ + strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0)); +} + +int main(int argc, const char* const argv[]) +{ + // These are global variables in ProcessState.cpp + mArgC = argc; + mArgV = argv; + + mArgLen = 0; + for (int i=0; i<argc; i++) { + mArgLen += strlen(argv[i]) + 1; + } + mArgLen--; + + AppRuntime runtime; + const char *arg; + const char *argv0; + + argv0 = argv[0]; + + // Process command line arguments + // ignore argv[0] + argc--; + argv++; + + // Everything up to '--' or first non '-' arg goes to the vm + + int i = runtime.addVmArguments(argc, argv); + + // Next arg is parent directory + if (i < argc) { + runtime.mParentDir = argv[i++]; + } + + // Next arg is startup classname or "--zygote" + if (i < argc) { + arg = argv[i++]; + if (0 == strcmp("--zygote", arg)) { + bool startSystemServer = (i < argc) ? + strcmp(argv[i], "--start-system-server") == 0 : false; + setArgv0(argv0, "zygote"); + set_process_name("zygote"); + runtime.start("com.android.internal.os.ZygoteInit", + startSystemServer); + } else { + set_process_name(argv0); + + runtime.mClassName = arg; + + // Remainder of args get passed to startup class main() + runtime.mArgC = argc-i; + runtime.mArgV = argv+i; + + LOGV("App process is starting with pid=%d, class=%s.\n", + getpid(), runtime.getClassName()); + runtime.start(); + } + } else { + LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); + fprintf(stderr, "Error: no class name or --zygote supplied.\n"); + app_usage(); + return 10; + } + +} diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk new file mode 100644 index 0000000..e101aeb --- /dev/null +++ b/cmds/dumpstate/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +ALL_PREBUILT += $(TARGET_OUT)/bin/dumpstate +$(TARGET_OUT)/bin/dumpstate : $(LOCAL_PATH)/dumpstate | $(ACP) + $(transform-prebuilt-to-target) + +SYMLINKS := $(TARGET_OUT_EXECUTABLES)/dumpcrash +$(SYMLINKS): DUMPSTATE_BINARY := dumpstate +$(SYMLINKS): $(LOCAL_INSTALLED_MODULE) $(LOCAL_PATH)/Android.mk + @echo "Symlink: $@ -> $(DUMPSTATE_BINARY)" + @mkdir -p $(dir $@) + @rm -rf $@ + $(hide) ln -sf $(DUMPSTATE_BINARY) $@ + +ALL_DEFAULT_INSTALLED_MODULES += $(SYMLINKS) diff --git a/cmds/dumpstate/dumpstate b/cmds/dumpstate/dumpstate new file mode 100755 index 0000000..8dd7d14 --- /dev/null +++ b/cmds/dumpstate/dumpstate @@ -0,0 +1,114 @@ +#!/system/bin/sh + +# Dumps to /tmp/state by default. +# Specify "-" to dump to stdout, or any file name to dump to that file. + +crashmode=0 +case $0 in + dumpcrash|*/dumpcrash) crashmode=1 ;; +esac + +case $1 in + "") echo "DUMPING STATE TO /tmp/state"; exec 1>/tmp/state ;; + -) ;; + *) echo "DUMPING STATE TO $1"; exec 1>$1 ;; +esac + +case $crashmode in 0) + echo "========================================================" + echo "== dumpstate" + echo "========================================================" + echo "------ SYSTEM LOG ------" + logcat -v time -d '*:v' + echo "------ VM TRACES ------" + cat /data/anr/traces.txt + echo "------ EVENT LOG TAGS ------" + cat /etc/event-log-tags + echo "------ EVENT LOG ------" + logcat -b events -v time -d '*:v' + echo "------ RADIO LOG ------" + logcat -b radio -v time -d '*:v' + echo "------ NETWORK STATE ------" + echo "Interfaces:" + netcfg + echo "" + echo "Routes:" + cat /proc/net/route + echo "------ SYSTEM PROPERTIES ------" + getprop + echo "------ KERNEL LOG ------" + dmesg + echo "------ KERNEL WAKELOCKS ------" + cat /proc/wakelocks + echo "" + echo "------ PROCESSES ------" + ps + echo "------ PROCESSES AND THREADS ------" + ps -t -p + echo "------ MEMORY INFO ------" + cat /proc/meminfo + echo "------ PSS INFO ------" + top -n 1 -d 0 -m 15 -s pss + echo "------ PROCRANK ------" + procrank + echo "------ LIBRANK ------" + librank + echo "------ VIRTUAL MEMORY STATS ------" + cat /proc/vmstat + echo "------ SLAB INFO ------" + cat /proc/slabinfo + echo "------ ZONEINFO ------" + cat /proc/zoneinfo + echo "------ BINDER FAILED TRANSACTION LOG ------" + cat /proc/binder/failed_transaction_log + echo "" + echo "------ BINDER TRANSACTION LOG ------" + cat /proc/binder/transaction_log + echo "" + echo "------ BINDER TRANSACTIONS ------" + cat /proc/binder/transactions + echo "" + echo "------ BINDER STATS ------" + cat /proc/binder/stats + echo "" + for i in `ls /proc/binder/proc`; do + echo "------ BINDER PROCESS STATE: $i ------" + cat /proc/binder/proc/$i + echo "" + done + echo "------ FILESYSTEMS ------" + df + echo "------ PACKAGE SETTINGS ------" + cat /data/system/packages.xml + echo "------ PACKAGE UID ERRORS ------" + cat /data/system/uiderrors.txt + echo "------ LAST KERNEL LOG ------" + cat /proc/last_kmsg +;; esac + +echo "========================================================" +echo "== build.prop" +echo "========================================================" + +# the crash server parses key-value pairs between the VERSION INFO and +# END lines so we can aggregate crash reports based on this data. +echo "------ VERSION INFO ------" +echo "currenttime=`date`" +echo "kernel.version=`cat /proc/version`" +echo "kernel.cmdline=`cat /proc/cmdline`" +cat /system/build.prop +echo "gsm.version.ril-impl=`getprop gsm.version.ril-impl`" +echo "gsm.version.baseband=`getprop gsm.version.baseband`" +echo "gsm.imei=`getprop gsm.imei`" +echo "gsm.sim.operator.numeric=`getprop gsm.sim.operator.numeric`" +echo "gsm.operator.alpha=`getprop gsm.operator.alpha`" +echo "------ END ------" + +case $crashmode in 0) + echo "========================================================" + echo "== dumpsys" + echo "========================================================" + dumpsys +;; esac + +exit 0 diff --git a/cmds/dumpsys/Android.mk b/cmds/dumpsys/Android.mk new file mode 100644 index 0000000..0c623cc --- /dev/null +++ b/cmds/dumpsys/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + dumpsys.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils + +ifeq ($(TARGET_OS),linux) + LOCAL_CFLAGS += -DXP_UNIX + #LOCAL_SHARED_LIBRARIES += librt +endif + +LOCAL_MODULE:= dumpsys + +include $(BUILD_EXECUTABLE) diff --git a/cmds/dumpsys/MODULE_LICENSE_APACHE2 b/cmds/dumpsys/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/dumpsys/MODULE_LICENSE_APACHE2 diff --git a/cmds/dumpsys/NOTICE b/cmds/dumpsys/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/dumpsys/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp new file mode 100644 index 0000000..a62fe55 --- /dev/null +++ b/cmds/dumpsys/dumpsys.cpp @@ -0,0 +1,81 @@ +/* + * Command that dumps interesting system state to the log. + * + */ + +#define LOG_TAG "dumpsys" + +#include <utils/Log.h> +#include <utils/Parcel.h> +#include <utils/ProcessState.h> +#include <utils/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) { + LOGE("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(); + + // 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) { + 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/Android.mk b/cmds/input/Android.mk new file mode 100644 index 0000000..3d56533 --- /dev/null +++ b/cmds/input/Android.mk @@ -0,0 +1,13 @@ +# Copyright 2008 The Android Open Source Project +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := input +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +ALL_PREBUILT += $(TARGET_OUT)/bin/input +$(TARGET_OUT)/bin/input : $(LOCAL_PATH)/input | $(ACP) + $(transform-prebuilt-to-target) diff --git a/cmds/input/MODULE_LICENSE_APACHE2 b/cmds/input/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/input/MODULE_LICENSE_APACHE2 diff --git a/cmds/input/NOTICE b/cmds/input/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/input/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/input/input b/cmds/input/input new file mode 100644 index 0000000..fa9dced --- /dev/null +++ b/cmds/input/input @@ -0,0 +1,7 @@ +# Script to start "input" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/input.jar +exec app_process $base/bin com.android.commands.input.Input $* + diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java new file mode 100755 index 0000000..3a1accd --- /dev/null +++ b/cmds/input/src/com/android/commands/input/Input.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2007 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.input; + +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemClock; +import android.util.Log; +import android.view.IWindowManager; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; + +/** + * Command that sends key events to the device, either by their keycode, or by + * desired character output. + */ + +public class Input { + + /** + * Command-line entry point. + * + * @param args The command-line arguments + */ + public static void main(String[] args) { + (new Input()).run(args); + } + + private void run(String[] args) { + if (args.length < 1) { + showUsage(); + return; + } + + 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; + } + } + + /** + * Convert the characters of string text into key event's and send to + * device. + * + * @param text is a string of characters you want to input to the device. + */ + + private void sendText(String text) { + + StringBuffer buff = new StringBuffer(text); + + boolean escapeFlag = false; + for (int i=0; i<buff.length(); i++) { + if (escapeFlag) { + escapeFlag = false; + if (buff.charAt(i) == 's') { + buff.setCharAt(i, ' '); + buff.deleteCharAt(--i); + } + } + if (buff.charAt(i) == '%') { + escapeFlag = true; + } + } + + char[] chars = buff.toString().toCharArray(); + + KeyCharacterMap mKeyCharacterMap = KeyCharacterMap. + load(KeyCharacterMap.BUILT_IN_KEYBOARD); + + KeyEvent[] events = mKeyCharacterMap.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"); + } + } + } + + /** + * 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); + long now = SystemClock.uptimeMillis(); + Log.i("SendKeyEvent", 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"); + } + } + + private void sendMotionEvent(long downTime, int action, float x, float y, + float pressure, float size) { + } + + private void showUsage() { + System.err.println("usage: input [text|keyevent]"); + System.err.println(" input text <string>"); + System.err.println(" input keyevent <event_code>"); + } +} diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk new file mode 100644 index 0000000..6673862 --- /dev/null +++ b/cmds/installd/Android.mk @@ -0,0 +1,21 @@ +ifneq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + installd.c commands.c utils.c + +LOCAL_C_INCLUDES := \ + $(call include-path-for, system-core)/cutils + +LOCAL_SHARED_LIBRARIES := \ + libcutils + +LOCAL_STATIC_LIBRARIES := + +LOCAL_MODULE:= installd + +include $(BUILD_EXECUTABLE) + +endif # !simulator)) diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c new file mode 100644 index 0000000..ab7d67a --- /dev/null +++ b/cmds/installd/commands.c @@ -0,0 +1,563 @@ +/* +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "installd.h" + +int install(const char *pkgname, uid_t uid, gid_t gid) +{ + char pkgdir[PKG_PATH_MAX]; + char libdir[PKG_PATH_MAX]; + + if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) { + LOGE("invalid uid/gid: %d %d\n", uid, gid); + return -1; + + } + if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + if (create_pkg_path(libdir, PKG_LIB_PREFIX, pkgname, PKG_LIB_POSTFIX)) + return -1; + + if (mkdir(pkgdir, 0755) < 0) { + LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno)); + return -errno; + } + if (chown(pkgdir, uid, gid) < 0) { + LOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno)); + unlink(pkgdir); + return -errno; + } + if (mkdir(libdir, 0755) < 0) { + LOGE("cannot create dir '%s': %s\n", libdir, strerror(errno)); + unlink(pkgdir); + return -errno; + } + if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) { + LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno)); + unlink(libdir); + unlink(pkgdir); + return -errno; + } + return 0; +} + +int uninstall(const char *pkgname) +{ + char pkgdir[PKG_PATH_MAX]; + + if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + + /* delete contents AND directory, no exceptions */ + return delete_dir_contents(pkgdir, 1, 0); +} + +int delete_user_data(const char *pkgname) +{ + char pkgdir[PKG_PATH_MAX]; + + if (create_pkg_path(pkgdir, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) + return -1; + + /* delete contents, excluding "lib", but not the directory itself */ + return delete_dir_contents(pkgdir, 0, "lib"); +} + +int delete_cache(const char *pkgname) +{ + char cachedir[PKG_PATH_MAX]; + + if (create_pkg_path(cachedir, CACHE_DIR_PREFIX, pkgname, CACHE_DIR_POSTFIX)) + return -1; + + /* delete contents, not the directory, no exceptions */ + return delete_dir_contents(cachedir, 0, 0); +} + + +static int disk_free(void) +{ + struct statfs sfs; + if (statfs(PKG_DIR_PREFIX, &sfs) == 0) { + return sfs.f_bavail * sfs.f_bsize; + } else { + return -1; + } +} + + +/* Try to ensure free_size bytes of storage are available. + * Returns 0 on success. + * This is rather simple-minded because doing a full LRU would + * be potentially memory-intensive, and without atime it would + * also require that apps constantly modify file metadata even + * when just reading from the cache, which is pretty awful. + */ +int free_cache(int free_size) +{ + const char *name; + int dfd, subfd; + DIR *d; + struct dirent *de; + int avail; + + avail = disk_free(); + if (avail < 0) return -1; + + LOGI("free_cache(%d) avail %d\n", free_size, avail); + if (avail > free_size) return 0; + + d = opendir(PKG_DIR_PREFIX); + if (d == NULL) { + LOGE("cannot open %s\n", PKG_DIR_PREFIX); + return 0; + } + dfd = dirfd(d); + + while ((de = readdir(d))) { + if (de->d_type != DT_DIR) continue; + name = de->d_name; + + /* always skip "." and ".." */ + if (name[0] == '.') { + if (name[1] == 0) continue; + if ((name[1] == '.') && (name[2] == 0)) continue; + } + + subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); + if (subfd < 0) continue; + + delete_dir_contents_fd(subfd, "cache"); + close(subfd); + + avail = disk_free(); + if (avail > free_size) { + closedir(d); + return 0; + } + } + closedir(d); + return -1; +} + + +/* used by move_dex, rm_dex, etc to ensure that the provided paths + * don't point anywhere other than at the APK_DIR_PREFIX + */ +static int is_valid_apk_path(const char *path) +{ + int len = strlen(APK_DIR_PREFIX); + if (strncmp(path, APK_DIR_PREFIX, len)) { + len = strlen(PROTECTED_DIR_PREFIX); + if (strncmp(path, PROTECTED_DIR_PREFIX, len)) { + LOGE("invalid apk path '%s' (bad prefix)\n", path); + return 0; + } + } + if (strchr(path + len, '/')) { + LOGE("invalid apk path '%s' (subdir?)\n", path); + return 0; + } + if (path[len] == '.') { + LOGE("invalid apk path '%s' (trickery)\n", path); + return 0; + } + return 1; +} + +int move_dex(const char *src, const char *dst) +{ + char src_dex[PKG_PATH_MAX]; + char dst_dex[PKG_PATH_MAX]; + + if (!is_valid_apk_path(src)) return -1; + if (!is_valid_apk_path(dst)) return -1; + + if (create_cache_path(src_dex, src)) return -1; + if (create_cache_path(dst_dex, dst)) return -1; + + LOGI("move %s -> %s\n", src_dex, dst_dex); + if (rename(src_dex, dst_dex) < 0) { + return -1; + } else { + return 0; + } +} + +int rm_dex(const char *path) +{ + char dex_path[PKG_PATH_MAX]; + + if (!is_valid_apk_path(path)) return -1; + if (create_cache_path(dex_path, path)) return -1; + + LOGI("unlink %s\n", dex_path); + if (unlink(dex_path) < 0) { + return -1; + } else { + return 0; + } +} + +int protect(char *pkgname, gid_t gid) +{ + struct stat s; + char pkgpath[PKG_PATH_MAX]; + + if (gid < AID_SYSTEM) return -1; + + if (create_pkg_path(pkgpath, PROTECTED_DIR_PREFIX, pkgname, ".apk")) + return -1; + + if (stat(pkgpath, &s) < 0) return -1; + + if (chown(pkgpath, s.st_uid, gid) < 0) { + LOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno)); + return -1; + } + + if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) { + LOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno)); + return -1; + } + + return 0; +} + +static int stat_size(struct stat *s) +{ + int blksize = s->st_blksize; + int size = s->st_size; + + if (blksize) { + /* round up to filesystem block size */ + size = (size + blksize - 1) & (~(blksize - 1)); + } + + return size; +} + +static int calculate_dir_size(int dfd) +{ + int size = 0; + struct stat s; + DIR *d; + struct dirent *de; + + d = fdopendir(dfd); + if (d == NULL) { + close(dfd); + return 0; + } + + 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; + } + subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); + if (subfd >= 0) { + size += calculate_dir_size(subfd); + } + } else { + if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { + size += stat_size(&s); + } + } + } + closedir(d); + return size; +} + +int get_size(const char *pkgname, const char *apkpath, + const char *fwdlock_apkpath, + int *_codesize, int *_datasize, int *_cachesize) +{ + DIR *d; + int dfd; + struct dirent *de; + struct stat s; + char path[PKG_PATH_MAX]; + + int codesize = 0; + int datasize = 0; + int cachesize = 0; + + /* count the source apk as code -- but only if it's not + * on the /system partition + */ + if (strncmp(apkpath, "/system", 7) != 0) { + if (stat(apkpath, &s) == 0) { + codesize += stat_size(&s); + } + } + /* count the forward locked apk as code if it is given + */ + if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') { + if (stat(fwdlock_apkpath, &s) == 0) { + codesize += stat_size(&s); + } + } + + + /* count the cached dexfile as code */ + if (!create_cache_path(path, apkpath)) { + if (stat(path, &s) == 0) { + codesize += stat_size(&s); + } + } + + if (create_pkg_path(path, PKG_DIR_PREFIX, pkgname, PKG_DIR_POSTFIX)) { + goto done; + } + + d = opendir(path); + if (d == NULL) { + goto done; + } + dfd = dirfd(d); + + /* most stuff in the pkgdir is data, except for the "cache" + * directory and below, which is cache, and the "lib" directory + * and below, which is code... + */ + while ((de = readdir(d))) { + const char *name = de->d_name; + + if (de->d_type == DT_DIR) { + int subfd; + /* always skip "." and ".." */ + if (name[0] == '.') { + if (name[1] == 0) continue; + if ((name[1] == '.') && (name[2] == 0)) continue; + } + subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); + if (subfd >= 0) { + int size = calculate_dir_size(subfd); + if (!strcmp(name,"lib")) { + codesize += size; + } else if(!strcmp(name,"cache")) { + cachesize += size; + } else { + datasize += size; + } + } + } else { + if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) { + datasize += stat_size(&s); + } + } + } + closedir(d); +done: + *_codesize = codesize; + *_datasize = datasize; + *_cachesize = cachesize; + return 0; +} + + +/* a simpler version of dexOptGenerateCacheFileName() */ +int create_cache_path(char path[PKG_PATH_MAX], const char *src) +{ + char *tmp; + int srclen; + int dstlen; + + srclen = strlen(src); + + /* demand that we are an absolute path */ + if ((src == 0) || (src[0] != '/') || strstr(src,"..")) { + return -1; + } + + if (srclen > PKG_PATH_MAX) { // XXX: PKG_NAME_MAX? + return -1; + } + + dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) + + strlen(DALVIK_CACHE_POSTFIX) + 1; + + if (dstlen > PKG_PATH_MAX) { + return -1; + } + + sprintf(path,"%s%s%s", + DALVIK_CACHE_PREFIX, + src + 1, /* skip the leading / */ + DALVIK_CACHE_POSTFIX); + + for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) { + if (*tmp == '/') { + *tmp = '@'; + } + } + + return 0; +} + +static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name) +{ + static const char* DEX_OPT_BIN = "/system/bin/dexopt"; + static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig + char zip_num[MAX_INT_LEN]; + char odex_num[MAX_INT_LEN]; + + sprintf(zip_num, "%d", zip_fd); + sprintf(odex_num, "%d", odex_fd); + + execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name, + (char*) NULL); + LOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno)); +} + +static int wait_dexopt(pid_t pid, const char* apk_path) +{ + int status; + pid_t got_pid; + + /* + * Wait for the optimization process to finish. + */ + while (1) { + got_pid = waitpid(pid, &status, 0); + if (got_pid == -1 && errno == EINTR) { + printf("waitpid interrupted, retrying\n"); + } else { + break; + } + } + if (got_pid != pid) { + LOGW("waitpid failed: wanted %d, got %d: %s\n", + (int) pid, (int) got_pid, strerror(errno)); + return 1; + } + + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { + LOGD("DexInv: --- END '%s' (success) ---\n", apk_path); + return 0; + } else { + LOGW("DexInv: --- END '%s' --- status=0x%04x, process failed\n", + apk_path, status); + return status; /* always nonzero */ + } +} + +int dexopt(const char *apk_path, uid_t uid, int is_public) +{ + struct utimbuf ut; + struct stat apk_stat, dex_stat; + char dex_path[PKG_PATH_MAX]; + char *end; + int res, zip_fd=-1, odex_fd=-1; + + /* Before anything else: is there a .odex file? If so, we have + * pre-optimized the apk and there is nothing to do here. + */ + if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { + return -1; + } + + strcpy(dex_path, apk_path); + end = strrchr(dex_path, '.'); + if (end != NULL) { + strcpy(end, ".odex"); + if (stat(dex_path, &dex_stat) == 0) { + return 0; + } + } + + if (create_cache_path(dex_path, apk_path)) { + return -1; + } + + memset(&apk_stat, 0, sizeof(apk_stat)); + stat(apk_path, &apk_stat); + + zip_fd = open(apk_path, O_RDONLY, 0); + if (zip_fd < 0) { + LOGE("dexopt cannot open '%s' for input\n", apk_path); + return -1; + } + + unlink(dex_path); + odex_fd = open(dex_path, O_RDWR | O_CREAT | O_EXCL, 0644); + if (odex_fd < 0) { + LOGE("dexopt cannot open '%s' for output\n", dex_path); + goto fail; + } + if (fchown(odex_fd, AID_SYSTEM, uid) < 0) { + LOGE("dexopt cannot chown '%s'\n", dex_path); + goto fail; + } + if (fchmod(odex_fd, + S_IRUSR|S_IWUSR|S_IRGRP | + (is_public ? S_IROTH : 0)) < 0) { + LOGE("dexopt cannot chmod '%s'\n", dex_path); + goto fail; + } + + LOGD("DexInv: --- BEGIN '%s' ---\n", apk_path); + + pid_t pid; + pid = fork(); + if (pid == 0) { + /* child -- drop privileges before continuing */ + if (setgid(uid) != 0) { + LOGE("setgid(%d) failed during dexopt\n", uid); + exit(64); + } + if (setuid(uid) != 0) { + LOGE("setuid(%d) during dexopt\n", uid); + exit(65); + } + if (flock(odex_fd, LOCK_EX | LOCK_NB) != 0) { + LOGE("flock(%s) failed: %s\n", dex_path, strerror(errno)); + exit(66); + } + + run_dexopt(zip_fd, odex_fd, apk_path); /* does not return */ + exit(67); + } else { + res = wait_dexopt(pid, apk_path); + if (res != 0) { + LOGE("dexopt failed on '%s' res = %d\n", dex_path, res); + goto fail; + } + } + + ut.actime = apk_stat.st_atime; + ut.modtime = apk_stat.st_mtime; + utime(dex_path, &ut); + + close(odex_fd); + close(zip_fd); + return 0; + +fail: + if (odex_fd >= 0) { + close(odex_fd); + unlink(dex_path); + } + if (zip_fd >= 0) { + close(zip_fd); + } + return -1; +} diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c new file mode 100644 index 0000000..7c7441f --- /dev/null +++ b/cmds/installd/installd.c @@ -0,0 +1,259 @@ +/* +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "installd.h" + + +#define BUFFER_MAX 1024 /* input buffer for commands */ +#define TOKEN_MAX 8 /* max number of arguments in buffer */ +#define REPLY_MAX 256 /* largest reply allowed */ + + +static int do_ping(char **arg, char reply[REPLY_MAX]) +{ + return 0; +} + +static int do_install(char **arg, char reply[REPLY_MAX]) +{ + return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */ +} + +static int do_dexopt(char **arg, char reply[REPLY_MAX]) +{ + /* apk_path, uid, is_public */ + return dexopt(arg[0], atoi(arg[1]), atoi(arg[2])); +} + +static int do_move_dex(char **arg, char reply[REPLY_MAX]) +{ + return move_dex(arg[0], arg[1]); /* src, dst */ +} + +static int do_rm_dex(char **arg, char reply[REPLY_MAX]) +{ + return rm_dex(arg[0]); /* pkgname */ +} + +static int do_remove(char **arg, char reply[REPLY_MAX]) +{ + return uninstall(arg[0]); /* pkgname */ +} + +static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */ +{ + return free_cache(atoi(arg[0])); /* free_size */ +} + +static int do_rm_cache(char **arg, char reply[REPLY_MAX]) +{ + return delete_cache(arg[0]); /* pkgname */ +} + +static int do_protect(char **arg, char reply[REPLY_MAX]) +{ + return protect(arg[0], atoi(arg[1])); /* pkgname, gid */ +} + +static int do_get_size(char **arg, char reply[REPLY_MAX]) +{ + int codesize = 0; + int datasize = 0; + int cachesize = 0; + int res = 0; + + /* pkgdir, apkpath */ + res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize); + + sprintf(reply,"%d %d %d", codesize, datasize, cachesize); + return res; +} + +static int do_rm_user_data(char **arg, char reply[REPLY_MAX]) +{ + return delete_user_data(arg[0]); /* pkgname */ +} + +struct cmdinfo { + const char *name; + unsigned numargs; + int (*func)(char **arg, char reply[REPLY_MAX]); +}; + +struct cmdinfo cmds[] = { + { "ping", 0, do_ping }, + { "install", 3, do_install }, + { "dexopt", 3, do_dexopt }, + { "movedex", 2, do_move_dex }, + { "rmdex", 1, do_rm_dex }, + { "remove", 1, do_remove }, + { "freecache", 1, do_free_cache }, + { "rmcache", 1, do_rm_cache }, + { "protect", 2, do_protect }, + { "getsize", 3, do_get_size }, + { "rmuserdata", 1, do_rm_user_data }, +}; + +static int readx(int s, void *_buf, int count) +{ + char *buf = _buf; + int n = 0, r; + if (count < 0) return -1; + while (n < count) { + r = read(s, buf + n, count - n); + if (r < 0) { + if (errno == EINTR) continue; + LOGE("read error: %s\n", strerror(errno)); + return -1; + } + if (r == 0) { + LOGE("eof\n"); + return -1; /* EOF */ + } + n += r; + } + return 0; +} + +static int writex(int s, const void *_buf, int count) +{ + const char *buf = _buf; + int n = 0, r; + if (count < 0) return -1; + while (n < count) { + r = write(s, buf + n, count - n); + if (r < 0) { + if (errno == EINTR) continue; + LOGE("write error: %s\n", strerror(errno)); + return -1; + } + n += r; + } + return 0; +} + + +/* Tokenize the command buffer, locate a matching command, + * ensure that the required number of arguments are provided, + * call the function(), return the result. + */ +static int execute(int s, char cmd[BUFFER_MAX]) +{ + char reply[REPLY_MAX]; + char *arg[TOKEN_MAX+1]; + unsigned i; + unsigned n = 0; + unsigned short count; + int ret = -1; + +// LOGI("execute('%s')\n", cmd); + + /* default reply is "" */ + reply[0] = 0; + + /* n is number of args (not counting arg[0]) */ + arg[0] = cmd; + while (*cmd) { + if (isspace(*cmd)) { + *cmd++ = 0; + n++; + arg[n] = cmd; + if (n == TOKEN_MAX) { + LOGE("too many arguments\n"); + goto done; + } + } + cmd++; + } + + for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) { + if (!strcmp(cmds[i].name,arg[0])) { + if (n != cmds[i].numargs) { + LOGE("%s requires %d arguments (%d given)\n", + cmds[i].name, cmds[i].numargs, n); + } else { + ret = cmds[i].func(arg + 1, reply); + } + goto done; + } + } + LOGE("unsupported command '%s'\n", arg[0]); + +done: + if (reply[0]) { + n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply); + } else { + n = snprintf(cmd, BUFFER_MAX, "%d", ret); + } + if (n > BUFFER_MAX) n = BUFFER_MAX; + count = n; + +// LOGI("reply: '%s'\n", cmd); + if (writex(s, &count, sizeof(count))) return -1; + if (writex(s, cmd, count)) return -1; + return 0; +} + +int main(const int argc, const char *argv[]) { + char buf[BUFFER_MAX]; + struct sockaddr addr; + socklen_t alen; + int lsocket, s, count; + + lsocket = android_get_control_socket(SOCKET_PATH); + if (lsocket < 0) { + LOGE("Failed to get socket from environment: %s\n", strerror(errno)); + exit(1); + } + if (listen(lsocket, 5)) { + LOGE("Listen on socket failed: %s\n", strerror(errno)); + exit(1); + } + fcntl(lsocket, F_SETFD, FD_CLOEXEC); + + for (;;) { + alen = sizeof(addr); + s = accept(lsocket, &addr, &alen); + if (s < 0) { + LOGE("Accept failed: %s\n", strerror(errno)); + continue; + } + fcntl(s, F_SETFD, FD_CLOEXEC); + + LOGI("new connection\n"); + for (;;) { + unsigned short count; + if (readx(s, &count, sizeof(count))) { + LOGE("failed to read size\n"); + break; + } + if ((count < 1) || (count >= BUFFER_MAX)) { + LOGE("invalid size %d\n", count); + break; + } + if (readx(s, buf, count)) { + LOGE("failed to read command\n"); + break; + } + buf[count] = 0; + if (execute(s, buf)) break; + } + LOGI("closing connection\n"); + close(s); + } + + return 0; +} diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h new file mode 100644 index 0000000..db3badd --- /dev/null +++ b/cmds/installd/installd.h @@ -0,0 +1,100 @@ +/* +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#define LOG_TAG "installd" + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <dirent.h> +#include <unistd.h> +#include <ctype.h> +#include <fcntl.h> +#include <errno.h> +#include <utime.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include <cutils/sockets.h> +#include <cutils/log.h> +#include <cutils/properties.h> + +#include <private/android_filesystem_config.h> + +#if INCLUDE_SYS_MOUNT_FOR_STATFS +#include <sys/mount.h> +#else +#include <sys/statfs.h> +#endif + +#define SOCKET_PATH "installd" + + +/* elements combined with a valid package name to form paths */ + +#define PKG_DIR_PREFIX "/data/data/" +#define PKG_DIR_POSTFIX "" + +#define PKG_LIB_PREFIX "/data/data/" +#define PKG_LIB_POSTFIX "/lib" + +#define CACHE_DIR_PREFIX "/data/data/" +#define CACHE_DIR_POSTFIX "/cache" + +#define APK_DIR_PREFIX "/data/app/" + +/* other handy constants */ + +#define PROTECTED_DIR_PREFIX "/data/app-private/" + +#define DALVIK_CACHE_PREFIX "/data/dalvik-cache/" +#define DALVIK_CACHE_POSTFIX "/classes.dex" + + +#define PKG_NAME_MAX 128 /* largest allowed package name */ +#define PKG_PATH_MAX 256 /* max size of any path we use */ + + +/* util.c */ + +int create_pkg_path(char path[PKG_PATH_MAX], + const char *prefix, + const char *pkgname, + const char *postfix); + +int create_cache_path(char path[PKG_PATH_MAX], const char *src); + +int delete_dir_contents(const char *pathname, + int also_delete_dir, + const char *ignore); + +int delete_dir_contents_fd(int dfd, const char *name); + +/* commands.c */ + +int install(const char *pkgname, uid_t uid, gid_t gid); +int uninstall(const char *pkgname); +int delete_user_data(const char *pkgname); +int delete_cache(const char *pkgname); +int move_dex(const char *src, const char *dst); +int rm_dex(const char *path); +int protect(char *pkgname, gid_t gid); +int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath, + int *codesize, int *datasize, int *cachesize); +int free_cache(int free_size); +int dexopt(const char *apk_path, uid_t uid, int is_public); diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c new file mode 100644 index 0000000..5db5545 --- /dev/null +++ b/cmds/installd/utils.c @@ -0,0 +1,149 @@ +/* +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#include "installd.h" + +int create_pkg_path(char path[PKG_PATH_MAX], + const char *prefix, + const char *pkgname, + const char *postfix) +{ + int len; + const char *x; + + len = strlen(pkgname); + if (len > PKG_NAME_MAX) { + return -1; + } + if ((len + strlen(prefix) + strlen(postfix)) >= PKG_PATH_MAX) { + return -1; + } + + x = pkgname; + while (*x) { + if (isalnum(*x) || (*x == '_')) { + /* alphanumeric or underscore are fine */ + } else if (*x == '.') { + if ((x == pkgname) || (x[1] == '.') || (x[1] == 0)) { + /* periods must not be first, last, or doubled */ + LOGE("invalid package name '%s'\n", pkgname); + return -1; + } + } else { + /* anything not A-Z, a-z, 0-9, _, or . is invalid */ + LOGE("invalid package name '%s'\n", pkgname); + return -1; + } + x++; + } + + sprintf(path, "%s%s%s", prefix, pkgname, postfix); + return 0; +} + +static int _delete_dir_contents(DIR *d, const char *ignore) +{ + int result = 0; + struct dirent *de; + int dfd; + + dfd = dirfd(d); + + if (dfd < 0) return -1; + + while ((de = readdir(d))) { + const char *name = de->d_name; + + /* skip the ignore name if provided */ + if (ignore && !strcmp(name, ignore)) continue; + + if (de->d_type == DT_DIR) { + int r, subfd; + DIR *subdir; + + /* always skip "." and ".." */ + if (name[0] == '.') { + if (name[1] == 0) continue; + if ((name[1] == '.') && (name[2] == 0)) continue; + } + + subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY); + if (subfd < 0) { + result = -1; + continue; + } + subdir = fdopendir(subfd); + if (subdir == NULL) { + close(subfd); + result = -1; + continue; + } + if (_delete_dir_contents(subdir, 0)) { + result = -1; + } + closedir(subdir); + if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { + result = -1; + } + } else { + if (unlinkat(dfd, name, 0) < 0) { + result = -1; + } + } + } + + return result; +} + +int delete_dir_contents(const char *pathname, + int also_delete_dir, + const char *ignore) +{ + int res = 0; + DIR *d; + + d = opendir(pathname); + if (d == NULL) { + return -errno; + } + res = _delete_dir_contents(d, ignore); + closedir(d); + if (also_delete_dir) { + if (rmdir(pathname)) { + res = -1; + } + } + return res; +} + +int delete_dir_contents_fd(int dfd, const char *name) +{ + int fd, res; + DIR *d; + + fd = openat(dfd, name, O_RDONLY | O_DIRECTORY); + if (fd < 0) { + return -1; + } + d = fdopendir(fd); + if (d == NULL) { + close(fd); + return -1; + } + res = _delete_dir_contents(d, 0); + closedir(d); + return res; +} diff --git a/cmds/pm/Android.mk b/cmds/pm/Android.mk new file mode 100644 index 0000000..7911d62 --- /dev/null +++ b/cmds/pm/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2007 The Android Open Source Project +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := pm +include $(BUILD_JAVA_LIBRARY) + + +include $(CLEAR_VARS) +ALL_PREBUILT += $(TARGET_OUT)/bin/pm +$(TARGET_OUT)/bin/pm : $(LOCAL_PATH)/pm | $(ACP) + $(transform-prebuilt-to-target) + diff --git a/cmds/pm/MODULE_LICENSE_APACHE2 b/cmds/pm/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/pm/MODULE_LICENSE_APACHE2 diff --git a/cmds/pm/NOTICE b/cmds/pm/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/pm/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/pm/pm b/cmds/pm/pm new file mode 100755 index 0000000..8183838 --- /dev/null +++ b/cmds/pm/pm @@ -0,0 +1,7 @@ +# Script to start "pm" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/pm.jar +exec app_process $base/bin com.android.commands.pm.Pm "$@" + diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java new file mode 100644 index 0000000..b79ee26 --- /dev/null +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -0,0 +1,693 @@ +/* + * Copyright (C) 2007 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.pm; + +import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageDeleteObserver; +import android.content.pm.IPackageInstallObserver; +import android.content.pm.IPackageManager; +import android.content.pm.PackageInfo; +import android.content.pm.PackageItemInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PermissionGroupInfo; +import android.content.pm.PermissionInfo; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.net.Uri; +import android.os.RemoteException; +import android.os.ServiceManager; + +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.List; +import java.util.WeakHashMap; + +public final class Pm { + IPackageManager mPm; + + private WeakHashMap<String, Resources> mResourceCache + = new WeakHashMap<String, Resources>(); + + private String[] mArgs; + private int mNextArg; + private String mCurArgData; + + public static void main(String[] args) { + new Pm().run(args); + } + + public void run(String[] args) { + boolean validCommand = false; + if (args.length < 1) { + showUsage(); + return; + } + + mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); + if (mPm == null) { + System.err.println("Error Type 1: Could not access the Package Manager!"); + showUsage(); + return; + } + + mArgs = args; + String op = args[0]; + mNextArg = 1; + + if ("list".equals(op)) { + runList(); + return; + } + + if ("path".equals(op)) { + runPath(); + return; + } + + if ("install".equals(op)) { + runInstall(); + return; + } + + if ("uninstall".equals(op)) { + runUninstall(); + return; + } + + try { + if (args.length == 1) { + if (args[0].equalsIgnoreCase("-l")) { + validCommand = true; + runListPackages(false); + } else if (args[0].equalsIgnoreCase("-lf")){ + validCommand = true; + runListPackages(true); + } + } else if (args.length == 2) { + if (args[0].equalsIgnoreCase("-p")) { + validCommand = true; + displayPackageFilePath(args[1]); + } + } + } finally { + if (validCommand == false) { + showUsage(); + } + } + } + + /** + * Execute the list sub-command. + */ + private void runList() { + String type = nextArg(); + if (type == null) { + System.err.println("Error: didn't specify type of data to list"); + showUsage(); + return; + } + if ("package".equals(type) || "packages".equals(type)) { + runListPackages(false); + } else if ("permission-groups".equals(type)) { + runListPermissionGroups(); + } else if ("permissions".equals(type)) { + runListPermissions(); + } else { + System.err.println("Error: unknown list type '" + type + "'"); + showUsage(); + } + } + + /** + * Lists all the installed packages. + */ + private void runListPackages(boolean showApplicationPackage) { + try { + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-l")) { + // old compat + } else if (opt.equals("-lf")) { + showApplicationPackage = true; + } else if (opt.equals("-f")) { + showApplicationPackage = true; + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return; + } + } + } catch (RuntimeException ex) { + System.err.println("Error: " + ex.toString()); + showUsage(); + return; + } + + try { + List<PackageInfo> packages = mPm.getInstalledPackages(0 /* all */); + + int count = packages.size(); + for (int p = 0 ; p < count ; p++) { + PackageInfo info = packages.get(p); + System.out.print("package:"); + if (showApplicationPackage) { + System.out.print(info.applicationInfo.sourceDir); + System.out.print("="); + } + System.out.println(info.packageName); + } + } catch (RemoteException e) { + } + } + + /** + * Lists all the known permission groups. + */ + private void runListPermissionGroups() { + try { + List<PermissionGroupInfo> pgs = mPm.getAllPermissionGroups(0); + + int count = pgs.size(); + for (int p = 0 ; p < count ; p++) { + PermissionGroupInfo pgi = pgs.get(p); + System.out.print("permission group:"); + System.out.println(pgi.name); + } + } catch (RemoteException e) { + } + } + + private String loadText(PackageItemInfo pii, int res, CharSequence nonLocalized) { + if (nonLocalized != null) { + return nonLocalized.toString(); + } + Resources r = getResources(pii); + if (r != null) { + return r.getString(res); + } + return null; + } + + /** + * Lists all the permissions in a group. + */ + private void runListPermissions() { + try { + boolean labels = false; + boolean groups = false; + boolean userOnly = false; + boolean summary = false; + boolean dangerousOnly = false; + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-f")) { + labels = true; + } else if (opt.equals("-g")) { + groups = true; + } else if (opt.equals("-s")) { + groups = true; + labels = true; + summary = true; + } else if (opt.equals("-u")) { + userOnly = true; + } else if (opt.equals("-d")) { + dangerousOnly = true; + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return; + } + } + + String grp = nextOption(); + ArrayList<String> groupList = new ArrayList<String>(); + if (groups) { + List<PermissionGroupInfo> infos = + mPm.getAllPermissionGroups(0); + for (int i=0; i<infos.size(); i++) { + groupList.add(infos.get(i).name); + } + groupList.add(null); + } else { + groupList.add(grp); + } + + if (dangerousOnly) { + System.out.println("Dangerous Permissions:"); + System.out.println(""); + doListPermissions(groupList, groups, labels, summary, + PermissionInfo.PROTECTION_DANGEROUS, + PermissionInfo.PROTECTION_DANGEROUS); + if (userOnly) { + System.out.println("Normal Permissions:"); + System.out.println(""); + doListPermissions(groupList, groups, labels, summary, + PermissionInfo.PROTECTION_NORMAL, + PermissionInfo.PROTECTION_NORMAL); + } + } else if (userOnly) { + System.out.println("Dangerous and Normal Permissions:"); + System.out.println(""); + doListPermissions(groupList, groups, labels, summary, + PermissionInfo.PROTECTION_NORMAL, + PermissionInfo.PROTECTION_DANGEROUS); + } else { + System.out.println("All Permissions:"); + System.out.println(""); + doListPermissions(groupList, groups, labels, summary, + -10000, 10000); + } + } catch (RemoteException e) { + } + } + + private void doListPermissions(ArrayList<String> groupList, + boolean groups, boolean labels, boolean summary, + int startProtectionLevel, int endProtectionLevel) + throws RemoteException { + for (int i=0; i<groupList.size(); i++) { + String groupName = groupList.get(i); + String prefix = ""; + if (groups) { + if (i > 0) System.out.println(""); + if (groupName != null) { + PermissionGroupInfo pgi = mPm.getPermissionGroupInfo( + groupName, 0); + if (summary) { + Resources res = getResources(pgi); + if (res != null) { + System.out.print(loadText(pgi, pgi.labelRes, + pgi.nonLocalizedLabel) + ": "); + } else { + System.out.print(pgi.name + ": "); + + } + } else { + System.out.println((labels ? "+ " : "") + + "group:" + pgi.name); + if (labels) { + System.out.println(" package:" + pgi.packageName); + Resources res = getResources(pgi); + if (res != null) { + System.out.println(" label:" + + loadText(pgi, pgi.labelRes, + pgi.nonLocalizedLabel)); + System.out.println(" description:" + + loadText(pgi, pgi.descriptionRes, + pgi.nonLocalizedDescription)); + } + } + } + } else { + System.out.println(((labels && !summary) + ? "+ " : "") + "ungrouped:"); + } + prefix = " "; + } + List<PermissionInfo> ps = mPm.queryPermissionsByGroup( + groupList.get(i), 0); + int count = ps.size(); + boolean first = true; + for (int p = 0 ; p < count ; p++) { + PermissionInfo pi = ps.get(p); + if (groups && groupName == null && pi.group != null) { + continue; + } + if (pi.protectionLevel < startProtectionLevel + || pi.protectionLevel > endProtectionLevel) { + continue; + } + if (summary) { + if (first) { + first = false; + } else { + System.out.print(", "); + } + Resources res = getResources(pi); + if (res != null) { + System.out.print(loadText(pi, pi.labelRes, + pi.nonLocalizedLabel)); + } else { + System.out.print(pi.name); + } + } else { + System.out.println(prefix + (labels ? "+ " : "") + + "permission:" + pi.name); + if (labels) { + System.out.println(prefix + " package:" + pi.packageName); + Resources res = getResources(pi); + if (res != null) { + System.out.println(prefix + " label:" + + loadText(pi, pi.labelRes, + pi.nonLocalizedLabel)); + System.out.println(prefix + " description:" + + 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); + } + } + } + + if (summary) { + System.out.println(""); + } + } + } + + private void runPath() { + String pkg = nextArg(); + if (pkg == null) { + System.err.println("Error: no package specified"); + showUsage(); + return; + } + displayPackageFilePath(pkg); + } + + class PackageInstallObserver extends IPackageInstallObserver.Stub { + boolean finished; + int result; + + public void packageInstalled(String name, int status) { + synchronized( this) { + finished = true; + result = status; + notifyAll(); + } + } + } + + private String installFailureToString(int result) { + String s; + switch (result) { + case PackageManager.INSTALL_FAILED_ALREADY_EXISTS: + s = "INSTALL_FAILED_ALREADY_EXISTS"; + break; + case PackageManager.INSTALL_FAILED_INVALID_APK: + s = "INSTALL_FAILED_INVALID_APK"; + break; + case PackageManager.INSTALL_FAILED_INVALID_URI: + s = "INSTALL_FAILED_INVALID_URI"; + break; + case PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE: + s = "INSTALL_FAILED_INSUFFICIENT_STORAGE"; + break; + case PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE: + s = "INSTALL_FAILED_DUPLICATE_PACKAGE"; + break; + case PackageManager.INSTALL_FAILED_NO_SHARED_USER: + s = "INSTALL_FAILED_NO_SHARED_USER"; + break; + case PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE: + s = "INSTALL_FAILED_UPDATE_INCOMPATIBLE"; + break; + case PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE: + s = "INSTALL_FAILED_SHARED_USER_INCOMPATIBLE"; + break; + case PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY: + s = "INSTALL_FAILED_MISSING_SHARED_LIBRARY"; + break; + case PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE: + s = "INSTALL_FAILED_REPLACE_COULDNT_DELETE"; + break; + case PackageManager.INSTALL_PARSE_FAILED_NOT_APK: + s = "INSTALL_PARSE_FAILED_NOT_APK"; + break; + case PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST: + s = "INSTALL_PARSE_FAILED_BAD_MANIFEST"; + break; + case PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: + s = "INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION"; + break; + case PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES: + s = "INSTALL_PARSE_FAILED_NO_CERTIFICATES"; + break; + case PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES: + s = "INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES"; + break; + case PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING: + s = "INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING"; + break; + case PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME: + s = "INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME"; + break; + case PackageManager.INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID: + s = "INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID"; + break; + case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED: + s = "INSTALL_PARSE_FAILED_MANIFEST_MALFORMED"; + break; + case PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY: + s = "INSTALL_PARSE_FAILED_MANIFEST_EMPTY"; + break; + default: + s = Integer.toString(result); + break; + } + return s; + } + + private void runInstall() { + int installFlags = 0; + + String opt; + while ((opt=nextOption()) != null) { + if (opt.equals("-l")) { + installFlags |= PackageManager.FORWARD_LOCK_PACKAGE; + } else if (opt.equals("-r")) { + installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE; + } else { + System.err.println("Error: Unknown option: " + opt); + showUsage(); + return; + } + } + + String apkFilePath = nextArg(); + System.err.println("\tpkg: " + apkFilePath); + if (apkFilePath == null) { + System.err.println("Error: no package specified"); + showUsage(); + return; + } + + PackageInstallObserver obs = new PackageInstallObserver(); + try { + mPm.installPackage(Uri.fromFile(new File(apkFilePath)), obs, installFlags); + + synchronized (obs) { + while (!obs.finished) { + try { + obs.wait(); + } catch (InterruptedException e) { + } + } + if (obs.result == PackageManager.INSTALL_SUCCEEDED) { + System.out.println("Success"); + } else { + System.err.println("Failure [" + + installFailureToString(obs.result) + + "]"); + } + } + } catch (RemoteException e) { + } + } + + class PackageDeleteObserver extends IPackageDeleteObserver.Stub { + boolean finished; + boolean result; + + public void packageDeleted(boolean succeeded) { + synchronized (this) { + finished = true; + result = succeeded; + notifyAll(); + } + } + } + + private void runUninstall() { + int unInstallFlags = 0; + + String opt = nextOption(); + if (opt != null && opt.equals("-k")) { + unInstallFlags = PackageManager.DONT_DELETE_DATA; + } + + String pkg = nextArg(); + if (pkg == null) { + System.err.println("Error: no package specified"); + showUsage(); + return; + } + boolean result = deletePackage(pkg, unInstallFlags); + if (result) { + System.out.println("Success"); + } else { + System.out.println("Failure"); + } + } + + private boolean deletePackage(String pkg, int unInstallFlags) { + PackageDeleteObserver obs = new PackageDeleteObserver(); + try { + mPm.deletePackage(pkg, obs, unInstallFlags); + + synchronized (obs) { + while (!obs.finished) { + try { + obs.wait(); + } catch (InterruptedException e) { + } + } + } + } catch (RemoteException e) { + } + return obs.result; + } + + /** + * Displays the package file for a package. + * @param pckg + */ + private void displayPackageFilePath(String pckg) { + try { + PackageInfo info = mPm.getPackageInfo(pckg, 0); + if (info != null && info.applicationInfo != null) { + System.out.print("package:"); + System.out.println(info.applicationInfo.sourceDir); + } + } catch (RemoteException e) { + } + } + + private Resources getResources(PackageItemInfo pii) { + Resources res = mResourceCache.get(pii.packageName); + if (res != null) return res; + + try { + ApplicationInfo ai = mPm.getApplicationInfo(pii.packageName, 0); + AssetManager am = new AssetManager(); + am.addAssetPath(ai.publicSourceDir); + res = new Resources(am, null, null); + mResourceCache.put(pii.packageName, res); + return res; + } catch (RemoteException e) { + System.err.println("Package manager gone!"); + return null; + } + } + + private String nextOption() { + 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 nextOptionData() { + if (mCurArgData != null) { + return mCurArgData; + } + if (mNextArg >= mArgs.length) { + return null; + } + String data = mArgs[mNextArg]; + mNextArg++; + return data; + } + + private String nextArg() { + if (mNextArg >= mArgs.length) { + return null; + } + String arg = mArgs[mNextArg]; + mNextArg++; + return arg; + } + + private static void showUsage() { + System.err.println("usage: pm [list|path|install|uninstall]"); + System.err.println(" pm list packages [-f]"); + System.err.println(" pm list permission-groups"); + System.err.println(" pm list permissions [-g] [-f] [-d] [-u] [GROUP]"); + System.err.println(" pm path PACKAGE"); + System.err.println(" pm install [-l] [-r] PATH"); + System.err.println(" pm uninstall [-k] PACKAGE"); + System.err.println(""); + System.err.println("The list packages command prints all packages. Use"); + System.err.println("the -f option to see their associated file."); + System.err.println(""); + System.err.println("The list permission-groups command prints all known"); + System.err.println("permission groups."); + System.err.println(""); + System.err.println("The list permissions command prints all known"); + System.err.println("permissions, optionally only those in GROUP. Use"); + System.err.println("the -g option to organize by group. Use"); + System.err.println("the -f option to print all information. Use"); + System.err.println("the -s option for a short summary. Use"); + System.err.println("the -d option to only list dangerous permissions. Use"); + System.err.println("the -u option to list only the permissions users will see."); + System.err.println(""); + System.err.println("The path command prints the path to the .apk of a package."); + System.err.println(""); + System.err.println("The install command installs a package to the system. Use"); + System.err.println("the -l option to install the package with FORWARD_LOCK. Use"); + System.err.println("the -r option to reinstall an exisiting app, keeping its data."); + System.err.println(""); + System.err.println("The uninstall command removes a package from the system. Use"); + System.err.println("the -k option to keep the data and cache directories around"); + System.err.println("after the package removal."); + } +} diff --git a/cmds/runtime/Android.mk b/cmds/runtime/Android.mk new file mode 100644 index 0000000..00fa8a2 --- /dev/null +++ b/cmds/runtime/Android.mk @@ -0,0 +1,29 @@ +ifeq ($(TARGET_SIMULATOR),true) + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + ServiceManager.cpp \ + SignalHandler.cpp \ + main_runtime.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libandroid_runtime \ + libcutils \ + libui \ + libsystem_server \ + libhardware + +LOCAL_C_INCLUDES := \ + $(JNI_H_INCLUDE) + +ifeq ($(TARGET_OS),linux) + LOCAL_CFLAGS += -DXP_UNIX +endif + +LOCAL_MODULE:= runtime + +include $(BUILD_EXECUTABLE) +endif diff --git a/cmds/runtime/MODULE_LICENSE_APACHE2 b/cmds/runtime/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/runtime/MODULE_LICENSE_APACHE2 diff --git a/cmds/runtime/NOTICE b/cmds/runtime/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/runtime/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/runtime/ServiceManager.cpp b/cmds/runtime/ServiceManager.cpp new file mode 100644 index 0000000..758a95c --- /dev/null +++ b/cmds/runtime/ServiceManager.cpp @@ -0,0 +1,74 @@ +// +// Copyright 2005 The Android Open Source Project +// + +#define LOG_TAG "ServiceManager" + +#include "ServiceManager.h" +#include "SignalHandler.h" + +#include <utils/Debug.h> +#include <utils/Log.h> +#include <utils/Parcel.h> +#include <utils/String8.h> +#include <utils/ProcessState.h> + +#include <private/utils/Static.h> + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> + +namespace android { + +BServiceManager::BServiceManager() +{ +} + +sp<IBinder> BServiceManager::getService(const String16& name) const +{ + AutoMutex _l(mLock); + ssize_t i = mServices.indexOfKey(name); + LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i); + if (i >= 0) return mServices.valueAt(i); + return NULL; +} + +sp<IBinder> BServiceManager::checkService(const String16& name) const +{ + AutoMutex _l(mLock); + ssize_t i = mServices.indexOfKey(name); + LOGV("ServiceManager: getService(%s) -> %d\n", String8(name).string(), i); + if (i >= 0) return mServices.valueAt(i); + return NULL; +} + +status_t BServiceManager::addService(const String16& name, const sp<IBinder>& service) +{ + AutoMutex _l(mLock); + LOGI("ServiceManager: addService(%s, %p)\n", String8(name).string(), service.get()); + const ssize_t res = mServices.add(name, service); + if (res >= NO_ERROR) { + mChanged.broadcast(); + return NO_ERROR; + } + return res; +} + +Vector<String16> BServiceManager::listServices() +{ + Vector<String16> res; + + AutoMutex _l(mLock); + const size_t N = mServices.size(); + for (size_t i=0; i<N; i++) { + res.add(mServices.keyAt(i)); + } + + return res; +} + +}; // namespace android diff --git a/cmds/runtime/ServiceManager.h b/cmds/runtime/ServiceManager.h new file mode 100644 index 0000000..d09cec8 --- /dev/null +++ b/cmds/runtime/ServiceManager.h @@ -0,0 +1,38 @@ +// +// Copyright 2005 The Android Open Source Project +// +#ifndef ANDROID_SERVICE_MANAGER_H +#define ANDROID_SERVICE_MANAGER_H + +#include <utils/IServiceManager.h> +#include <utils/KeyedVector.h> +#include <utils/threads.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class BServiceManager : public BnServiceManager +{ +public: + BServiceManager(); + + virtual sp<IBinder> getService( const String16& name) const; + virtual sp<IBinder> checkService( const String16& name) const; + virtual status_t addService( const String16& name, + const sp<IBinder>& service); + virtual Vector<String16> listServices(); + + +private: + mutable Mutex mLock; + mutable Condition mChanged; + sp<IPermissionController> mPermissionController; + KeyedVector<String16, sp<IBinder> > mServices; +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_SERVICE_MANAGER_H diff --git a/cmds/runtime/SignalHandler.cpp b/cmds/runtime/SignalHandler.cpp new file mode 100644 index 0000000..cccaabf --- /dev/null +++ b/cmds/runtime/SignalHandler.cpp @@ -0,0 +1,249 @@ +// +// Copyright 2005 The Android Open Source Project +// + +#define LOG_TAG "SignalHandler" + +#include "SignalHandler.h" + +#include <utils/Atomic.h> +#include <utils/Debug.h> +#include <utils/Log.h> + +#include <errno.h> +#include <sys/wait.h> +#include <unistd.h> + +namespace android { + +class SignalHandler::ProcessThread : public Thread +{ +public: + ProcessThread(SignalHandler& sh) + : Thread(false) + , mOwner(sh) + { + } + + virtual bool threadLoop() + { + char buffer[32]; + read(mOwner.mAvailMsg[0], buffer, sizeof(buffer)); + + LOGV("Signal command processing thread woke up!"); + + if (mOwner.mLostCommands) { + LOGE("Lost %d signals!", mOwner.mLostCommands); + mOwner.mLostCommands = 0; + } + + int cur; + while ((cur=mOwner.mCommandBottom) != mOwner.mCommandTop) { + if (mOwner.mCommands[cur].filled == 0) { + LOGV("Command at %d is not yet filled", cur); + break; + } + + LOGV("Processing command at %d, top is %d", + cur, mOwner.mCommandTop); + processCommand(mOwner.mCommands[cur]); + mOwner.mCommands[cur].filled = 0; + + int next = mOwner.mCommandBottom+1; + if (next >= COMMAND_QUEUE_SIZE) { + next = 0; + } + + mOwner.mCommandBottom = next; + } + + return true; + } + + void processCommand(const CommandEntry& entry) + { + switch (entry.signum) { + case SIGCHLD: { + mOwner.mLock.lock(); + ssize_t i = mOwner.mChildHandlers.indexOfKey(entry.info.si_pid); + ChildHandler ch; + if (i >= 0) { + ch = mOwner.mChildHandlers.valueAt(i); + mOwner.mChildHandlers.removeItemsAt(i); + } + mOwner.mLock.unlock(); + + LOGD("SIGCHLD: pid=%d, handle index=%d", entry.info.si_pid, i); + + if (i >= 0) { + int res = waitpid(entry.info.si_pid, NULL, WNOHANG); + LOGW_IF(res == 0, + "Received SIGCHLD, but pid %d is not yet stopped", + entry.info.si_pid); + if (ch.handler) { + ch.handler(entry.info.si_pid, ch.userData); + } + } else { + LOGW("Unhandled SIGCHLD for pid %d", entry.info.si_pid); + } + } break; + } + } + + SignalHandler& mOwner; +}; + + +Mutex SignalHandler::mInstanceLock; +SignalHandler* SignalHandler::mInstance = NULL; + +status_t SignalHandler::setChildHandler(pid_t childPid, + int tag, + child_callback_t handler, + void* userData) +{ + SignalHandler* const self = getInstance(); + + self->mLock.lock(); + + // First make sure this child hasn't already exited. + pid_t res = waitpid(childPid, NULL, WNOHANG); + if (res != 0) { + if (res < 0) { + LOGW("setChildHandler waitpid of %d failed: %d (%s)", + childPid, res, strerror(errno)); + } else { + LOGW("setChildHandler waitpid of %d said %d already dead", + childPid, res); + } + + // Some kind of error... just handle the exit now. + self->mLock.unlock(); + + if (handler) { + handler(childPid, userData); + } + + // Return an error code -- 0 means it already exited. + return (status_t)res; + } + + ChildHandler entry; + entry.childPid = childPid; + entry.tag = tag; + entry.handler = handler; + entry.userData = userData; + + // Note: this replaces an existing entry for this pid, if there already + // is one. This is the required behavior. + LOGD("setChildHandler adding pid %d, tag %d, handler %p, data %p", + childPid, tag, handler, userData); + self->mChildHandlers.add(childPid, entry); + + self->mLock.unlock(); + + return NO_ERROR; +} + +void SignalHandler::killAllChildren(int tag) +{ + SignalHandler* const self = getInstance(); + + AutoMutex _l (self->mLock); + const size_t N = self->mChildHandlers.size(); + for (size_t i=0; i<N; i++) { + const ChildHandler& ch(self->mChildHandlers.valueAt(i)); + if (tag == 0 || ch.tag == tag) { + const pid_t pid = ch.childPid; + LOGI("Killing child %d (tag %d)\n", pid, ch.tag); + kill(pid, SIGKILL); + } + } +} + +SignalHandler::SignalHandler() + : mCommandTop(0) + , mCommandBottom(0) + , mLostCommands(0) +{ + memset(mCommands, 0, sizeof(mCommands)); + + int res = pipe(mAvailMsg); + LOGE_IF(res != 0, "Unable to create signal handler pipe: %s", strerror(errno)); + + mProcessThread = new ProcessThread(*this); + mProcessThread->run("SignalHandler", PRIORITY_HIGHEST); + + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = sigAction; + sa.sa_flags = SA_NOCLDSTOP|SA_SIGINFO; + sigaction(SIGCHLD, &sa, NULL); +} + +SignalHandler::~SignalHandler() +{ +} + +SignalHandler* SignalHandler::getInstance() +{ + AutoMutex _l(mInstanceLock); + if (mInstance == NULL) { + mInstance = new SignalHandler(); + } + return mInstance; +} + +void SignalHandler::sigAction(int signum, siginfo_t* info, void*) +{ + static const char wakeupMsg[1] = { 0xff }; + + // If our signal handler is being called, then we know we have + // already initialized the SignalHandler class and thus mInstance + // is valid. + SignalHandler* const self = mInstance; + + // XXX This is not safe! + #if 0 + LOGV("Signal %d: signo=%d, errno=%d, code=%d, pid=%d\n", + signum, + info->si_signo, info->si_errno, info->si_code, + info->si_pid); + #endif + + int32_t oldTop, newTop; + + // Find the next command slot... + do { + oldTop = self->mCommandTop; + + newTop = oldTop + 1; + if (newTop >= COMMAND_QUEUE_SIZE) { + newTop = 0; + } + + if (newTop == self->mCommandBottom) { + // The buffer is filled up! Ouch! + // XXX This is not safe! + #if 0 + LOGE("Command buffer overflow! newTop=%d\n", newTop); + #endif + android_atomic_add(1, &self->mLostCommands); + write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg)); + return; + } + } while(android_atomic_cmpxchg(oldTop, newTop, &(self->mCommandTop))); + + // Fill in the command data... + self->mCommands[oldTop].signum = signum; + self->mCommands[oldTop].info = *info; + + // And now make this command available. + self->mCommands[oldTop].filled = 1; + + // Wake up the processing thread. + write(self->mAvailMsg[1], wakeupMsg, sizeof(wakeupMsg)); +} + +}; // namespace android + diff --git a/cmds/runtime/SignalHandler.h b/cmds/runtime/SignalHandler.h new file mode 100644 index 0000000..7f4ef8e --- /dev/null +++ b/cmds/runtime/SignalHandler.h @@ -0,0 +1,137 @@ +// +// Copyright 2005 The Android Open Source Project +// +#ifndef ANDROID_SIGNAL_HANDLER_H +#define ANDROID_SIGNAL_HANDLER_H + +#include <utils/KeyedVector.h> +#include <utils/threads.h> + +#include <signal.h> + +namespace android { + +// ---------------------------------------------------------------------- + +enum { + DEFAULT_PROCESS_TAG = 1 +}; + +class SignalHandler +{ +public: + typedef void (*child_callback_t)(pid_t child, void* userData); + + /** + * Set a handler for when a child process exits. By calling + * this, a waitpid() will be done when the child exits to remove + * it from the zombie state. You can also optionally specify a + * handler to be called when the child exits. + * + * If there is already a handler for this child process, it is + * replaced by this new handler. In this case the old handler's + * function is not called. + * + * @param childPid Process ID of child to watch. + * @param childTag User-defined tag for this child. Must be + * greater than zero. + * @param handler If non-NULL, this will be called when the + * child exits. It may be called in either a + * separate signal handling thread, or + * immediately if the child has already exited. + * @param userData Propageted as-is to handler. + * + * @return status_t NO_ERROR if all is well. + */ + static status_t setChildHandler(pid_t childPid, + int childTag = DEFAULT_PROCESS_TAG, + child_callback_t handler = NULL, + void* userData = NULL); + + /** + * Kill all of the child processes for which we have a waiting + * handler, whose tag is the given value. If tag is 0, all + * children are killed. + * + * @param tag + */ + static void killAllChildren(int tag = 0); + +private: + SignalHandler(); + ~SignalHandler(); + + static SignalHandler* getInstance(); + + static void sigAction(int, siginfo_t*, void*); + + // -------------------------------------------------- + // Shared state... all of this is protected by mLock. + // -------------------------------------------------- + + mutable Mutex mLock; + + struct ChildHandler + { + pid_t childPid; + int tag; + child_callback_t handler; + void* userData; + }; + KeyedVector<pid_t, ChildHandler> mChildHandlers; + + // -------------------------------------------------- + // Commmand queue... data is inserted by the signal + // handler using atomic ops, and retrieved by the + // signal processing thread. Because these are touched + // by the signal handler, no lock is used. + // -------------------------------------------------- + + enum { + COMMAND_QUEUE_SIZE = 64 + }; + struct CommandEntry + { + int filled; + int signum; + siginfo_t info; + }; + + // The top of the queue. This is incremented atomically by the + // signal handler before placing a command in the queue. + volatile int32_t mCommandTop; + + // The bottom of the queue. Only modified by the processing + // thread; the signal handler reads it only to determine if the + // queue is full. + int32_t mCommandBottom; + + // Incremented each time we receive a signal and don't have room + // for it on the command queue. + volatile int32_t mLostCommands; + + // The command processing thread. + class ProcessThread; + sp<Thread> mProcessThread; + + // Pipe used to tell command processing thread when new commands. + // are available. The thread blocks on the read end, the signal + // handler writes when it enqueues new commands. + int mAvailMsg[2]; + + // The commands. + CommandEntry mCommands[COMMAND_QUEUE_SIZE]; + + // -------------------------------------------------- + // Singleton. + // -------------------------------------------------- + + static Mutex mInstanceLock; + static SignalHandler* mInstance; +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_SIGNAL_HANDLER_H diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp new file mode 100644 index 0000000..1531a9e --- /dev/null +++ b/cmds/runtime/main_runtime.cpp @@ -0,0 +1,514 @@ +// +// Copyright 2005 The Android Open Source Project +// +// Main entry point for runtime. +// + +#include "ServiceManager.h" +#include "SignalHandler.h" + +#include <utils.h> +#include <utils/IPCThreadState.h> +#include <utils/ProcessState.h> +#include <utils/Log.h> +#include <cutils/zygote.h> + +#include <cutils/properties.h> + +#include <private/utils/Static.h> + +#include <ui/ISurfaceComposer.h> + +#include <android_runtime/AndroidRuntime.h> + +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <signal.h> +#include <errno.h> +#include <sys/stat.h> +#include <linux/capability.h> +#include <linux/ioctl.h> +#ifdef HAVE_ANDROID_OS +# include <linux/android_alarm.h> +#endif + +#undef LOG_TAG +#define LOG_TAG "runtime" + +static const char* ZYGOTE_ARGV[] = { + "--setuid=1000", + "--setgid=1000", + "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003", + /* CAP_SYS_TTY_CONFIG & CAP_SYS_RESOURCE & CAP_NET_BROADCAST & + * CAP_NET_ADMIN & CAP_NET_RAW & CAP_NET_BIND_SERVICE & CAP_KILL & + * CAP_SYS_BOOT + */ + "--capabilities=88161312,88161312", + "--runtime-init", + "--nice-name=system_server", + "com.android.server.SystemServer" +}; + +using namespace android; + +extern "C" status_t system_init(); + +enum { + SYSTEM_PROCESS_TAG = DEFAULT_PROCESS_TAG+1 +}; + +extern Mutex gEventQMutex; +extern Condition gEventQCondition; + +namespace android { + +extern status_t app_init(const char* className); +extern void set_finish_init_func(void (*func)()); + + +/** + * This class is used to kill this process (runtime) when the system_server dies. + */ +class GrimReaper : public IBinder::DeathRecipient { +public: + GrimReaper() { } + + virtual void binderDied(const wp<IBinder>& who) + { + LOGI("Grim Reaper killing runtime..."); + kill(getpid(), SIGKILL); + } +}; + +extern void QuickTests(); + +/* + * Print usage info. + */ +static void usage(const char* argv0) +{ + fprintf(stderr, + "Usage: runtime [-g gamma] [-l logfile] [-n] [-s]\n" + " [-j app-component] [-v app-verb] [-d app-data]\n" + "\n" + "-l: File to send log messages to\n" + "-n: Don't print to stdout/stderr\n" + "-s: Force single-process mode\n" + "-j: Custom home app component name\n" + "-v: Custom home app intent verb\n" + "-d: Custom home app intent data\n" + ); + exit(1); +} + +// Selected application to run. +static const char* gInitialApplication = NULL; +static const char* gInitialVerb = NULL; +static const char* gInitialData = NULL; + +static void writeStringToParcel(Parcel& parcel, const char* str) +{ + if (str) { + parcel.writeString16(String16(str)); + } else { + parcel.writeString16(NULL, 0); + } +} + +/* + * Starting point for program logic. + * + * Returns with an exit status code (0 on success, nonzero on error). + */ +static int run(sp<ProcessState>& proc) +{ + // Temporary hack to call startRunning() on the activity manager. + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> am; + while ((am = sm->getService(String16("activity"))) == NULL) { + LOGI("Waiting for activity manager..."); + } + Parcel data, reply; + // XXX Need to also supply a package name for this to work again. + // IActivityManager::getInterfaceDescriptor() is the token for invoking on this interface; + // hardcoding it here avoids having to link with the full Activity Manager library + data.writeInterfaceToken(String16("android.app.IActivityManager")); + writeStringToParcel(data, NULL); + writeStringToParcel(data, gInitialApplication); + writeStringToParcel(data, gInitialVerb); + writeStringToParcel(data, gInitialData); +LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager"); + am->transact(IBinder::FIRST_CALL_TRANSACTION, data, &reply); + + if (proc->supportsProcesses()) { + // Now we link to the Activity Manager waiting for it to die. If it does kill ourself. + // initd will restart this process and bring the system back up. + sp<GrimReaper> grim = new GrimReaper(); + am->linkToDeath(grim, grim.get(), 0); + + // Now join the thread pool. Note this is needed so that the message enqueued in the driver + // for the linkToDeath gets processed. + IPCThreadState::self()->joinThreadPool(); + } else { + // Keep this thread running forever... + while (1) { + usleep(100000); + } + } + return 1; +} + + +}; // namespace android + + +/* + * Post-system-process initialization. + * + * This function continues initialization after the system process + * has been initialized. It needs to be separate because the system + * initialization needs to care of starting the Android runtime if it is not + * running in its own process, which doesn't return until the runtime is + * being shut down. So it will call back to here from inside of Dalvik, + * to allow us to continue booting up. + */ +static void finish_system_init(sp<ProcessState>& proc) +{ + // If we are running multiprocess, we now need to have the + // thread pool started here. We don't do this in boot_init() + // because when running single process we need to start the + // thread pool after the Android runtime has been started (so + // the pool uses Dalvik threads). + if (proc->supportsProcesses()) { + proc->startThreadPool(); + } +} + + +// This function can be used to enforce security to different +// root contexts. For now, we just give every access. +static bool contextChecker( + const String16& name, const sp<IBinder>& caller, void* userData) +{ + return true; +} + +/* + * Initialization of boot services. + * + * This is where we perform initialization of all of our low-level + * boot services. Most importantly, here we become the context + * manager and use that to publish the service manager that will provide + * access to all other services. + */ +static void boot_init() +{ + LOGI("Entered boot_init()!\n"); + + sp<ProcessState> proc(ProcessState::self()); + LOGD("ProcessState: %p\n", proc.get()); + proc->becomeContextManager(contextChecker, NULL); + + if (proc->supportsProcesses()) { + LOGI("Binder driver opened. Multiprocess enabled.\n"); + } else { + LOGI("Binder driver not found. Processes not supported.\n"); + } + + sp<BServiceManager> sm = new BServiceManager; + proc->setContextObject(sm); +} + +/* + * Redirect stdin/stdout/stderr to /dev/null. + */ +static void redirectStdFds(void) +{ + int fd = open("/dev/null", O_RDWR, 0); + if (fd < 0) { + LOGW("Unable to open /dev/null: %s\n", strerror(errno)); + } else { + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + close(fd); + } +} + +static int hasDir(const char* dir) +{ + struct stat s; + int res = stat(dir, &s); + if (res == 0) { + return S_ISDIR(s.st_mode); + } + return 0; +} + +static void validateTime() +{ +#if HAVE_ANDROID_OS + int fd; + int res; + time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year + struct timespec ts; + + fd = open("/dev/alarm", O_RDWR); + if(fd < 0) { + LOGW("Unable to open alarm driver: %s\n", strerror(errno)); + return; + } + res = ioctl(fd, ANDROID_ALARM_GET_TIME(ANDROID_ALARM_RTC_WAKEUP), &ts); + if(res < 0) { + LOGW("Unable to read rtc, %s\n", strerror(errno)); + } + else if(ts.tv_sec >= min_time) { + goto done; + } + LOGW("Invalid time detected, %ld set to %ld\n", ts.tv_sec, min_time); + ts.tv_sec = min_time; + ts.tv_nsec = 0; + res = ioctl(fd, ANDROID_ALARM_SET_RTC, &ts); + if(res < 0) { + LOGW("Unable to set rtc to %ld: %s\n", ts.tv_sec, strerror(errno)); + } +done: + close(fd); +#endif +} + +#ifndef HAVE_ANDROID_OS +class QuickRuntime : public AndroidRuntime +{ +public: + QuickRuntime() {} + + virtual void onStarted() + { + printf("QuickRuntime: onStarted\n"); + } +}; +#endif + +static status_t start_process(const char* name); + +static void restart_me(pid_t child, void* userData) +{ + start_process((const char*)userData); +} + +static status_t start_process(const char* name) +{ + String8 path(name); + Vector<const char*> args; + String8 leaf(path.getPathLeaf()); + String8 parentDir(path.getPathDir()); + args.insertAt(leaf.string(), 0); + args.add(parentDir.string()); + args.add(NULL); + pid_t child = fork(); + if (child < 0) { + status_t err = errno; + LOGE("*** fork of child %s failed: %s", leaf.string(), strerror(err)); + return -errno; + } else if (child == 0) { + LOGI("Executing: %s", path.string()); + execv(path.string(), const_cast<char**>(args.array())); + int err = errno; + LOGE("Exec failed: %s\n", strerror(err)); + _exit(err); + } else { + SignalHandler::setChildHandler(child, DEFAULT_PROCESS_TAG, + restart_me, (void*)name); + } + return -errno; +} + +/* + * Application entry point. + * + * Parse arguments, set some values, and pass control off to Run(). + * + * This is redefined to "SDL_main" on SDL simulator builds, and + * "runtime_main" on wxWidgets builds. + */ +extern "C" +int main(int argc, char* const argv[]) +{ + bool singleProcess = false; + const char* logFile = NULL; + int ic; + int result = 1; + pid_t systemPid; + + sp<ProcessState> proc; + +#ifndef HAVE_ANDROID_OS + /* Set stdout/stderr to unbuffered for MinGW/MSYS. */ + //setvbuf(stdout, NULL, _IONBF, 0); + //setvbuf(stderr, NULL, _IONBF, 0); + + LOGI("commandline args:\n"); + for (int i = 0; i < argc; i++) + LOGI(" %2d: '%s'\n", i, argv[i]); +#endif + + while (1) { + ic = getopt(argc, argv, "g:j:v:d:l:ns"); + if (ic < 0) + break; + + switch (ic) { + case 'g': + break; + case 'j': + gInitialApplication = optarg; + break; + case 'v': + gInitialVerb = optarg; + break; + case 'd': + gInitialData = optarg; + break; + case 'l': + logFile = optarg; + break; + case 'n': + redirectStdFds(); + break; + case 's': + singleProcess = true; + break; + case '?': + default: + LOGE("runtime: unrecognized flag -%c\n", ic); + usage(argv[0]); + break; + } + } + if (optind < argc) { + LOGE("runtime: extra stuff: %s\n", argv[optind]); + usage(argv[0]); + } + + if (singleProcess) { + ProcessState::setSingleProcess(true); + } + + if (logFile != NULL) { + android_logToFile(NULL, logFile); + } + + /* + * Set up ANDROID_* environment variables. + * + * TODO: the use of $ANDROID_PRODUCT_OUT will go away soon. + */ + static const char* kSystemDir = "/system"; + static const char* kDataDir = "/data"; + static const char* kAppSubdir = "/app"; + const char* out = NULL; +#ifndef HAVE_ANDROID_OS + //out = getenv("ANDROID_PRODUCT_OUT"); +#endif + if (out == NULL) + out = ""; + + char* systemDir = (char*) malloc(strlen(out) + strlen(kSystemDir) +1); + char* dataDir = (char*) malloc(strlen(out) + strlen(kDataDir) +1); + + sprintf(systemDir, "%s%s", out, kSystemDir); + sprintf(dataDir, "%s%s", out, kDataDir); + setenv("ANDROID_ROOT", systemDir, 1); + setenv("ANDROID_DATA", dataDir, 1); + + char* assetDir = (char*) malloc(strlen(systemDir) + strlen(kAppSubdir) +1); + sprintf(assetDir, "%s%s", systemDir, kAppSubdir); + + LOGI("Startup: sys='%s' asset='%s' data='%s'\n", + systemDir, assetDir, dataDir); + free(systemDir); + free(dataDir); + +#ifdef HAVE_ANDROID_OS + /* set up a process group for easier killing on the device */ + setpgid(0, getpid()); +#endif + + // Change to asset dir. This is only necessary if we've changed to + // a different directory, but there's little harm in doing it regardless. + // + // Expecting assets to live in the current dir is not a great idea, + // because some of our code or one of our libraries could change the + // directory out from under us. Preserve the behavior for now. + if (chdir(assetDir) != 0) { + LOGW("WARNING: could not change dir to '%s': %s\n", + assetDir, strerror(errno)); + } + free(assetDir); + +#if 0 + // Hack to keep libc from beating the filesystem to death. It's + // hitting /etc/localtime frequently, + // + // This statement locks us into Pacific time. We could do better, + // but there's not much point until we're sure that the library + // can't be changed to do more along the lines of what we want. +#ifndef XP_WIN + setenv("TZ", "PST+8PDT,M4.1.0/2,M10.5.0/2", true); +#endif +#endif + + /* track our progress through the boot sequence */ + const int LOG_BOOT_PROGRESS_START = 3000; + LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, + ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); + + validateTime(); + + proc = ProcessState::self(); + + boot_init(); + + /* If we are in multiprocess mode, have zygote spawn the system + * server process and call system_init(). If we are running in + * single process mode just call system_init() directly. + */ + if (proc->supportsProcesses()) { + // If stdio logging is on, system_server should not inherit our stdio + // The dalvikvm instance will copy stdio to the log on its own + char propBuf[PROPERTY_VALUE_MAX]; + bool logStdio = false; + property_get("log.redirect-stdio", propBuf, ""); + logStdio = (strcmp(propBuf, "true") == 0); + + zygote_run_oneshot((int)(!logStdio), + sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]), + ZYGOTE_ARGV); + + //start_process("/system/bin/mediaserver"); + + } else { +#ifndef HAVE_ANDROID_OS + QuickRuntime* runt = new QuickRuntime(); + runt->start("com/android/server/SystemServer", + false /* spontaneously fork system server from zygote */); +#endif + } + + //printf("+++ post-zygote\n"); + + finish_system_init(proc); + run(proc); + +bail: + if (proc != NULL) { + proc->setContextObject(NULL); + } + + return 0; +} diff --git a/cmds/service/Android.mk b/cmds/service/Android.mk new file mode 100644 index 0000000..8c5005c --- /dev/null +++ b/cmds/service/Android.mk @@ -0,0 +1,17 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + service.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils + +ifeq ($(TARGET_OS),linux) + LOCAL_CFLAGS += -DXP_UNIX + #LOCAL_SHARED_LIBRARIES += librt +endif + +LOCAL_MODULE:= service + +include $(BUILD_EXECUTABLE) diff --git a/cmds/service/MODULE_LICENSE_APACHE2 b/cmds/service/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/service/MODULE_LICENSE_APACHE2 diff --git a/cmds/service/NOTICE b/cmds/service/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/service/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/service/service.cpp b/cmds/service/service.cpp new file mode 100644 index 0000000..859a9bf --- /dev/null +++ b/cmds/service/service.cpp @@ -0,0 +1,275 @@ +/* + * Command line access to services. + * + */ + +#include <utils/Parcel.h> +#include <utils/ProcessState.h> +#include <utils/IServiceManager.h> +#include <utils/TextOutput.h> + +#include <getopt.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + +using namespace android; + +void writeString16(Parcel& parcel, const char* string) +{ + if (string != NULL) + { + parcel.writeString16(String16(string)); + } + else + { + parcel.writeInt32(-1); + } +} + +// get the name of the generic interface we hold a reference to +static String16 get_interface_name(sp<IBinder> service) +{ + if (service != NULL) { + Parcel data, reply; + status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply); + if (err == NO_ERROR) { + return reply.readString16(); + } + } + return String16(); +} + +static String8 good_old_string(const String16& src) +{ + String8 name8; + char ch8[2]; + ch8[1] = 0; + for (unsigned j = 0; j < src.size(); j++) { + char16_t ch = src[j]; + if (ch < 128) ch8[0] = (char)ch; + name8.append(ch8); + } + return name8; +} + +int main(int argc, char* const argv[]) +{ + sp<IServiceManager> sm = defaultServiceManager(); + fflush(stdout); + if (sm == NULL) { + aerr << "service: Unable to get default service manager!" << endl; + return 20; + } + + bool wantsUsage = false; + int result = 0; + + while (1) { + int ic = getopt(argc, argv, "h?"); + if (ic < 0) + break; + + switch (ic) { + case 'h': + case '?': + wantsUsage = true; + break; + default: + aerr << "service: Unknown option -" << ic << endl; + wantsUsage = true; + result = 10; + break; + } + } + + if (optind >= argc) { + wantsUsage = true; + } else if (!wantsUsage) { + if (strcmp(argv[optind], "check") == 0) { + optind++; + if (optind < argc) { + sp<IBinder> service = sm->checkService(String16(argv[optind])); + aout << "Service " << argv[optind] << + (service == NULL ? ": not found" : ": found") << endl; + } else { + aerr << "service: No service specified for check" << endl; + wantsUsage = true; + result = 10; + } + } + else if (strcmp(argv[optind], "list") == 0) { + Vector<String16> services = sm->listServices(); + aout << "Found " << services.size() << " services:" << endl; + for (unsigned i = 0; i < services.size(); i++) { + String16 name = services[i]; + sp<IBinder> service = sm->checkService(name); + aout << i + << "\t" << good_old_string(name) + << ": [" << good_old_string(get_interface_name(service)) << "]" + << endl; + } + } else if (strcmp(argv[optind], "call") == 0) { + optind++; + if (optind+1 < argc) { + int serviceArg = optind; + sp<IBinder> service = sm->checkService(String16(argv[optind++])); + String16 ifName = get_interface_name(service); + int32_t code = atoi(argv[optind++]); + if (service != NULL && ifName.size() > 0) { + Parcel data, reply; + + // the interface name is first + data.writeInterfaceToken(ifName); + + // then the rest of the call arguments + while (optind < argc) { + if (strcmp(argv[optind], "i32") == 0) { + optind++; + if (optind >= argc) { + aerr << "service: no integer supplied for 'i32'" << endl; + wantsUsage = true; + result = 10; + break; + } + data.writeInt32(atoi(argv[optind++])); + } else if (strcmp(argv[optind], "s16") == 0) { + optind++; + if (optind >= argc) { + aerr << "service: no string supplied for 's16'" << endl; + wantsUsage = true; + result = 10; + break; + } + data.writeString16(String16(argv[optind++])); + } else if (strcmp(argv[optind], "null") == 0) { + optind++; + data.writeStrongBinder(NULL); + } else if (strcmp(argv[optind], "intent") == 0) { + + char* action = NULL; + char* dataArg = NULL; + char* type = NULL; + int launchFlags = 0; + char* component = NULL; + int categoryCount = 0; + char* categories[16]; + + char* context1 = NULL; + + optind++; + + while (optind < argc) + { + char* key = strtok_r(argv[optind], "=", &context1); + char* value = strtok_r(NULL, "=", &context1); + + // we have reached the end of the XXX=XXX args. + if (key == NULL) break; + + if (strcmp(key, "action") == 0) + { + action = value; + } + else if (strcmp(key, "data") == 0) + { + dataArg = value; + } + else if (strcmp(key, "type") == 0) + { + type = value; + } + else if (strcmp(key, "launchFlags") == 0) + { + launchFlags = atoi(value); + } + else if (strcmp(key, "component") == 0) + { + component = value; + } + else if (strcmp(key, "categories") == 0) + { + char* context2 = NULL; + int categoryCount = 0; + categories[categoryCount] = strtok_r(value, ",", &context2); + + while (categories[categoryCount] != NULL) + { + categoryCount++; + categories[categoryCount] = strtok_r(NULL, ",", &context2); + } + } + + optind++; + } + + writeString16(data, action); + writeString16(data, dataArg); + writeString16(data, type); + data.writeInt32(launchFlags); + writeString16(data, component); + + if (categoryCount > 0) + { + data.writeInt32(categoryCount); + for (int i = 0 ; i < categoryCount ; i++) + { + writeString16(data, categories[i]); + } + } + else + { + data.writeInt32(0); + } + + // for now just set the extra field to be null. + data.writeInt32(-1); + } else { + aerr << "service: unknown option " << argv[optind] << endl; + wantsUsage = true; + result = 10; + break; + } + } + + service->transact(code, data, &reply); + aout << "Result: " << reply << endl; + } else { + aerr << "service: Service " << argv[serviceArg] + << " does not exist" << endl; + result = 10; + } + } else { + if (optind < argc) { + aerr << "service: No service specified for call" << endl; + } else { + aerr << "service: No code specified for call" << endl; + } + wantsUsage = true; + result = 10; + } + } else { + aerr << "service: Unknown command " << argv[optind] << endl; + wantsUsage = true; + result = 10; + } + } + + if (wantsUsage) { + aout << "Usage: service [-h|-?]\n" + " service list\n" + " service check SERVICE\n" + " service call SERVICE CODE [i32 INT | s16 STR] ...\n" + "Options:\n" + " i32: Write the integer INT into the send parcel.\n" + " s16: Write the UTF-16 string STR into the send parcel.\n"; +// " intent: Write and Intent int the send parcel. ARGS can be\n" +// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; + return result; + } + + return result; +} + diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk new file mode 100644 index 0000000..25266a2 --- /dev/null +++ b/cmds/servicemanager/Android.mk @@ -0,0 +1,14 @@ +ifneq ($(TARGET_SIMULATOR),true) +LOCAL_PATH:= $(call my-dir) + +#include $(CLEAR_VARS) +#LOCAL_SRC_FILES := bctest.c binder.c +#LOCAL_MODULE := bctest +#include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_SHARED_LIBRARIES := liblog +LOCAL_SRC_FILES := service_manager.c binder.c +LOCAL_MODULE := servicemanager +include $(BUILD_EXECUTABLE) +endif diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c new file mode 100644 index 0000000..6dee816 --- /dev/null +++ b/cmds/servicemanager/bctest.c @@ -0,0 +1,102 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#include "binder.h" + +void *svcmgr_lookup(struct binder_state *bs, void *target, const char *name) +{ + void *ptr; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE)) + return 0; + + ptr = bio_get_ref(&reply); + + if (ptr) + binder_acquire(bs, ptr); + + binder_done(bs, &msg, &reply); + + return ptr; +} + +int svcmgr_publish(struct binder_state *bs, void *target, const char *name, void *ptr) +{ + unsigned status; + unsigned iodata[512/4]; + struct binder_io msg, reply; + + bio_init(&msg, iodata, sizeof(iodata), 4); + + bio_put_string16_x(&msg, SVC_MGR_NAME); + bio_put_string16_x(&msg, name); + bio_put_obj(&msg, ptr); + + if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)) + return -1; + + status = bio_get_uint32(&reply); + + binder_done(bs, &msg, &reply); + + return status; +} + +unsigned token; + +int main(int argc, char **argv) +{ + int fd; + struct binder_state *bs; + void *svcmgr = BINDER_SERVICE_MANAGER; + + bs = binder_open(128*1024); + + argc--; + argv++; + while (argc > 0) { + if (!strcmp(argv[0],"alt")) { + void *ptr = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr"); + if (!ptr) { + fprintf(stderr,"cannot find alt_svc_mgr\n"); + return -1; + } + svcmgr = ptr; + fprintf(stderr,"svcmgr is via %p\n", ptr); + } else if (!strcmp(argv[0],"lookup")) { + void *ptr; + if (argc < 2) { + fprintf(stderr,"argument required\n"); + return -1; + } + ptr = svcmgr_lookup(bs, svcmgr, argv[1]); + fprintf(stderr,"lookup(%s) = %p\n", argv[1], ptr); + argc--; + argv++; + } else if (!strcmp(argv[0],"publish")) { + if (argc < 2) { + fprintf(stderr,"argument required\n"); + return -1; + } + svcmgr_publish(bs, svcmgr, argv[1], &token); + argc--; + argv++; + } else { + fprintf(stderr,"unknown command %s\n", argv[0]); + return -1; + } + argc--; + argv++; + } + return 0; +} diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c new file mode 100644 index 0000000..b03b620 --- /dev/null +++ b/cmds/servicemanager/binder.c @@ -0,0 +1,616 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include "binder.h" + +#define MAX_BIO_SIZE (1 << 30) + +#define TRACE 0 + +#define LOG_TAG "Binder" +#include <cutils/log.h> + +void bio_init_from_txn(struct binder_io *io, struct binder_txn *txn); + +#if TRACE +void hexdump(void *_data, unsigned len) +{ + unsigned char *data = _data; + unsigned count; + + for (count = 0; count < len; count++) { + if ((count & 15) == 0) + fprintf(stderr,"%04x:", count); + fprintf(stderr," %02x %c", *data, + (*data < 32) || (*data > 126) ? '.' : *data); + data++; + if ((count & 15) == 15) + fprintf(stderr,"\n"); + } + if ((count & 15) != 0) + fprintf(stderr,"\n"); +} + +void binder_dump_txn(struct binder_txn *txn) +{ + struct binder_object *obj; + unsigned *offs = txn->offs; + unsigned count = txn->offs_size / 4; + + fprintf(stderr," target %p cookie %p code %08x flags %08x\n", + txn->target, txn->cookie, txn->code, txn->flags); + fprintf(stderr," pid %8d uid %8d data %8d offs %8d\n", + txn->sender_pid, txn->sender_euid, txn->data_size, txn->offs_size); + hexdump(txn->data, txn->data_size); + while (count--) { + obj = (void*) (((char*) txn->data) + *offs++); + fprintf(stderr," - type %08x flags %08x ptr %p cookie %p\n", + obj->type, obj->flags, obj->pointer, obj->cookie); + } +} + +#define NAME(n) case n: return #n +const char *cmd_name(uint32_t cmd) +{ + switch(cmd) { + NAME(BR_NOOP); + NAME(BR_TRANSACTION_COMPLETE); + NAME(BR_INCREFS); + NAME(BR_ACQUIRE); + NAME(BR_RELEASE); + NAME(BR_DECREFS); + NAME(BR_TRANSACTION); + NAME(BR_REPLY); + NAME(BR_FAILED_REPLY); + NAME(BR_DEAD_REPLY); + NAME(BR_DEAD_BINDER); + default: return "???"; + } +} +#else +#define hexdump(a,b) do{} while (0) +#define binder_dump_txn(txn) do{} while (0) +#endif + +#define BIO_F_SHARED 0x01 /* needs to be buffer freed */ +#define BIO_F_OVERFLOW 0x02 /* ran out of space */ +#define BIO_F_IOERROR 0x04 +#define BIO_F_MALLOCED 0x08 /* needs to be free()'d */ + +struct binder_state +{ + int fd; + void *mapped; + unsigned mapsize; +}; + +struct binder_state *binder_open(unsigned mapsize) +{ + struct binder_state *bs; + + bs = malloc(sizeof(*bs)); + if (!bs) { + errno = ENOMEM; + return 0; + } + + bs->fd = open("/dev/binder", O_RDWR); + if (bs->fd < 0) { + fprintf(stderr,"binder: cannot open device (%s)\n", + strerror(errno)); + goto fail_open; + } + + bs->mapsize = mapsize; + bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); + if (bs->mapped == MAP_FAILED) { + fprintf(stderr,"binder: cannot map device (%s)\n", + strerror(errno)); + goto fail_map; + } + + /* TODO: check version */ + + return bs; + +fail_map: + close(bs->fd); +fail_open: + free(bs); + return 0; +} + +void binder_close(struct binder_state *bs) +{ + munmap(bs->mapped, bs->mapsize); + close(bs->fd); + free(bs); +} + +int binder_become_context_manager(struct binder_state *bs) +{ + return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); +} + +int binder_write(struct binder_state *bs, void *data, unsigned len) +{ + struct binder_write_read bwr; + int res; + bwr.write_size = len; + bwr.write_consumed = 0; + bwr.write_buffer = (unsigned) data; + bwr.read_size = 0; + bwr.read_consumed = 0; + bwr.read_buffer = 0; + res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); + if (res < 0) { + fprintf(stderr,"binder_write: ioctl failed (%s)\n", + strerror(errno)); + } + return res; +} + +void binder_send_reply(struct binder_state *bs, + struct binder_io *reply, + void *buffer_to_free, + int status) +{ + struct { + uint32_t cmd_free; + void *buffer; + uint32_t cmd_reply; + struct binder_txn txn; + } __attribute__((packed)) data; + + data.cmd_free = BC_FREE_BUFFER; + data.buffer = buffer_to_free; + data.cmd_reply = BC_REPLY; + data.txn.target = 0; + data.txn.cookie = 0; + data.txn.code = 0; + if (status) { + data.txn.flags = TF_STATUS_CODE; + data.txn.data_size = sizeof(int); + data.txn.offs_size = 0; + data.txn.data = &status; + data.txn.offs = 0; + } else { + data.txn.flags = 0; + data.txn.data_size = reply->data - reply->data0; + data.txn.offs_size = ((char*) reply->offs) - ((char*) reply->offs0); + data.txn.data = reply->data0; + data.txn.offs = reply->offs0; + } + binder_write(bs, &data, sizeof(data)); +} + +int binder_parse(struct binder_state *bs, struct binder_io *bio, + uint32_t *ptr, uint32_t size, binder_handler func) +{ + int r = 1; + uint32_t *end = ptr + (size / 4); + + while (ptr < end) { + uint32_t cmd = *ptr++; +#if TRACE + fprintf(stderr,"%s:\n", cmd_name(cmd)); +#endif + switch(cmd) { + case BR_NOOP: + break; + case BR_TRANSACTION_COMPLETE: + break; + case BR_INCREFS: + case BR_ACQUIRE: + case BR_RELEASE: + case BR_DECREFS: +#if TRACE + fprintf(stderr," %08x %08x\n", ptr[0], ptr[1]); +#endif + ptr += 2; + break; + case BR_TRANSACTION: { + struct binder_txn *txn = (void *) ptr; + if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) { + LOGE("parse: txn too small!\n"); + return -1; + } + binder_dump_txn(txn); + if (func) { + unsigned rdata[256/4]; + struct binder_io msg; + struct binder_io reply; + int res; + + bio_init(&reply, rdata, sizeof(rdata), 4); + bio_init_from_txn(&msg, txn); + res = func(bs, txn, &msg, &reply); + binder_send_reply(bs, &reply, txn->data, res); + } + ptr += sizeof(*txn) / sizeof(uint32_t); + break; + } + case BR_REPLY: { + struct binder_txn *txn = (void*) ptr; + if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) { + LOGE("parse: reply too small!\n"); + return -1; + } + binder_dump_txn(txn); + if (bio) { + bio_init_from_txn(bio, txn); + bio = 0; + } else { + /* todo FREE BUFFER */ + } + ptr += (sizeof(*txn) / sizeof(uint32_t)); + r = 0; + break; + } + case BR_DEAD_BINDER: { + struct binder_death *death = (void*) *ptr++; + death->func(bs, death->ptr); + break; + } + case BR_FAILED_REPLY: + r = -1; + break; + case BR_DEAD_REPLY: + r = -1; + break; + default: + LOGE("parse: OOPS %d\n", cmd); + return -1; + } + } + + return r; +} + +void binder_acquire(struct binder_state *bs, void *ptr) +{ + uint32_t cmd[2]; + cmd[0] = BC_ACQUIRE; + cmd[1] = (uint32_t) ptr; + binder_write(bs, cmd, sizeof(cmd)); +} + +void binder_release(struct binder_state *bs, void *ptr) +{ + uint32_t cmd[2]; + cmd[0] = BC_RELEASE; + cmd[1] = (uint32_t) ptr; + binder_write(bs, cmd, sizeof(cmd)); +} + +void binder_link_to_death(struct binder_state *bs, void *ptr, struct binder_death *death) +{ + uint32_t cmd[3]; + cmd[0] = BC_REQUEST_DEATH_NOTIFICATION; + cmd[1] = (uint32_t) ptr; + cmd[2] = (uint32_t) death; + binder_write(bs, cmd, sizeof(cmd)); +} + + +int binder_call(struct binder_state *bs, + struct binder_io *msg, struct binder_io *reply, + void *target, uint32_t code) +{ + int res; + struct binder_write_read bwr; + struct { + uint32_t cmd; + struct binder_txn txn; + } writebuf; + unsigned readbuf[32]; + + if (msg->flags & BIO_F_OVERFLOW) { + fprintf(stderr,"binder: txn buffer overflow\n"); + goto fail; + } + + writebuf.cmd = BC_TRANSACTION; + writebuf.txn.target = target; + writebuf.txn.code = code; + writebuf.txn.flags = 0; + writebuf.txn.data_size = msg->data - msg->data0; + writebuf.txn.offs_size = ((char*) msg->offs) - ((char*) msg->offs0); + writebuf.txn.data = msg->data0; + writebuf.txn.offs = msg->offs0; + + bwr.write_size = sizeof(writebuf); + bwr.write_consumed = 0; + bwr.write_buffer = (unsigned) &writebuf; + + hexdump(msg->data0, msg->data - msg->data0); + for (;;) { + bwr.read_size = sizeof(readbuf); + bwr.read_consumed = 0; + bwr.read_buffer = (unsigned) readbuf; + + res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); + + if (res < 0) { + fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno)); + goto fail; + } + + res = binder_parse(bs, reply, readbuf, bwr.read_consumed, 0); + if (res == 0) return 0; + if (res < 0) goto fail; + } + +fail: + memset(reply, 0, sizeof(*reply)); + reply->flags |= BIO_F_IOERROR; + return -1; +} + +void binder_loop(struct binder_state *bs, binder_handler func) +{ + int res; + struct binder_write_read bwr; + unsigned readbuf[32]; + + bwr.write_size = 0; + bwr.write_consumed = 0; + bwr.write_buffer = 0; + + readbuf[0] = BC_ENTER_LOOPER; + binder_write(bs, readbuf, sizeof(unsigned)); + + for (;;) { + bwr.read_size = sizeof(readbuf); + bwr.read_consumed = 0; + bwr.read_buffer = (unsigned) readbuf; + + res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); + + if (res < 0) { + LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); + break; + } + + res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func); + if (res == 0) { + LOGE("binder_loop: unexpected reply?!\n"); + break; + } + if (res < 0) { + LOGE("binder_loop: io error %d %s\n", res, strerror(errno)); + break; + } + } +} + +void bio_init_from_txn(struct binder_io *bio, struct binder_txn *txn) +{ + bio->data = bio->data0 = txn->data; + bio->offs = bio->offs0 = txn->offs; + bio->data_avail = txn->data_size; + bio->offs_avail = txn->offs_size / 4; + bio->flags = BIO_F_SHARED; +} + +void bio_init(struct binder_io *bio, void *data, + uint32_t maxdata, uint32_t maxoffs) +{ + uint32_t n = maxoffs * sizeof(uint32_t); + + if (n > maxdata) { + bio->flags = BIO_F_OVERFLOW; + bio->data_avail = 0; + bio->offs_avail = 0; + return; + } + + bio->data = bio->data0 = data + n; + bio->offs = bio->offs0 = data; + bio->data_avail = maxdata - n; + bio->offs_avail = maxoffs; + bio->flags = 0; +} + +static void *bio_alloc(struct binder_io *bio, uint32_t size) +{ + size = (size + 3) & (~3); + if (size > bio->data_avail) { + bio->flags |= BIO_F_OVERFLOW; + return 0; + } else { + void *ptr = bio->data; + bio->data += size; + bio->data_avail -= size; + return ptr; + } +} + +void binder_done(struct binder_state *bs, + struct binder_io *msg, + struct binder_io *reply) +{ + if (reply->flags & BIO_F_SHARED) { + uint32_t cmd[2]; + cmd[0] = BC_FREE_BUFFER; + cmd[1] = (uint32_t) reply->data0; + binder_write(bs, cmd, sizeof(cmd)); + reply->flags = 0; + } +} + +static struct binder_object *bio_alloc_obj(struct binder_io *bio) +{ + struct binder_object *obj; + + obj = bio_alloc(bio, sizeof(*obj)); + + if (obj && bio->offs_avail) { + bio->offs_avail--; + *bio->offs++ = ((char*) obj) - ((char*) bio->data0); + return obj; + } + + bio->flags |= BIO_F_OVERFLOW; + return 0; +} + +void bio_put_uint32(struct binder_io *bio, uint32_t n) +{ + uint32_t *ptr = bio_alloc(bio, sizeof(n)); + if (ptr) + *ptr = n; +} + +void bio_put_obj(struct binder_io *bio, void *ptr) +{ + struct binder_object *obj; + + obj = bio_alloc_obj(bio); + if (!obj) + return; + + obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; + obj->type = BINDER_TYPE_BINDER; + obj->pointer = ptr; + obj->cookie = 0; +} + +void bio_put_ref(struct binder_io *bio, void *ptr) +{ + struct binder_object *obj; + + if (ptr) + obj = bio_alloc_obj(bio); + else + obj = bio_alloc(bio, sizeof(*obj)); + + if (!obj) + return; + + obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; + obj->type = BINDER_TYPE_HANDLE; + obj->pointer = ptr; + obj->cookie = 0; +} + +void bio_put_string16(struct binder_io *bio, const uint16_t *str) +{ + uint32_t len; + uint16_t *ptr; + + if (!str) { + bio_put_uint32(bio, 0xffffffff); + return; + } + + len = 0; + while (str[len]) len++; + + if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { + bio_put_uint32(bio, 0xffffffff); + return; + } + + bio_put_uint32(bio, len); + len = (len + 1) * sizeof(uint16_t); + ptr = bio_alloc(bio, len); + if (ptr) + memcpy(ptr, str, len); +} + +void bio_put_string16_x(struct binder_io *bio, const char *_str) +{ + unsigned char *str = (unsigned char*) _str; + uint32_t len; + uint16_t *ptr; + + if (!str) { + bio_put_uint32(bio, 0xffffffff); + return; + } + + len = strlen(_str); + + if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) { + bio_put_uint32(bio, 0xffffffff); + return; + } + + bio_put_uint32(bio, len); + ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t)); + if (!ptr) + return; + + while (*str) + *ptr++ = *str++; + *ptr++ = 0; +} + +static void *bio_get(struct binder_io *bio, uint32_t size) +{ + size = (size + 3) & (~3); + + if (bio->data_avail < size){ + bio->data_avail = 0; + bio->flags |= BIO_F_OVERFLOW; + return 0; + } else { + void *ptr = bio->data; + bio->data += size; + bio->data_avail -= size; + return ptr; + } +} + +uint32_t bio_get_uint32(struct binder_io *bio) +{ + uint32_t *ptr = bio_get(bio, sizeof(*ptr)); + return ptr ? *ptr : 0; +} + +uint16_t *bio_get_string16(struct binder_io *bio, unsigned *sz) +{ + unsigned len; + len = bio_get_uint32(bio); + if (sz) + *sz = len; + return bio_get(bio, (len + 1) * sizeof(uint16_t)); +} + +static struct binder_object *_bio_get_obj(struct binder_io *bio) +{ + unsigned n; + unsigned off = bio->data - bio->data0; + + /* TODO: be smarter about this? */ + for (n = 0; n < bio->offs_avail; n++) { + if (bio->offs[n] == off) + return bio_get(bio, sizeof(struct binder_object)); + } + + bio->data_avail = 0; + bio->flags |= BIO_F_OVERFLOW; + return 0; +} + +void *bio_get_ref(struct binder_io *bio) +{ + struct binder_object *obj; + + obj = _bio_get_obj(bio); + if (!obj) + return 0; + + if (obj->type == BINDER_TYPE_HANDLE) + return obj->pointer; + + return 0; +} diff --git a/cmds/servicemanager/binder.h b/cmds/servicemanager/binder.h new file mode 100644 index 0000000..d8c51ef --- /dev/null +++ b/cmds/servicemanager/binder.h @@ -0,0 +1,119 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#ifndef _BINDER_H_ +#define _BINDER_H_ + +#include <sys/ioctl.h> +#include <linux/binder.h> + +struct binder_state; + +struct binder_object +{ + uint32_t type; + uint32_t flags; + void *pointer; + void *cookie; +}; + +struct binder_txn +{ + void *target; + void *cookie; + uint32_t code; + uint32_t flags; + + uint32_t sender_pid; + uint32_t sender_euid; + + uint32_t data_size; + uint32_t offs_size; + void *data; + void *offs; +}; + +struct binder_io +{ + char *data; /* pointer to read/write from */ + uint32_t *offs; /* array of offsets */ + uint32_t data_avail; /* bytes available in data buffer */ + uint32_t offs_avail; /* entries available in offsets array */ + + char *data0; /* start of data buffer */ + uint32_t *offs0; /* start of offsets buffer */ + uint32_t flags; + uint32_t unused; +}; + +struct binder_death { + void (*func)(struct binder_state *bs, void *ptr); + void *ptr; +}; + +/* the one magic object */ +#define BINDER_SERVICE_MANAGER ((void*) 0) + +#define SVC_MGR_NAME "android.os.IServiceManager" + +enum { + SVC_MGR_GET_SERVICE = 1, + SVC_MGR_CHECK_SERVICE, + SVC_MGR_ADD_SERVICE, + SVC_MGR_LIST_SERVICES, +}; + +typedef int (*binder_handler)(struct binder_state *bs, + struct binder_txn *txn, + struct binder_io *msg, + struct binder_io *reply); + +struct binder_state *binder_open(unsigned mapsize); +void binder_close(struct binder_state *bs); + +/* initiate a blocking binder call + * - returns zero on success + */ +int binder_call(struct binder_state *bs, + struct binder_io *msg, struct binder_io *reply, + void *target, uint32_t code); + +/* release any state associate with the binder_io + * - call once any necessary data has been extracted from the + * binder_io after binder_call() returns + * - can safely be called even if binder_call() fails + */ +void binder_done(struct binder_state *bs, + struct binder_io *msg, struct binder_io *reply); + +/* manipulate strong references */ +void binder_acquire(struct binder_state *bs, void *ptr); +void binder_release(struct binder_state *bs, void *ptr); + +void binder_link_to_death(struct binder_state *bs, void *ptr, struct binder_death *death); + +void binder_loop(struct binder_state *bs, binder_handler func); + +int binder_become_context_manager(struct binder_state *bs); + +/* allocate a binder_io, providing a stack-allocated working + * buffer, size of the working buffer, and how many object + * offset entries to reserve from the buffer + */ +void bio_init(struct binder_io *bio, void *data, + uint32_t maxdata, uint32_t maxobjects); + +void bio_destroy(struct binder_io *bio); + +void bio_put_obj(struct binder_io *bio, void *ptr); +void bio_put_ref(struct binder_io *bio, void *ptr); +void bio_put_uint32(struct binder_io *bio, uint32_t n); +void bio_put_string16(struct binder_io *bio, const uint16_t *str); +void bio_put_string16_x(struct binder_io *bio, const char *_str); + +uint32_t bio_get_uint32(struct binder_io *bio); +uint16_t *bio_get_string16(struct binder_io *bio, uint32_t *sz); +void *bio_get_obj(struct binder_io *bio); +void *bio_get_ref(struct binder_io *bio); + +#endif diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c new file mode 100644 index 0000000..e4aa8b5 --- /dev/null +++ b/cmds/servicemanager/service_manager.c @@ -0,0 +1,260 @@ +/* Copyright 2008 The Android Open Source Project + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> + +#include <private/android_filesystem_config.h> + +#include "binder.h" + +#if 0 +#define LOGI(x...) fprintf(stderr, "svcmgr: " x) +#define LOGE(x...) fprintf(stderr, "svcmgr: " x) +#else +#define LOG_TAG "ServiceManager" +#include <cutils/log.h> +#endif + +/* TODO: + * These should come from a config file or perhaps be + * based on some namespace rules of some sort (media + * uid can register media.*, etc) + */ +static struct { + unsigned uid; + const char *name; +} allowed[] = { + { AID_MEDIA, "media.audio_flinger" }, + { AID_MEDIA, "media.player" }, + { AID_MEDIA, "media.camera" }, + { AID_RADIO, "radio.phone" }, + { AID_RADIO, "radio.sms" }, + { AID_RADIO, "radio.phonesubinfo" }, + { AID_RADIO, "radio.simphonebook" }, +/* TODO: remove after phone services are updated: */ + { AID_RADIO, "phone" }, + { AID_RADIO, "isms" }, + { AID_RADIO, "iphonesubinfo" }, + { AID_RADIO, "simphonebook" }, +}; + +void *svcmgr_handle; + +const char *str8(uint16_t *x) +{ + static char buf[128]; + unsigned max = 127; + char *p = buf; + + if (x) { + while (*x && max--) { + *p++ = *x++; + } + } + *p++ = 0; + return buf; +} + +int str16eq(uint16_t *a, const char *b) +{ + while (*a && *b) + if (*a++ != *b++) return 0; + if (*a || *b) + return 0; + return 1; +} + +int svc_can_register(unsigned uid, uint16_t *name) +{ + unsigned n; + + if ((uid == 0) || (uid == AID_SYSTEM)) + return 1; + + for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++) + if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name)) + return 1; + + return 0; +} + +struct svcinfo +{ + struct svcinfo *next; + void *ptr; + struct binder_death death; + unsigned len; + uint16_t name[0]; +}; + +struct svcinfo *svclist = 0; + +struct svcinfo *find_svc(uint16_t *s16, unsigned len) +{ + struct svcinfo *si; + + for (si = svclist; si; si = si->next) { + if ((len == si->len) && + !memcmp(s16, si->name, len * sizeof(uint16_t))) { + return si; + } + } + return 0; +} + +void svcinfo_death(struct binder_state *bs, void *ptr) +{ + struct svcinfo *si = ptr; + LOGI("service '%s' died\n", str8(si->name)); + if (si->ptr) { + binder_release(bs, si->ptr); + si->ptr = 0; + } +} + +uint16_t svcmgr_id[] = { + 'a','n','d','r','o','i','d','.','o','s','.', + 'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r' +}; + + +void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len) +{ + struct svcinfo *si; + si = find_svc(s, len); + +// LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0); + if (si && si->ptr) { + return si->ptr; + } else { + return 0; + } +} + +int do_add_service(struct binder_state *bs, + uint16_t *s, unsigned len, + void *ptr, unsigned uid) +{ + struct svcinfo *si; +// LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid); + + if (!ptr || (len == 0) || (len > 127)) + return -1; + + if (!svc_can_register(uid, s)) { + LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n", + str8(s), ptr, uid); + return -1; + } + + si = find_svc(s, len); + if (si) { + if (si->ptr) { + LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n", + str8(s), ptr, uid); + return -1; + } + si->ptr = ptr; + } else { + si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); + if (!si) { + LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n", + str8(s), ptr, uid); + return -1; + } + si->ptr = ptr; + si->len = len; + memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); + si->name[len] = '\0'; + si->death.func = svcinfo_death; + si->death.ptr = si; + si->next = svclist; + svclist = si; + } + + binder_acquire(bs, ptr); + binder_link_to_death(bs, ptr, &si->death); + return 0; +} + +int svcmgr_handler(struct binder_state *bs, + struct binder_txn *txn, + struct binder_io *msg, + struct binder_io *reply) +{ + struct svcinfo *si; + uint16_t *s; + unsigned len; + void *ptr; + +// LOGI("target=%p code=%d pid=%d uid=%d\n", +// txn->target, txn->code, txn->sender_pid, txn->sender_euid); + + if (txn->target != svcmgr_handle) + return -1; + + s = bio_get_string16(msg, &len); + + if ((len != (sizeof(svcmgr_id) / 2)) || + memcmp(svcmgr_id, s, sizeof(svcmgr_id))) { + fprintf(stderr,"invalid id %s\n", str8(s)); + return -1; + } + + switch(txn->code) { + case SVC_MGR_GET_SERVICE: + case SVC_MGR_CHECK_SERVICE: + s = bio_get_string16(msg, &len); + ptr = do_find_service(bs, s, len); + if (!ptr) + break; + bio_put_ref(reply, ptr); + return 0; + + case SVC_MGR_ADD_SERVICE: + s = bio_get_string16(msg, &len); + ptr = bio_get_ref(msg); + if (do_add_service(bs, s, len, ptr, txn->sender_euid)) + return -1; + break; + + case SVC_MGR_LIST_SERVICES: { + unsigned n = bio_get_uint32(msg); + + si = svclist; + while ((n-- > 0) && si) + si = si->next; + if (si) { + bio_put_string16(reply, si->name); + return 0; + } + return -1; + } + default: + LOGE("unknown code %d\n", txn->code); + return -1; + } + + bio_put_uint32(reply, 0); + return 0; +} + +int main(int argc, char **argv) +{ + struct binder_state *bs; + void *svcmgr = BINDER_SERVICE_MANAGER; + + bs = binder_open(128*1024); + + if (binder_become_context_manager(bs)) { + LOGE("cannot become context manager (%s)\n", strerror(errno)); + return -1; + } + + svcmgr_handle = svcmgr; + binder_loop(bs, svcmgr_handler); + return 0; +} diff --git a/cmds/surfaceflinger/Android.mk b/cmds/surfaceflinger/Android.mk new file mode 100644 index 0000000..37c3d94 --- /dev/null +++ b/cmds/surfaceflinger/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + main_surfaceflinger.cpp + +LOCAL_SHARED_LIBRARIES := \ + libsurfaceflinger \ + libutils + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../../libs/surfaceflinger + +LOCAL_MODULE:= surfaceflinger + +include $(BUILD_EXECUTABLE) diff --git a/cmds/surfaceflinger/main_surfaceflinger.cpp b/cmds/surfaceflinger/main_surfaceflinger.cpp new file mode 100644 index 0000000..7c89578 --- /dev/null +++ b/cmds/surfaceflinger/main_surfaceflinger.cpp @@ -0,0 +1,18 @@ +#include <utils/IPCThreadState.h> +#include <utils/ProcessState.h> +#include <utils/IServiceManager.h> +#include <utils/Log.h> + +#include <SurfaceFlinger.h> + +using namespace android; + +int main(int argc, char** argv) +{ + sp<ProcessState> proc(ProcessState::self()); + sp<IServiceManager> sm = defaultServiceManager(); + LOGI("ServiceManager: %p", sm.get()); + SurfaceFlinger::instantiate(); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); +} diff --git a/cmds/svc/Android.mk b/cmds/svc/Android.mk new file mode 100644 index 0000000..198efb2 --- /dev/null +++ b/cmds/svc/Android.mk @@ -0,0 +1,15 @@ +# Copyright 2007 The Android Open Source Project +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-subdir-java-files) +LOCAL_MODULE := svc +include $(BUILD_JAVA_LIBRARY) + + +include $(CLEAR_VARS) +ALL_PREBUILT += $(TARGET_OUT)/bin/svc +$(TARGET_OUT)/bin/svc : $(LOCAL_PATH)/svc | $(ACP) + $(transform-prebuilt-to-target) + diff --git a/cmds/svc/MODULE_LICENSE_APACHE2 b/cmds/svc/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/svc/MODULE_LICENSE_APACHE2 diff --git a/cmds/svc/NOTICE b/cmds/svc/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/svc/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java new file mode 100644 index 0000000..990837f --- /dev/null +++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package com.android.commands.svc; + +import android.os.IPowerManager; +import android.os.ServiceManager; +import android.os.RemoteException; + +public class PowerCommand extends Svc.Command { + public PowerCommand() { + super("power"); + } + + public String shortHelp() { + return "Control the power manager"; + } + + public String longHelp() { + return shortHelp() + "\n" + + "\n" + + "usage: svc power stayon [true|false]\n" + + " Set the 'keep awake while plugged in' setting.\n"; + } + + public void run(String[] args) { + fail: { + if (args.length >= 2) { + if ("stayon".equals(args[1]) && args.length == 3) { + boolean val; + if ("true".equals(args[2])) { + val = true; + } + else if ("false".equals(args[2])) { + val = false; + } + else { + break fail; + } + IPowerManager pm + = IPowerManager.Stub.asInterface(ServiceManager.getService("power")); + try { + pm.setStayOnSetting(val); + } + catch (RemoteException e) { + System.err.println("Faild to set setting: " + e); + } + return; + } + } + } + System.err.println(longHelp()); + } +} diff --git a/cmds/svc/src/com/android/commands/svc/Svc.java b/cmds/svc/src/com/android/commands/svc/Svc.java new file mode 100644 index 0000000..ae397a0 --- /dev/null +++ b/cmds/svc/src/com/android/commands/svc/Svc.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package com.android.commands.svc; + +import android.app.ActivityManagerNative; +import android.app.IActivityManager; +import android.app.IInstrumentationWatcher; +import android.content.ComponentName; +import android.content.Intent; +import android.net.Uri; +import android.os.RemoteException; +import android.os.Bundle; +import android.os.ServiceManager; +import android.view.IWindowManager; + +import java.util.Iterator; +import java.util.Set; + +public class Svc { + + public static abstract class Command { + private String mName; + + public Command(String name) { + mName = name; + } + + public String name() { + return mName; + } + + public abstract String shortHelp(); // should fit on one short line + public abstract String longHelp(); // take as much space as you need, 75 col max + public abstract void run(String[] args); // run the command + } + + public static void main(String[] args) { + if (true) { + for (String a: args) { + System.err.print(a + " "); + } + System.err.println(); + } + + if (args.length >= 1) { + Command c = lookupCommand(args[0]); + if (c != null) { + c.run(args); + return; + } + } + COMMAND_HELP.run(args); + } + + private static final Command lookupCommand(String name) { + final int N = COMMANDS.length; + for (int i=0; i<N; i++) { + Command c = COMMANDS[i]; + if (c.name().equals(name)) { + return c; + } + } + return null; + } + + public static final Command COMMAND_HELP = new Command("help") { + public String shortHelp() { + return "Show information about the subcommands"; + } + public String longHelp() { + return shortHelp(); + } + public void run(String[] args) { + if (args.length == 2) { + Command c = lookupCommand(args[1]); + if (c != null) { + System.err.println(c.longHelp()); + return; + } + } + + System.err.println("Available commands:"); + final int N = COMMANDS.length; + int maxlen = 0; + for (int i=0; i<N; i++) { + Command c = COMMANDS[i]; + int len = c.name().length(); + if (maxlen < len) { + maxlen = len; + } + } + String format = " %-" + maxlen + "s %s"; + for (int i=0; i<N; i++) { + Command c = COMMANDS[i]; + System.err.println(String.format(format, c.name(), c.shortHelp())); + } + } + }; + + public static final Command[] COMMANDS = new Command[] { + COMMAND_HELP, + new PowerCommand(), + }; +} diff --git a/cmds/svc/svc b/cmds/svc/svc new file mode 100755 index 0000000..27111cd --- /dev/null +++ b/cmds/svc/svc @@ -0,0 +1,7 @@ +# Script to start "am" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/svc.jar +exec app_process $base/bin com.android.commands.svc.Svc $* + diff --git a/cmds/system_server/Android.mk b/cmds/system_server/Android.mk new file mode 100644 index 0000000..0a684e8 --- /dev/null +++ b/cmds/system_server/Android.mk @@ -0,0 +1,19 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + system_main.cpp + +LOCAL_SHARED_LIBRARIES := \ + libutils \ + libsystem_server + +LOCAL_C_INCLUDES := \ + $(JNI_H_INCLUDE) + +LOCAL_MODULE:= system_server + +include $(BUILD_EXECUTABLE) + +include $(LOCAL_PATH)/library/Android.mk + diff --git a/cmds/system_server/MODULE_LICENSE_APACHE2 b/cmds/system_server/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmds/system_server/MODULE_LICENSE_APACHE2 diff --git a/cmds/system_server/NOTICE b/cmds/system_server/NOTICE new file mode 100644 index 0000000..c5b1efa --- /dev/null +++ b/cmds/system_server/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2005-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. + + 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/system_server/library/Android.mk b/cmds/system_server/library/Android.mk new file mode 100644 index 0000000..580331a --- /dev/null +++ b/cmds/system_server/library/Android.mk @@ -0,0 +1,27 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + system_init.cpp + +base = $(LOCAL_PATH)/../../.. + +LOCAL_C_INCLUDES := \ + $(base)/camera/libcameraservice \ + $(base)/libs/audioflinger \ + $(base)/libs/surfaceflinger \ + $(base)/media/libmediaplayerservice \ + $(JNI_H_INCLUDE) + +LOCAL_SHARED_LIBRARIES := \ + libandroid_runtime \ + libsurfaceflinger \ + libaudioflinger \ + libcameraservice \ + libmediaplayerservice \ + libutils \ + libcutils + +LOCAL_MODULE:= libsystem_server + +include $(BUILD_SHARED_LIBRARY) diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp new file mode 100644 index 0000000..73b23e2 --- /dev/null +++ b/cmds/system_server/library/system_init.cpp @@ -0,0 +1,109 @@ +/* + * System server main initialization. + * + * The system server is responsible for becoming the Binder + * context manager, supplying the root ServiceManager object + * through which other services can be found. + */ + +#define LOG_TAG "sysproc" + +#include <utils/IPCThreadState.h> +#include <utils/ProcessState.h> +#include <utils/IServiceManager.h> +#include <utils/TextOutput.h> +#include <utils/Log.h> + +#include <SurfaceFlinger.h> +#include <AudioFlinger.h> +#include <CameraService.h> +#include <MediaPlayerService.h> + +#include <android_runtime/AndroidRuntime.h> + +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <cutils/properties.h> + +using namespace android; + +namespace android { +/** + * This class is used to kill this process when the runtime dies. + */ +class GrimReaper : public IBinder::DeathRecipient { +public: + GrimReaper() { } + + virtual void binderDied(const wp<IBinder>& who) + { + LOGI("Grim Reaper killing system_server..."); + kill(getpid(), SIGKILL); + } +}; + +} // namespace android + + + +extern "C" status_t system_init() +{ + LOGI("Entered system_init()"); + + sp<ProcessState> proc(ProcessState::self()); + + sp<IServiceManager> sm = defaultServiceManager(); + LOGI("ServiceManager: %p\n", sm.get()); + + sp<GrimReaper> grim = new GrimReaper(); + sm->asBinder()->linkToDeath(grim, grim.get(), 0); + + char propBuf[PROPERTY_VALUE_MAX]; + property_get("system_init.startsurfaceflinger", propBuf, "1"); + if (strcmp(propBuf, "1") == 0) { + // Start the SurfaceFlinger + SurfaceFlinger::instantiate(); + } + + // On the simulator, audioflinger et al don't get started the + // same way as on the device, and we need to start them here + if (!proc->supportsProcesses()) { + + // Start the AudioFlinger + AudioFlinger::instantiate(); + + // Start the media playback service + MediaPlayerService::instantiate(); + + // Start the camera service + CameraService::instantiate(); + } + + // And now start the Android runtime. We have to do this bit + // of nastiness because the Android runtime initialization requires + // some of the core system services to already be started. + // All other servers should just start the Android runtime at + // the beginning of their processes's main(), before calling + // the init function. + LOGI("System server: starting Android runtime.\n"); + + AndroidRuntime* runtime = AndroidRuntime::getRuntime(); + + LOGI("System server: starting Android services.\n"); + runtime->callStatic("com/android/server/SystemServer", "init2"); + + // If running in our own process, just go into the thread + // pool. Otherwise, call the initialization finished + // func to let this process continue its initilization. + if (proc->supportsProcesses()) { + LOGI("System server: entering thread pool.\n"); + ProcessState::self()->startThreadPool(); + IPCThreadState::self()->joinThreadPool(); + LOGI("System server: exiting thread pool.\n"); + } + return NO_ERROR; +} + diff --git a/cmds/system_server/system_main.cpp b/cmds/system_server/system_main.cpp new file mode 100644 index 0000000..ca16e57 --- /dev/null +++ b/cmds/system_server/system_main.cpp @@ -0,0 +1,61 @@ +/* + * Main entry of system server process. + * + * Calls the standard system initialization function, and then + * puts the main thread into the thread pool so it can handle + * incoming transactions. + * + */ + +#define LOG_TAG "sysproc" + +#include <utils/IPCThreadState.h> +#include <utils/Log.h> + +#include <private/android_filesystem_config.h> + +#include <sys/time.h> +#include <sys/resource.h> + +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + +using namespace android; + +extern "C" status_t system_init(); + +bool finish_system_init() +{ + return true; +} + +static void blockSignals() +{ + sigset_t mask; + int cc; + + sigemptyset(&mask); + sigaddset(&mask, SIGQUIT); + sigaddset(&mask, SIGUSR1); + cc = sigprocmask(SIG_BLOCK, &mask, NULL); + assert(cc == 0); +} + +int main(int argc, const char* const argv[]) +{ + LOGI("System server is starting with pid=%d.\n", getpid()); + + blockSignals(); + + // You can trust me, honestly! + LOGW("*** Current priority: %d\n", getpriority(PRIO_PROCESS, 0)); + setpriority(PRIO_PROCESS, 0, -1); + + #if HAVE_ANDROID_OS + //setgid(GID_SYSTEM); + //setuid(UID_SYSTEM); + #endif + + system_init(); +} |