Move non-Java commands over from frameworks/base
Change-Id: I0571813c1cfcf66abd36eb9f178fc49b618e88a6 Signed-off-by: Mike Lockwood <lockwood@google.com>
This commit is contained in:
parent
ba0b9cca69
commit
94afecf4b6
41
cmds/app_process/Android.mk
Normal file
41
cmds/app_process/Android.mk
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES:= \
|
||||||
|
app_main.cpp
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
|
libcutils \
|
||||||
|
libutils \
|
||||||
|
libbinder \
|
||||||
|
libandroid_runtime
|
||||||
|
|
||||||
|
LOCAL_MODULE:= app_process
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
|
||||||
|
# Build a variant of app_process binary linked with ASan runtime.
|
||||||
|
# ARM-only at the moment.
|
||||||
|
ifeq ($(TARGET_ARCH),arm)
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES:= \
|
||||||
|
app_main.cpp
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
|
libcutils \
|
||||||
|
libutils \
|
||||||
|
libbinder \
|
||||||
|
libandroid_runtime
|
||||||
|
|
||||||
|
LOCAL_MODULE := app_process__asan
|
||||||
|
LOCAL_MODULE_TAGS := eng
|
||||||
|
LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
|
||||||
|
LOCAL_MODULE_STEM := app_process
|
||||||
|
LOCAL_ADDRESS_SANITIZER := true
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
endif # ifeq($(TARGET_ARCH),arm)
|
0
cmds/app_process/MODULE_LICENSE_APACHE2
Normal file
0
cmds/app_process/MODULE_LICENSE_APACHE2
Normal file
190
cmds/app_process/NOTICE
Normal file
190
cmds/app_process/NOTICE
Normal file
@ -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
|
||||||
|
|
204
cmds/app_process/app_main.cpp
Normal file
204
cmds/app_process/app_main.cpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/*
|
||||||
|
* Main entry of app process.
|
||||||
|
*
|
||||||
|
* Starts the interpreted runtime, then starts up the application.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_TAG "appproc"
|
||||||
|
|
||||||
|
#include <binder/IPCThreadState.h>
|
||||||
|
#include <binder/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");
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppRuntime : public AndroidRuntime
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AppRuntime()
|
||||||
|
: mParentDir(NULL)
|
||||||
|
, mClassName(NULL)
|
||||||
|
, mClass(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 onVmCreated(JNIEnv* env)
|
||||||
|
{
|
||||||
|
if (mClassName == NULL) {
|
||||||
|
return; // Zygote. Nothing to do here.
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a little awkward because the JNI FindClass call uses the
|
||||||
|
* class loader associated with the native method we're executing in.
|
||||||
|
* If called in onStarted (from RuntimeInit.finishInit because we're
|
||||||
|
* launching "am", for example), FindClass would see that we're calling
|
||||||
|
* from a boot class' native method, and so wouldn't look for the class
|
||||||
|
* we're trying to look up in CLASSPATH. Unfortunately it needs to,
|
||||||
|
* because the "am" classes are not boot classes.
|
||||||
|
*
|
||||||
|
* The easiest fix is to call FindClass here, early on before we start
|
||||||
|
* executing boot class Java code and thereby deny ourselves access to
|
||||||
|
* non-boot classes.
|
||||||
|
*/
|
||||||
|
char* slashClassName = toSlashClassName(mClassName);
|
||||||
|
mClass = env->FindClass(slashClassName);
|
||||||
|
if (mClass == NULL) {
|
||||||
|
ALOGE("ERROR: could not find class '%s'\n", mClassName);
|
||||||
|
}
|
||||||
|
free(slashClassName);
|
||||||
|
|
||||||
|
mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onStarted()
|
||||||
|
{
|
||||||
|
sp<ProcessState> proc = ProcessState::self();
|
||||||
|
ALOGV("App process: starting thread pool.\n");
|
||||||
|
proc->startThreadPool();
|
||||||
|
|
||||||
|
AndroidRuntime* ar = AndroidRuntime::getRuntime();
|
||||||
|
ar->callMain(mClassName, mClass, mArgC, mArgV);
|
||||||
|
|
||||||
|
IPCThreadState::self()->stopProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onZygoteInit()
|
||||||
|
{
|
||||||
|
sp<ProcessState> proc = ProcessState::self();
|
||||||
|
ALOGV("App process: starting thread pool.\n");
|
||||||
|
proc->startThreadPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void onExit(int code)
|
||||||
|
{
|
||||||
|
if (mClassName == NULL) {
|
||||||
|
// if zygote
|
||||||
|
IPCThreadState::self()->stopProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidRuntime::onExit(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char* mParentDir;
|
||||||
|
const char* mClassName;
|
||||||
|
jclass mClass;
|
||||||
|
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* 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);
|
||||||
|
|
||||||
|
// Parse runtime arguments. Stop at first unrecognized option.
|
||||||
|
bool zygote = false;
|
||||||
|
bool startSystemServer = false;
|
||||||
|
bool application = false;
|
||||||
|
const char* parentDir = NULL;
|
||||||
|
const char* niceName = NULL;
|
||||||
|
const char* className = NULL;
|
||||||
|
while (i < argc) {
|
||||||
|
const char* arg = argv[i++];
|
||||||
|
if (!parentDir) {
|
||||||
|
parentDir = arg;
|
||||||
|
} else if (strcmp(arg, "--zygote") == 0) {
|
||||||
|
zygote = true;
|
||||||
|
niceName = "zygote";
|
||||||
|
} else if (strcmp(arg, "--start-system-server") == 0) {
|
||||||
|
startSystemServer = true;
|
||||||
|
} else if (strcmp(arg, "--application") == 0) {
|
||||||
|
application = true;
|
||||||
|
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
|
||||||
|
niceName = arg + 12;
|
||||||
|
} else {
|
||||||
|
className = arg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (niceName && *niceName) {
|
||||||
|
setArgv0(argv0, niceName);
|
||||||
|
set_process_name(niceName);
|
||||||
|
}
|
||||||
|
|
||||||
|
runtime.mParentDir = parentDir;
|
||||||
|
|
||||||
|
if (zygote) {
|
||||||
|
runtime.start("com.android.internal.os.ZygoteInit",
|
||||||
|
startSystemServer ? "start-system-server" : "");
|
||||||
|
} else if (className) {
|
||||||
|
// Remainder of args get passed to startup class main()
|
||||||
|
runtime.mClassName = className;
|
||||||
|
runtime.mArgC = argc - i;
|
||||||
|
runtime.mArgV = argv + i;
|
||||||
|
runtime.start("com.android.internal.os.RuntimeInit",
|
||||||
|
application ? "application" : "tool");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
|
||||||
|
app_usage();
|
||||||
|
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
}
|
10
cmds/bugreport/Android.mk
Normal file
10
cmds/bugreport/Android.mk
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES:= bugreport.c
|
||||||
|
|
||||||
|
LOCAL_MODULE:= bugreport
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := libcutils
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
56
cmds/bugreport/bugreport.c
Normal file
56
cmds/bugreport/bugreport.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
#include <cutils/sockets.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
char buffer[65536];
|
||||||
|
int i, s;
|
||||||
|
|
||||||
|
/* start the dumpstate service */
|
||||||
|
property_set("ctl.start", "dumpstate");
|
||||||
|
|
||||||
|
/* socket will not be available until service starts */
|
||||||
|
for (i = 0; i < 10; i++) {
|
||||||
|
s = socket_local_client("dumpstate",
|
||||||
|
ANDROID_SOCKET_NAMESPACE_RESERVED,
|
||||||
|
SOCK_STREAM);
|
||||||
|
if (s >= 0)
|
||||||
|
break;
|
||||||
|
/* try again in 1 second */
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s < 0) {
|
||||||
|
fprintf(stderr, "Failed to connect to dumpstate service\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int length = read(s, buffer, sizeof(buffer));
|
||||||
|
if (length <= 0)
|
||||||
|
break;
|
||||||
|
fwrite(buffer, 1, length, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(s);
|
||||||
|
return 0;
|
||||||
|
}
|
42
cmds/installd/Android.mk
Normal file
42
cmds/installd/Android.mk
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
|
||||||
|
common_src_files := \
|
||||||
|
commands.c utils.c
|
||||||
|
|
||||||
|
#
|
||||||
|
# Static library used in testing and executable
|
||||||
|
#
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
$(common_src_files)
|
||||||
|
|
||||||
|
LOCAL_MODULE := libinstalld
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := eng tests
|
||||||
|
|
||||||
|
include $(BUILD_STATIC_LIBRARY)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Executable
|
||||||
|
#
|
||||||
|
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := \
|
||||||
|
installd.c \
|
||||||
|
$(common_src_files)
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
|
libcutils \
|
||||||
|
libselinux
|
||||||
|
|
||||||
|
LOCAL_STATIC_LIBRARIES := \
|
||||||
|
libdiskusage
|
||||||
|
|
||||||
|
LOCAL_MODULE := installd
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
1136
cmds/installd/commands.c
Normal file
1136
cmds/installd/commands.c
Normal file
File diff suppressed because it is too large
Load Diff
592
cmds/installd/installd.c
Normal file
592
cmds/installd/installd.c
Normal file
@ -0,0 +1,592 @@
|
|||||||
|
/*
|
||||||
|
** 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 <linux/capability.h>
|
||||||
|
#include <linux/prctl.h>
|
||||||
|
|
||||||
|
#include "installd.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BUFFER_MAX 1024 /* input buffer for commands */
|
||||||
|
#define TOKEN_MAX 8 /* max number of arguments in buffer */
|
||||||
|
#define REPLY_MAX 256 /* largest reply allowed */
|
||||||
|
|
||||||
|
static int do_ping(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_install(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* 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], atoi(arg[1])); /* pkgname, userid */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_rename(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_fixuid(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return fix_uid(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */
|
||||||
|
{
|
||||||
|
return free_cache((int64_t)atoll(arg[0])); /* free_size */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_rm_cache(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return delete_cache(arg[0], atoi(arg[1])); /* pkgname, userid */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_get_size(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
int64_t codesize = 0;
|
||||||
|
int64_t datasize = 0;
|
||||||
|
int64_t cachesize = 0;
|
||||||
|
int64_t asecsize = 0;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
/* pkgdir, persona, apkpath */
|
||||||
|
res = get_size(arg[0], atoi(arg[1]), arg[2], arg[3], arg[4],
|
||||||
|
&codesize, &datasize, &cachesize, &asecsize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each int64_t can take up 22 characters printed out. Make sure it
|
||||||
|
* doesn't go over REPLY_MAX in the future.
|
||||||
|
*/
|
||||||
|
snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64,
|
||||||
|
codesize, datasize, cachesize, asecsize);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_rm_user_data(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return delete_user_data(arg[0], atoi(arg[1])); /* pkgname, userid */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_mk_user_data(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, userid */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_rm_user(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return delete_persona(atoi(arg[0])); /* userid */
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_clone_user_data(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return clone_persona_data(atoi(arg[0]), atoi(arg[1]), atoi(arg[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_movefiles(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return movefiles();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int do_linklib(char **arg, char reply[REPLY_MAX])
|
||||||
|
{
|
||||||
|
return linklib(arg[0], arg[1], atoi(arg[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct cmdinfo {
|
||||||
|
const char *name;
|
||||||
|
unsigned numargs;
|
||||||
|
int (*func)(char **arg, char reply[REPLY_MAX]);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cmdinfo cmds[] = {
|
||||||
|
{ "ping", 0, do_ping },
|
||||||
|
{ "install", 3, do_install },
|
||||||
|
{ "dexopt", 3, do_dexopt },
|
||||||
|
{ "movedex", 2, do_move_dex },
|
||||||
|
{ "rmdex", 1, do_rm_dex },
|
||||||
|
{ "remove", 2, do_remove },
|
||||||
|
{ "rename", 2, do_rename },
|
||||||
|
{ "fixuid", 3, do_fixuid },
|
||||||
|
{ "freecache", 1, do_free_cache },
|
||||||
|
{ "rmcache", 2, do_rm_cache },
|
||||||
|
{ "getsize", 5, do_get_size },
|
||||||
|
{ "rmuserdata", 2, do_rm_user_data },
|
||||||
|
{ "movefiles", 0, do_movefiles },
|
||||||
|
{ "linklib", 3, do_linklib },
|
||||||
|
{ "mkuserdata", 3, do_mk_user_data },
|
||||||
|
{ "rmuser", 1, do_rm_user },
|
||||||
|
{ "cloneuserdata", 3, do_clone_user_data },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int readx(int s, void *_buf, int count)
|
||||||
|
{
|
||||||
|
char *buf = _buf;
|
||||||
|
int n = 0, r;
|
||||||
|
if (count < 0) return -1;
|
||||||
|
while (n < count) {
|
||||||
|
r = read(s, buf + n, count - n);
|
||||||
|
if (r < 0) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
ALOGE("read error: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (r == 0) {
|
||||||
|
ALOGE("eof\n");
|
||||||
|
return -1; /* EOF */
|
||||||
|
}
|
||||||
|
n += r;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int writex(int s, const void *_buf, int count)
|
||||||
|
{
|
||||||
|
const char *buf = _buf;
|
||||||
|
int n = 0, r;
|
||||||
|
if (count < 0) return -1;
|
||||||
|
while (n < count) {
|
||||||
|
r = write(s, buf + n, count - n);
|
||||||
|
if (r < 0) {
|
||||||
|
if (errno == EINTR) continue;
|
||||||
|
ALOGE("write error: %s\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
n += r;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Tokenize the command buffer, locate a matching command,
|
||||||
|
* ensure that the required number of arguments are provided,
|
||||||
|
* call the function(), return the result.
|
||||||
|
*/
|
||||||
|
static int execute(int s, char cmd[BUFFER_MAX])
|
||||||
|
{
|
||||||
|
char reply[REPLY_MAX];
|
||||||
|
char *arg[TOKEN_MAX+1];
|
||||||
|
unsigned i;
|
||||||
|
unsigned n = 0;
|
||||||
|
unsigned short count;
|
||||||
|
int ret = -1;
|
||||||
|
|
||||||
|
// ALOGI("execute('%s')\n", cmd);
|
||||||
|
|
||||||
|
/* default reply is "" */
|
||||||
|
reply[0] = 0;
|
||||||
|
|
||||||
|
/* n is number of args (not counting arg[0]) */
|
||||||
|
arg[0] = cmd;
|
||||||
|
while (*cmd) {
|
||||||
|
if (isspace(*cmd)) {
|
||||||
|
*cmd++ = 0;
|
||||||
|
n++;
|
||||||
|
arg[n] = cmd;
|
||||||
|
if (n == TOKEN_MAX) {
|
||||||
|
ALOGE("too many arguments\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
|
||||||
|
if (!strcmp(cmds[i].name,arg[0])) {
|
||||||
|
if (n != cmds[i].numargs) {
|
||||||
|
ALOGE("%s requires %d arguments (%d given)\n",
|
||||||
|
cmds[i].name, cmds[i].numargs, n);
|
||||||
|
} else {
|
||||||
|
ret = cmds[i].func(arg + 1, reply);
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ALOGE("unsupported command '%s'\n", arg[0]);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (reply[0]) {
|
||||||
|
n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
|
||||||
|
} else {
|
||||||
|
n = snprintf(cmd, BUFFER_MAX, "%d", ret);
|
||||||
|
}
|
||||||
|
if (n > BUFFER_MAX) n = BUFFER_MAX;
|
||||||
|
count = n;
|
||||||
|
|
||||||
|
// ALOGI("reply: '%s'\n", cmd);
|
||||||
|
if (writex(s, &count, sizeof(count))) return -1;
|
||||||
|
if (writex(s, cmd, count)) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize all the global variables that are used elsewhere. Returns 0 upon
|
||||||
|
* success and -1 on error.
|
||||||
|
*/
|
||||||
|
void free_globals() {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < android_system_dirs.count; i++) {
|
||||||
|
if (android_system_dirs.dirs[i].path != NULL) {
|
||||||
|
free(android_system_dirs.dirs[i].path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(android_system_dirs.dirs);
|
||||||
|
}
|
||||||
|
|
||||||
|
int initialize_globals() {
|
||||||
|
// Get the android data directory.
|
||||||
|
if (get_path_from_env(&android_data_dir, "ANDROID_DATA") < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the android app directory.
|
||||||
|
if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the android protected app directory.
|
||||||
|
if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the android app native library directory.
|
||||||
|
if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the sd-card ASEC mount point.
|
||||||
|
if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the android media directory.
|
||||||
|
if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take note of the system and vendor directories.
|
||||||
|
android_system_dirs.count = 2;
|
||||||
|
|
||||||
|
android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t));
|
||||||
|
if (android_system_dirs.dirs == NULL) {
|
||||||
|
ALOGE("Couldn't allocate array for dirs; aborting\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// system
|
||||||
|
if (get_path_from_env(&android_system_dirs.dirs[0], "ANDROID_ROOT") < 0) {
|
||||||
|
free_globals();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// append "app/" to dirs[0]
|
||||||
|
char *system_app_path = build_string2(android_system_dirs.dirs[0].path, APP_SUBDIR);
|
||||||
|
android_system_dirs.dirs[0].path = system_app_path;
|
||||||
|
android_system_dirs.dirs[0].len = strlen(system_app_path);
|
||||||
|
|
||||||
|
// vendor
|
||||||
|
// TODO replace this with an environment variable (doesn't exist yet)
|
||||||
|
android_system_dirs.dirs[1].path = "/vendor/app/";
|
||||||
|
android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int initialize_directories() {
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
// Read current filesystem layout version to handle upgrade paths
|
||||||
|
char version_path[PATH_MAX];
|
||||||
|
snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);
|
||||||
|
|
||||||
|
int oldVersion;
|
||||||
|
if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
|
||||||
|
oldVersion = 0;
|
||||||
|
}
|
||||||
|
int version = oldVersion;
|
||||||
|
|
||||||
|
// /data/user
|
||||||
|
char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
|
||||||
|
// /data/data
|
||||||
|
char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);
|
||||||
|
// /data/user/0
|
||||||
|
char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0");
|
||||||
|
if (!user_data_dir || !legacy_data_dir || !primary_data_dir) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the /data/user directory if necessary
|
||||||
|
if (access(user_data_dir, R_OK) < 0) {
|
||||||
|
if (mkdir(user_data_dir, 0711) < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (chown(user_data_dir, AID_SYSTEM, AID_SYSTEM) < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (chmod(user_data_dir, 0711) < 0) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Make the /data/user/0 symlink to /data/data if necessary
|
||||||
|
if (access(primary_data_dir, R_OK) < 0) {
|
||||||
|
if (symlink(legacy_data_dir, primary_data_dir)) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version == 0) {
|
||||||
|
// Introducing multi-user, so migrate /data/media contents into /data/media/0
|
||||||
|
ALOGD("Upgrading /data/media for multi-user");
|
||||||
|
|
||||||
|
// Ensure /data/media
|
||||||
|
if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /data/media.tmp
|
||||||
|
char media_tmp_dir[PATH_MAX];
|
||||||
|
snprintf(media_tmp_dir, PATH_MAX, "%smedia.tmp", android_data_dir.path);
|
||||||
|
|
||||||
|
// Only copy when upgrade not already in progress
|
||||||
|
if (access(media_tmp_dir, F_OK) == -1) {
|
||||||
|
if (rename(android_media_dir.path, media_tmp_dir) == -1) {
|
||||||
|
ALOGE("Failed to move legacy media path: %s", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create /data/media again
|
||||||
|
if (fs_prepare_dir(android_media_dir.path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /data/media/0
|
||||||
|
char owner_media_dir[PATH_MAX];
|
||||||
|
snprintf(owner_media_dir, PATH_MAX, "%s0", android_media_dir.path);
|
||||||
|
|
||||||
|
// Move any owner data into place
|
||||||
|
if (access(media_tmp_dir, F_OK) == 0) {
|
||||||
|
if (rename(media_tmp_dir, owner_media_dir) == -1) {
|
||||||
|
ALOGE("Failed to move owner media path: %s", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure media directories for any existing users
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *dirent;
|
||||||
|
char user_media_dir[PATH_MAX];
|
||||||
|
|
||||||
|
dir = opendir(user_data_dir);
|
||||||
|
if (dir != NULL) {
|
||||||
|
while ((dirent = readdir(dir))) {
|
||||||
|
if (dirent->d_type == DT_DIR) {
|
||||||
|
const char *name = dirent->d_name;
|
||||||
|
|
||||||
|
// skip "." and ".."
|
||||||
|
if (name[0] == '.') {
|
||||||
|
if (name[1] == 0) continue;
|
||||||
|
if ((name[1] == '.') && (name[2] == 0)) continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /data/media/<user_id>
|
||||||
|
snprintf(user_media_dir, PATH_MAX, "%s%s", android_media_dir.path, name);
|
||||||
|
if (fs_prepare_dir(user_media_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
version = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /data/media/obb
|
||||||
|
char media_obb_dir[PATH_MAX];
|
||||||
|
snprintf(media_obb_dir, PATH_MAX, "%sobb", android_media_dir.path);
|
||||||
|
|
||||||
|
if (version == 1) {
|
||||||
|
// Introducing /data/media/obb for sharing OBB across users; migrate
|
||||||
|
// any existing OBB files from owner.
|
||||||
|
ALOGD("Upgrading to shared /data/media/obb");
|
||||||
|
|
||||||
|
// /data/media/0/Android/obb
|
||||||
|
char owner_obb_path[PATH_MAX];
|
||||||
|
snprintf(owner_obb_path, PATH_MAX, "%s0/Android/obb", android_media_dir.path);
|
||||||
|
|
||||||
|
// Only move if target doesn't already exist
|
||||||
|
if (access(media_obb_dir, F_OK) != 0 && access(owner_obb_path, F_OK) == 0) {
|
||||||
|
if (rename(owner_obb_path, media_obb_dir) == -1) {
|
||||||
|
ALOGE("Failed to move OBB from owner: %s", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
version = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ensure_media_user_dirs(0) == -1) {
|
||||||
|
ALOGE("Failed to setup media for user 0");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
if (fs_prepare_dir(media_obb_dir, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persist layout version if changed
|
||||||
|
if (version != oldVersion) {
|
||||||
|
if (fs_write_atomic_int(version_path, version) == -1) {
|
||||||
|
ALOGE("Failed to save version to %s: %s", version_path, strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success!
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
free(user_data_dir);
|
||||||
|
free(legacy_data_dir);
|
||||||
|
free(primary_data_dir);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drop_privileges() {
|
||||||
|
if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
|
||||||
|
ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setgid(AID_INSTALL) < 0) {
|
||||||
|
ALOGE("setgid() can't drop privileges; exiting.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setuid(AID_INSTALL) < 0) {
|
||||||
|
ALOGE("setuid() can't drop privileges; exiting.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct __user_cap_header_struct capheader;
|
||||||
|
struct __user_cap_data_struct capdata[2];
|
||||||
|
memset(&capheader, 0, sizeof(capheader));
|
||||||
|
memset(&capdata, 0, sizeof(capdata));
|
||||||
|
capheader.version = _LINUX_CAPABILITY_VERSION_3;
|
||||||
|
capheader.pid = 0;
|
||||||
|
|
||||||
|
capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);
|
||||||
|
capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN);
|
||||||
|
capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
|
||||||
|
capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
|
||||||
|
|
||||||
|
capdata[0].effective = capdata[0].permitted;
|
||||||
|
capdata[1].effective = capdata[1].permitted;
|
||||||
|
capdata[0].inheritable = 0;
|
||||||
|
capdata[1].inheritable = 0;
|
||||||
|
|
||||||
|
if (capset(&capheader, &capdata[0]) < 0) {
|
||||||
|
ALOGE("capset failed: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(const int argc, const char *argv[]) {
|
||||||
|
char buf[BUFFER_MAX];
|
||||||
|
struct sockaddr addr;
|
||||||
|
socklen_t alen;
|
||||||
|
int lsocket, s, count;
|
||||||
|
|
||||||
|
ALOGI("installd firing up\n");
|
||||||
|
|
||||||
|
if (initialize_globals() < 0) {
|
||||||
|
ALOGE("Could not initialize globals; exiting.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (initialize_directories() < 0) {
|
||||||
|
ALOGE("Could not create directories; exiting.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
drop_privileges();
|
||||||
|
|
||||||
|
lsocket = android_get_control_socket(SOCKET_PATH);
|
||||||
|
if (lsocket < 0) {
|
||||||
|
ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (listen(lsocket, 5)) {
|
||||||
|
ALOGE("Listen on socket failed: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
fcntl(lsocket, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
alen = sizeof(addr);
|
||||||
|
s = accept(lsocket, &addr, &alen);
|
||||||
|
if (s < 0) {
|
||||||
|
ALOGE("Accept failed: %s\n", strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fcntl(s, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
ALOGI("new connection\n");
|
||||||
|
for (;;) {
|
||||||
|
unsigned short count;
|
||||||
|
if (readx(s, &count, sizeof(count))) {
|
||||||
|
ALOGE("failed to read size\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ((count < 1) || (count >= BUFFER_MAX)) {
|
||||||
|
ALOGE("invalid size %d\n", count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (readx(s, buf, count)) {
|
||||||
|
ALOGE("failed to read command\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
buf[count] = 0;
|
||||||
|
if (execute(s, buf)) break;
|
||||||
|
}
|
||||||
|
ALOGI("closing connection\n");
|
||||||
|
close(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
213
cmds/installd/installd.h
Normal file
213
cmds/installd/installd.h
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
/*
|
||||||
|
**
|
||||||
|
** Copyright 2008, The Android Open Source Project
|
||||||
|
**
|
||||||
|
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
** you may not use this file except in compliance with the License.
|
||||||
|
** You may obtain a copy of the License at
|
||||||
|
**
|
||||||
|
** http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
**
|
||||||
|
** Unless required by applicable law or agreed to in writing, software
|
||||||
|
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
** See the License for the specific language governing permissions and
|
||||||
|
** limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_TAG "installd"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
|
||||||
|
#include <cutils/fs.h>
|
||||||
|
#include <cutils/sockets.h>
|
||||||
|
#include <cutils/log.h>
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
#include <cutils/multiuser.h>
|
||||||
|
|
||||||
|
#include <private/android_filesystem_config.h>
|
||||||
|
|
||||||
|
#if INCLUDE_SYS_MOUNT_FOR_STATFS
|
||||||
|
#include <sys/mount.h>
|
||||||
|
#else
|
||||||
|
#include <sys/statfs.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SOCKET_PATH "installd"
|
||||||
|
|
||||||
|
|
||||||
|
/* elements combined with a valid package name to form paths */
|
||||||
|
|
||||||
|
#define PRIMARY_USER_PREFIX "data/"
|
||||||
|
#define SECONDARY_USER_PREFIX "user/"
|
||||||
|
|
||||||
|
#define PKG_DIR_POSTFIX ""
|
||||||
|
|
||||||
|
#define PKG_LIB_POSTFIX "/lib"
|
||||||
|
|
||||||
|
#define CACHE_DIR_POSTFIX "/cache"
|
||||||
|
|
||||||
|
#define APP_SUBDIR "app/" // sub-directory under ANDROID_DATA
|
||||||
|
|
||||||
|
#define APP_LIB_SUBDIR "app-lib/" // sub-directory under ANDROID_DATA
|
||||||
|
|
||||||
|
#define MEDIA_SUBDIR "media/" // sub-directory under ANDROID_DATA
|
||||||
|
|
||||||
|
/* other handy constants */
|
||||||
|
|
||||||
|
#define PRIVATE_APP_SUBDIR "app-private/" // sub-directory under ANDROID_DATA
|
||||||
|
|
||||||
|
#define DALVIK_CACHE_PREFIX "/data/dalvik-cache/"
|
||||||
|
#define DALVIK_CACHE_POSTFIX "/classes.dex"
|
||||||
|
|
||||||
|
#define UPDATE_COMMANDS_DIR_PREFIX "/system/etc/updatecmds/"
|
||||||
|
|
||||||
|
#define PKG_NAME_MAX 128 /* largest allowed package name */
|
||||||
|
#define PKG_PATH_MAX 256 /* max size of any path we use */
|
||||||
|
|
||||||
|
#define PER_USER_RANGE ((uid_t)100000) /* range of uids per user
|
||||||
|
uid = persona * PER_USER_RANGE + appid */
|
||||||
|
|
||||||
|
/* data structures */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* path;
|
||||||
|
size_t len;
|
||||||
|
} dir_rec_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t count;
|
||||||
|
dir_rec_t* dirs;
|
||||||
|
} dir_rec_array_t;
|
||||||
|
|
||||||
|
extern dir_rec_t android_app_dir;
|
||||||
|
extern dir_rec_t android_app_private_dir;
|
||||||
|
extern dir_rec_t android_app_lib_dir;
|
||||||
|
extern dir_rec_t android_data_dir;
|
||||||
|
extern dir_rec_t android_asec_dir;
|
||||||
|
extern dir_rec_t android_media_dir;
|
||||||
|
extern dir_rec_array_t android_system_dirs;
|
||||||
|
|
||||||
|
typedef struct cache_dir_struct {
|
||||||
|
struct cache_dir_struct* parent;
|
||||||
|
int32_t childCount;
|
||||||
|
int32_t hiddenCount;
|
||||||
|
int32_t deleted;
|
||||||
|
char name[];
|
||||||
|
} cache_dir_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
cache_dir_t* dir;
|
||||||
|
time_t modTime;
|
||||||
|
char name[];
|
||||||
|
} cache_file_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t numDirs;
|
||||||
|
size_t availDirs;
|
||||||
|
cache_dir_t** dirs;
|
||||||
|
size_t numFiles;
|
||||||
|
size_t availFiles;
|
||||||
|
cache_file_t** files;
|
||||||
|
size_t numCollected;
|
||||||
|
void* memBlocks;
|
||||||
|
int8_t* curMemBlockAvail;
|
||||||
|
int8_t* curMemBlockEnd;
|
||||||
|
} cache_t;
|
||||||
|
|
||||||
|
/* util.c */
|
||||||
|
|
||||||
|
int create_pkg_path_in_dir(char path[PKG_PATH_MAX],
|
||||||
|
const dir_rec_t* dir,
|
||||||
|
const char* pkgname,
|
||||||
|
const char* postfix);
|
||||||
|
|
||||||
|
int create_pkg_path(char path[PKG_PATH_MAX],
|
||||||
|
const char *pkgname,
|
||||||
|
const char *postfix,
|
||||||
|
uid_t persona);
|
||||||
|
|
||||||
|
int create_persona_path(char path[PKG_PATH_MAX],
|
||||||
|
uid_t persona);
|
||||||
|
|
||||||
|
int create_persona_media_path(char path[PKG_PATH_MAX], userid_t userid);
|
||||||
|
|
||||||
|
int create_move_path(char path[PKG_PATH_MAX],
|
||||||
|
const char* pkgname,
|
||||||
|
const char* leaf,
|
||||||
|
uid_t persona);
|
||||||
|
|
||||||
|
int is_valid_package_name(const char* pkgname);
|
||||||
|
|
||||||
|
int create_cache_path(char path[PKG_PATH_MAX], const char *src);
|
||||||
|
|
||||||
|
int delete_dir_contents(const char *pathname,
|
||||||
|
int also_delete_dir,
|
||||||
|
const char *ignore);
|
||||||
|
|
||||||
|
int delete_dir_contents_fd(int dfd, const char *name);
|
||||||
|
|
||||||
|
int lookup_media_dir(char basepath[PATH_MAX], const char *dir);
|
||||||
|
|
||||||
|
int64_t data_disk_free();
|
||||||
|
|
||||||
|
cache_t* start_cache_collection();
|
||||||
|
|
||||||
|
void add_cache_files(cache_t* cache, const char *basepath, const char *cachedir);
|
||||||
|
|
||||||
|
void clear_cache_files(cache_t* cache, int64_t free_size);
|
||||||
|
|
||||||
|
void finish_cache_collection(cache_t* cache);
|
||||||
|
|
||||||
|
int validate_system_app_path(const char* path);
|
||||||
|
|
||||||
|
int get_path_from_env(dir_rec_t* rec, const char* var);
|
||||||
|
|
||||||
|
int get_path_from_string(dir_rec_t* rec, const char* path);
|
||||||
|
|
||||||
|
int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
|
||||||
|
|
||||||
|
int validate_apk_path(const char *path);
|
||||||
|
|
||||||
|
int append_and_increment(char** dst, const char* src, size_t* dst_size);
|
||||||
|
|
||||||
|
char *build_string2(char *s1, char *s2);
|
||||||
|
char *build_string3(char *s1, char *s2, char *s3);
|
||||||
|
|
||||||
|
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
|
||||||
|
int ensure_media_user_dirs(userid_t userid);
|
||||||
|
|
||||||
|
/* commands.c */
|
||||||
|
|
||||||
|
int install(const char *pkgname, uid_t uid, gid_t gid);
|
||||||
|
int uninstall(const char *pkgname, uid_t persona);
|
||||||
|
int renamepkg(const char *oldpkgname, const char *newpkgname);
|
||||||
|
int fix_uid(const char *pkgname, uid_t uid, gid_t gid);
|
||||||
|
int delete_user_data(const char *pkgname, uid_t persona);
|
||||||
|
int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
|
||||||
|
int delete_persona(uid_t persona);
|
||||||
|
int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy);
|
||||||
|
int delete_cache(const char *pkgname, uid_t persona);
|
||||||
|
int move_dex(const char *src, const char *dst);
|
||||||
|
int rm_dex(const char *path);
|
||||||
|
int protect(char *pkgname, gid_t gid);
|
||||||
|
int get_size(const char *pkgname, int persona, const char *apkpath, const char *fwdlock_apkpath,
|
||||||
|
const char *asecpath, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
|
||||||
|
int64_t *asecsize);
|
||||||
|
int free_cache(int64_t free_size);
|
||||||
|
int dexopt(const char *apk_path, uid_t uid, int is_public);
|
||||||
|
int movefiles();
|
||||||
|
int linklib(const char* target, const char* source, int userId);
|
31
cmds/installd/tests/Android.mk
Normal file
31
cmds/installd/tests/Android.mk
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Build the unit tests for installd
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
# Build the unit tests.
|
||||||
|
test_src_files := \
|
||||||
|
installd_utils_test.cpp
|
||||||
|
|
||||||
|
shared_libraries := \
|
||||||
|
libutils \
|
||||||
|
libcutils \
|
||||||
|
libstlport
|
||||||
|
|
||||||
|
static_libraries := \
|
||||||
|
libinstalld \
|
||||||
|
libdiskusage \
|
||||||
|
libgtest \
|
||||||
|
libgtest_main
|
||||||
|
|
||||||
|
c_includes := \
|
||||||
|
frameworks/base/cmds/installd
|
||||||
|
|
||||||
|
$(foreach file,$(test_src_files), \
|
||||||
|
$(eval include $(CLEAR_VARS)) \
|
||||||
|
$(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
|
||||||
|
$(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
|
||||||
|
$(eval LOCAL_SRC_FILES := $(file)) \
|
||||||
|
$(eval LOCAL_C_INCLUDES := $(c_includes)) \
|
||||||
|
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
|
||||||
|
$(eval include $(BUILD_NATIVE_TEST)) \
|
||||||
|
)
|
437
cmds/installd/tests/installd_utils_test.cpp
Normal file
437
cmds/installd/tests/installd_utils_test.cpp
Normal file
@ -0,0 +1,437 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define LOG_TAG "utils_test"
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "installd.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_DATA_DIR "/data/"
|
||||||
|
#define TEST_APP_DIR "/data/app/"
|
||||||
|
#define TEST_APP_PRIVATE_DIR "/data/app-private/"
|
||||||
|
#define TEST_ASEC_DIR "/mnt/asec/"
|
||||||
|
|
||||||
|
#define TEST_SYSTEM_DIR1 "/system/app/"
|
||||||
|
#define TEST_SYSTEM_DIR2 "/vendor/app/"
|
||||||
|
|
||||||
|
#define REALLY_LONG_APP_NAME "com.example." \
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." \
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
|
||||||
|
#define REALLY_LONG_LEAF_NAME "shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
|
||||||
|
"shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
|
||||||
|
"shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_" \
|
||||||
|
"shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_shared_prefs_"
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
class UtilsTest : public testing::Test {
|
||||||
|
protected:
|
||||||
|
virtual void SetUp() {
|
||||||
|
android_app_dir.path = TEST_APP_DIR;
|
||||||
|
android_app_dir.len = strlen(TEST_APP_DIR);
|
||||||
|
|
||||||
|
android_app_private_dir.path = TEST_APP_PRIVATE_DIR;
|
||||||
|
android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
|
||||||
|
|
||||||
|
android_data_dir.path = TEST_DATA_DIR;
|
||||||
|
android_data_dir.len = strlen(TEST_DATA_DIR);
|
||||||
|
|
||||||
|
android_asec_dir.path = TEST_ASEC_DIR;
|
||||||
|
android_asec_dir.len = strlen(TEST_ASEC_DIR);
|
||||||
|
|
||||||
|
android_system_dirs.count = 2;
|
||||||
|
|
||||||
|
android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
|
||||||
|
android_system_dirs.dirs[0].path = TEST_SYSTEM_DIR1;
|
||||||
|
android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1);
|
||||||
|
|
||||||
|
android_system_dirs.dirs[1].path = TEST_SYSTEM_DIR2;
|
||||||
|
android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void TearDown() {
|
||||||
|
free(android_system_dirs.dirs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_BadPrefix) {
|
||||||
|
// Bad prefixes directories
|
||||||
|
const char *badprefix1 = "/etc/passwd";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badprefix1))
|
||||||
|
<< badprefix1 << " should be allowed as a valid path";
|
||||||
|
|
||||||
|
const char *badprefix2 = "../.." TEST_APP_DIR "../../../blah";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badprefix2))
|
||||||
|
<< badprefix2 << " should be allowed as a valid path";
|
||||||
|
|
||||||
|
const char *badprefix3 = "init.rc";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badprefix3))
|
||||||
|
<< badprefix3 << " should be allowed as a valid path";
|
||||||
|
|
||||||
|
const char *badprefix4 = "/init.rc";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badprefix4))
|
||||||
|
<< badprefix4 << " should be allowed as a valid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_Internal) {
|
||||||
|
// Internal directories
|
||||||
|
const char *internal1 = TEST_APP_DIR "example.apk";
|
||||||
|
EXPECT_EQ(0, validate_apk_path(internal1))
|
||||||
|
<< internal1 << " should be allowed as a valid path";
|
||||||
|
|
||||||
|
const char *badint1 = TEST_APP_DIR "../example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badint1))
|
||||||
|
<< badint1 << " should be rejected as a invalid path";
|
||||||
|
|
||||||
|
const char *badint2 = TEST_APP_DIR "/../example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badint2))
|
||||||
|
<< badint2 << " should be rejected as a invalid path";
|
||||||
|
|
||||||
|
const char *badint3 = TEST_APP_DIR "example.com/pkg.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badint3))
|
||||||
|
<< badint3 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_Private) {
|
||||||
|
// Internal directories
|
||||||
|
const char *private1 = TEST_APP_PRIVATE_DIR "example.apk";
|
||||||
|
EXPECT_EQ(0, validate_apk_path(private1))
|
||||||
|
<< private1 << " should be allowed as a valid path";
|
||||||
|
|
||||||
|
const char *badpriv1 = TEST_APP_PRIVATE_DIR "../example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badpriv1))
|
||||||
|
<< badpriv1 << " should be rejected as a invalid path";
|
||||||
|
|
||||||
|
const char *badpriv2 = TEST_APP_PRIVATE_DIR "/../example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badpriv2))
|
||||||
|
<< badpriv2 << " should be rejected as a invalid path";
|
||||||
|
|
||||||
|
const char *badpriv3 = TEST_APP_PRIVATE_DIR "example.com/pkg.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badpriv3))
|
||||||
|
<< badpriv3 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_AsecGood1) {
|
||||||
|
const char *asec1 = TEST_ASEC_DIR "example.apk";
|
||||||
|
EXPECT_EQ(0, validate_apk_path(asec1))
|
||||||
|
<< asec1 << " should be allowed as a valid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_AsecGood2) {
|
||||||
|
const char *asec2 = TEST_ASEC_DIR "com.example.asec/pkg.apk";
|
||||||
|
EXPECT_EQ(0, validate_apk_path(asec2))
|
||||||
|
<< asec2 << " should be allowed as a valid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_EscapeFail) {
|
||||||
|
const char *badasec1 = TEST_ASEC_DIR "../example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badasec1))
|
||||||
|
<< badasec1 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_DoubleSlashFail) {
|
||||||
|
const char *badasec2 = TEST_ASEC_DIR "com.example.asec//pkg.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badasec2))
|
||||||
|
<< badasec2 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeFail) {
|
||||||
|
const char *badasec3 = TEST_ASEC_DIR "com.example.asec/../../../pkg.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badasec3))
|
||||||
|
<< badasec3 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_SlashEscapeFail) {
|
||||||
|
const char *badasec4 = TEST_ASEC_DIR "/../example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badasec4))
|
||||||
|
<< badasec4 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_CrazyDirFail) {
|
||||||
|
const char *badasec5 = TEST_ASEC_DIR ".//../..";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badasec5))
|
||||||
|
<< badasec5 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_SubdirEscapeSingleFail) {
|
||||||
|
const char *badasec6 = TEST_ASEC_DIR "com.example.asec/../pkg.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badasec6))
|
||||||
|
<< badasec6 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, IsValidApkPath_TwoSubdirFail) {
|
||||||
|
const char *badasec7 = TEST_ASEC_DIR "com.example.asec/subdir1/pkg.apk";
|
||||||
|
EXPECT_EQ(-1, validate_apk_path(badasec7))
|
||||||
|
<< badasec7 << " should be rejected as a invalid path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CheckSystemApp_Dir1) {
|
||||||
|
const char *sysapp1 = TEST_SYSTEM_DIR1 "Voice.apk";
|
||||||
|
EXPECT_EQ(0, validate_system_app_path(sysapp1))
|
||||||
|
<< sysapp1 << " should be allowed as a system path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CheckSystemApp_Dir2) {
|
||||||
|
const char *sysapp2 = TEST_SYSTEM_DIR2 "com.example.myapp.apk";
|
||||||
|
EXPECT_EQ(0, validate_system_app_path(sysapp2))
|
||||||
|
<< sysapp2 << " should be allowed as a system path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CheckSystemApp_EscapeFail) {
|
||||||
|
const char *badapp1 = TEST_SYSTEM_DIR1 "../com.example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_system_app_path(badapp1))
|
||||||
|
<< badapp1 << " should be rejected not a system path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CheckSystemApp_DoubleEscapeFail) {
|
||||||
|
const char *badapp2 = TEST_SYSTEM_DIR2 "/../../com.example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_system_app_path(badapp2))
|
||||||
|
<< badapp2 << " should be rejected not a system path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CheckSystemApp_BadPathEscapeFail) {
|
||||||
|
const char *badapp3 = TEST_APP_DIR "/../../com.example.apk";
|
||||||
|
EXPECT_EQ(-1, validate_system_app_path(badapp3))
|
||||||
|
<< badapp3 << " should be rejected not a system path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
|
||||||
|
dir_rec_t test1;
|
||||||
|
EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
|
||||||
|
<< "Should not allow NULL as a path.";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, GetPathFromString_EmptyPathFail) {
|
||||||
|
dir_rec_t test1;
|
||||||
|
EXPECT_EQ(-1, get_path_from_string(&test1, ""))
|
||||||
|
<< "Should not allow empty paths.";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, GetPathFromString_RelativePathFail) {
|
||||||
|
dir_rec_t test1;
|
||||||
|
EXPECT_EQ(-1, get_path_from_string(&test1, "mnt/asec"))
|
||||||
|
<< "Should not allow relative paths.";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, GetPathFromString_NonCanonical) {
|
||||||
|
dir_rec_t test1;
|
||||||
|
|
||||||
|
EXPECT_EQ(0, get_path_from_string(&test1, "/mnt/asec"))
|
||||||
|
<< "Should be able to canonicalize directory /mnt/asec";
|
||||||
|
EXPECT_STREQ("/mnt/asec/", test1.path)
|
||||||
|
<< "/mnt/asec should be canonicalized to /mnt/asec/";
|
||||||
|
EXPECT_EQ(10, (ssize_t) test1.len)
|
||||||
|
<< "path len should be equal to the length of /mnt/asec/ (10)";
|
||||||
|
free(test1.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, GetPathFromString_CanonicalPath) {
|
||||||
|
dir_rec_t test3;
|
||||||
|
EXPECT_EQ(0, get_path_from_string(&test3, "/data/app/"))
|
||||||
|
<< "Should be able to canonicalize directory /data/app/";
|
||||||
|
EXPECT_STREQ("/data/app/", test3.path)
|
||||||
|
<< "/data/app/ should be canonicalized to /data/app/";
|
||||||
|
EXPECT_EQ(10, (ssize_t) test3.len)
|
||||||
|
<< "path len should be equal to the length of /data/app/ (10)";
|
||||||
|
free(test3.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
// Create long packagename of "aaaaa..."
|
||||||
|
size_t pkgnameSize = PKG_NAME_MAX;
|
||||||
|
char pkgname[pkgnameSize + 1];
|
||||||
|
memset(pkgname, 'a', pkgnameSize);
|
||||||
|
pkgname[pkgnameSize] = '\0';
|
||||||
|
|
||||||
|
EXPECT_EQ(0, create_pkg_path(path, pkgname, "", 0))
|
||||||
|
<< "Should successfully be able to create package name.";
|
||||||
|
|
||||||
|
const char *prefix = TEST_DATA_DIR PRIMARY_USER_PREFIX;
|
||||||
|
size_t offset = strlen(prefix);
|
||||||
|
EXPECT_STREQ(pkgname, path + offset)
|
||||||
|
<< "Package path should be a really long string of a's";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreatePkgPath_LongPkgNameFail) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
// Create long packagename of "aaaaa..."
|
||||||
|
size_t pkgnameSize = PKG_NAME_MAX + 1;
|
||||||
|
char pkgname[pkgnameSize + 1];
|
||||||
|
memset(pkgname, 'a', pkgnameSize);
|
||||||
|
pkgname[pkgnameSize] = '\0';
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, create_pkg_path(path, pkgname, "", 0))
|
||||||
|
<< "Should return error because package name is too long.";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreatePkgPath_LongPostfixFail) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
// Create long packagename of "aaaaa..."
|
||||||
|
size_t postfixSize = PKG_PATH_MAX;
|
||||||
|
char postfix[postfixSize + 1];
|
||||||
|
memset(postfix, 'a', postfixSize);
|
||||||
|
postfix[postfixSize] = '\0';
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, create_pkg_path(path, "com.example.package", postfix, 0))
|
||||||
|
<< "Should return error because postfix is too long.";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreatePkgPath_PrimaryUser) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 0))
|
||||||
|
<< "Should return error because postfix is too long.";
|
||||||
|
|
||||||
|
EXPECT_STREQ(TEST_DATA_DIR PRIMARY_USER_PREFIX "com.example.package", path)
|
||||||
|
<< "Package path should be in /data/data/";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
EXPECT_EQ(0, create_pkg_path(path, "com.example.package", "", 1))
|
||||||
|
<< "Should successfully create package path.";
|
||||||
|
|
||||||
|
EXPECT_STREQ(TEST_DATA_DIR SECONDARY_USER_PREFIX "1/com.example.package", path)
|
||||||
|
<< "Package path should be in /data/user/";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreatePkgPathInDir_ProtectedDir) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
dir_rec_t dir;
|
||||||
|
dir.path = "/data/app-private/";
|
||||||
|
dir.len = strlen(dir.path);
|
||||||
|
|
||||||
|
EXPECT_EQ(0, create_pkg_path_in_dir(path, &dir, "com.example.package", ".apk"))
|
||||||
|
<< "Should successfully create package path.";
|
||||||
|
|
||||||
|
EXPECT_STREQ("/data/app-private/com.example.package.apk", path)
|
||||||
|
<< "Package path should be in /data/app-private/";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreatePersonaPath_Primary) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
EXPECT_EQ(0, create_persona_path(path, 0))
|
||||||
|
<< "Should successfully build primary user path.";
|
||||||
|
|
||||||
|
EXPECT_STREQ("/data/data/", path)
|
||||||
|
<< "Primary user should have correct path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreatePersonaPath_Secondary) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
EXPECT_EQ(0, create_persona_path(path, 1))
|
||||||
|
<< "Should successfully build primary user path.";
|
||||||
|
|
||||||
|
EXPECT_STREQ("/data/user/1/", path)
|
||||||
|
<< "Primary user should have correct path";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreateMovePath_Primary) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
EXPECT_EQ(0, create_move_path(path, "com.android.test", "shared_prefs", 0))
|
||||||
|
<< "Should be able to create move path for primary user";
|
||||||
|
|
||||||
|
EXPECT_STREQ("/data/data/com.android.test/shared_prefs", path)
|
||||||
|
<< "Primary user package directory should be created correctly";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreateMovePath_Fail_AppTooLong) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, create_move_path(path, REALLY_LONG_APP_NAME, "shared_prefs", 0))
|
||||||
|
<< "Should fail to create move path for primary user";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CreateMovePath_Fail_LeafTooLong) {
|
||||||
|
char path[PKG_PATH_MAX];
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, create_move_path(path, "com.android.test", REALLY_LONG_LEAF_NAME, 0))
|
||||||
|
<< "Should fail to create move path for primary user";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, CopyAndAppend_Normal) {
|
||||||
|
//int copy_and_append(dir_rec_t* dst, dir_rec_t* src, char* suffix)
|
||||||
|
dir_rec_t dst;
|
||||||
|
dir_rec_t src;
|
||||||
|
|
||||||
|
src.path = "/data/";
|
||||||
|
src.len = strlen(src.path);
|
||||||
|
|
||||||
|
EXPECT_EQ(0, copy_and_append(&dst, &src, "app/"))
|
||||||
|
<< "Should return error because postfix is too long.";
|
||||||
|
|
||||||
|
EXPECT_STREQ("/data/app/", dst.path)
|
||||||
|
<< "Appended path should be correct";
|
||||||
|
|
||||||
|
EXPECT_EQ(10, (ssize_t) dst.len)
|
||||||
|
<< "Appended path should be length of '/data/app/' (10)";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, AppendAndIncrement_Normal) {
|
||||||
|
size_t dst_size = 10;
|
||||||
|
char dst[dst_size];
|
||||||
|
char *dstp = dst;
|
||||||
|
const char* src = "FOO";
|
||||||
|
|
||||||
|
EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
|
||||||
|
<< "String should append successfully";
|
||||||
|
|
||||||
|
EXPECT_STREQ("FOO", dst)
|
||||||
|
<< "String should append correctly";
|
||||||
|
|
||||||
|
EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
|
||||||
|
<< "String should append successfully again";
|
||||||
|
|
||||||
|
EXPECT_STREQ("FOOFOO", dst)
|
||||||
|
<< "String should append correctly again";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(UtilsTest, AppendAndIncrement_TooBig) {
|
||||||
|
size_t dst_size = 5;
|
||||||
|
char dst[dst_size];
|
||||||
|
char *dstp = dst;
|
||||||
|
const char* src = "FOO";
|
||||||
|
|
||||||
|
EXPECT_EQ(0, append_and_increment(&dstp, src, &dst_size))
|
||||||
|
<< "String should append successfully";
|
||||||
|
|
||||||
|
EXPECT_STREQ("FOO", dst)
|
||||||
|
<< "String should append correctly";
|
||||||
|
|
||||||
|
EXPECT_EQ(-1, append_and_increment(&dstp, src, &dst_size))
|
||||||
|
<< "String should fail because it's too large to fit";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1006
cmds/installd/utils.c
Normal file
1006
cmds/installd/utils.c
Normal file
File diff suppressed because it is too large
Load Diff
26
cmds/ip-up-vpn/Android.mk
Normal file
26
cmds/ip-up-vpn/Android.mk
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2011 The Android Open Source Project
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
LOCAL_PATH := $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := ip-up-vpn.c
|
||||||
|
LOCAL_SHARED_LIBRARIES := libcutils
|
||||||
|
LOCAL_MODULE := ip-up-vpn
|
||||||
|
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/ppp
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
153
cmds/ip-up-vpn/ip-up-vpn.c
Normal file
153
cmds/ip-up-vpn/ip-up-vpn.c
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2011 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/if.h>
|
||||||
|
#include <linux/route.h>
|
||||||
|
|
||||||
|
#define LOG_TAG "ip-up-vpn"
|
||||||
|
#include <cutils/log.h>
|
||||||
|
|
||||||
|
#define DIR "/data/misc/vpn/"
|
||||||
|
|
||||||
|
static const char *env(const char *name) {
|
||||||
|
const char *value = getenv(name);
|
||||||
|
return value ? value : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_address(struct sockaddr *sa, const char *address) {
|
||||||
|
sa->sa_family = AF_INET;
|
||||||
|
errno = EINVAL;
|
||||||
|
return inet_pton(AF_INET, address, &((struct sockaddr_in *)sa)->sin_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The primary goal is to create a file with VPN parameters. Currently they
|
||||||
|
* are interface, addresses, routes, DNS servers, and search domains. Each
|
||||||
|
* parameter occupies one line in the file, and it can be an empty string or
|
||||||
|
* space-separated values. The order and the format must be consistent with
|
||||||
|
* com.android.server.connectivity.Vpn. Here is an example.
|
||||||
|
*
|
||||||
|
* ppp0
|
||||||
|
* 192.168.1.100/24
|
||||||
|
* 0.0.0.0/0
|
||||||
|
* 192.168.1.1 192.168.1.2
|
||||||
|
* example.org
|
||||||
|
*
|
||||||
|
* The secondary goal is to unify the outcome of VPN. The current baseline
|
||||||
|
* is to have an interface configured with the given address and netmask
|
||||||
|
* and maybe add a host route to protect the tunnel. PPP-based VPN already
|
||||||
|
* does this, but others might not. Routes, DNS servers, and search domains
|
||||||
|
* are handled by the framework since they can be overridden by the users.
|
||||||
|
*/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *state = fopen(DIR ".tmp", "wb");
|
||||||
|
if (!state) {
|
||||||
|
ALOGE("Cannot create state: %s", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc >= 6) {
|
||||||
|
/* Invoked by pppd. */
|
||||||
|
fprintf(state, "%s\n", argv[1]);
|
||||||
|
fprintf(state, "%s/32\n", argv[4]);
|
||||||
|
fprintf(state, "0.0.0.0/0\n");
|
||||||
|
fprintf(state, "%s %s\n", env("DNS1"), env("DNS2"));
|
||||||
|
fprintf(state, "\n");
|
||||||
|
} else if (argc == 2) {
|
||||||
|
/* Invoked by racoon. */
|
||||||
|
const char *interface = env("INTERFACE");
|
||||||
|
const char *address = env("INTERNAL_ADDR4");
|
||||||
|
const char *routes = env("SPLIT_INCLUDE_CIDR");
|
||||||
|
|
||||||
|
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||||
|
struct rtentry rt;
|
||||||
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
memset(&rt, 0, sizeof(rt));
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
|
||||||
|
/* Remove the old host route. There could be more than one. */
|
||||||
|
rt.rt_flags |= RTF_UP | RTF_HOST;
|
||||||
|
if (set_address(&rt.rt_dst, env("REMOTE_ADDR"))) {
|
||||||
|
while (!ioctl(s, SIOCDELRT, &rt));
|
||||||
|
}
|
||||||
|
if (errno != ESRCH) {
|
||||||
|
ALOGE("Cannot remove host route: %s", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new host route. */
|
||||||
|
rt.rt_flags |= RTF_GATEWAY;
|
||||||
|
if (!set_address(&rt.rt_gateway, argv[1]) ||
|
||||||
|
(ioctl(s, SIOCADDRT, &rt) && errno != EEXIST)) {
|
||||||
|
ALOGE("Cannot create host route: %s", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Bring up the interface. */
|
||||||
|
ifr.ifr_flags = IFF_UP;
|
||||||
|
strncpy(ifr.ifr_name, interface, IFNAMSIZ);
|
||||||
|
if (ioctl(s, SIOCSIFFLAGS, &ifr)) {
|
||||||
|
ALOGE("Cannot bring up %s: %s", interface, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the address. */
|
||||||
|
if (!set_address(&ifr.ifr_addr, address) ||
|
||||||
|
ioctl(s, SIOCSIFADDR, &ifr)) {
|
||||||
|
ALOGE("Cannot set address: %s", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the netmask. */
|
||||||
|
if (set_address(&ifr.ifr_netmask, env("INTERNAL_NETMASK4"))) {
|
||||||
|
if (ioctl(s, SIOCSIFNETMASK, &ifr)) {
|
||||||
|
ALOGE("Cannot set netmask: %s", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Send few packets to trigger phase 2? */
|
||||||
|
|
||||||
|
fprintf(state, "%s\n", interface);
|
||||||
|
fprintf(state, "%s/%s\n", address, env("INTERNAL_CIDR4"));
|
||||||
|
fprintf(state, "%s\n", routes[0] ? routes : "0.0.0.0/0");
|
||||||
|
fprintf(state, "%s\n", env("INTERNAL_DNS4_LIST"));
|
||||||
|
fprintf(state, "%s\n", env("DEFAULT_DOMAIN"));
|
||||||
|
} else {
|
||||||
|
ALOGE("Cannot parse parameters");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(state);
|
||||||
|
if (chmod(DIR ".tmp", 0444) || rename(DIR ".tmp", DIR "state")) {
|
||||||
|
ALOGE("Cannot write state: %s", strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
15
cmds/rawbu/Android.mk
Normal file
15
cmds/rawbu/Android.mk
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Copyright 2009 The Android Open Source Project
|
||||||
|
|
||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES:= backup.cpp
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := libcutils libc
|
||||||
|
|
||||||
|
LOCAL_MODULE:= rawbu
|
||||||
|
|
||||||
|
LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
|
||||||
|
LOCAL_MODULE_TAGS := debug
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
190
cmds/rawbu/NOTICE
Normal file
190
cmds/rawbu/NOTICE
Normal file
@ -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
|
||||||
|
|
746
cmds/rawbu/backup.cpp
Normal file
746
cmds/rawbu/backup.cpp
Normal file
@ -0,0 +1,746 @@
|
|||||||
|
// Copyright 2009 The Android Open Source Project
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <utime.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <cutils/properties.h>
|
||||||
|
|
||||||
|
#include <private/android_filesystem_config.h>
|
||||||
|
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX 4096
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// First version.
|
||||||
|
#define FILE_VERSION_1 0xffff0001
|
||||||
|
|
||||||
|
// Introduces backup all option to header.
|
||||||
|
#define FILE_VERSION_2 0xffff0002
|
||||||
|
|
||||||
|
#define FILE_VERSION FILE_VERSION_2
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
static char nameBuffer[PATH_MAX];
|
||||||
|
static struct stat statBuffer;
|
||||||
|
|
||||||
|
static char copyBuffer[8192];
|
||||||
|
static char *backupFilePath = NULL;
|
||||||
|
|
||||||
|
static uint32_t inputFileVersion;
|
||||||
|
|
||||||
|
static int opt_backupAll;
|
||||||
|
|
||||||
|
#define SPECIAL_NO_TOUCH 0
|
||||||
|
#define SPECIAL_NO_BACKUP 1
|
||||||
|
|
||||||
|
struct special_dir {
|
||||||
|
const char* path;
|
||||||
|
int type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Directory paths that we will not backup/restore */
|
||||||
|
static const struct special_dir SKIP_PATHS[] = {
|
||||||
|
{ "/data/misc", SPECIAL_NO_TOUCH },
|
||||||
|
{ "/data/system/batterystats.bin", SPECIAL_NO_TOUCH },
|
||||||
|
{ "/data/system/location", SPECIAL_NO_TOUCH },
|
||||||
|
{ "/data/dalvik-cache", SPECIAL_NO_BACKUP },
|
||||||
|
{ NULL, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is just copied from the shell's built-in wipe command. */
|
||||||
|
static int wipe (const char *path)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *de;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
|
||||||
|
if (dir == NULL) {
|
||||||
|
fprintf (stderr, "Error opendir'ing %s: %s\n",
|
||||||
|
path, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *filenameOffset;
|
||||||
|
|
||||||
|
strcpy(nameBuffer, path);
|
||||||
|
strcat(nameBuffer, "/");
|
||||||
|
|
||||||
|
filenameOffset = nameBuffer + strlen(nameBuffer);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
de = readdir(dir);
|
||||||
|
|
||||||
|
if (de == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcmp(de->d_name, ".")
|
||||||
|
|| 0 == strcmp(de->d_name, "..")
|
||||||
|
|| 0 == strcmp(de->d_name, "lost+found")
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(filenameOffset, de->d_name);
|
||||||
|
bool noBackup = false;
|
||||||
|
|
||||||
|
/* See if this is a path we should skip. */
|
||||||
|
for (i = 0; SKIP_PATHS[i].path; i++) {
|
||||||
|
if (strcmp(SKIP_PATHS[i].path, nameBuffer) == 0) {
|
||||||
|
if (opt_backupAll || SKIP_PATHS[i].type == SPECIAL_NO_BACKUP) {
|
||||||
|
// In this case we didn't back up the directory --
|
||||||
|
// we do want to wipe its contents, but not the
|
||||||
|
// directory itself, since the restore file won't
|
||||||
|
// contain the directory.
|
||||||
|
noBackup = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noBackup && SKIP_PATHS[i].path != NULL) {
|
||||||
|
// This is a SPECIAL_NO_TOUCH directory.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = lstat (nameBuffer, &statBuffer);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "warning -- stat() error on '%s': %s\n",
|
||||||
|
nameBuffer, strerror(errno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(S_ISDIR(statBuffer.st_mode)) {
|
||||||
|
int i;
|
||||||
|
char *newpath;
|
||||||
|
|
||||||
|
newpath = strdup(nameBuffer);
|
||||||
|
if (wipe(newpath) == 0) {
|
||||||
|
free(newpath);
|
||||||
|
closedir(dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noBackup) {
|
||||||
|
ret = rmdir(newpath);
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "warning -- rmdir() error on '%s': %s\n",
|
||||||
|
newpath, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(newpath);
|
||||||
|
|
||||||
|
strcpy(nameBuffer, path);
|
||||||
|
strcat(nameBuffer, "/");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Don't delete the backup file
|
||||||
|
if (backupFilePath && strcmp(backupFilePath, nameBuffer) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ret = unlink(nameBuffer);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "warning -- unlink() error on '%s': %s\n",
|
||||||
|
nameBuffer, strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_int32(FILE* fh, int32_t val)
|
||||||
|
{
|
||||||
|
int res = fwrite(&val, 1, sizeof(val), fh);
|
||||||
|
if (res != sizeof(val)) {
|
||||||
|
fprintf(stderr, "unable to write int32 (%d bytes): %s\n", res, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int write_int64(FILE* fh, int64_t val)
|
||||||
|
{
|
||||||
|
int res = fwrite(&val, 1, sizeof(val), fh);
|
||||||
|
if (res != sizeof(val)) {
|
||||||
|
fprintf(stderr, "unable to write int64 (%d bytes): %s\n", res, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int copy_file(FILE* dest, FILE* src, off_t size, const char* destName,
|
||||||
|
const char* srcName)
|
||||||
|
{
|
||||||
|
errno = 0;
|
||||||
|
|
||||||
|
off_t origSize = size;
|
||||||
|
|
||||||
|
while (size > 0) {
|
||||||
|
int amt = size > (off_t)sizeof(copyBuffer) ? sizeof(copyBuffer) : (int)size;
|
||||||
|
int readLen = fread(copyBuffer, 1, amt, src);
|
||||||
|
if (readLen <= 0) {
|
||||||
|
if (srcName != NULL) {
|
||||||
|
fprintf(stderr, "unable to read source (%d of %ld bytes) file '%s': %s\n",
|
||||||
|
amt, origSize, srcName, errno != 0 ? strerror(errno) : "unexpected EOF");
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "unable to read buffer (%d of %ld bytes): %s\n",
|
||||||
|
amt, origSize, errno != 0 ? strerror(errno) : "unexpected EOF");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int writeLen = fwrite(copyBuffer, 1, readLen, dest);
|
||||||
|
if (writeLen != readLen) {
|
||||||
|
if (destName != NULL) {
|
||||||
|
fprintf(stderr, "unable to write file (%d of %d bytes) '%s': '%s'\n",
|
||||||
|
writeLen, readLen, destName, strerror(errno));
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "unable to write buffer (%d of %d bytes): '%s'\n",
|
||||||
|
writeLen, readLen, strerror(errno));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size -= readLen;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TYPE_END 0
|
||||||
|
#define TYPE_DIR 1
|
||||||
|
#define TYPE_FILE 2
|
||||||
|
|
||||||
|
static int write_header(FILE* fh, int type, const char* path, const struct stat* st)
|
||||||
|
{
|
||||||
|
int pathLen = strlen(path);
|
||||||
|
if (!write_int32(fh, type)) return 0;
|
||||||
|
if (!write_int32(fh, pathLen)) return 0;
|
||||||
|
if (fwrite(path, 1, pathLen, fh) != (size_t)pathLen) {
|
||||||
|
fprintf(stderr, "unable to write: %s\n", strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!write_int32(fh, st->st_uid)) return 0;
|
||||||
|
if (!write_int32(fh, st->st_gid)) return 0;
|
||||||
|
if (!write_int32(fh, st->st_mode)) return 0;
|
||||||
|
if (!write_int64(fh, ((int64_t)st->st_atime)*1000*1000*1000)) return 0;
|
||||||
|
if (!write_int64(fh, ((int64_t)st->st_mtime)*1000*1000*1000)) return 0;
|
||||||
|
if (!write_int64(fh, ((int64_t)st->st_ctime)*1000*1000*1000)) return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int backup_dir(FILE* fh, const char* srcPath)
|
||||||
|
{
|
||||||
|
DIR *dir;
|
||||||
|
struct dirent *de;
|
||||||
|
char* fullPath = NULL;
|
||||||
|
int srcLen = strlen(srcPath);
|
||||||
|
int result = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dir = opendir(srcPath);
|
||||||
|
|
||||||
|
if (dir == NULL) {
|
||||||
|
fprintf (stderr, "error opendir'ing '%s': %s\n",
|
||||||
|
srcPath, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
de = readdir(dir);
|
||||||
|
|
||||||
|
if (de == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcmp(de->d_name, ".")
|
||||||
|
|| 0 == strcmp(de->d_name, "..")
|
||||||
|
|| 0 == strcmp(de->d_name, "lost+found")
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullPath != NULL) {
|
||||||
|
free(fullPath);
|
||||||
|
}
|
||||||
|
fullPath = (char*)malloc(srcLen + strlen(de->d_name) + 2);
|
||||||
|
strcpy(fullPath, srcPath);
|
||||||
|
fullPath[srcLen] = '/';
|
||||||
|
strcpy(fullPath+srcLen+1, de->d_name);
|
||||||
|
|
||||||
|
/* See if this is a path we should skip. */
|
||||||
|
if (!opt_backupAll) {
|
||||||
|
for (i = 0; SKIP_PATHS[i].path; i++) {
|
||||||
|
if (strcmp(SKIP_PATHS[i].path, fullPath) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (SKIP_PATHS[i].path != NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = lstat(fullPath, &statBuffer);
|
||||||
|
|
||||||
|
if (ret != 0) {
|
||||||
|
fprintf(stderr, "stat() error on '%s': %s\n",
|
||||||
|
fullPath, strerror(errno));
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(S_ISDIR(statBuffer.st_mode)) {
|
||||||
|
printf("Saving dir %s...\n", fullPath);
|
||||||
|
|
||||||
|
if (write_header(fh, TYPE_DIR, fullPath, &statBuffer) == 0) {
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (backup_dir(fh, fullPath) == 0) {
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
} else if (S_ISREG(statBuffer.st_mode)) {
|
||||||
|
// Skip the backup file
|
||||||
|
if (backupFilePath && strcmp(fullPath, backupFilePath) == 0) {
|
||||||
|
printf("Skipping backup file %s...\n", backupFilePath);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
printf("Saving file %s...\n", fullPath);
|
||||||
|
}
|
||||||
|
if (write_header(fh, TYPE_FILE, fullPath, &statBuffer) == 0) {
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t size = statBuffer.st_size;
|
||||||
|
if (!write_int64(fh, size)) {
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* src = fopen(fullPath, "r");
|
||||||
|
if (src == NULL) {
|
||||||
|
fprintf(stderr, "unable to open source file '%s': %s\n",
|
||||||
|
fullPath, strerror(errno));
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
int copyres = copy_file(fh, src, size, NULL, fullPath);
|
||||||
|
fclose(src);
|
||||||
|
if (!copyres) {
|
||||||
|
result = 0;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (fullPath != NULL) {
|
||||||
|
free(fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int backup_data(const char* destPath)
|
||||||
|
{
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
FILE* fh = fopen(destPath, "w");
|
||||||
|
if (fh == NULL) {
|
||||||
|
fprintf(stderr, "unable to open destination '%s': %s\n",
|
||||||
|
destPath, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Backing up /data to %s...\n", destPath);
|
||||||
|
|
||||||
|
// The path that shouldn't be backed up
|
||||||
|
backupFilePath = strdup(destPath);
|
||||||
|
|
||||||
|
if (!write_int32(fh, FILE_VERSION)) goto done;
|
||||||
|
if (!write_int32(fh, opt_backupAll)) goto done;
|
||||||
|
if (!backup_dir(fh, "/data")) goto done;
|
||||||
|
if (!write_int32(fh, 0)) goto done;
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (fflush(fh) != 0) {
|
||||||
|
fprintf(stderr, "error flushing destination '%s': %s\n",
|
||||||
|
destPath, strerror(errno));
|
||||||
|
res = -1;
|
||||||
|
goto donedone;
|
||||||
|
}
|
||||||
|
if (fsync(fileno(fh)) != 0) {
|
||||||
|
fprintf(stderr, "error syncing destination '%s': %s\n",
|
||||||
|
destPath, strerror(errno));
|
||||||
|
res = -1;
|
||||||
|
goto donedone;
|
||||||
|
}
|
||||||
|
fclose(fh);
|
||||||
|
sync();
|
||||||
|
|
||||||
|
donedone:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t read_int32(FILE* fh, int32_t defVal)
|
||||||
|
{
|
||||||
|
int32_t val;
|
||||||
|
if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) {
|
||||||
|
fprintf(stderr, "unable to read: %s\n", strerror(errno));
|
||||||
|
return defVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t read_int64(FILE* fh, int64_t defVal)
|
||||||
|
{
|
||||||
|
int64_t val;
|
||||||
|
if (fread(&val, 1, sizeof(val), fh) != sizeof(val)) {
|
||||||
|
fprintf(stderr, "unable to read: %s\n", strerror(errno));
|
||||||
|
return defVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_header(FILE* fh, int* type, char** path, struct stat* st)
|
||||||
|
{
|
||||||
|
*type = read_int32(fh, -1);
|
||||||
|
if (*type == TYPE_END) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*type < 0) {
|
||||||
|
fprintf(stderr, "bad token %d in restore file\n", *type);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t pathLen = read_int32(fh, -1);
|
||||||
|
if (pathLen <= 0) {
|
||||||
|
fprintf(stderr, "bad path length %d in restore file\n", pathLen);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char* readPath = (char*)malloc(pathLen+1);
|
||||||
|
if (fread(readPath, 1, pathLen, fh) != (size_t)pathLen) {
|
||||||
|
fprintf(stderr, "truncated path in restore file\n");
|
||||||
|
free(readPath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
readPath[pathLen] = 0;
|
||||||
|
*path = readPath;
|
||||||
|
|
||||||
|
st->st_uid = read_int32(fh, -1);
|
||||||
|
if (st->st_uid == (uid_t)-1) {
|
||||||
|
fprintf(stderr, "bad uid in restore file at '%s'\n", readPath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
st->st_gid = read_int32(fh, -1);
|
||||||
|
if (st->st_gid == (gid_t)-1) {
|
||||||
|
fprintf(stderr, "bad gid in restore file at '%s'\n", readPath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
st->st_mode = read_int32(fh, -1);
|
||||||
|
if (st->st_mode == (mode_t)-1) {
|
||||||
|
fprintf(stderr, "bad mode in restore file at '%s'\n", readPath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int64_t ltime = read_int64(fh, -1);
|
||||||
|
if (ltime < 0) {
|
||||||
|
fprintf(stderr, "bad atime in restore file at '%s'\n", readPath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
st->st_atime = (time_t)(ltime/1000/1000/1000);
|
||||||
|
ltime = read_int64(fh, -1);
|
||||||
|
if (ltime < 0) {
|
||||||
|
fprintf(stderr, "bad mtime in restore file at '%s'\n", readPath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
st->st_mtime = (time_t)(ltime/1000/1000/1000);
|
||||||
|
ltime = read_int64(fh, -1);
|
||||||
|
if (ltime < 0) {
|
||||||
|
fprintf(stderr, "bad ctime in restore file at '%s'\n", readPath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
st->st_ctime = (time_t)(ltime/1000/1000/1000);
|
||||||
|
|
||||||
|
st->st_mode &= (S_IRWXU|S_IRWXG|S_IRWXO);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int restore_data(const char* srcPath)
|
||||||
|
{
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
FILE* fh = fopen(srcPath, "r");
|
||||||
|
if (fh == NULL) {
|
||||||
|
fprintf(stderr, "Unable to open source '%s': %s\n",
|
||||||
|
srcPath, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inputFileVersion = read_int32(fh, 0);
|
||||||
|
if (inputFileVersion < FILE_VERSION_1 || inputFileVersion > FILE_VERSION) {
|
||||||
|
fprintf(stderr, "Restore file has bad version: 0x%x\n", inputFileVersion);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputFileVersion >= FILE_VERSION_2) {
|
||||||
|
opt_backupAll = read_int32(fh, 0);
|
||||||
|
} else {
|
||||||
|
opt_backupAll = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The path that shouldn't be deleted
|
||||||
|
backupFilePath = strdup(srcPath);
|
||||||
|
|
||||||
|
printf("Wiping contents of /data...\n");
|
||||||
|
if (!wipe("/data")) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Restoring from %s to /data...\n", srcPath);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int type;
|
||||||
|
char* path = NULL;
|
||||||
|
if (read_header(fh, &type, &path, &statBuffer) == 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (type == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* typeName = "?";
|
||||||
|
|
||||||
|
if (type == TYPE_DIR) {
|
||||||
|
typeName = "dir";
|
||||||
|
|
||||||
|
printf("Restoring dir %s...\n", path);
|
||||||
|
|
||||||
|
if (mkdir(path, statBuffer.st_mode) != 0) {
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
fprintf(stderr, "unable to create directory '%s': %s\n",
|
||||||
|
path, strerror(errno));
|
||||||
|
free(path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (type == TYPE_FILE) {
|
||||||
|
typeName = "file";
|
||||||
|
off_t size = read_int64(fh, -1);
|
||||||
|
if (size < 0) {
|
||||||
|
fprintf(stderr, "bad file size %ld in restore file\n", size);
|
||||||
|
free(path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Restoring file %s...\n", path);
|
||||||
|
|
||||||
|
FILE* dest = fopen(path, "w");
|
||||||
|
if (dest == NULL) {
|
||||||
|
fprintf(stderr, "unable to open destination file '%s': %s\n",
|
||||||
|
path, strerror(errno));
|
||||||
|
free(path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
int copyres = copy_file(dest, fh, size, path, NULL);
|
||||||
|
fclose(dest);
|
||||||
|
if (!copyres) {
|
||||||
|
free(path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "unknown node type %d\n", type);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do this even for directories, since the dir may have already existed
|
||||||
|
// so we need to make sure it gets the correct mode.
|
||||||
|
if (chmod(path, statBuffer.st_mode&(S_IRWXU|S_IRWXG|S_IRWXO)) != 0) {
|
||||||
|
fprintf(stderr, "unable to chmod destination %s '%s' to 0x%x: %s\n",
|
||||||
|
typeName, path, statBuffer.st_mode, strerror(errno));
|
||||||
|
free(path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chown(path, statBuffer.st_uid, statBuffer.st_gid) != 0) {
|
||||||
|
fprintf(stderr, "unable to chown destination %s '%s' to uid %d / gid %d: %s\n",
|
||||||
|
typeName, path, (int)statBuffer.st_uid, (int)statBuffer.st_gid, strerror(errno));
|
||||||
|
free(path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct utimbuf timbuf;
|
||||||
|
timbuf.actime = statBuffer.st_atime;
|
||||||
|
timbuf.modtime = statBuffer.st_mtime;
|
||||||
|
if (utime(path, &timbuf) != 0) {
|
||||||
|
fprintf(stderr, "unable to utime destination %s '%s': %s\n",
|
||||||
|
typeName, path, strerror(errno));
|
||||||
|
free(path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
res = 0;
|
||||||
|
|
||||||
|
done:
|
||||||
|
fclose(fh);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show_help(const char *cmd)
|
||||||
|
{
|
||||||
|
fprintf(stderr,"Usage: %s COMMAND [options] [backup-file-path]\n", cmd);
|
||||||
|
|
||||||
|
fprintf(stderr, "commands are:\n"
|
||||||
|
" help Show this help text.\n"
|
||||||
|
" backup Perform a backup of /data.\n"
|
||||||
|
" restore Perform a restore of /data.\n");
|
||||||
|
fprintf(stderr, "options include:\n"
|
||||||
|
" -h Show this help text.\n"
|
||||||
|
" -a Backup all files.\n");
|
||||||
|
fprintf(stderr, "\nThe %s command allows you to perform low-level\n"
|
||||||
|
"backup and restore of the /data partition. This is\n"
|
||||||
|
"where all user data is kept, allowing for a fairly\n"
|
||||||
|
"complete restore of a device's state. Note that\n"
|
||||||
|
"because this is low-level, it will only work across\n"
|
||||||
|
"builds of the same (or very similar) device software.\n",
|
||||||
|
cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* namespace android */
|
||||||
|
|
||||||
|
int main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
int restore = 0;
|
||||||
|
|
||||||
|
if (getuid() != AID_ROOT) {
|
||||||
|
fprintf(stderr, "error -- %s must run as root\n", argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr, "No command specified.\n");
|
||||||
|
android::show_help(argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strcmp(argv[1], "restore")) {
|
||||||
|
restore = 1;
|
||||||
|
} else if (0 == strcmp(argv[1], "help")) {
|
||||||
|
android::show_help(argv[0]);
|
||||||
|
exit(0);
|
||||||
|
} else if (0 != strcmp(argv[1], "backup")) {
|
||||||
|
fprintf(stderr, "Unknown command: %s\n", argv[1]);
|
||||||
|
android::show_help(argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
android::opt_backupAll = 0;
|
||||||
|
|
||||||
|
optind = 2;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = getopt(argc, argv, "ah");
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(ret) {
|
||||||
|
case 'a':
|
||||||
|
android::opt_backupAll = 1;
|
||||||
|
if (restore) fprintf(stderr, "Warning: -a option ignored on restore\n");
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
android::show_help(argv[0]);
|
||||||
|
exit(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr,"Unrecognized Option\n");
|
||||||
|
android::show_help(argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* backupFile = "/sdcard/backup.dat";
|
||||||
|
|
||||||
|
if (argc > optind) {
|
||||||
|
backupFile = argv[optind];
|
||||||
|
optind++;
|
||||||
|
if (argc != optind) {
|
||||||
|
fprintf(stderr, "Too many arguments\n");
|
||||||
|
android::show_help(argv[0]);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Stopping system...\n");
|
||||||
|
property_set("ctl.stop", "runtime");
|
||||||
|
property_set("ctl.stop", "zygote");
|
||||||
|
sleep(1);
|
||||||
|
|
||||||
|
int res;
|
||||||
|
if (restore) {
|
||||||
|
res = android::restore_data(backupFile);
|
||||||
|
if (res != 0) {
|
||||||
|
// Don't restart system, since the data partition is hosed.
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
printf("Restore complete! Restarting system, cross your fingers...\n");
|
||||||
|
} else {
|
||||||
|
res = android::backup_data(backupFile);
|
||||||
|
if (res == 0) {
|
||||||
|
printf("Backup complete! Restarting system...\n");
|
||||||
|
} else {
|
||||||
|
printf("Restarting system...\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
property_set("ctl.start", "zygote");
|
||||||
|
property_set("ctl.start", "runtime");
|
||||||
|
}
|
26
cmds/screencap/Android.mk
Normal file
26
cmds/screencap/Android.mk
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES:= \
|
||||||
|
screencap.cpp
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
|
libcutils \
|
||||||
|
libutils \
|
||||||
|
libbinder \
|
||||||
|
libskia \
|
||||||
|
libui \
|
||||||
|
libgui
|
||||||
|
|
||||||
|
LOCAL_MODULE:= screencap
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES += \
|
||||||
|
external/skia/include/core \
|
||||||
|
external/skia/include/effects \
|
||||||
|
external/skia/include/images \
|
||||||
|
external/skia/src/ports \
|
||||||
|
external/skia/include/utils
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
195
cmds/screencap/screencap.cpp
Normal file
195
cmds/screencap/screencap.cpp
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <linux/fb.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <binder/IMemory.h>
|
||||||
|
#include <gui/SurfaceComposerClient.h>
|
||||||
|
#include <gui/ISurfaceComposer.h>
|
||||||
|
|
||||||
|
#include <SkImageEncoder.h>
|
||||||
|
#include <SkBitmap.h>
|
||||||
|
#include <SkData.h>
|
||||||
|
#include <SkStream.h>
|
||||||
|
|
||||||
|
using namespace android;
|
||||||
|
|
||||||
|
static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
|
||||||
|
|
||||||
|
static void usage(const char* pname)
|
||||||
|
{
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage: %s [-hp] [-d display-id] [FILENAME]\n"
|
||||||
|
" -h: this message\n"
|
||||||
|
" -p: save the file as a png.\n"
|
||||||
|
" -d: specify the display id to capture, default %d.\n"
|
||||||
|
"If FILENAME ends with .png it will be saved as a png.\n"
|
||||||
|
"If FILENAME is not given, the results will be printed to stdout.\n",
|
||||||
|
pname, DEFAULT_DISPLAY_ID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SkBitmap::Config flinger2skia(PixelFormat f)
|
||||||
|
{
|
||||||
|
switch (f) {
|
||||||
|
case PIXEL_FORMAT_A_8:
|
||||||
|
return SkBitmap::kA8_Config;
|
||||||
|
case PIXEL_FORMAT_RGB_565:
|
||||||
|
return SkBitmap::kRGB_565_Config;
|
||||||
|
case PIXEL_FORMAT_RGBA_4444:
|
||||||
|
return SkBitmap::kARGB_4444_Config;
|
||||||
|
default:
|
||||||
|
return SkBitmap::kARGB_8888_Config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static status_t vinfoToPixelFormat(const fb_var_screeninfo& vinfo,
|
||||||
|
uint32_t* bytespp, uint32_t* f)
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (vinfo.bits_per_pixel) {
|
||||||
|
case 16:
|
||||||
|
*f = PIXEL_FORMAT_RGB_565;
|
||||||
|
*bytespp = 2;
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
*f = PIXEL_FORMAT_RGB_888;
|
||||||
|
*bytespp = 3;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
// TODO: do better decoding of vinfo here
|
||||||
|
*f = PIXEL_FORMAT_RGBX_8888;
|
||||||
|
*bytespp = 4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
const char* pname = argv[0];
|
||||||
|
bool png = false;
|
||||||
|
int32_t displayId = DEFAULT_DISPLAY_ID;
|
||||||
|
int c;
|
||||||
|
while ((c = getopt(argc, argv, "phd:")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 'p':
|
||||||
|
png = true;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
displayId = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
usage(pname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
int fd = -1;
|
||||||
|
if (argc == 0) {
|
||||||
|
fd = dup(STDOUT_FILENO);
|
||||||
|
} else if (argc == 1) {
|
||||||
|
const char* fn = argv[0];
|
||||||
|
fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
|
||||||
|
if (fd == -1) {
|
||||||
|
fprintf(stderr, "Error opening file: %s (%s)\n", fn, strerror(errno));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
const int len = strlen(fn);
|
||||||
|
if (len >= 4 && 0 == strcmp(fn+len-4, ".png")) {
|
||||||
|
png = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd == -1) {
|
||||||
|
usage(pname);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void const* mapbase = MAP_FAILED;
|
||||||
|
ssize_t mapsize = -1;
|
||||||
|
|
||||||
|
void const* base = 0;
|
||||||
|
uint32_t w, h, f;
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
ScreenshotClient screenshot;
|
||||||
|
sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
|
||||||
|
if (display != NULL && screenshot.update(display) == NO_ERROR) {
|
||||||
|
base = screenshot.getPixels();
|
||||||
|
w = screenshot.getWidth();
|
||||||
|
h = screenshot.getHeight();
|
||||||
|
f = screenshot.getFormat();
|
||||||
|
size = screenshot.getSize();
|
||||||
|
} else {
|
||||||
|
const char* fbpath = "/dev/graphics/fb0";
|
||||||
|
int fb = open(fbpath, O_RDONLY);
|
||||||
|
if (fb >= 0) {
|
||||||
|
struct fb_var_screeninfo vinfo;
|
||||||
|
if (ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) == 0) {
|
||||||
|
uint32_t bytespp;
|
||||||
|
if (vinfoToPixelFormat(vinfo, &bytespp, &f) == NO_ERROR) {
|
||||||
|
size_t offset = (vinfo.xoffset + vinfo.yoffset*vinfo.xres) * bytespp;
|
||||||
|
w = vinfo.xres;
|
||||||
|
h = vinfo.yres;
|
||||||
|
size = w*h*bytespp;
|
||||||
|
mapsize = offset + size;
|
||||||
|
mapbase = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, fb, 0);
|
||||||
|
if (mapbase != MAP_FAILED) {
|
||||||
|
base = (void const *)((char const *)mapbase + offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (base) {
|
||||||
|
if (png) {
|
||||||
|
SkBitmap b;
|
||||||
|
b.setConfig(flinger2skia(f), w, h);
|
||||||
|
b.setPixels((void*)base);
|
||||||
|
SkDynamicMemoryWStream stream;
|
||||||
|
SkImageEncoder::EncodeStream(&stream, b,
|
||||||
|
SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
|
||||||
|
SkData* streamData = stream.copyToData();
|
||||||
|
write(fd, streamData->data(), streamData->size());
|
||||||
|
streamData->unref();
|
||||||
|
} else {
|
||||||
|
write(fd, &w, 4);
|
||||||
|
write(fd, &h, 4);
|
||||||
|
write(fd, &f, 4);
|
||||||
|
write(fd, base, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
if (mapbase != MAP_FAILED) {
|
||||||
|
munmap((void *)mapbase, mapsize);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
12
cmds/screenshot/Android.mk
Normal file
12
cmds/screenshot/Android.mk
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := screenshot.c
|
||||||
|
|
||||||
|
LOCAL_MODULE := screenshot
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := libcutils libz
|
||||||
|
LOCAL_STATIC_LIBRARIES := libpng
|
||||||
|
LOCAL_C_INCLUDES += external/zlib
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
171
cmds/screenshot/screenshot.c
Normal file
171
cmds/screenshot/screenshot.c
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <linux/fb.h>
|
||||||
|
|
||||||
|
#include <zlib.h>
|
||||||
|
#include <libpng/png.h>
|
||||||
|
|
||||||
|
#include "private/android_filesystem_config.h"
|
||||||
|
|
||||||
|
#define LOG_TAG "screenshot"
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
void take_screenshot(FILE *fb_in, FILE *fb_out) {
|
||||||
|
int fb;
|
||||||
|
char imgbuf[0x10000];
|
||||||
|
struct fb_var_screeninfo vinfo;
|
||||||
|
png_structp png;
|
||||||
|
png_infop info;
|
||||||
|
unsigned int r,c,rowlen;
|
||||||
|
unsigned int bytespp,offset;
|
||||||
|
|
||||||
|
fb = fileno(fb_in);
|
||||||
|
if(fb < 0) {
|
||||||
|
ALOGE("failed to open framebuffer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fb_in = fdopen(fb, "r");
|
||||||
|
|
||||||
|
if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) {
|
||||||
|
ALOGE("failed to get framebuffer info\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fcntl(fb, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
|
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (png == NULL) {
|
||||||
|
ALOGE("failed png_create_write_struct\n");
|
||||||
|
fclose(fb_in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init_io(png, fb_out);
|
||||||
|
info = png_create_info_struct(png);
|
||||||
|
if (info == NULL) {
|
||||||
|
ALOGE("failed png_create_info_struct\n");
|
||||||
|
png_destroy_write_struct(&png, NULL);
|
||||||
|
fclose(fb_in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (setjmp(png_jmpbuf(png))) {
|
||||||
|
ALOGE("failed png setjmp\n");
|
||||||
|
png_destroy_write_struct(&png, NULL);
|
||||||
|
fclose(fb_in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytespp = vinfo.bits_per_pixel / 8;
|
||||||
|
png_set_IHDR(png, info,
|
||||||
|
vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4,
|
||||||
|
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
|
||||||
|
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||||
|
png_write_info(png, info);
|
||||||
|
|
||||||
|
rowlen=vinfo.xres * bytespp;
|
||||||
|
if (rowlen > sizeof(imgbuf)) {
|
||||||
|
ALOGE("crazy rowlen: %d\n", rowlen);
|
||||||
|
png_destroy_write_struct(&png, NULL);
|
||||||
|
fclose(fb_in);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp;
|
||||||
|
fseek(fb_in, offset, SEEK_SET);
|
||||||
|
|
||||||
|
for(r=0; r<vinfo.yres; r++) {
|
||||||
|
int len = fread(imgbuf, 1, rowlen, fb_in);
|
||||||
|
if (len <= 0) break;
|
||||||
|
png_write_row(png, (png_bytep)imgbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
png_write_end(png, info);
|
||||||
|
fclose(fb_in);
|
||||||
|
png_destroy_write_struct(&png, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fork_sound(const char* path) {
|
||||||
|
pid_t pid = fork();
|
||||||
|
if (pid == 0) {
|
||||||
|
execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void usage() {
|
||||||
|
fprintf(stderr,
|
||||||
|
"usage: screenshot [-s soundfile] filename.png\n"
|
||||||
|
" -s: play a sound effect to signal success\n"
|
||||||
|
" -i: autoincrement to avoid overwriting filename.png\n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char**argv) {
|
||||||
|
FILE *png = NULL;
|
||||||
|
FILE *fb_in = NULL;
|
||||||
|
char outfile[PATH_MAX] = "";
|
||||||
|
|
||||||
|
char * soundfile = NULL;
|
||||||
|
int do_increment = 0;
|
||||||
|
|
||||||
|
int c;
|
||||||
|
while ((c = getopt(argc, argv, "s:i")) != -1) {
|
||||||
|
switch (c) {
|
||||||
|
case 's': soundfile = optarg; break;
|
||||||
|
case 'i': do_increment = 1; break;
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
usage(); exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc -= optind;
|
||||||
|
argv += optind;
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
usage(); exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(outfile, argv[0], PATH_MAX);
|
||||||
|
if (do_increment) {
|
||||||
|
struct stat st;
|
||||||
|
char base[PATH_MAX] = "";
|
||||||
|
int i = 0;
|
||||||
|
while (stat(outfile, &st) == 0) {
|
||||||
|
if (!base[0]) {
|
||||||
|
char *p = strrchr(outfile, '.');
|
||||||
|
if (p) *p = '\0';
|
||||||
|
strcpy(base, outfile);
|
||||||
|
}
|
||||||
|
snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fb_in = fopen("/dev/graphics/fb0", "r");
|
||||||
|
if (!fb_in) {
|
||||||
|
fprintf(stderr, "error: could not read framebuffer\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* switch to non-root user and group */
|
||||||
|
gid_t groups[] = { AID_LOG, AID_SDCARD_RW };
|
||||||
|
setgroups(sizeof(groups)/sizeof(groups[0]), groups);
|
||||||
|
setuid(AID_SHELL);
|
||||||
|
|
||||||
|
png = fopen(outfile, "w");
|
||||||
|
if (!png) {
|
||||||
|
fprintf(stderr, "error: writing file %s: %s\n",
|
||||||
|
outfile, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
take_screenshot(fb_in, png);
|
||||||
|
|
||||||
|
if (soundfile) {
|
||||||
|
fork_sound(soundfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
16
cmds/service/Android.mk
Normal file
16
cmds/service/Android.mk
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES:= \
|
||||||
|
service.cpp
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := libutils libbinder
|
||||||
|
|
||||||
|
ifeq ($(TARGET_OS),linux)
|
||||||
|
LOCAL_CFLAGS += -DXP_UNIX
|
||||||
|
#LOCAL_SHARED_LIBRARIES += librt
|
||||||
|
endif
|
||||||
|
|
||||||
|
LOCAL_MODULE:= service
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
0
cmds/service/MODULE_LICENSE_APACHE2
Normal file
0
cmds/service/MODULE_LICENSE_APACHE2
Normal file
190
cmds/service/NOTICE
Normal file
190
cmds/service/NOTICE
Normal file
@ -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
|
||||||
|
|
275
cmds/service/service.cpp
Normal file
275
cmds/service/service.cpp
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
/*
|
||||||
|
* Command line access to services.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <binder/Parcel.h>
|
||||||
|
#include <binder/ProcessState.h>
|
||||||
|
#include <binder/IServiceManager.h>
|
||||||
|
#include <utils/TextOutput.h>
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
|
||||||
|
using namespace android;
|
||||||
|
|
||||||
|
void writeString16(Parcel& parcel, const char* string)
|
||||||
|
{
|
||||||
|
if (string != NULL)
|
||||||
|
{
|
||||||
|
parcel.writeString16(String16(string));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parcel.writeInt32(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the name of the generic interface we hold a reference to
|
||||||
|
static String16 get_interface_name(sp<IBinder> service)
|
||||||
|
{
|
||||||
|
if (service != NULL) {
|
||||||
|
Parcel data, reply;
|
||||||
|
status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
|
||||||
|
if (err == NO_ERROR) {
|
||||||
|
return reply.readString16();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return String16();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String8 good_old_string(const String16& src)
|
||||||
|
{
|
||||||
|
String8 name8;
|
||||||
|
char ch8[2];
|
||||||
|
ch8[1] = 0;
|
||||||
|
for (unsigned j = 0; j < src.size(); j++) {
|
||||||
|
char16_t ch = src[j];
|
||||||
|
if (ch < 128) ch8[0] = (char)ch;
|
||||||
|
name8.append(ch8);
|
||||||
|
}
|
||||||
|
return name8;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* const argv[])
|
||||||
|
{
|
||||||
|
sp<IServiceManager> sm = defaultServiceManager();
|
||||||
|
fflush(stdout);
|
||||||
|
if (sm == NULL) {
|
||||||
|
aerr << "service: Unable to get default service manager!" << endl;
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wantsUsage = false;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
int ic = getopt(argc, argv, "h?");
|
||||||
|
if (ic < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (ic) {
|
||||||
|
case 'h':
|
||||||
|
case '?':
|
||||||
|
wantsUsage = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
aerr << "service: Unknown option -" << ic << endl;
|
||||||
|
wantsUsage = true;
|
||||||
|
result = 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind >= argc) {
|
||||||
|
wantsUsage = true;
|
||||||
|
} else if (!wantsUsage) {
|
||||||
|
if (strcmp(argv[optind], "check") == 0) {
|
||||||
|
optind++;
|
||||||
|
if (optind < argc) {
|
||||||
|
sp<IBinder> service = sm->checkService(String16(argv[optind]));
|
||||||
|
aout << "Service " << argv[optind] <<
|
||||||
|
(service == NULL ? ": not found" : ": found") << endl;
|
||||||
|
} else {
|
||||||
|
aerr << "service: No service specified for check" << endl;
|
||||||
|
wantsUsage = true;
|
||||||
|
result = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strcmp(argv[optind], "list") == 0) {
|
||||||
|
Vector<String16> services = sm->listServices();
|
||||||
|
aout << "Found " << services.size() << " services:" << endl;
|
||||||
|
for (unsigned i = 0; i < services.size(); i++) {
|
||||||
|
String16 name = services[i];
|
||||||
|
sp<IBinder> service = sm->checkService(name);
|
||||||
|
aout << i
|
||||||
|
<< "\t" << good_old_string(name)
|
||||||
|
<< ": [" << good_old_string(get_interface_name(service)) << "]"
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
} else if (strcmp(argv[optind], "call") == 0) {
|
||||||
|
optind++;
|
||||||
|
if (optind+1 < argc) {
|
||||||
|
int serviceArg = optind;
|
||||||
|
sp<IBinder> service = sm->checkService(String16(argv[optind++]));
|
||||||
|
String16 ifName = get_interface_name(service);
|
||||||
|
int32_t code = atoi(argv[optind++]);
|
||||||
|
if (service != NULL && ifName.size() > 0) {
|
||||||
|
Parcel data, reply;
|
||||||
|
|
||||||
|
// the interface name is first
|
||||||
|
data.writeInterfaceToken(ifName);
|
||||||
|
|
||||||
|
// then the rest of the call arguments
|
||||||
|
while (optind < argc) {
|
||||||
|
if (strcmp(argv[optind], "i32") == 0) {
|
||||||
|
optind++;
|
||||||
|
if (optind >= argc) {
|
||||||
|
aerr << "service: no integer supplied for 'i32'" << endl;
|
||||||
|
wantsUsage = true;
|
||||||
|
result = 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data.writeInt32(atoi(argv[optind++]));
|
||||||
|
} else if (strcmp(argv[optind], "s16") == 0) {
|
||||||
|
optind++;
|
||||||
|
if (optind >= argc) {
|
||||||
|
aerr << "service: no string supplied for 's16'" << endl;
|
||||||
|
wantsUsage = true;
|
||||||
|
result = 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
data.writeString16(String16(argv[optind++]));
|
||||||
|
} else if (strcmp(argv[optind], "null") == 0) {
|
||||||
|
optind++;
|
||||||
|
data.writeStrongBinder(NULL);
|
||||||
|
} else if (strcmp(argv[optind], "intent") == 0) {
|
||||||
|
|
||||||
|
char* action = NULL;
|
||||||
|
char* dataArg = NULL;
|
||||||
|
char* type = NULL;
|
||||||
|
int launchFlags = 0;
|
||||||
|
char* component = NULL;
|
||||||
|
int categoryCount = 0;
|
||||||
|
char* categories[16];
|
||||||
|
|
||||||
|
char* context1 = NULL;
|
||||||
|
|
||||||
|
optind++;
|
||||||
|
|
||||||
|
while (optind < argc)
|
||||||
|
{
|
||||||
|
char* key = strtok_r(argv[optind], "=", &context1);
|
||||||
|
char* value = strtok_r(NULL, "=", &context1);
|
||||||
|
|
||||||
|
// we have reached the end of the XXX=XXX args.
|
||||||
|
if (key == NULL) break;
|
||||||
|
|
||||||
|
if (strcmp(key, "action") == 0)
|
||||||
|
{
|
||||||
|
action = value;
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "data") == 0)
|
||||||
|
{
|
||||||
|
dataArg = value;
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "type") == 0)
|
||||||
|
{
|
||||||
|
type = value;
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "launchFlags") == 0)
|
||||||
|
{
|
||||||
|
launchFlags = atoi(value);
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "component") == 0)
|
||||||
|
{
|
||||||
|
component = value;
|
||||||
|
}
|
||||||
|
else if (strcmp(key, "categories") == 0)
|
||||||
|
{
|
||||||
|
char* context2 = NULL;
|
||||||
|
int categoryCount = 0;
|
||||||
|
categories[categoryCount] = strtok_r(value, ",", &context2);
|
||||||
|
|
||||||
|
while (categories[categoryCount] != NULL)
|
||||||
|
{
|
||||||
|
categoryCount++;
|
||||||
|
categories[categoryCount] = strtok_r(NULL, ",", &context2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
optind++;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeString16(data, action);
|
||||||
|
writeString16(data, dataArg);
|
||||||
|
writeString16(data, type);
|
||||||
|
data.writeInt32(launchFlags);
|
||||||
|
writeString16(data, component);
|
||||||
|
|
||||||
|
if (categoryCount > 0)
|
||||||
|
{
|
||||||
|
data.writeInt32(categoryCount);
|
||||||
|
for (int i = 0 ; i < categoryCount ; i++)
|
||||||
|
{
|
||||||
|
writeString16(data, categories[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data.writeInt32(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// for now just set the extra field to be null.
|
||||||
|
data.writeInt32(-1);
|
||||||
|
} else {
|
||||||
|
aerr << "service: unknown option " << argv[optind] << endl;
|
||||||
|
wantsUsage = true;
|
||||||
|
result = 10;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
service->transact(code, data, &reply);
|
||||||
|
aout << "Result: " << reply << endl;
|
||||||
|
} else {
|
||||||
|
aerr << "service: Service " << argv[serviceArg]
|
||||||
|
<< " does not exist" << endl;
|
||||||
|
result = 10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (optind < argc) {
|
||||||
|
aerr << "service: No service specified for call" << endl;
|
||||||
|
} else {
|
||||||
|
aerr << "service: No code specified for call" << endl;
|
||||||
|
}
|
||||||
|
wantsUsage = true;
|
||||||
|
result = 10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
aerr << "service: Unknown command " << argv[optind] << endl;
|
||||||
|
wantsUsage = true;
|
||||||
|
result = 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wantsUsage) {
|
||||||
|
aout << "Usage: service [-h|-?]\n"
|
||||||
|
" service list\n"
|
||||||
|
" service check SERVICE\n"
|
||||||
|
" service call SERVICE CODE [i32 INT | s16 STR] ...\n"
|
||||||
|
"Options:\n"
|
||||||
|
" i32: Write the integer INT into the send parcel.\n"
|
||||||
|
" s16: Write the UTF-16 string STR into the send parcel.\n";
|
||||||
|
// " intent: Write and Intent int the send parcel. ARGS can be\n"
|
||||||
|
// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
12
cmds/servicemanager/Android.mk
Normal file
12
cmds/servicemanager/Android.mk
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
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)
|
103
cmds/servicemanager/bctest.c
Normal file
103
cmds/servicemanager/bctest.c
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/* Copyright 2008 The Android Open Source Project
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "binder.h"
|
||||||
|
|
||||||
|
void *svcmgr_lookup(struct binder_state *bs, void *target, const char *name)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
unsigned iodata[512/4];
|
||||||
|
struct binder_io msg, reply;
|
||||||
|
|
||||||
|
bio_init(&msg, iodata, sizeof(iodata), 4);
|
||||||
|
bio_put_uint32(&msg, 0); // strict mode header
|
||||||
|
bio_put_string16_x(&msg, SVC_MGR_NAME);
|
||||||
|
bio_put_string16_x(&msg, name);
|
||||||
|
|
||||||
|
if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ptr = bio_get_ref(&reply);
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
binder_acquire(bs, ptr);
|
||||||
|
|
||||||
|
binder_done(bs, &msg, &reply);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int svcmgr_publish(struct binder_state *bs, void *target, const char *name, void *ptr)
|
||||||
|
{
|
||||||
|
unsigned status;
|
||||||
|
unsigned iodata[512/4];
|
||||||
|
struct binder_io msg, reply;
|
||||||
|
|
||||||
|
bio_init(&msg, iodata, sizeof(iodata), 4);
|
||||||
|
bio_put_uint32(&msg, 0); // strict mode header
|
||||||
|
bio_put_string16_x(&msg, SVC_MGR_NAME);
|
||||||
|
bio_put_string16_x(&msg, name);
|
||||||
|
bio_put_obj(&msg, ptr);
|
||||||
|
|
||||||
|
if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
status = bio_get_uint32(&reply);
|
||||||
|
|
||||||
|
binder_done(bs, &msg, &reply);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned token;
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
struct binder_state *bs;
|
||||||
|
void *svcmgr = BINDER_SERVICE_MANAGER;
|
||||||
|
|
||||||
|
bs = binder_open(128*1024);
|
||||||
|
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
while (argc > 0) {
|
||||||
|
if (!strcmp(argv[0],"alt")) {
|
||||||
|
void *ptr = svcmgr_lookup(bs, svcmgr, "alt_svc_mgr");
|
||||||
|
if (!ptr) {
|
||||||
|
fprintf(stderr,"cannot find alt_svc_mgr\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
svcmgr = ptr;
|
||||||
|
fprintf(stderr,"svcmgr is via %p\n", ptr);
|
||||||
|
} else if (!strcmp(argv[0],"lookup")) {
|
||||||
|
void *ptr;
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr,"argument required\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ptr = svcmgr_lookup(bs, svcmgr, argv[1]);
|
||||||
|
fprintf(stderr,"lookup(%s) = %p\n", argv[1], ptr);
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
} else if (!strcmp(argv[0],"publish")) {
|
||||||
|
if (argc < 2) {
|
||||||
|
fprintf(stderr,"argument required\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
svcmgr_publish(bs, svcmgr, argv[1], &token);
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr,"unknown command %s\n", argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
616
cmds/servicemanager/binder.c
Normal file
616
cmds/servicemanager/binder.c
Normal file
@ -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)) {
|
||||||
|
ALOGE("parse: txn too small!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
binder_dump_txn(txn);
|
||||||
|
if (func) {
|
||||||
|
unsigned rdata[256/4];
|
||||||
|
struct binder_io msg;
|
||||||
|
struct binder_io reply;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
bio_init(&reply, rdata, sizeof(rdata), 4);
|
||||||
|
bio_init_from_txn(&msg, txn);
|
||||||
|
res = func(bs, txn, &msg, &reply);
|
||||||
|
binder_send_reply(bs, &reply, txn->data, res);
|
||||||
|
}
|
||||||
|
ptr += sizeof(*txn) / sizeof(uint32_t);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BR_REPLY: {
|
||||||
|
struct binder_txn *txn = (void*) ptr;
|
||||||
|
if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {
|
||||||
|
ALOGE("parse: reply too small!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
binder_dump_txn(txn);
|
||||||
|
if (bio) {
|
||||||
|
bio_init_from_txn(bio, txn);
|
||||||
|
bio = 0;
|
||||||
|
} else {
|
||||||
|
/* todo FREE BUFFER */
|
||||||
|
}
|
||||||
|
ptr += (sizeof(*txn) / sizeof(uint32_t));
|
||||||
|
r = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BR_DEAD_BINDER: {
|
||||||
|
struct binder_death *death = (void*) *ptr++;
|
||||||
|
death->func(bs, death->ptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BR_FAILED_REPLY:
|
||||||
|
r = -1;
|
||||||
|
break;
|
||||||
|
case BR_DEAD_REPLY:
|
||||||
|
r = -1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ALOGE("parse: OOPS %d\n", cmd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void binder_acquire(struct binder_state *bs, void *ptr)
|
||||||
|
{
|
||||||
|
uint32_t cmd[2];
|
||||||
|
cmd[0] = BC_ACQUIRE;
|
||||||
|
cmd[1] = (uint32_t) ptr;
|
||||||
|
binder_write(bs, cmd, sizeof(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
void binder_release(struct binder_state *bs, void *ptr)
|
||||||
|
{
|
||||||
|
uint32_t cmd[2];
|
||||||
|
cmd[0] = BC_RELEASE;
|
||||||
|
cmd[1] = (uint32_t) ptr;
|
||||||
|
binder_write(bs, cmd, sizeof(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
void binder_link_to_death(struct binder_state *bs, void *ptr, struct binder_death *death)
|
||||||
|
{
|
||||||
|
uint32_t cmd[3];
|
||||||
|
cmd[0] = BC_REQUEST_DEATH_NOTIFICATION;
|
||||||
|
cmd[1] = (uint32_t) ptr;
|
||||||
|
cmd[2] = (uint32_t) death;
|
||||||
|
binder_write(bs, cmd, sizeof(cmd));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int binder_call(struct binder_state *bs,
|
||||||
|
struct binder_io *msg, struct binder_io *reply,
|
||||||
|
void *target, uint32_t code)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct binder_write_read bwr;
|
||||||
|
struct {
|
||||||
|
uint32_t cmd;
|
||||||
|
struct binder_txn txn;
|
||||||
|
} writebuf;
|
||||||
|
unsigned readbuf[32];
|
||||||
|
|
||||||
|
if (msg->flags & BIO_F_OVERFLOW) {
|
||||||
|
fprintf(stderr,"binder: txn buffer overflow\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
writebuf.cmd = BC_TRANSACTION;
|
||||||
|
writebuf.txn.target = target;
|
||||||
|
writebuf.txn.code = code;
|
||||||
|
writebuf.txn.flags = 0;
|
||||||
|
writebuf.txn.data_size = msg->data - msg->data0;
|
||||||
|
writebuf.txn.offs_size = ((char*) msg->offs) - ((char*) msg->offs0);
|
||||||
|
writebuf.txn.data = msg->data0;
|
||||||
|
writebuf.txn.offs = msg->offs0;
|
||||||
|
|
||||||
|
bwr.write_size = sizeof(writebuf);
|
||||||
|
bwr.write_consumed = 0;
|
||||||
|
bwr.write_buffer = (unsigned) &writebuf;
|
||||||
|
|
||||||
|
hexdump(msg->data0, msg->data - msg->data0);
|
||||||
|
for (;;) {
|
||||||
|
bwr.read_size = sizeof(readbuf);
|
||||||
|
bwr.read_consumed = 0;
|
||||||
|
bwr.read_buffer = (unsigned) readbuf;
|
||||||
|
|
||||||
|
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = binder_parse(bs, reply, readbuf, bwr.read_consumed, 0);
|
||||||
|
if (res == 0) return 0;
|
||||||
|
if (res < 0) goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
memset(reply, 0, sizeof(*reply));
|
||||||
|
reply->flags |= BIO_F_IOERROR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void binder_loop(struct binder_state *bs, binder_handler func)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
struct binder_write_read bwr;
|
||||||
|
unsigned readbuf[32];
|
||||||
|
|
||||||
|
bwr.write_size = 0;
|
||||||
|
bwr.write_consumed = 0;
|
||||||
|
bwr.write_buffer = 0;
|
||||||
|
|
||||||
|
readbuf[0] = BC_ENTER_LOOPER;
|
||||||
|
binder_write(bs, readbuf, sizeof(unsigned));
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
bwr.read_size = sizeof(readbuf);
|
||||||
|
bwr.read_consumed = 0;
|
||||||
|
bwr.read_buffer = (unsigned) readbuf;
|
||||||
|
|
||||||
|
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
|
||||||
|
if (res == 0) {
|
||||||
|
ALOGE("binder_loop: unexpected reply?!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (res < 0) {
|
||||||
|
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bio_init_from_txn(struct binder_io *bio, struct binder_txn *txn)
|
||||||
|
{
|
||||||
|
bio->data = bio->data0 = txn->data;
|
||||||
|
bio->offs = bio->offs0 = txn->offs;
|
||||||
|
bio->data_avail = txn->data_size;
|
||||||
|
bio->offs_avail = txn->offs_size / 4;
|
||||||
|
bio->flags = BIO_F_SHARED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bio_init(struct binder_io *bio, void *data,
|
||||||
|
uint32_t maxdata, uint32_t maxoffs)
|
||||||
|
{
|
||||||
|
uint32_t n = maxoffs * sizeof(uint32_t);
|
||||||
|
|
||||||
|
if (n > maxdata) {
|
||||||
|
bio->flags = BIO_F_OVERFLOW;
|
||||||
|
bio->data_avail = 0;
|
||||||
|
bio->offs_avail = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bio->data = bio->data0 = (char *) data + n;
|
||||||
|
bio->offs = bio->offs0 = data;
|
||||||
|
bio->data_avail = maxdata - n;
|
||||||
|
bio->offs_avail = maxoffs;
|
||||||
|
bio->flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *bio_alloc(struct binder_io *bio, uint32_t size)
|
||||||
|
{
|
||||||
|
size = (size + 3) & (~3);
|
||||||
|
if (size > bio->data_avail) {
|
||||||
|
bio->flags |= BIO_F_OVERFLOW;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
void *ptr = bio->data;
|
||||||
|
bio->data += size;
|
||||||
|
bio->data_avail -= size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void binder_done(struct binder_state *bs,
|
||||||
|
struct binder_io *msg,
|
||||||
|
struct binder_io *reply)
|
||||||
|
{
|
||||||
|
if (reply->flags & BIO_F_SHARED) {
|
||||||
|
uint32_t cmd[2];
|
||||||
|
cmd[0] = BC_FREE_BUFFER;
|
||||||
|
cmd[1] = (uint32_t) reply->data0;
|
||||||
|
binder_write(bs, cmd, sizeof(cmd));
|
||||||
|
reply->flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct binder_object *bio_alloc_obj(struct binder_io *bio)
|
||||||
|
{
|
||||||
|
struct binder_object *obj;
|
||||||
|
|
||||||
|
obj = bio_alloc(bio, sizeof(*obj));
|
||||||
|
|
||||||
|
if (obj && bio->offs_avail) {
|
||||||
|
bio->offs_avail--;
|
||||||
|
*bio->offs++ = ((char*) obj) - ((char*) bio->data0);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
bio->flags |= BIO_F_OVERFLOW;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bio_put_uint32(struct binder_io *bio, uint32_t n)
|
||||||
|
{
|
||||||
|
uint32_t *ptr = bio_alloc(bio, sizeof(n));
|
||||||
|
if (ptr)
|
||||||
|
*ptr = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bio_put_obj(struct binder_io *bio, void *ptr)
|
||||||
|
{
|
||||||
|
struct binder_object *obj;
|
||||||
|
|
||||||
|
obj = bio_alloc_obj(bio);
|
||||||
|
if (!obj)
|
||||||
|
return;
|
||||||
|
|
||||||
|
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||||
|
obj->type = BINDER_TYPE_BINDER;
|
||||||
|
obj->pointer = ptr;
|
||||||
|
obj->cookie = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bio_put_ref(struct binder_io *bio, void *ptr)
|
||||||
|
{
|
||||||
|
struct binder_object *obj;
|
||||||
|
|
||||||
|
if (ptr)
|
||||||
|
obj = bio_alloc_obj(bio);
|
||||||
|
else
|
||||||
|
obj = bio_alloc(bio, sizeof(*obj));
|
||||||
|
|
||||||
|
if (!obj)
|
||||||
|
return;
|
||||||
|
|
||||||
|
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
|
||||||
|
obj->type = BINDER_TYPE_HANDLE;
|
||||||
|
obj->pointer = ptr;
|
||||||
|
obj->cookie = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bio_put_string16(struct binder_io *bio, const uint16_t *str)
|
||||||
|
{
|
||||||
|
uint32_t len;
|
||||||
|
uint16_t *ptr;
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
bio_put_uint32(bio, 0xffffffff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
while (str[len]) len++;
|
||||||
|
|
||||||
|
if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) {
|
||||||
|
bio_put_uint32(bio, 0xffffffff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bio_put_uint32(bio, len);
|
||||||
|
len = (len + 1) * sizeof(uint16_t);
|
||||||
|
ptr = bio_alloc(bio, len);
|
||||||
|
if (ptr)
|
||||||
|
memcpy(ptr, str, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bio_put_string16_x(struct binder_io *bio, const char *_str)
|
||||||
|
{
|
||||||
|
unsigned char *str = (unsigned char*) _str;
|
||||||
|
uint32_t len;
|
||||||
|
uint16_t *ptr;
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
bio_put_uint32(bio, 0xffffffff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(_str);
|
||||||
|
|
||||||
|
if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) {
|
||||||
|
bio_put_uint32(bio, 0xffffffff);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bio_put_uint32(bio, len);
|
||||||
|
ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t));
|
||||||
|
if (!ptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (*str)
|
||||||
|
*ptr++ = *str++;
|
||||||
|
*ptr++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *bio_get(struct binder_io *bio, uint32_t size)
|
||||||
|
{
|
||||||
|
size = (size + 3) & (~3);
|
||||||
|
|
||||||
|
if (bio->data_avail < size){
|
||||||
|
bio->data_avail = 0;
|
||||||
|
bio->flags |= BIO_F_OVERFLOW;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
void *ptr = bio->data;
|
||||||
|
bio->data += size;
|
||||||
|
bio->data_avail -= size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bio_get_uint32(struct binder_io *bio)
|
||||||
|
{
|
||||||
|
uint32_t *ptr = bio_get(bio, sizeof(*ptr));
|
||||||
|
return ptr ? *ptr : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t *bio_get_string16(struct binder_io *bio, unsigned *sz)
|
||||||
|
{
|
||||||
|
unsigned len;
|
||||||
|
len = bio_get_uint32(bio);
|
||||||
|
if (sz)
|
||||||
|
*sz = len;
|
||||||
|
return bio_get(bio, (len + 1) * sizeof(uint16_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct binder_object *_bio_get_obj(struct binder_io *bio)
|
||||||
|
{
|
||||||
|
unsigned n;
|
||||||
|
unsigned off = bio->data - bio->data0;
|
||||||
|
|
||||||
|
/* TODO: be smarter about this? */
|
||||||
|
for (n = 0; n < bio->offs_avail; n++) {
|
||||||
|
if (bio->offs[n] == off)
|
||||||
|
return bio_get(bio, sizeof(struct binder_object));
|
||||||
|
}
|
||||||
|
|
||||||
|
bio->data_avail = 0;
|
||||||
|
bio->flags |= BIO_F_OVERFLOW;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *bio_get_ref(struct binder_io *bio)
|
||||||
|
{
|
||||||
|
struct binder_object *obj;
|
||||||
|
|
||||||
|
obj = _bio_get_obj(bio);
|
||||||
|
if (!obj)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (obj->type == BINDER_TYPE_HANDLE)
|
||||||
|
return obj->pointer;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
119
cmds/servicemanager/binder.h
Normal file
119
cmds/servicemanager/binder.h
Normal file
@ -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
|
285
cmds/servicemanager/service_manager.c
Normal file
285
cmds/servicemanager/service_manager.c
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
/* Copyright 2008 The Android Open Source Project
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <private/android_filesystem_config.h>
|
||||||
|
|
||||||
|
#include "binder.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#define ALOGI(x...) fprintf(stderr, "svcmgr: " x)
|
||||||
|
#define ALOGE(x...) fprintf(stderr, "svcmgr: " x)
|
||||||
|
#else
|
||||||
|
#define LOG_TAG "ServiceManager"
|
||||||
|
#include <cutils/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
* These should come from a config file or perhaps be
|
||||||
|
* based on some namespace rules of some sort (media
|
||||||
|
* uid can register media.*, etc)
|
||||||
|
*/
|
||||||
|
static struct {
|
||||||
|
unsigned uid;
|
||||||
|
const char *name;
|
||||||
|
} allowed[] = {
|
||||||
|
{ AID_MEDIA, "media.audio_flinger" },
|
||||||
|
{ AID_MEDIA, "media.player" },
|
||||||
|
{ AID_MEDIA, "media.camera" },
|
||||||
|
{ AID_MEDIA, "media.audio_policy" },
|
||||||
|
{ AID_DRM, "drm.drmManager" },
|
||||||
|
{ AID_NFC, "nfc" },
|
||||||
|
{ AID_BLUETOOTH, "bluetooth" },
|
||||||
|
{ AID_RADIO, "radio.phone" },
|
||||||
|
{ AID_RADIO, "radio.sms" },
|
||||||
|
{ AID_RADIO, "radio.phonesubinfo" },
|
||||||
|
{ AID_RADIO, "radio.simphonebook" },
|
||||||
|
/* TODO: remove after phone services are updated: */
|
||||||
|
{ AID_RADIO, "phone" },
|
||||||
|
{ AID_RADIO, "sip" },
|
||||||
|
{ AID_RADIO, "isms" },
|
||||||
|
{ AID_RADIO, "iphonesubinfo" },
|
||||||
|
{ AID_RADIO, "simphonebook" },
|
||||||
|
{ AID_MEDIA, "common_time.clock" },
|
||||||
|
{ AID_MEDIA, "common_time.config" },
|
||||||
|
};
|
||||||
|
|
||||||
|
void *svcmgr_handle;
|
||||||
|
|
||||||
|
const char *str8(uint16_t *x)
|
||||||
|
{
|
||||||
|
static char buf[128];
|
||||||
|
unsigned max = 127;
|
||||||
|
char *p = buf;
|
||||||
|
|
||||||
|
if (x) {
|
||||||
|
while (*x && max--) {
|
||||||
|
*p++ = *x++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p++ = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int str16eq(uint16_t *a, const char *b)
|
||||||
|
{
|
||||||
|
while (*a && *b)
|
||||||
|
if (*a++ != *b++) return 0;
|
||||||
|
if (*a || *b)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int svc_can_register(unsigned uid, uint16_t *name)
|
||||||
|
{
|
||||||
|
unsigned n;
|
||||||
|
|
||||||
|
if ((uid == 0) || (uid == AID_SYSTEM))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++)
|
||||||
|
if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct svcinfo
|
||||||
|
{
|
||||||
|
struct svcinfo *next;
|
||||||
|
void *ptr;
|
||||||
|
struct binder_death death;
|
||||||
|
int allow_isolated;
|
||||||
|
unsigned len;
|
||||||
|
uint16_t name[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct svcinfo *svclist = 0;
|
||||||
|
|
||||||
|
struct svcinfo *find_svc(uint16_t *s16, unsigned len)
|
||||||
|
{
|
||||||
|
struct svcinfo *si;
|
||||||
|
|
||||||
|
for (si = svclist; si; si = si->next) {
|
||||||
|
if ((len == si->len) &&
|
||||||
|
!memcmp(s16, si->name, len * sizeof(uint16_t))) {
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void svcinfo_death(struct binder_state *bs, void *ptr)
|
||||||
|
{
|
||||||
|
struct svcinfo *si = ptr;
|
||||||
|
ALOGI("service '%s' died\n", str8(si->name));
|
||||||
|
if (si->ptr) {
|
||||||
|
binder_release(bs, si->ptr);
|
||||||
|
si->ptr = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t svcmgr_id[] = {
|
||||||
|
'a','n','d','r','o','i','d','.','o','s','.',
|
||||||
|
'I','S','e','r','v','i','c','e','M','a','n','a','g','e','r'
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid)
|
||||||
|
{
|
||||||
|
struct svcinfo *si;
|
||||||
|
si = find_svc(s, len);
|
||||||
|
|
||||||
|
// ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
|
||||||
|
if (si && si->ptr) {
|
||||||
|
if (!si->allow_isolated) {
|
||||||
|
// If this service doesn't allow access from isolated processes,
|
||||||
|
// then check the uid to see if it is isolated.
|
||||||
|
unsigned appid = uid % AID_USER;
|
||||||
|
if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return si->ptr;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int do_add_service(struct binder_state *bs,
|
||||||
|
uint16_t *s, unsigned len,
|
||||||
|
void *ptr, unsigned uid, int allow_isolated)
|
||||||
|
{
|
||||||
|
struct svcinfo *si;
|
||||||
|
//ALOGI("add_service('%s',%p,%s) uid=%d\n", str8(s), ptr,
|
||||||
|
// allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
|
||||||
|
|
||||||
|
if (!ptr || (len == 0) || (len > 127))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (!svc_can_register(uid, s)) {
|
||||||
|
ALOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",
|
||||||
|
str8(s), ptr, uid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
si = find_svc(s, len);
|
||||||
|
if (si) {
|
||||||
|
if (si->ptr) {
|
||||||
|
ALOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
|
||||||
|
str8(s), ptr, uid);
|
||||||
|
svcinfo_death(bs, si);
|
||||||
|
}
|
||||||
|
si->ptr = ptr;
|
||||||
|
} else {
|
||||||
|
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
|
||||||
|
if (!si) {
|
||||||
|
ALOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",
|
||||||
|
str8(s), ptr, uid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
si->ptr = ptr;
|
||||||
|
si->len = len;
|
||||||
|
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
|
||||||
|
si->name[len] = '\0';
|
||||||
|
si->death.func = svcinfo_death;
|
||||||
|
si->death.ptr = si;
|
||||||
|
si->allow_isolated = allow_isolated;
|
||||||
|
si->next = svclist;
|
||||||
|
svclist = si;
|
||||||
|
}
|
||||||
|
|
||||||
|
binder_acquire(bs, ptr);
|
||||||
|
binder_link_to_death(bs, ptr, &si->death);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int svcmgr_handler(struct binder_state *bs,
|
||||||
|
struct binder_txn *txn,
|
||||||
|
struct binder_io *msg,
|
||||||
|
struct binder_io *reply)
|
||||||
|
{
|
||||||
|
struct svcinfo *si;
|
||||||
|
uint16_t *s;
|
||||||
|
unsigned len;
|
||||||
|
void *ptr;
|
||||||
|
uint32_t strict_policy;
|
||||||
|
int allow_isolated;
|
||||||
|
|
||||||
|
// ALOGI("target=%p code=%d pid=%d uid=%d\n",
|
||||||
|
// txn->target, txn->code, txn->sender_pid, txn->sender_euid);
|
||||||
|
|
||||||
|
if (txn->target != svcmgr_handle)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// Equivalent to Parcel::enforceInterface(), reading the RPC
|
||||||
|
// header with the strict mode policy mask and the interface name.
|
||||||
|
// Note that we ignore the strict_policy and don't propagate it
|
||||||
|
// further (since we do no outbound RPCs anyway).
|
||||||
|
strict_policy = bio_get_uint32(msg);
|
||||||
|
s = bio_get_string16(msg, &len);
|
||||||
|
if ((len != (sizeof(svcmgr_id) / 2)) ||
|
||||||
|
memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
|
||||||
|
fprintf(stderr,"invalid id %s\n", str8(s));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(txn->code) {
|
||||||
|
case SVC_MGR_GET_SERVICE:
|
||||||
|
case SVC_MGR_CHECK_SERVICE:
|
||||||
|
s = bio_get_string16(msg, &len);
|
||||||
|
ptr = do_find_service(bs, s, len, txn->sender_euid);
|
||||||
|
if (!ptr)
|
||||||
|
break;
|
||||||
|
bio_put_ref(reply, ptr);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case SVC_MGR_ADD_SERVICE:
|
||||||
|
s = bio_get_string16(msg, &len);
|
||||||
|
ptr = bio_get_ref(msg);
|
||||||
|
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
|
||||||
|
if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SVC_MGR_LIST_SERVICES: {
|
||||||
|
unsigned n = bio_get_uint32(msg);
|
||||||
|
|
||||||
|
si = svclist;
|
||||||
|
while ((n-- > 0) && si)
|
||||||
|
si = si->next;
|
||||||
|
if (si) {
|
||||||
|
bio_put_string16(reply, si->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
ALOGE("unknown code %d\n", txn->code);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bio_put_uint32(reply, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct binder_state *bs;
|
||||||
|
void *svcmgr = BINDER_SERVICE_MANAGER;
|
||||||
|
|
||||||
|
bs = binder_open(128*1024);
|
||||||
|
|
||||||
|
if (binder_become_context_manager(bs)) {
|
||||||
|
ALOGE("cannot become context manager (%s)\n", strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
svcmgr_handle = svcmgr;
|
||||||
|
binder_loop(bs, svcmgr_handler);
|
||||||
|
return 0;
|
||||||
|
}
|
20
cmds/system_server/Android.mk
Normal file
20
cmds/system_server/Android.mk
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES:= \
|
||||||
|
system_main.cpp
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
|
libutils \
|
||||||
|
libbinder \
|
||||||
|
libsystem_server
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES := \
|
||||||
|
$(JNI_H_INCLUDE)
|
||||||
|
|
||||||
|
LOCAL_MODULE:= system_server
|
||||||
|
|
||||||
|
include $(BUILD_EXECUTABLE)
|
||||||
|
|
||||||
|
include $(LOCAL_PATH)/library/Android.mk
|
||||||
|
|
0
cmds/system_server/MODULE_LICENSE_APACHE2
Normal file
0
cmds/system_server/MODULE_LICENSE_APACHE2
Normal file
190
cmds/system_server/NOTICE
Normal file
190
cmds/system_server/NOTICE
Normal file
@ -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
|
||||||
|
|
26
cmds/system_server/library/Android.mk
Normal file
26
cmds/system_server/library/Android.mk
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES:= \
|
||||||
|
system_init.cpp
|
||||||
|
|
||||||
|
base = $(LOCAL_PATH)/../../..
|
||||||
|
native = $(LOCAL_PATH)/../../../../native
|
||||||
|
|
||||||
|
LOCAL_C_INCLUDES := \
|
||||||
|
$(native)/services/sensorservice \
|
||||||
|
$(native)/services/surfaceflinger \
|
||||||
|
$(JNI_H_INCLUDE)
|
||||||
|
|
||||||
|
LOCAL_SHARED_LIBRARIES := \
|
||||||
|
libandroid_runtime \
|
||||||
|
libsensorservice \
|
||||||
|
libsurfaceflinger \
|
||||||
|
libinput \
|
||||||
|
libutils \
|
||||||
|
libbinder \
|
||||||
|
libcutils
|
||||||
|
|
||||||
|
LOCAL_MODULE:= libsystem_server
|
||||||
|
|
||||||
|
include $(BUILD_SHARED_LIBRARY)
|
105
cmds/system_server/library/system_init.cpp
Normal file
105
cmds/system_server/library/system_init.cpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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 <binder/IPCThreadState.h>
|
||||||
|
#include <binder/ProcessState.h>
|
||||||
|
#include <binder/IServiceManager.h>
|
||||||
|
#include <utils/TextOutput.h>
|
||||||
|
#include <utils/Log.h>
|
||||||
|
|
||||||
|
#include <SurfaceFlinger.h>
|
||||||
|
#include <SensorService.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)
|
||||||
|
{
|
||||||
|
ALOGI("Grim Reaper killing system_server...");
|
||||||
|
kill(getpid(), SIGKILL);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" status_t system_init()
|
||||||
|
{
|
||||||
|
ALOGI("Entered system_init()");
|
||||||
|
|
||||||
|
sp<ProcessState> proc(ProcessState::self());
|
||||||
|
|
||||||
|
sp<IServiceManager> sm = defaultServiceManager();
|
||||||
|
ALOGI("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();
|
||||||
|
}
|
||||||
|
|
||||||
|
property_get("system_init.startsensorservice", propBuf, "1");
|
||||||
|
if (strcmp(propBuf, "1") == 0) {
|
||||||
|
// Start the sensor service
|
||||||
|
SensorService::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.
|
||||||
|
ALOGI("System server: starting Android runtime.\n");
|
||||||
|
AndroidRuntime* runtime = AndroidRuntime::getRuntime();
|
||||||
|
|
||||||
|
ALOGI("System server: starting Android services.\n");
|
||||||
|
JNIEnv* env = runtime->getJNIEnv();
|
||||||
|
if (env == NULL) {
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
jclass clazz = env->FindClass("com/android/server/SystemServer");
|
||||||
|
if (clazz == NULL) {
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
|
||||||
|
if (methodId == NULL) {
|
||||||
|
return UNKNOWN_ERROR;
|
||||||
|
}
|
||||||
|
env->CallStaticVoidMethod(clazz, methodId);
|
||||||
|
|
||||||
|
ALOGI("System server: entering thread pool.\n");
|
||||||
|
ProcessState::self()->startThreadPool();
|
||||||
|
IPCThreadState::self()->joinThreadPool();
|
||||||
|
ALOGI("System server: exiting thread pool.\n");
|
||||||
|
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
56
cmds/system_server/system_main.cpp
Normal file
56
cmds/system_server/system_main.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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 <binder/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[])
|
||||||
|
{
|
||||||
|
ALOGI("System server is starting with pid=%d.\n", getpid());
|
||||||
|
|
||||||
|
blockSignals();
|
||||||
|
|
||||||
|
// You can trust me, honestly!
|
||||||
|
ALOGW("*** Current priority: %d\n", getpriority(PRIO_PROCESS, 0));
|
||||||
|
setpriority(PRIO_PROCESS, 0, -1);
|
||||||
|
|
||||||
|
system_init();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user