Move non-Java commands over from frameworks/base

Change-Id: I0571813c1cfcf66abd36eb9f178fc49b618e88a6
Signed-off-by: Mike Lockwood <lockwood@google.com>
This commit is contained in:
Mike Lockwood 2012-10-24 10:45:23 -07:00
parent ba0b9cca69
commit 94afecf4b6
37 changed files with 7505 additions and 0 deletions

View 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)

View File

190
cmds/app_process/NOTICE Normal file
View 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

View 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
View 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)

View 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
View 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

File diff suppressed because it is too large Load Diff

592
cmds/installd/installd.c Normal file
View 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
View 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);

View 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)) \
)

View 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

File diff suppressed because it is too large Load Diff

26
cmds/ip-up-vpn/Android.mk Normal file
View 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
View 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
View 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
View 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
View 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
View 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)

View 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;
}

View 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)

View 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
View 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)

View File

190
cmds/service/NOTICE Normal file
View 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
View 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;
}

View 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)

View 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;
}

View 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;
}

View 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

View 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;
}

View 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

190
cmds/system_server/NOTICE Normal file
View 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

View 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)

View 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;
}

View 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();
}