summaryrefslogtreecommitdiffstats
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java310
-rw-r--r--cmds/app_process/app_main.cpp29
-rw-r--r--cmds/appops/Android.mk16
-rw-r--r--cmds/appops/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/appops/NOTICE190
-rwxr-xr-xcmds/appops/appops5
-rw-r--r--cmds/appops/src/com/android/commands/appops/AppOpsCommand.java137
-rw-r--r--cmds/appwidget/Android.mk16
-rw-r--r--cmds/appwidget/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/appwidget/NOTICE190
-rwxr-xr-xcmds/appwidget/appwidget5
-rw-r--r--cmds/appwidget/src/com/android/commands/appwidget/AppWidget.java167
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java32
-rw-r--r--cmds/bootanimation/Android.mk9
-rw-r--r--cmds/bootanimation/AudioPlayer.cpp314
-rw-r--r--cmds/bootanimation/AudioPlayer.h47
-rw-r--r--cmds/bootanimation/BootAnimation.cpp145
-rw-r--r--cmds/bootanimation/BootAnimation.h7
-rw-r--r--cmds/bu/src/com/android/commands/bu/Backup.java21
-rw-r--r--cmds/content/src/com/android/commands/content/Content.java63
-rw-r--r--cmds/dpm/Android.mk15
-rw-r--r--cmds/dpm/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/dpm/NOTICE190
-rwxr-xr-xcmds/dpm/dpm6
-rw-r--r--cmds/dpm/src/com/android/commands/dpm/Dpm.java135
-rw-r--r--cmds/idmap/create.cpp2
-rw-r--r--cmds/idmap/idmap.cpp42
-rw-r--r--cmds/idmap/inspect.cpp299
-rw-r--r--cmds/idmap/scan.cpp3
-rw-r--r--cmds/media/src/com/android/commands/media/Media.java191
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java655
-rw-r--r--cmds/screencap/Android.mk7
-rw-r--r--cmds/screencap/screencap.cpp13
-rw-r--r--cmds/settings/src/com/android/commands/settings/SettingsCmd.java34
-rw-r--r--cmds/svc/src/com/android/commands/svc/DataCommand.java15
-rw-r--r--cmds/svc/src/com/android/commands/svc/WifiCommand.java15
36 files changed, 2741 insertions, 584 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index ffe7ac9..ba11a81 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -19,29 +19,44 @@
package com.android.commands.am;
import android.app.ActivityManager;
-import android.app.ActivityManager.StackBoxInfo;
+import android.app.ActivityManager.StackInfo;
import android.app.ActivityManagerNative;
+import android.app.IActivityContainer;
import android.app.IActivityController;
import android.app.IActivityManager;
import android.app.IInstrumentationWatcher;
import android.app.Instrumentation;
+import android.app.ProfilerInfo;
import android.app.UiAutomationConnection;
+import android.app.usage.ConfigurationStats;
+import android.app.usage.IUsageStatsManager;
+import android.app.usage.UsageStatsManager;
import android.content.ComponentName;
+import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.pm.IPackageManager;
+import android.content.pm.ParceledListSlice;
import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
+import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.AndroidException;
+import android.util.ArrayMap;
import android.view.IWindowManager;
+import android.view.View;
+
import com.android.internal.os.BaseCommand;
import dalvik.system.VMRuntime;
@@ -53,6 +68,9 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
@@ -69,6 +87,8 @@ public class Am extends BaseCommand {
private String mReceiverPermission;
private String mProfileFile;
+ private int mSamplingInterval;
+ private boolean mAutoStop;
/**
* Command-line entry point.
@@ -84,7 +104,7 @@ public class Am extends BaseCommand {
out.println(
"usage: am [subcommand] [options]\n" +
"usage: am start [-D] [-W] [-P <FILE>] [--start-profiler <FILE>]\n" +
- " [--R COUNT] [-S] [--opengl-trace]\n" +
+ " [--sampling INTERVAL] [-R COUNT] [-S] [--opengl-trace]\n" +
" [--user <USER_ID> | current] <INTENT>\n" +
" am startservice [--user <USER_ID> | current] <INTENT>\n" +
" am stopservice [--user <USER_ID> | current] <INTENT>\n" +
@@ -94,11 +114,7 @@ public class Am extends BaseCommand {
" am broadcast [--user <USER_ID> | all | current] <INTENT>\n" +
" am instrument [-r] [-e <NAME> <VALUE>] [-p <FILE>] [-w]\n" +
" [--user <USER_ID> | current]\n" +
- " [--no-window-animation]\n" +
- " [--abi <ABI>]\n : Launch the instrumented process with the " +
- " selected ABI. This assumes that the process supports the" +
- " selected ABI." +
- " <COMPONENT>\n" +
+ " [--no-window-animation] [--abi <ABI>] <COMPONENT>\n" +
" am profile start [--user <USER_ID> current] <PROCESS> <FILE>\n" +
" am profile stop [--user <USER_ID> current] [<PROCESS>]\n" +
" am dumpheap [--user <USER_ID> current] [-n] <PROCESS> <FILE>\n" +
@@ -112,17 +128,23 @@ public class Am extends BaseCommand {
" am to-uri [INTENT]\n" +
" am to-intent-uri [INTENT]\n" +
" am switch-user <USER_ID>\n" +
+ " am start-user <USER_ID>\n" +
" am stop-user <USER_ID>\n" +
- " am stack create <TASK_ID> <RELATIVE_STACK_BOX_ID> <POSITION> <WEIGHT>\n" +
+ " am stack start <DISPLAY_ID> <INTENT>\n" +
" am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
- " am stack resize <STACK_ID> <WEIGHT>\n" +
- " am stack boxes\n" +
- " am stack box <STACK_BOX_ID>\n" +
+ " am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+ " am stack list\n" +
+ " am stack info <STACK_ID>\n" +
+ " am lock-task <TASK_ID>\n" +
+ " am lock-task stop\n" +
+ " am get-config\n" +
"\n" +
"am start: start an Activity. Options are:\n" +
" -D: enable debugging\n" +
" -W: wait for launch to complete\n" +
" --start-profiler <FILE>: start profiler and send results to <FILE>\n" +
+ " --sampling INTERVAL: use sample profiling with INTERVAL microseconds\n" +
+ " between samples (use with --start-profiler)\n" +
" -P <FILE>: like above, but profiling stops when app goes idle\n" +
" -R: repeat the activity launch <COUNT> times. Prior to each repeat,\n" +
" the top activity will be finished.\n" +
@@ -168,6 +190,8 @@ public class Am extends BaseCommand {
" --user <USER_ID> | current: Specify user instrumentation runs in;\n" +
" current user if not specified.\n" +
" --no-window-animation: turn off window animations while running.\n" +
+ " --abi <ABI>: Launch the instrumented process with the selected ABI.\n" +
+ " This assumes that the process supports the selected ABI.\n" +
"\n" +
"am profile: start and stop profiler on a process. The given <PROCESS> argument\n" +
" may be either a process name or pid. Options are:\n" +
@@ -208,27 +232,27 @@ public class Am extends BaseCommand {
"am switch-user: switch to put USER_ID in the foreground, starting\n" +
" execution of that user if it is currently stopped.\n" +
"\n" +
+ "am start-user: start USER_ID in background if it is currently stopped,\n" +
+ " use switch-user if you want to start the user in foreground.\n" +
+ "\n" +
"am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
- " code until a later explicit switch to it.\n" +
+ " code until a later explicit start or switch to it.\n" +
"\n" +
- "am stack create: create a new stack relative to an existing one.\n" +
- " <TASK_ID>: the task to populate the new stack with. Must exist.\n" +
- " <RELATIVE_STACK_BOX_ID>: existing stack box's id.\n" +
- " <POSITION>: 0: before <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
- " 1: after <RELATIVE_STACK_BOX_ID>, per RTL/LTR configuration,\n" +
- " 2: to left of <RELATIVE_STACK_BOX_ID>,\n" +
- " 3: to right of <RELATIVE_STACK_BOX_ID>," +
- " 4: above <RELATIVE_STACK_BOX_ID>, 5: below <RELATIVE_STACK_BOX_ID>\n" +
- " <WEIGHT>: float between 0.2 and 0.8 inclusive.\n" +
+ "am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.\n" +
"\n" +
"am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
" bottom (false) of <STACK_ID>.\n" +
"\n" +
- "am stack resize: change <STACK_ID> relative size to new <WEIGHT>.\n" +
+ "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
+ "\n" +
+ "am stack list: list all of the activity stacks and their sizes.\n" +
"\n" +
- "am stack boxes: list the hierarchy of stack boxes and their contents.\n" +
+ "am stack info: display the information about activity stack <STACK_ID>.\n" +
"\n" +
- "am stack box: list the hierarchy of stack boxes rooted at <STACK_BOX_ID>.\n" +
+ "am lock-task: bring <TASK_ID> to the front and don't allow other tasks to run\n" +
+ "\n" +
+ "am get-config: retrieve the configuration and any recent configurations\n" +
+ " of the device\n" +
"\n" +
"<INTENT> specifications include these flags and arguments:\n" +
" [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
@@ -244,8 +268,11 @@ public class Am extends BaseCommand {
" [--eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]]\n" +
" [--ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]]\n" +
" [--efa <EXTRA_KEY> <EXTRA_FLOAT_VALUE>[,<EXTRA_FLOAT_VALUE...]]\n" +
+ " [--esa <EXTRA_KEY> <EXTRA_STRING_VALUE>[,<EXTRA_STRING_VALUE...]]\n" +
+ " (to embed a comma into a string escape it using \"\\,\")\n" +
" [-n <COMPONENT>] [-f <FLAGS>]\n" +
" [--grant-read-uri-permission] [--grant-write-uri-permission]\n" +
+ " [--grant-persistable-uri-permission] [--grant-prefix-uri-permission]\n" +
" [--debug-log-resolution] [--exclude-stopped-packages]\n" +
" [--include-stopped-packages]\n" +
" [--activity-brought-to-front] [--activity-clear-top]\n" +
@@ -315,10 +342,16 @@ public class Am extends BaseCommand {
runToUri(true);
} else if (op.equals("switch-user")) {
runSwitchUser();
+ } else if (op.equals("start-user")) {
+ runStartUserInBackground();
} else if (op.equals("stop-user")) {
runStopUser();
} else if (op.equals("stack")) {
runStack();
+ } else if (op.equals("lock-task")) {
+ runLockTask();
+ } else if (op.equals("get-config")) {
+ runGetConfig();
} else {
showError("Error: unknown command '" + op + "'");
}
@@ -346,6 +379,8 @@ public class Am extends BaseCommand {
mStopOption = false;
mRepeat = 0;
mProfileFile = null;
+ mSamplingInterval = 0;
+ mAutoStop = false;
mUserId = defUser;
Uri data = null;
String type = null;
@@ -431,6 +466,15 @@ public class Am extends BaseCommand {
}
intent.putExtra(key, list);
hasIntentInfo = true;
+ } else if (opt.equals("--esa")) {
+ String key = nextArgRequired();
+ String value = nextArgRequired();
+ // Split on commas unless they are preceeded by an escape.
+ // The escape character must be escaped for the string and
+ // again for the regex, thus four escape characters become one.
+ String[] strings = value.split("(?<!\\\\),");
+ intent.putExtra(key, strings);
+ hasIntentInfo = true;
} else if (opt.equals("--ez")) {
String key = nextArgRequired();
String value = nextArgRequired();
@@ -450,6 +494,10 @@ public class Am extends BaseCommand {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else if (opt.equals("--grant-write-uri-permission")) {
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ } else if (opt.equals("--grant-persistable-uri-permission")) {
+ intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+ } else if (opt.equals("--grant-prefix-uri-permission")) {
+ intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
} else if (opt.equals("--exclude-stopped-packages")) {
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
} else if (opt.equals("--include-stopped-packages")) {
@@ -499,10 +547,12 @@ public class Am extends BaseCommand {
mWaitOption = true;
} else if (opt.equals("-P")) {
mProfileFile = nextArgRequired();
- mStartFlags |= ActivityManager.START_FLAG_AUTO_STOP_PROFILER;
+ mAutoStop = true;
} else if (opt.equals("--start-profiler")) {
mProfileFile = nextArgRequired();
- mStartFlags &= ~ActivityManager.START_FLAG_AUTO_STOP_PROFILER;
+ mAutoStop = false;
+ } else if (opt.equals("--sampling")) {
+ mSamplingInterval = Integer.parseInt(nextArgRequired());
} else if (opt.equals("-R")) {
mRepeat = Integer.parseInt(nextArgRequired());
} else if (opt.equals("-S")) {
@@ -658,12 +708,13 @@ public class Am extends BaseCommand {
mAm.forceStopPackage(packageName, mUserId);
Thread.sleep(250);
}
-
+
System.out.println("Starting: " + intent);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
+
ParcelFileDescriptor fd = null;
-
+ ProfilerInfo profilerInfo = null;
+
if (mProfileFile != null) {
try {
fd = ParcelFileDescriptor.open(
@@ -675,18 +726,21 @@ public class Am extends BaseCommand {
System.err.println("Error: Unable to open file: " + mProfileFile);
return;
}
+ profilerInfo = new ProfilerInfo(mProfileFile, fd, mSamplingInterval, mAutoStop);
}
IActivityManager.WaitResult result = null;
int res;
+ final long startTime = SystemClock.uptimeMillis();
if (mWaitOption) {
result = mAm.startActivityAndWait(null, null, intent, mimeType,
- null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
+ null, null, 0, mStartFlags, profilerInfo, null, mUserId);
res = result.result;
} else {
res = mAm.startActivityAsUser(null, null, intent, mimeType,
- null, null, 0, mStartFlags, mProfileFile, fd, null, mUserId);
+ null, null, 0, mStartFlags, profilerInfo, null, mUserId);
}
+ final long endTime = SystemClock.uptimeMillis();
PrintStream out = mWaitOption ? System.out : System.err;
boolean launched = false;
switch (res) {
@@ -739,6 +793,11 @@ public class Am extends BaseCommand {
"Error: Activity not started, you do not "
+ "have permission to access it.");
break;
+ case ActivityManager.START_NOT_VOICE_COMPATIBLE:
+ out.println(
+ "Error: Activity not started, voice control not allowed for: "
+ + intent);
+ break;
default:
out.println(
"Error: Activity not started, unknown error code " + res);
@@ -759,6 +818,7 @@ public class Am extends BaseCommand {
if (result.totalTime >= 0) {
System.out.println("TotalTime: " + result.totalTime);
}
+ System.out.println("WaitTime: " + (endTime-startTime));
System.out.println("Complete");
}
mRepeat--;
@@ -803,7 +863,7 @@ public class Am extends BaseCommand {
}
private void sendBroadcast() throws Exception {
- Intent intent = makeIntent(UserHandle.USER_ALL);
+ Intent intent = makeIntent(UserHandle.USER_CURRENT);
IntentReceiver receiver = new IntentReceiver();
System.out.println("Broadcasting: " + intent);
mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission,
@@ -887,8 +947,7 @@ public class Am extends BaseCommand {
}
}
- if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId,
- abi)) {
+ if (!mAm.startInstrumentation(cn, profileFile, 0, args, watcher, connection, userId, abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
}
@@ -911,7 +970,7 @@ public class Am extends BaseCommand {
SystemProperties.set("dalvik.vm.extra-opts", props);
}
}
-
+
private void runProfile() throws Exception {
String profileFile = null;
boolean start = false;
@@ -965,6 +1024,7 @@ public class Am extends BaseCommand {
}
ParcelFileDescriptor fd = null;
+ ProfilerInfo profilerInfo = null;
if (start) {
profileFile = nextArgRequired();
@@ -978,6 +1038,7 @@ public class Am extends BaseCommand {
System.err.println("Error: Unable to open file: " + profileFile);
return;
}
+ profilerInfo = new ProfilerInfo(profileFile, fd, 0, false);
}
try {
@@ -991,7 +1052,7 @@ public class Am extends BaseCommand {
} else if (start) {
//removeWallOption();
}
- if (!mAm.profileControl(process, userId, start, profileFile, fd, profileType)) {
+ if (!mAm.profileControl(process, userId, start, profilerInfo, profileType)) {
wall = false;
throw new AndroidException("PROFILE FAILED on process " + process);
}
@@ -1076,6 +1137,16 @@ public class Am extends BaseCommand {
mAm.switchUser(Integer.parseInt(user));
}
+ private void runStartUserInBackground() throws Exception {
+ String user = nextArgRequired();
+ boolean success = mAm.startUserInBackground(Integer.parseInt(user));
+ if (success) {
+ System.out.println("Success: user started");
+ } else {
+ System.err.println("Error: could not start user");
+ }
+ }
+
private void runStopUser() throws Exception {
String user = nextArgRequired();
int res = mAm.stopUser(Integer.parseInt(user), null);
@@ -1434,7 +1505,7 @@ public class Am extends BaseCommand {
System.out.println("Performing idle maintenance...");
Intent intent = new Intent(
- "com.android.server.IdleMaintenanceService.action.FORCE_IDLE_MAINTENANCE");
+ "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE");
mAm.broadcastIntent(null, intent, null, null, 0, null, null, null,
android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL);
}
@@ -1573,35 +1644,32 @@ public class Am extends BaseCommand {
private void runStack() throws Exception {
String op = nextArgRequired();
- if (op.equals("create")) {
- runStackCreate();
+ if (op.equals("start")) {
+ runStackStart();
} else if (op.equals("movetask")) {
runStackMoveTask();
} else if (op.equals("resize")) {
- runStackBoxResize();
- } else if (op.equals("boxes")) {
- runStackBoxes();
- } else if (op.equals("box")) {
- runStackBoxInfo();
+ runStackResize();
+ } else if (op.equals("list")) {
+ runStackList();
+ } else if (op.equals("info")) {
+ runStackInfo();
} else {
showError("Error: unknown command '" + op + "'");
return;
}
}
- private void runStackCreate() throws Exception {
- String taskIdStr = nextArgRequired();
- int taskId = Integer.valueOf(taskIdStr);
- String relativeToStr = nextArgRequired();
- int relativeTo = Integer.valueOf(relativeToStr);
- String positionStr = nextArgRequired();
- int position = Integer.valueOf(positionStr);
- String weightStr = nextArgRequired();
- float weight = Float.valueOf(weightStr);
+ private void runStackStart() throws Exception {
+ String displayIdStr = nextArgRequired();
+ int displayId = Integer.valueOf(displayIdStr);
+ Intent intent = makeIntent(UserHandle.USER_CURRENT);
try {
- int stackId = mAm.createStack(taskId, relativeTo, position, weight);
- System.out.println("createStack returned new stackId=" + stackId + "\n\n");
+ IBinder homeActivityToken = mAm.getHomeActivityToken();
+ IActivityContainer container = mAm.createActivityContainer(homeActivityToken, null);
+ container.attachToDisplay(displayId);
+ container.startActivity(intent);
} catch (RemoteException e) {
}
}
@@ -1628,34 +1696,138 @@ public class Am extends BaseCommand {
}
}
- private void runStackBoxResize() throws Exception {
- String stackBoxIdStr = nextArgRequired();
- int stackBoxId = Integer.valueOf(stackBoxIdStr);
- String weightStr = nextArgRequired();
- float weight = Float.valueOf(weightStr);
+ private void runStackResize() throws Exception {
+ String stackIdStr = nextArgRequired();
+ int stackId = Integer.valueOf(stackIdStr);
+ String leftStr = nextArgRequired();
+ int left = Integer.valueOf(leftStr);
+ String topStr = nextArgRequired();
+ int top = Integer.valueOf(topStr);
+ String rightStr = nextArgRequired();
+ int right = Integer.valueOf(rightStr);
+ String bottomStr = nextArgRequired();
+ int bottom = Integer.valueOf(bottomStr);
try {
- mAm.resizeStackBox(stackBoxId, weight);
+ mAm.resizeStack(stackId, new Rect(left, top, right, bottom));
} catch (RemoteException e) {
}
}
- private void runStackBoxes() throws Exception {
+ private void runStackList() throws Exception {
try {
- List<StackBoxInfo> stackBoxes = mAm.getStackBoxes();
- for (StackBoxInfo info : stackBoxes) {
+ List<StackInfo> stacks = mAm.getAllStackInfos();
+ for (StackInfo info : stacks) {
System.out.println(info);
}
} catch (RemoteException e) {
}
}
- private void runStackBoxInfo() throws Exception {
+ private void runStackInfo() throws Exception {
try {
- String stackBoxIdStr = nextArgRequired();
- int stackBoxId = Integer.valueOf(stackBoxIdStr);
- StackBoxInfo stackBoxInfo = mAm.getStackBoxInfo(stackBoxId);
- System.out.println(stackBoxInfo);
+ String stackIdStr = nextArgRequired();
+ int stackId = Integer.valueOf(stackIdStr);
+ StackInfo info = mAm.getStackInfo(stackId);
+ System.out.println(info);
+ } catch (RemoteException e) {
+ }
+ }
+
+ private void runLockTask() throws Exception {
+ String taskIdStr = nextArgRequired();
+ try {
+ if (taskIdStr.equals("stop")) {
+ mAm.stopLockTaskMode();
+ } else {
+ int taskId = Integer.valueOf(taskIdStr);
+ mAm.startLockTaskMode(taskId);
+ }
+ System.err.println("Activity manager is " + (mAm.isInLockTaskMode() ? "" : "not ") +
+ "in lockTaskMode");
+ } catch (RemoteException e) {
+ }
+ }
+
+ private List<Configuration> getRecentConfigurations(int days) {
+ IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
+ Context.USAGE_STATS_SERVICE));
+ final long now = System.currentTimeMillis();
+ final long nDaysAgo = now - (days * 24 * 60 * 60 * 1000);
+ try {
+ @SuppressWarnings("unchecked")
+ ParceledListSlice<ConfigurationStats> configStatsSlice = usm.queryConfigurationStats(
+ UsageStatsManager.INTERVAL_BEST, nDaysAgo, now, "com.android.shell");
+ if (configStatsSlice == null) {
+ return Collections.emptyList();
+ }
+
+ final ArrayMap<Configuration, Integer> recentConfigs = new ArrayMap<>();
+ final List<ConfigurationStats> configStatsList = configStatsSlice.getList();
+ final int configStatsListSize = configStatsList.size();
+ for (int i = 0; i < configStatsListSize; i++) {
+ final ConfigurationStats stats = configStatsList.get(i);
+ final int indexOfKey = recentConfigs.indexOfKey(stats.getConfiguration());
+ if (indexOfKey < 0) {
+ recentConfigs.put(stats.getConfiguration(), stats.getActivationCount());
+ } else {
+ recentConfigs.setValueAt(indexOfKey,
+ recentConfigs.valueAt(indexOfKey) + stats.getActivationCount());
+ }
+ }
+
+ final Comparator<Configuration> comparator = new Comparator<Configuration>() {
+ @Override
+ public int compare(Configuration a, Configuration b) {
+ return recentConfigs.get(b).compareTo(recentConfigs.get(a));
+ }
+ };
+
+ ArrayList<Configuration> configs = new ArrayList<>(recentConfigs.size());
+ configs.addAll(recentConfigs.keySet());
+ Collections.sort(configs, comparator);
+ return configs;
+
+ } catch (RemoteException e) {
+ return Collections.emptyList();
+ }
+ }
+
+ private void runGetConfig() throws Exception {
+ int days = 14;
+ String option = nextOption();
+ if (option != null) {
+ if (!option.equals("--days")) {
+ throw new IllegalArgumentException("unrecognized option " + option);
+ }
+
+ days = Integer.parseInt(nextArgRequired());
+ if (days <= 0) {
+ throw new IllegalArgumentException("--days must be a positive integer");
+ }
+ }
+
+ try {
+ Configuration config = mAm.getConfiguration();
+ if (config == null) {
+ System.err.println("Activity manager has no configuration");
+ return;
+ }
+
+ System.out.println("config: " + Configuration.resourceQualifierString(config));
+ System.out.println("abi: " + TextUtils.join(",", Build.SUPPORTED_ABIS));
+
+ final List<Configuration> recentConfigs = getRecentConfigurations(days);
+ final int recentConfigSize = recentConfigs.size();
+ if (recentConfigSize > 0) {
+ System.out.println("recentConfigs:");
+ }
+
+ for (int i = 0; i < recentConfigSize; i++) {
+ System.out.println(" config: " + Configuration.resourceQualifierString(
+ recentConfigs.get(i)));
+ }
+
} catch (RemoteException e) {
}
}
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 6e77e13..1bb28c3 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -133,8 +133,7 @@ static size_t computeArgBlockSize(int argc, char* const argv[]) {
// names if the zygote command line decreases in size.
uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
uintptr_t end = reinterpret_cast<uintptr_t>(argv[argc - 1]);
- end += strlen(argv[argc - 1]);
-
+ end += strlen(argv[argc - 1]) + 1;
return (end - start);
}
@@ -220,15 +219,27 @@ int main(int argc, char* const argv[])
//
// For zygote starts, all remaining arguments are passed to the zygote.
// main function.
+ //
+ // Note that we must copy argument string values since we will rewrite the
+ // entire argument block when we apply the nice name to argv0.
-
- int i = runtime.addVmArguments(argc, argv);
+ int i;
+ for (i = 0; i < argc; i++) {
+ if (argv[i][0] != '-') {
+ break;
+ }
+ if (argv[i][1] == '-' && argv[i][2] == 0) {
+ ++i; // Skip --.
+ break;
+ }
+ runtime.addOption(strdup(argv[i]));
+ }
// Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
- const char* niceName = NULL;
+ String8 niceName;
String8 className;
++i; // Skip unused "parent dir" argument.
@@ -242,7 +253,7 @@ int main(int argc, char* const argv[])
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
- niceName = arg + 12;
+ niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
@@ -287,9 +298,9 @@ int main(int argc, char* const argv[])
}
}
- if (niceName && *niceName) {
- runtime.setArgv0(niceName);
- set_process_name(niceName);
+ if (!niceName.isEmpty()) {
+ runtime.setArgv0(niceName.string());
+ set_process_name(niceName.string());
}
if (zygote) {
diff --git a/cmds/appops/Android.mk b/cmds/appops/Android.mk
new file mode 100644
index 0000000..1e15204
--- /dev/null
+++ b/cmds/appops/Android.mk
@@ -0,0 +1,16 @@
+# Copyright 2014 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := appops
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := appops
+LOCAL_SRC_FILES := appops
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
+
diff --git a/cmds/appops/MODULE_LICENSE_APACHE2 b/cmds/appops/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/appops/MODULE_LICENSE_APACHE2
diff --git a/cmds/appops/NOTICE b/cmds/appops/NOTICE
new file mode 100644
index 0000000..06a9081
--- /dev/null
+++ b/cmds/appops/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2014, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/appops/appops b/cmds/appops/appops
new file mode 100755
index 0000000..407e551
--- /dev/null
+++ b/cmds/appops/appops
@@ -0,0 +1,5 @@
+# Script to start "appwidget" on the device, which has a very rudimentary shell.
+base=/system
+export CLASSPATH=$base/framework/appops.jar
+exec app_process $base/bin com.android.commands.appops.AppOpsCommand "$@"
+
diff --git a/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
new file mode 100644
index 0000000..c414f58
--- /dev/null
+++ b/cmds/appops/src/com/android/commands/appops/AppOpsCommand.java
@@ -0,0 +1,137 @@
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.commands.appops;
+
+import android.app.ActivityManager;
+import android.app.ActivityThread;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+
+import com.android.internal.app.IAppOpsService;
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
+
+/**
+ * This class is a command line utility for manipulating AppOps permissions.
+ */
+public class AppOpsCommand extends BaseCommand {
+
+ public static void main(String[] args) {
+ new AppOpsCommand().run(args);
+ }
+
+ @Override
+ public void onShowUsage(PrintStream out) {
+ out.println("usage: adb shell appops set <PACKAGE> <OP> "
+ + "<allow|ignore|deny|default> [--user <USER_ID>]\n"
+ + " <PACKAGE> an Android package name.\n"
+ + " <OP> an AppOps operation.\n"
+ + " <USER_ID> the user id under which the package is installed. If --user is not\n"
+ + " specified, the current user is assumed.\n");
+ }
+
+ private static final String COMMAND_SET = "set";
+
+ @Override
+ public void onRun() throws Exception {
+ String command = nextArgRequired();
+ switch (command) {
+ case COMMAND_SET:
+ runSet();
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown command '" + command + "'.");
+ }
+ }
+
+ private static final String ARGUMENT_USER = "--user";
+
+ // Modes
+ private static final String MODE_ALLOW = "allow";
+ private static final String MODE_DENY = "deny";
+ private static final String MODE_IGNORE = "ignore";
+ private static final String MODE_DEFAULT = "default";
+
+ private void runSet() throws Exception {
+ String packageName = null;
+ String op = null;
+ String mode = null;
+ int userId = UserHandle.USER_CURRENT;
+ for (String argument; (argument = nextArg()) != null;) {
+ if (ARGUMENT_USER.equals(argument)) {
+ userId = Integer.parseInt(nextArgRequired());
+ } else {
+ if (packageName == null) {
+ packageName = argument;
+ } else if (op == null) {
+ op = argument;
+ } else if (mode == null) {
+ mode = argument;
+ } else {
+ throw new IllegalArgumentException("Unsupported argument: " + argument);
+ }
+ }
+ }
+
+ if (packageName == null) {
+ throw new IllegalArgumentException("Package name not specified.");
+ } else if (op == null) {
+ throw new IllegalArgumentException("Operation not specified.");
+ } else if (mode == null) {
+ throw new IllegalArgumentException("Mode not specified.");
+ }
+
+ final int opInt = AppOpsManager.strOpToOp(op);
+ final int modeInt;
+ switch (mode) {
+ case MODE_ALLOW:
+ modeInt = AppOpsManager.MODE_ALLOWED;
+ break;
+ case MODE_DENY:
+ modeInt = AppOpsManager.MODE_ERRORED;
+ break;
+ case MODE_IGNORE:
+ modeInt = AppOpsManager.MODE_IGNORED;
+ break;
+ case MODE_DEFAULT:
+ modeInt = AppOpsManager.MODE_DEFAULT;
+ break;
+ default:
+ throw new IllegalArgumentException("Mode is invalid.");
+ }
+
+ // Parsing complete, let's execute the command.
+
+ if (userId == UserHandle.USER_CURRENT) {
+ userId = ActivityManager.getCurrentUser();
+ }
+
+ final IPackageManager pm = ActivityThread.getPackageManager();
+ final IAppOpsService appOpsService = IAppOpsService.Stub.asInterface(
+ ServiceManager.getService(Context.APP_OPS_SERVICE));
+ final int uid = pm.getPackageUid(packageName, userId);
+ if (uid < 0) {
+ throw new Exception("No UID for " + packageName + " for user " + userId);
+ }
+ appOpsService.setMode(opInt, uid, packageName, modeInt);
+ }
+}
diff --git a/cmds/appwidget/Android.mk b/cmds/appwidget/Android.mk
new file mode 100644
index 0000000..1fb258d
--- /dev/null
+++ b/cmds/appwidget/Android.mk
@@ -0,0 +1,16 @@
+# Copyright 2014 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := appwidget
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := appwidget
+LOCAL_SRC_FILES := appwidget
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
+
diff --git a/cmds/appwidget/MODULE_LICENSE_APACHE2 b/cmds/appwidget/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/appwidget/MODULE_LICENSE_APACHE2
diff --git a/cmds/appwidget/NOTICE b/cmds/appwidget/NOTICE
new file mode 100644
index 0000000..06a9081
--- /dev/null
+++ b/cmds/appwidget/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2014, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/appwidget/appwidget b/cmds/appwidget/appwidget
new file mode 100755
index 0000000..6105009
--- /dev/null
+++ b/cmds/appwidget/appwidget
@@ -0,0 +1,5 @@
+# Script to start "appwidget" on the device, which has a very rudimentary shell.
+base=/system
+export CLASSPATH=$base/framework/appwidget.jar
+exec app_process $base/bin com.android.commands.appwidget.AppWidget "$@"
+
diff --git a/cmds/appwidget/src/com/android/commands/appwidget/AppWidget.java b/cmds/appwidget/src/com/android/commands/appwidget/AppWidget.java
new file mode 100644
index 0000000..5ea7352
--- /dev/null
+++ b/cmds/appwidget/src/com/android/commands/appwidget/AppWidget.java
@@ -0,0 +1,167 @@
+/*
+** Copyright 2014, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.commands.appwidget;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.text.TextUtils;
+
+import com.android.internal.appwidget.IAppWidgetService;
+
+/**
+ * This class is a command line utility for manipulating app widgets. A client
+ * can grant or revoke the permission for a given package to bind app widgets.
+ */
+public class AppWidget {
+
+ private static final String USAGE =
+ "usage: adb shell appwidget [subcommand] [options]\n"
+ + "\n"
+ + "usage: adb shell appwidget grantbind --package <PACKAGE> "
+ + " [--user <USER_ID> | current]\n"
+ + " <PACKAGE> an Android package name.\n"
+ + " <USER_ID> The user id under which the package is installed.\n"
+ + " Example:\n"
+ + " # Grant the \"foo.bar.baz\" package to bind app widgets for the current user.\n"
+ + " adb shell grantbind --package foo.bar.baz --user current\n"
+ + "\n"
+ + "usage: adb shell appwidget revokebind --package <PACKAGE> "
+ + "[--user <USER_ID> | current]\n"
+ + " <PACKAGE> an Android package name.\n"
+ + " <USER_ID> The user id under which the package is installed.\n"
+ + " Example:\n"
+ + " # Revoke the permisison to bind app widgets from the \"foo.bar.baz\" package.\n"
+ + " adb shell revokebind --package foo.bar.baz --user current\n"
+ + "\n";
+
+ private static class Parser {
+ private static final String ARGUMENT_GRANT_BIND = "grantbind";
+ private static final String ARGUMENT_REVOKE_BIND = "revokebind";
+ private static final String ARGUMENT_PACKAGE = "--package";
+ private static final String ARGUMENT_USER = "--user";
+ private static final String ARGUMENT_PREFIX = "--";
+ private static final String VALUE_USER_CURRENT = "current";
+
+ private final Tokenizer mTokenizer;
+
+ public Parser(String[] args) {
+ mTokenizer = new Tokenizer(args);
+ }
+
+ public Runnable parseCommand() {
+ try {
+ String operation = mTokenizer.nextArg();
+ if (ARGUMENT_GRANT_BIND.equals(operation)) {
+ return parseSetGrantBindAppWidgetPermissionCommand(true);
+ } else if (ARGUMENT_REVOKE_BIND.equals(operation)) {
+ return parseSetGrantBindAppWidgetPermissionCommand(false);
+ } else {
+ throw new IllegalArgumentException("Unsupported operation: " + operation);
+ }
+ } catch (IllegalArgumentException iae) {
+ System.out.println(USAGE);
+ System.out.println("[ERROR] " + iae.getMessage());
+ return null;
+ }
+ }
+
+ private SetBindAppWidgetPermissionCommand parseSetGrantBindAppWidgetPermissionCommand(
+ boolean granted) {
+ String packageName = null;
+ int userId = UserHandle.USER_OWNER;
+ for (String argument; (argument = mTokenizer.nextArg()) != null;) {
+ if (ARGUMENT_PACKAGE.equals(argument)) {
+ packageName = argumentValueRequired(argument);
+ } else if (ARGUMENT_USER.equals(argument)) {
+ String user = argumentValueRequired(argument);
+ if (VALUE_USER_CURRENT.equals(user)) {
+ userId = UserHandle.USER_CURRENT;
+ } else {
+ userId = Integer.parseInt(user);
+ }
+ } else {
+ throw new IllegalArgumentException("Unsupported argument: " + argument);
+ }
+ }
+ if (packageName == null) {
+ throw new IllegalArgumentException("Package name not specified."
+ + " Did you specify --package argument?");
+ }
+ return new SetBindAppWidgetPermissionCommand(packageName, granted, userId);
+ }
+
+ private String argumentValueRequired(String argument) {
+ String value = mTokenizer.nextArg();
+ if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
+ throw new IllegalArgumentException("No value for argument: " + argument);
+ }
+ return value;
+ }
+ }
+
+ private static class Tokenizer {
+ private final String[] mArgs;
+ private int mNextArg;
+
+ public Tokenizer(String[] args) {
+ mArgs = args;
+ }
+
+ private String nextArg() {
+ if (mNextArg < mArgs.length) {
+ return mArgs[mNextArg++];
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private static class SetBindAppWidgetPermissionCommand implements Runnable {
+ final String mPackageName;
+ final boolean mGranted;
+ final int mUserId;
+
+ public SetBindAppWidgetPermissionCommand(String packageName, boolean granted,
+ int userId) {
+ mPackageName = packageName;
+ mGranted = granted;
+ mUserId = userId;
+ }
+
+ @Override
+ public void run() {
+ IBinder binder = ServiceManager.getService(Context.APPWIDGET_SERVICE);
+ IAppWidgetService appWidgetService = IAppWidgetService.Stub.asInterface(binder);
+ try {
+ appWidgetService.setBindAppWidgetPermission(mPackageName, mUserId, mGranted);
+ } catch (RemoteException re) {
+ re.printStackTrace();
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ Parser parser = new Parser(args);
+ Runnable command = parser.parseCommand();
+ if (command != null) {
+ command.run();
+ }
+ }
+}
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index db3d8bb..d683851 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -23,6 +23,7 @@ import android.app.backup.IRestoreSession;
import android.os.RemoteException;
import android.os.ServiceManager;
+import java.util.ArrayList;
import java.util.HashSet;
public final class Bmgr {
@@ -102,6 +103,11 @@ public final class Bmgr {
return;
}
+ if ("fullbackup".equals(op)) {
+ doFullTransportBackup();
+ return;
+ }
+
System.err.println("Unknown command");
showUsage();
}
@@ -165,6 +171,24 @@ public final class Bmgr {
}
}
+ private void doFullTransportBackup() {
+ System.out.println("Performing full transport backup");
+
+ String pkg;
+ ArrayList<String> allPkgs = new ArrayList<String>();
+ while ((pkg = nextArg()) != null) {
+ allPkgs.add(pkg);
+ }
+ if (allPkgs.size() > 0) {
+ try {
+ mBmgr.fullTransportBackup(allPkgs.toArray(new String[allPkgs.size()]));
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+ }
+
private void doTransport() {
try {
String which = nextArg();
@@ -453,6 +477,7 @@ public final class Bmgr {
System.err.println(" bmgr restore PACKAGE");
System.err.println(" bmgr run");
System.err.println(" bmgr wipe TRANSPORT PACKAGE");
+ System.err.println(" bmgr fullbackup PACKAGE...");
System.err.println("");
System.err.println("The 'backup' command schedules a backup pass for the named package.");
System.err.println("Note that the backup pass will effectively be a no-op if the package");
@@ -468,11 +493,11 @@ public final class Bmgr {
System.err.println("");
System.err.println("The 'list transports' command reports the names of the backup transports");
System.err.println("currently available on the device. These names can be passed as arguments");
- System.err.println("to the 'transport' and 'wipe' commands. The currently selected transport");
+ System.err.println("to the 'transport' and 'wipe' commands. The currently active transport");
System.err.println("is indicated with a '*' character.");
System.err.println("");
System.err.println("The 'list sets' command reports the token and name of each restore set");
- System.err.println("available to the device via the current transport.");
+ System.err.println("available to the device via the currently active transport.");
System.err.println("");
System.err.println("The 'transport' command designates the named transport as the currently");
System.err.println("active one. This setting is persistent across reboots.");
@@ -500,5 +525,8 @@ public final class Bmgr {
System.err.println("erased from the given transport's storage. The next backup operation");
System.err.println("that the given application performs will rewrite its entire data set.");
System.err.println("Transport names to use here are those reported by 'list transports'.");
+ System.err.println("");
+ System.err.println("The 'fullbackup' command induces a full-data stream backup for one or more");
+ System.err.println("packages. The data is sent via the currently active transport.");
}
}
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index dd987e0..d6ecbe3 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -3,10 +3,13 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
bootanimation_main.cpp \
+ AudioPlayer.cpp \
BootAnimation.cpp
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_C_INCLUDES += external/tinyalsa/include
+
LOCAL_SHARED_LIBRARIES := \
libcutils \
liblog \
@@ -17,10 +20,8 @@ LOCAL_SHARED_LIBRARIES := \
libskia \
libEGL \
libGLESv1_CM \
- libgui
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, corecg graphics)
+ libgui \
+ libtinyalsa
LOCAL_MODULE:= bootanimation
diff --git a/cmds/bootanimation/AudioPlayer.cpp b/cmds/bootanimation/AudioPlayer.cpp
new file mode 100644
index 0000000..471b77f
--- /dev/null
+++ b/cmds/bootanimation/AudioPlayer.cpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "BootAnim_AudioPlayer"
+
+#include "AudioPlayer.h"
+
+#include <androidfw/ZipFileRO.h>
+#include <tinyalsa/asoundlib.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+
+// Maximum line length for audio_conf.txt
+// We only accept lines less than this length to avoid overflows using sscanf()
+#define MAX_LINE_LENGTH 1024
+
+struct riff_wave_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t wave_id;
+};
+
+struct chunk_header {
+ uint32_t id;
+ uint32_t sz;
+};
+
+struct chunk_fmt {
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate;
+ uint16_t block_align;
+ uint16_t bits_per_sample;
+};
+
+
+namespace android {
+
+AudioPlayer::AudioPlayer()
+ : mCard(-1),
+ mDevice(-1),
+ mPeriodSize(0),
+ mPeriodCount(0),
+ mCurrentFile(NULL)
+{
+}
+
+AudioPlayer::~AudioPlayer() {
+}
+
+static bool setMixerValue(struct mixer* mixer, const char* name, const char* values)
+{
+ if (!mixer) {
+ ALOGE("no mixer in setMixerValue");
+ return false;
+ }
+ struct mixer_ctl *ctl = mixer_get_ctl_by_name(mixer, name);
+ if (!ctl) {
+ ALOGE("mixer_get_ctl_by_name failed for %s", name);
+ return false;
+ }
+
+ enum mixer_ctl_type type = mixer_ctl_get_type(ctl);
+ int numValues = mixer_ctl_get_num_values(ctl);
+ int intValue;
+ char stringValue[MAX_LINE_LENGTH];
+
+ for (int i = 0; i < numValues && values; i++) {
+ // strip leading space
+ while (*values == ' ') values++;
+ if (*values == 0) break;
+
+ switch (type) {
+ case MIXER_CTL_TYPE_BOOL:
+ case MIXER_CTL_TYPE_INT:
+ if (sscanf(values, "%d", &intValue) == 1) {
+ if (mixer_ctl_set_value(ctl, i, intValue) != 0) {
+ ALOGE("mixer_ctl_set_value failed for %s %d", name, intValue);
+ }
+ } else {
+ ALOGE("Could not parse %s as int for %d", intValue, name);
+ }
+ break;
+ case MIXER_CTL_TYPE_ENUM:
+ if (sscanf(values, "%s", stringValue) == 1) {
+ if (mixer_ctl_set_enum_by_string(ctl, stringValue) != 0) {
+ ALOGE("mixer_ctl_set_enum_by_string failed for %s %%s", name, stringValue);
+ }
+ } else {
+ ALOGE("Could not parse %s as enum for %d", stringValue, name);
+ }
+ break;
+ default:
+ ALOGE("unsupported mixer type %d for %s", type, name);
+ break;
+ }
+
+ values = strchr(values, ' ');
+ }
+
+ return true;
+}
+
+
+/*
+ * Parse the audio configuration file.
+ * The file is named audio_conf.txt and must begin with the following header:
+ *
+ * card=<ALSA card number>
+ * device=<ALSA device number>
+ * period_size=<period size>
+ * period_count=<period count>
+ *
+ * This header is followed by zero or more mixer settings, each with the format:
+ * mixer "<name>" = <value list>
+ * Since mixer names can contain spaces, the name must be enclosed in double quotes.
+ * The values in the value list can be integers, booleans (represented by 0 or 1)
+ * or strings for enum values.
+ */
+bool AudioPlayer::init(const char* config)
+{
+ int tempInt;
+ struct mixer* mixer = NULL;
+ char name[MAX_LINE_LENGTH];
+
+ for (;;) {
+ const char* endl = strstr(config, "\n");
+ if (!endl) break;
+ String8 line(config, endl - config);
+ if (line.length() >= MAX_LINE_LENGTH) {
+ ALOGE("Line too long in audio_conf.txt");
+ return false;
+ }
+ const char* l = line.string();
+
+ if (sscanf(l, "card=%d", &tempInt) == 1) {
+ ALOGD("card=%d", tempInt);
+ mCard = tempInt;
+
+ mixer = mixer_open(mCard);
+ if (!mixer) {
+ ALOGE("could not open mixer for card %d", mCard);
+ return false;
+ }
+ } else if (sscanf(l, "device=%d", &tempInt) == 1) {
+ ALOGD("device=%d", tempInt);
+ mDevice = tempInt;
+ } else if (sscanf(l, "period_size=%d", &tempInt) == 1) {
+ ALOGD("period_size=%d", tempInt);
+ mPeriodSize = tempInt;
+ } else if (sscanf(l, "period_count=%d", &tempInt) == 1) {
+ ALOGD("period_count=%d", tempInt);
+ mPeriodCount = tempInt;
+ } else if (sscanf(l, "mixer \"%[0-9a-zA-Z _]s\"", name) == 1) {
+ const char* values = strchr(l, '=');
+ if (values) {
+ values++; // skip '='
+ ALOGD("name: \"%s\" = %s", name, values);
+ setMixerValue(mixer, name, values);
+ } else {
+ ALOGE("values missing for name: \"%s\"", name);
+ }
+ }
+ config = ++endl;
+ }
+
+ mixer_close(mixer);
+
+ if (mCard >= 0 && mDevice >= 0) {
+ return true;
+ }
+
+ return false;
+}
+
+void AudioPlayer::playFile(struct FileMap* fileMap) {
+ // stop any currently playing sound
+ requestExitAndWait();
+
+ mCurrentFile = fileMap;
+ run("bootanim audio", PRIORITY_URGENT_AUDIO);
+}
+
+bool AudioPlayer::threadLoop()
+{
+ struct pcm_config config;
+ struct pcm *pcm = NULL;
+ bool moreChunks = true;
+ const struct chunk_fmt* chunkFmt = NULL;
+ void* buffer = NULL;
+ int bufferSize;
+ const uint8_t* wavData;
+ size_t wavLength;
+ const struct riff_wave_header* wavHeader;
+
+ if (mCurrentFile == NULL) {
+ ALOGE("mCurrentFile is NULL");
+ return false;
+ }
+
+ wavData = (const uint8_t *)mCurrentFile->getDataPtr();
+ if (!wavData) {
+ ALOGE("Could not access WAV file data");
+ goto exit;
+ }
+ wavLength = mCurrentFile->getDataLength();
+
+ wavHeader = (const struct riff_wave_header *)wavData;
+ if (wavLength < sizeof(*wavHeader) || (wavHeader->riff_id != ID_RIFF) ||
+ (wavHeader->wave_id != ID_WAVE)) {
+ ALOGE("Error: audio file is not a riff/wave file\n");
+ goto exit;
+ }
+ wavData += sizeof(*wavHeader);
+ wavLength -= sizeof(*wavHeader);
+
+ do {
+ const struct chunk_header* chunkHeader = (const struct chunk_header*)wavData;
+ if (wavLength < sizeof(*chunkHeader)) {
+ ALOGE("EOF reading chunk headers");
+ goto exit;
+ }
+
+ wavData += sizeof(*chunkHeader);
+ wavLength -= sizeof(*chunkHeader);
+
+ switch (chunkHeader->id) {
+ case ID_FMT:
+ chunkFmt = (const struct chunk_fmt *)wavData;
+ wavData += chunkHeader->sz;
+ wavLength -= chunkHeader->sz;
+ break;
+ case ID_DATA:
+ /* Stop looking for chunks */
+ moreChunks = 0;
+ break;
+ default:
+ /* Unknown chunk, skip bytes */
+ wavData += chunkHeader->sz;
+ wavLength -= chunkHeader->sz;
+ }
+ } while (moreChunks);
+
+ if (!chunkFmt) {
+ ALOGE("format not found in WAV file");
+ goto exit;
+ }
+
+
+ memset(&config, 0, sizeof(config));
+ config.channels = chunkFmt->num_channels;
+ config.rate = chunkFmt->sample_rate;
+ config.period_size = mPeriodSize;
+ config.period_count = mPeriodCount;
+ config.start_threshold = mPeriodSize / 4;
+ config.stop_threshold = INT_MAX;
+ config.avail_min = config.start_threshold;
+ if (chunkFmt->bits_per_sample != 16) {
+ ALOGE("only 16 bit WAV files are supported");
+ goto exit;
+ }
+ config.format = PCM_FORMAT_S16_LE;
+
+ pcm = pcm_open(mCard, mDevice, PCM_OUT, &config);
+ if (!pcm || !pcm_is_ready(pcm)) {
+ ALOGE("Unable to open PCM device (%s)\n", pcm_get_error(pcm));
+ goto exit;
+ }
+
+ bufferSize = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
+
+ while (wavLength > 0) {
+ if (exitPending()) goto exit;
+ size_t count = bufferSize;
+ if (count > wavLength)
+ count = wavLength;
+
+ if (pcm_write(pcm, wavData, count)) {
+ ALOGE("pcm_write failed (%s)", pcm_get_error(pcm));
+ goto exit;
+ }
+ wavData += count;
+ wavLength -= count;
+ }
+
+exit:
+ if (pcm)
+ pcm_close(pcm);
+ mCurrentFile->release();
+ mCurrentFile = NULL;
+ return false;
+}
+
+} // namespace android
diff --git a/cmds/bootanimation/AudioPlayer.h b/cmds/bootanimation/AudioPlayer.h
new file mode 100644
index 0000000..7e82a07
--- /dev/null
+++ b/cmds/bootanimation/AudioPlayer.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _BOOTANIMATION_AUDIOPLAYER_H
+#define _BOOTANIMATION_AUDIOPLAYER_H
+
+#include <utils/Thread.h>
+
+namespace android {
+
+class AudioPlayer : public Thread
+{
+public:
+ AudioPlayer();
+ virtual ~AudioPlayer();
+ bool init(const char* config);
+
+ void playFile(struct FileMap* fileMap);
+
+private:
+ virtual bool threadLoop();
+
+private:
+ int mCard; // ALSA card to use
+ int mDevice; // ALSA device to use
+ int mPeriodSize;
+ int mPeriodCount;
+
+ struct FileMap* mCurrentFile;
+};
+
+} // namespace android
+
+#endif // _BOOTANIMATION_AUDIOPLAYER_H
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index f3e3aff..167014e 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_NDEBUG 0
#define LOG_TAG "BootAnimation"
#include <stdint.h>
@@ -31,28 +32,28 @@
#include <utils/Atomic.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include <utils/threads.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
#include <ui/Region.h>
#include <ui/DisplayInfo.h>
-#include <ui/FramebufferNativeWindow.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
-#include <core/SkBitmap.h>
-#include <core/SkStream.h>
-#include <core/SkImageDecoder.h>
+#include <SkBitmap.h>
+#include <SkStream.h>
+#include <SkImageDecoder.h>
#include <GLES/gl.h>
#include <GLES/glext.h>
#include <EGL/eglext.h>
#include "BootAnimation.h"
+#include "AudioPlayer.h"
+#define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
#define EXIT_PROP_NAME "service.bootanim.exit"
@@ -96,6 +97,9 @@ void BootAnimation::binderDied(const wp<IBinder>&)
// might be blocked on a condition variable that will never be updated.
kill( getpid(), SIGKILL );
requestExit();
+ if (mAudioPlayer != NULL) {
+ mAudioPlayer->requestExit();
+ }
}
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
@@ -105,7 +109,7 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
return NO_INIT;
SkBitmap bitmap;
SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(),
- &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode);
+ &bitmap, kUnknown_SkColorType, SkImageDecoder::kDecodePixels_Mode);
asset->close();
delete asset;
@@ -124,20 +128,20 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
glGenTextures(1, &texture->name);
glBindTexture(GL_TEXTURE_2D, texture->name);
- switch (bitmap.getConfig()) {
- case SkBitmap::kA8_Config:
+ switch (bitmap.colorType()) {
+ case kAlpha_8_SkColorType:
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA,
GL_UNSIGNED_BYTE, p);
break;
- case SkBitmap::kARGB_4444_Config:
+ case kARGB_4444_SkColorType:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_SHORT_4_4_4_4, p);
break;
- case SkBitmap::kARGB_8888_Config:
+ case kN32_SkColorType:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, p);
break;
- case SkBitmap::kRGB_565_Config:
+ case kRGB_565_SkColorType:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, p);
break;
@@ -163,7 +167,7 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame)
if (codec) {
codec->setDitherImage(false);
codec->decode(&stream, &bitmap,
- SkBitmap::kARGB_8888_Config,
+ kN32_SkColorType,
SkImageDecoder::kDecodePixels_Mode);
delete codec;
}
@@ -187,8 +191,8 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame)
if (tw < w) tw <<= 1;
if (th < h) th <<= 1;
- switch (bitmap.getConfig()) {
- case SkBitmap::kARGB_8888_Config:
+ switch (bitmap.colorType()) {
+ case kN32_SkColorType:
if (tw != w || th != h) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tw, th, 0, GL_RGBA,
GL_UNSIGNED_BYTE, 0);
@@ -200,7 +204,7 @@ status_t BootAnimation::initTexture(const Animation::Frame& frame)
}
break;
- case SkBitmap::kRGB_565_Config:
+ case kRGB_565_SkColorType:
if (tw != w || th != h) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB,
GL_UNSIGNED_SHORT_5_6_5, 0);
@@ -286,6 +290,9 @@ status_t BootAnimation::readyToRun() {
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) ||
+ ((access(OEM_BOOTANIMATION_FILE, R_OK) == 0) &&
+ ((zipFile = ZipFileRO::open(OEM_BOOTANIMATION_FILE)) != NULL)) ||
+
((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) {
mZip = zipFile;
@@ -388,29 +395,76 @@ void BootAnimation::checkExit() {
int exitnow = atoi(value);
if (exitnow) {
requestExit();
+ if (mAudioPlayer != NULL) {
+ mAudioPlayer->requestExit();
+ }
}
}
-bool BootAnimation::movie()
+// Parse a color represented as an HTML-style 'RRGGBB' string: each pair of
+// characters in str is a hex number in [0, 255], which are converted to
+// floating point values in the range [0.0, 1.0] and placed in the
+// corresponding elements of color.
+//
+// If the input string isn't valid, parseColor returns false and color is
+// left unchanged.
+static bool parseColor(const char str[7], float color[3]) {
+ float tmpColor[3];
+ for (int i = 0; i < 3; i++) {
+ int val = 0;
+ for (int j = 0; j < 2; j++) {
+ val *= 16;
+ char c = str[2*i + j];
+ if (c >= '0' && c <= '9') val += c - '0';
+ else if (c >= 'A' && c <= 'F') val += (c - 'A') + 10;
+ else if (c >= 'a' && c <= 'f') val += (c - 'a') + 10;
+ else return false;
+ }
+ tmpColor[i] = static_cast<float>(val) / 255.0f;
+ }
+ memcpy(color, tmpColor, sizeof(tmpColor));
+ return true;
+}
+
+bool BootAnimation::readFile(const char* name, String8& outString)
{
- ZipEntryRO desc = mZip->findEntryByName("desc.txt");
- ALOGE_IF(!desc, "couldn't find desc.txt");
- if (!desc) {
+ ZipEntryRO entry = mZip->findEntryByName(name);
+ ALOGE_IF(!entry, "couldn't find %s", name);
+ if (!entry) {
return false;
}
- FileMap* descMap = mZip->createEntryFileMap(desc);
- mZip->releaseEntry(desc);
- ALOGE_IF(!descMap, "descMap is null");
- if (!descMap) {
+ FileMap* entryMap = mZip->createEntryFileMap(entry);
+ mZip->releaseEntry(entry);
+ ALOGE_IF(!entryMap, "entryMap is null");
+ if (!entryMap) {
return false;
}
- String8 desString((char const*)descMap->getDataPtr(),
- descMap->getDataLength());
- descMap->release();
+ outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
+ entryMap->release();
+ return true;
+}
+
+bool BootAnimation::movie()
+{
+ String8 desString;
+
+ if (!readFile("desc.txt", desString)) {
+ return false;
+ }
char const* s = desString.string();
+ // Create and initialize an AudioPlayer if we have an audio_conf.txt file
+ String8 audioConf;
+ if (readFile("audio_conf.txt", audioConf)) {
+ mAudioPlayer = new AudioPlayer;
+ if (!mAudioPlayer->init(audioConf.string())) {
+ ALOGE("mAudioPlayer.init failed");
+ mAudioPlayer = NULL;
+ }
+ }
+
Animation animation;
// Parse the description file
@@ -421,20 +475,29 @@ bool BootAnimation::movie()
const char* l = line.string();
int fps, width, height, count, pause;
char path[ANIM_ENTRY_NAME_MAX];
+ char color[7] = "000000"; // default to black if unspecified
+
char pathType;
if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
- //LOGD("> w=%d, h=%d, fps=%d", width, height, fps);
+ // ALOGD("> w=%d, h=%d, fps=%d", width, height, fps);
animation.width = width;
animation.height = height;
animation.fps = fps;
}
- else if (sscanf(l, " %c %d %d %s", &pathType, &count, &pause, path) == 4) {
- //LOGD("> type=%c, count=%d, pause=%d, path=%s", pathType, count, pause, path);
+ else if (sscanf(l, " %c %d %d %s #%6s", &pathType, &count, &pause, path, color) >= 4) {
+ // ALOGD("> type=%c, count=%d, pause=%d, path=%s, color=%s", pathType, count, pause, path, color);
Animation::Part part;
part.playUntilComplete = pathType == 'c';
part.count = count;
part.pause = pause;
part.path = path;
+ part.audioFile = NULL;
+ if (!parseColor(color, part.backgroundColor)) {
+ ALOGE("> invalid color '#%s'", color);
+ part.backgroundColor[0] = 0.0f;
+ part.backgroundColor[1] = 0.0f;
+ part.backgroundColor[2] = 0.0f;
+ }
animation.parts.add(part);
}
@@ -469,11 +532,16 @@ bool BootAnimation::movie()
if (method == ZipFileRO::kCompressStored) {
FileMap* map = mZip->createEntryFileMap(entry);
if (map) {
- Animation::Frame frame;
- frame.name = leaf;
- frame.map = map;
Animation::Part& part(animation.parts.editItemAt(j));
- part.frames.add(frame);
+ if (leaf == "audio.wav") {
+ // a part may have at most one audio file
+ part.audioFile = map;
+ } else {
+ Animation::Frame frame;
+ frame.name = leaf;
+ frame.map = map;
+ part.frames.add(frame);
+ }
}
}
}
@@ -520,6 +588,17 @@ bool BootAnimation::movie()
if(exitPending() && !part.playUntilComplete)
break;
+ // only play audio file the first time we animate the part
+ if (r == 0 && mAudioPlayer != NULL && part.audioFile) {
+ mAudioPlayer->playFile(part.audioFile);
+ }
+
+ glClearColor(
+ part.backgroundColor[0],
+ part.backgroundColor[1],
+ part.backgroundColor[2],
+ 1.0f);
+
for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
const Animation::Frame& frame(part.frames[j]);
nsecs_t lastFrame = systemTime();
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index ba1c507..f968b25 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -21,7 +21,7 @@
#include <sys/types.h>
#include <androidfw/AssetManager.h>
-#include <utils/threads.h>
+#include <utils/Thread.h>
#include <EGL/egl.h>
#include <GLES/gl.h>
@@ -30,6 +30,7 @@ class SkBitmap;
namespace android {
+class AudioPlayer;
class Surface;
class SurfaceComposerClient;
class SurfaceControl;
@@ -71,6 +72,8 @@ private:
String8 path;
SortedVector<Frame> frames;
bool playUntilComplete;
+ float backgroundColor[3];
+ FileMap* audioFile;
};
int fps;
int width;
@@ -81,11 +84,13 @@ private:
status_t initTexture(Texture* texture, AssetManager& asset, const char* name);
status_t initTexture(const Animation::Frame& frame);
bool android();
+ bool readFile(const char* name, String8& outString);
bool movie();
void checkExit();
sp<SurfaceComposerClient> mSession;
+ sp<AudioPlayer> mAudioPlayer;
AssetManager mAssets;
Texture mAndroid[2];
int mWidth;
diff --git a/cmds/bu/src/com/android/commands/bu/Backup.java b/cmds/bu/src/com/android/commands/bu/Backup.java
index 73fd660..ffc0f87 100644
--- a/cmds/bu/src/com/android/commands/bu/Backup.java
+++ b/cmds/bu/src/com/android/commands/bu/Backup.java
@@ -20,6 +20,7 @@ import android.app.backup.IBackupManager;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.system.OsConstants;
import android.util.Log;
import java.io.IOException;
@@ -50,13 +51,11 @@ public final class Backup {
return;
}
- int socketFd = Integer.parseInt(nextArg());
-
String arg = nextArg();
if (arg.equals("backup")) {
- doFullBackup(socketFd);
+ doFullBackup(OsConstants.STDOUT_FILENO);
} else if (arg.equals("restore")) {
- doFullRestore(socketFd);
+ doFullRestore(OsConstants.STDIN_FILENO);
} else {
Log.e(TAG, "Invalid operation '" + arg + "'");
}
@@ -68,7 +67,9 @@ public final class Backup {
boolean saveObbs = false;
boolean saveShared = false;
boolean doEverything = false;
+ boolean doWidgets = false;
boolean allIncludesSystem = true;
+ boolean doCompress = true;
String arg;
while ((arg = nextArg()) != null) {
@@ -89,8 +90,16 @@ public final class Backup {
allIncludesSystem = true;
} else if ("-nosystem".equals(arg)) {
allIncludesSystem = false;
+ } else if ("-widgets".equals(arg)) {
+ doWidgets = true;
+ } else if ("-nowidgets".equals(arg)) {
+ doWidgets = false;
} else if ("-all".equals(arg)) {
doEverything = true;
+ } else if ("-compress".equals(arg)) {
+ doCompress = true;
+ } else if ("-nocompress".equals(arg)) {
+ doCompress = false;
} else {
Log.w(TAG, "Unknown backup flag " + arg);
continue;
@@ -114,8 +123,8 @@ public final class Backup {
try {
fd = ParcelFileDescriptor.adoptFd(socketFd);
String[] packArray = new String[packages.size()];
- mBackupManager.fullBackup(fd, saveApks, saveObbs, saveShared, doEverything,
- allIncludesSystem, packages.toArray(packArray));
+ mBackupManager.fullBackup(fd, saveApks, saveObbs, saveShared, doWidgets,
+ doEverything, allIncludesSystem, doCompress, packages.toArray(packArray));
} catch (RemoteException e) {
Log.e(TAG, "Unable to invoke backup manager for backup");
} finally {
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
index e66bdf4..948c9a2 100644
--- a/cmds/content/src/com/android/commands/content/Content.java
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -26,9 +26,17 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
import android.os.UserHandle;
import android.text.TextUtils;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import libcore.io.IoUtils;
+
/**
* This class is a command line utility for manipulating content. A client
* can insert, update, and remove records in a content provider. For example,
@@ -109,6 +117,12 @@ public class Content {
+ " <METHOD> is the name of a provider-defined method\n"
+ " <ARG> is an optional string argument\n"
+ " <BINDING> is like --bind above, typed data of the form <KEY>:{b,s,i,l,f,d}:<VAL>\n"
+ + "\n"
+ + "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n"
+ + " Example:\n"
+ + " # cat default ringtone to a file, then pull to host\n"
+ + " adb shell 'content read --uri content://settings/system/ringtone >"
+ + " /mnt/sdcard/tmp.ogg' && adb pull /mnt/sdcard/tmp.ogg\n"
+ "\n";
private static class Parser {
@@ -117,6 +131,7 @@ public class Content {
private static final String ARGUMENT_UPDATE = "update";
private static final String ARGUMENT_QUERY = "query";
private static final String ARGUMENT_CALL = "call";
+ private static final String ARGUMENT_READ = "read";
private static final String ARGUMENT_WHERE = "--where";
private static final String ARGUMENT_BIND = "--bind";
private static final String ARGUMENT_URI = "--uri";
@@ -154,6 +169,8 @@ public class Content {
return parseQueryCommand();
} else if (ARGUMENT_CALL.equals(operation)) {
return parseCallCommand();
+ } else if (ARGUMENT_READ.equals(operation)) {
+ return parseReadCommand();
} else {
throw new IllegalArgumentException("Unsupported operation: " + operation);
}
@@ -273,6 +290,25 @@ public class Content {
return new CallCommand(uri, userId, method, arg, values);
}
+ private ReadCommand parseReadCommand() {
+ Uri uri = null;
+ int userId = UserHandle.USER_OWNER;
+ for (String argument; (argument = mTokenizer.nextArg())!= null;) {
+ if (ARGUMENT_URI.equals(argument)) {
+ uri = Uri.parse(argumentValueRequired(argument));
+ } else if (ARGUMENT_USER.equals(argument)) {
+ userId = Integer.parseInt(argumentValueRequired(argument));
+ } else {
+ throw new IllegalArgumentException("Unsupported argument: " + argument);
+ }
+ }
+ if (uri == null) {
+ throw new IllegalArgumentException("Content provider URI not specified."
+ + " Did you specify --uri argument?");
+ }
+ return new ReadCommand(uri, userId);
+ }
+
public QueryCommand parseQueryCommand() {
Uri uri = null;
int userId = UserHandle.USER_OWNER;
@@ -458,6 +494,31 @@ public class Content {
}
}
+ private static class ReadCommand extends Command {
+ public ReadCommand(Uri uri, int userId) {
+ super(uri, userId);
+ }
+
+ @Override
+ public void onExecute(IContentProvider provider) throws Exception {
+ final ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null);
+ copy(new FileInputStream(fd.getFileDescriptor()), System.out);
+ }
+
+ private static void copy(InputStream is, OutputStream os) throws IOException {
+ final byte[] buffer = new byte[8 * 1024];
+ int read;
+ try {
+ while ((read = is.read(buffer)) > -1) {
+ os.write(buffer, 0, read);
+ }
+ } finally {
+ IoUtils.closeQuietly(is);
+ IoUtils.closeQuietly(os);
+ }
+ }
+ }
+
private static class QueryCommand extends DeleteCommand {
final String[] mProjection;
final String mSortOrder;
@@ -498,7 +559,7 @@ public class Content {
columnValue = String.valueOf(cursor.getFloat(columnIndex));
break;
case Cursor.FIELD_TYPE_INTEGER:
- columnValue = String.valueOf(cursor.getInt(columnIndex));
+ columnValue = String.valueOf(cursor.getLong(columnIndex));
break;
case Cursor.FIELD_TYPE_STRING:
columnValue = cursor.getString(columnIndex);
diff --git a/cmds/dpm/Android.mk b/cmds/dpm/Android.mk
new file mode 100644
index 0000000..9f5aee4
--- /dev/null
+++ b/cmds/dpm/Android.mk
@@ -0,0 +1,15 @@
+# Copyright 2014 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := dpm
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := dpm
+LOCAL_SRC_FILES := dpm
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_PREBUILT)
diff --git a/cmds/dpm/MODULE_LICENSE_APACHE2 b/cmds/dpm/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/dpm/MODULE_LICENSE_APACHE2
diff --git a/cmds/dpm/NOTICE b/cmds/dpm/NOTICE
new file mode 100644
index 0000000..316b4eb
--- /dev/null
+++ b/cmds/dpm/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2014, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/dpm/dpm b/cmds/dpm/dpm
new file mode 100755
index 0000000..c2e5cbb
--- /dev/null
+++ b/cmds/dpm/dpm
@@ -0,0 +1,6 @@
+# Script to start "dpm" on the device
+#
+base=/system
+export CLASSPATH=$base/framework/dpm.jar
+exec app_process $base/bin com.android.commands.dpm.Dpm "$@"
+
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
new file mode 100644
index 0000000..3b9a785
--- /dev/null
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.dpm;
+
+import android.app.admin.IDevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+
+import com.android.internal.os.BaseCommand;
+
+import java.io.PrintStream;
+
+public final class Dpm extends BaseCommand {
+
+ /**
+ * Command-line entry point.
+ *
+ * @param args The command-line arguments
+ */
+ public static void main(String[] args) {
+ (new Dpm()).run(args);
+ }
+
+ private static final String COMMAND_SET_DEVICE_OWNER = "set-device-owner";
+ private static final String COMMAND_SET_PROFILE_OWNER = "set-profile-owner";
+
+ private IDevicePolicyManager mDevicePolicyManager;
+
+ @Override
+ public void onShowUsage(PrintStream out) {
+ out.println(
+ "usage: dpm [subcommand] [options]\n" +
+ "usage: dpm set-device-owner <COMPONENT>\n" +
+ "usage: dpm set-profile-owner <COMPONENT> <USER_ID>\n" +
+ "\n" +
+ "dpm set-device-owner: Sets the given component as active admin, and its\n" +
+ " package as device owner.\n" +
+ "\n" +
+ "dpm set-profile-owner: Sets the given component as active admin and profile" +
+ " owner for an existing user.\n");
+ }
+
+ @Override
+ public void onRun() throws Exception {
+ mDevicePolicyManager = IDevicePolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+ if (mDevicePolicyManager == null) {
+ showError("Error: Could not access the Device Policy Manager. Is the system running?");
+ return;
+ }
+
+ String command = nextArgRequired();
+ switch (command) {
+ case COMMAND_SET_DEVICE_OWNER:
+ runSetDeviceOwner();
+ break;
+ case COMMAND_SET_PROFILE_OWNER:
+ runSetProfileOwner();
+ break;
+ default:
+ throw new IllegalArgumentException ("unknown command '" + command + "'");
+ }
+ }
+
+ private void runSetDeviceOwner() throws RemoteException {
+ ComponentName component = parseComponentName(nextArgRequired());
+ mDevicePolicyManager.setActiveAdmin(component, true /*refreshing*/, UserHandle.USER_OWNER);
+
+ String packageName = component.getPackageName();
+ try {
+ if (!mDevicePolicyManager.setDeviceOwner(packageName, null /*ownerName*/)) {
+ throw new RuntimeException(
+ "Can't set package " + packageName + " as device owner.");
+ }
+ } catch (Exception e) {
+ // Need to remove the admin that we just added.
+ mDevicePolicyManager.removeActiveAdmin(component, UserHandle.USER_OWNER);
+ throw e;
+ }
+ System.out.println("Success: Device owner set to package " + packageName);
+ System.out.println("Active admin set to component " + component.toShortString());
+ }
+
+ private void runSetProfileOwner() throws RemoteException {
+ ComponentName component = parseComponentName(nextArgRequired());
+ int userId = parseInt(nextArgRequired());
+ mDevicePolicyManager.setActiveAdmin(component, true /*refreshing*/, userId);
+
+ try {
+ if (!mDevicePolicyManager.setProfileOwner(component, "" /*ownerName*/, userId)) {
+ throw new RuntimeException("Can't set component " + component.toShortString() +
+ " as profile owner for user " + userId);
+ }
+ } catch (Exception e) {
+ // Need to remove the admin that we just added.
+ mDevicePolicyManager.removeActiveAdmin(component, userId);
+ throw e;
+ }
+ System.out.println("Success: Active admin and profile owner set to "
+ + component.toShortString() + " for user " + userId);
+ }
+
+ private ComponentName parseComponentName(String component) {
+ ComponentName cn = ComponentName.unflattenFromString(component);
+ if (cn == null) {
+ throw new IllegalArgumentException ("Invalid component " + component);
+ }
+ return cn;
+ }
+
+ private int parseInt(String argument) {
+ try {
+ return Integer.parseInt(argument);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException ("Invalid integer argument '" + argument + "'", e);
+ }
+ }
+} \ No newline at end of file
diff --git a/cmds/idmap/create.cpp b/cmds/idmap/create.cpp
index ae35f7b..593a197 100644
--- a/cmds/idmap/create.cpp
+++ b/cmds/idmap/create.cpp
@@ -105,7 +105,7 @@ fail:
uint32_t cached_target_crc, cached_overlay_crc;
String8 cached_target_path, cached_overlay_path;
- if (!ResTable::getIdmapInfo(buf, N, &cached_target_crc, &cached_overlay_crc,
+ if (!ResTable::getIdmapInfo(buf, N, NULL, &cached_target_crc, &cached_overlay_crc,
&cached_target_path, &cached_overlay_path)) {
return true;
}
diff --git a/cmds/idmap/idmap.cpp b/cmds/idmap/idmap.cpp
index 46c0edc..90cfa2c 100644
--- a/cmds/idmap/idmap.cpp
+++ b/cmds/idmap/idmap.cpp
@@ -66,26 +66,32 @@ EXAMPLES \n\
Display an idmap file: \n\
\n\
$ adb shell idmap --inspect /data/resource-cache/vendor@overlay@overlay.apk@idmap \n\
- SECTION ENTRY VALUE OFFSET COMMENT \n\
- IDMAP HEADER magic 0x706d6469 0x0 \n\
- base crc 0x484aa77f 0x1 \n\
- overlay crc 0x03c66fa5 0x2 \n\
- base path .......... 0x03-0x42 /system/app/target.apk \n\
- overlay path .......... 0x43-0x82 /vendor/overlay/overlay.apk \n\
- DATA HEADER types count 0x00000003 0x83 \n\
- padding 0x00000000 0x84 \n\
- type offset 0x00000004 0x85 absolute offset 0x87, xml \n\
- type offset 0x00000007 0x86 absolute offset 0x8a, string \n\
- DATA BLOCK entry count 0x00000001 0x87 \n\
- entry offset 0x00000000 0x88 \n\
- entry 0x7f020000 0x89 xml/integer \n\
- DATA BLOCK entry count 0x00000002 0x8a \n\
- entry offset 0x00000000 0x8b \n\
- entry 0x7f030000 0x8c string/str \n\
- entry 0x7f030001 0x8d string/str2 \n\
+ SECTION ENTRY VALUE COMMENT \n\
+ IDMAP HEADER magic 0x706d6469 \n\
+ base crc 0xb65a383f \n\
+ overlay crc 0x7b9675e8 \n\
+ base path .......... /path/to/target.apk \n\
+ overlay path .......... /path/to/overlay.apk \n\
+ DATA HEADER target pkg 0x0000007f \n\
+ types count 0x00000003 \n\
+ DATA BLOCK target type 0x00000002 \n\
+ overlay type 0x00000002 \n\
+ entry count 0x00000001 \n\
+ entry offset 0x00000000 \n\
+ entry 0x00000000 drawable/drawable \n\
+ DATA BLOCK target type 0x00000003 \n\
+ overlay type 0x00000003 \n\
+ entry count 0x00000001 \n\
+ entry offset 0x00000000 \n\
+ entry 0x00000000 xml/integer \n\
+ DATA BLOCK target type 0x00000004 \n\
+ overlay type 0x00000004 \n\
+ entry count 0x00000001 \n\
+ entry offset 0x00000000 \n\
+ entry 0x00000000 raw/lorem_ipsum \n\
\n\
In this example, the overlay package provides three alternative resource values:\n\
- xml/integer, string/str and string/str2.\n\
+ drawable/drawable, xml/integer, and raw/lorem_ipsum \n\
\n\
NOTES \n\
This tool and its expected invocation from installd is modelled on dexopt.";
diff --git a/cmds/idmap/inspect.cpp b/cmds/idmap/inspect.cpp
index a59f5d3..b9ac8a5 100644
--- a/cmds/idmap/inspect.cpp
+++ b/cmds/idmap/inspect.cpp
@@ -10,92 +10,108 @@
using namespace android;
-#define NEXT(b, i, o) do { if (buf.next(&i, &o) < 0) { return -1; } } while (0)
-
namespace {
- static const uint32_t IDMAP_MAGIC = 0x706d6469;
+ static const uint32_t IDMAP_MAGIC = 0x504D4449;
static const size_t PATH_LENGTH = 256;
- static const uint32_t IDMAP_HEADER_SIZE = (3 + 2 * (PATH_LENGTH / sizeof(uint32_t)));
void printe(const char *fmt, ...);
class IdmapBuffer {
private:
- char *buf_;
+ const char* buf_;
size_t len_;
- mutable size_t pos_;
+ size_t pos_;
public:
- IdmapBuffer() : buf_((char *)MAP_FAILED), len_(0), pos_(0) {}
+ IdmapBuffer() : buf_((const char *)MAP_FAILED), len_(0), pos_(0) {}
~IdmapBuffer() {
if (buf_ != MAP_FAILED) {
- munmap(buf_, len_);
+ munmap(const_cast<char*>(buf_), len_);
}
}
- int init(const char *idmap_path)
- {
+ status_t init(const char *idmap_path) {
struct stat st;
int fd;
if (stat(idmap_path, &st) < 0) {
printe("failed to stat idmap '%s': %s\n", idmap_path, strerror(errno));
- return -1;
+ return UNKNOWN_ERROR;
}
len_ = st.st_size;
if ((fd = TEMP_FAILURE_RETRY(open(idmap_path, O_RDONLY))) < 0) {
printe("failed to open idmap '%s': %s\n", idmap_path, strerror(errno));
- return -1;
+ return UNKNOWN_ERROR;
}
- if ((buf_ = (char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
+ if ((buf_ = (const char*)mmap(NULL, len_, PROT_READ, MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
close(fd);
printe("failed to mmap idmap: %s\n", strerror(errno));
- return -1;
+ return UNKNOWN_ERROR;
}
close(fd);
- return 0;
+ return NO_ERROR;
}
- int next(uint32_t *i, uint32_t *offset) const
- {
+ status_t nextUint32(uint32_t* i) {
if (!buf_) {
printe("failed to read next uint32_t: buffer not initialized\n");
- return -1;
+ return UNKNOWN_ERROR;
}
- if (pos_ + 4 > len_) {
+
+ if (pos_ + sizeof(uint32_t) > len_) {
printe("failed to read next uint32_t: end of buffer reached at pos=0x%08x\n",
pos_);
- return -1;
+ return UNKNOWN_ERROR;
+ }
+
+ if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x3) != 0) {
+ printe("failed to read next uint32_t: not aligned on 4-byte boundary\n");
+ return UNKNOWN_ERROR;
}
- *offset = pos_ / sizeof(uint32_t);
- char a = buf_[pos_++];
- char b = buf_[pos_++];
- char c = buf_[pos_++];
- char d = buf_[pos_++];
- *i = (d << 24) | (c << 16) | (b << 8) | a;
- return 0;
+
+ *i = dtohl(*reinterpret_cast<const uint32_t*>(buf_ + pos_));
+ pos_ += sizeof(uint32_t);
+ return NO_ERROR;
}
- int nextPath(char *b, uint32_t *offset_start, uint32_t *offset_end) const
- {
+ status_t nextUint16(uint16_t* i) {
+ if (!buf_) {
+ printe("failed to read next uint16_t: buffer not initialized\n");
+ return UNKNOWN_ERROR;
+ }
+
+ if (pos_ + sizeof(uint16_t) > len_) {
+ printe("failed to read next uint16_t: end of buffer reached at pos=0x%08x\n",
+ pos_);
+ return UNKNOWN_ERROR;
+ }
+
+ if ((reinterpret_cast<uintptr_t>(buf_ + pos_) & 0x1) != 0) {
+ printe("failed to read next uint32_t: not aligned on 2-byte boundary\n");
+ return UNKNOWN_ERROR;
+ }
+
+ *i = dtohs(*reinterpret_cast<const uint16_t*>(buf_ + pos_));
+ pos_ += sizeof(uint16_t);
+ return NO_ERROR;
+ }
+
+ status_t nextPath(char *b) {
if (!buf_) {
printe("failed to read next path: buffer not initialized\n");
- return -1;
+ return UNKNOWN_ERROR;
}
if (pos_ + PATH_LENGTH > len_) {
printe("failed to read next path: end of buffer reached at pos=0x%08x\n", pos_);
- return -1;
+ return UNKNOWN_ERROR;
}
memcpy(b, buf_ + pos_, PATH_LENGTH);
- *offset_start = pos_ / sizeof(uint32_t);
pos_ += PATH_LENGTH;
- *offset_end = pos_ / sizeof(uint32_t) - 1;
- return 0;
+ return NO_ERROR;
}
};
- void printe(const char *fmt, ...)
- {
+ void printe(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
@@ -104,44 +120,37 @@ namespace {
va_end(ap);
}
- void print_header()
- {
- printf("SECTION ENTRY VALUE OFFSET COMMENT\n");
+ void print_header() {
+ printf("SECTION ENTRY VALUE COMMENT\n");
}
- void print(const char *section, const char *subsection, uint32_t value, uint32_t offset,
- const char *fmt, ...)
- {
+ void print(const char *section, const char *subsection, uint32_t value, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
- printf("%-12s %-12s 0x%08x 0x%-4x ", section, subsection, value, offset);
+ printf("%-12s %-12s 0x%08x ", section, subsection, value);
vprintf(fmt, ap);
printf("\n");
va_end(ap);
}
- void print_path(const char *section, const char *subsection, uint32_t offset_start,
- uint32_t offset_end, const char *fmt, ...)
- {
+ void print_path(const char *section, const char *subsection, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
- printf("%-12s %-12s .......... 0x%02x-0x%02x ", section, subsection, offset_start,
- offset_end);
+ printf("%-12s %-12s .......... ", section, subsection);
vprintf(fmt, ap);
printf("\n");
va_end(ap);
}
- int resource_metadata(const AssetManager& am, uint32_t res_id,
- String8 *package, String8 *type, String8 *name)
- {
+ status_t resource_metadata(const AssetManager& am, uint32_t res_id,
+ String8 *package, String8 *type, String8 *name) {
const ResTable& rt = am.getResources();
struct ResTable::resource_name data;
if (!rt.getResourceName(res_id, false, &data)) {
printe("failed to get resource name id=0x%08x\n", res_id);
- return -1;
+ return UNKNOWN_ERROR;
}
if (package) {
*package = String8(String16(data.package, data.packageLen));
@@ -152,140 +161,150 @@ namespace {
if (name) {
*name = String8(String16(data.name, data.nameLen));
}
- return 0;
- }
-
- int package_id(const AssetManager& am)
- {
- return (am.getResources().getBasePackageId(0)) << 24;
+ return NO_ERROR;
}
- int parse_idmap_header(const IdmapBuffer& buf, AssetManager& am)
- {
- uint32_t i, o, e;
+ status_t parse_idmap_header(IdmapBuffer& buf, AssetManager& am) {
+ uint32_t i;
char path[PATH_LENGTH];
- NEXT(buf, i, o);
+ status_t err = buf.nextUint32(&i);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
if (i != IDMAP_MAGIC) {
printe("not an idmap file: actual magic constant 0x%08x does not match expected magic "
"constant 0x%08x\n", i, IDMAP_MAGIC);
- return -1;
+ return UNKNOWN_ERROR;
}
+
print_header();
- print("IDMAP HEADER", "magic", i, o, "");
+ print("IDMAP HEADER", "magic", i, "");
+
+ err = buf.nextUint32(&i);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ print("", "version", i, "");
- NEXT(buf, i, o);
- print("", "base crc", i, o, "");
+ err = buf.nextUint32(&i);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ print("", "base crc", i, "");
- NEXT(buf, i, o);
- print("", "overlay crc", i, o, "");
+ err = buf.nextUint32(&i);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ print("", "overlay crc", i, "");
- if (buf.nextPath(path, &o, &e) < 0) {
+ err = buf.nextPath(path);
+ if (err != NO_ERROR) {
// printe done from IdmapBuffer::nextPath
- return -1;
+ return err;
}
- print_path("", "base path", o, e, "%s", path);
+ print_path("", "base path", "%s", path);
+
if (!am.addAssetPath(String8(path), NULL)) {
printe("failed to add '%s' as asset path\n", path);
- return -1;
+ return UNKNOWN_ERROR;
}
- if (buf.nextPath(path, &o, &e) < 0) {
+ err = buf.nextPath(path);
+ if (err != NO_ERROR) {
// printe done from IdmapBuffer::nextPath
- return -1;
+ return err;
}
- print_path("", "overlay path", o, e, "%s", path);
+ print_path("", "overlay path", "%s", path);
- return 0;
+ return NO_ERROR;
}
- int parse_data_header(const IdmapBuffer& buf, const AssetManager& am, Vector<uint32_t>& types)
- {
- uint32_t i, o;
- const uint32_t numeric_package = package_id(am);
+ status_t parse_data(IdmapBuffer& buf, const AssetManager& am) {
+ const uint32_t packageId = am.getResources().getBasePackageId(0);
- NEXT(buf, i, o);
- print("DATA HEADER", "types count", i, o, "");
- const uint32_t N = i;
+ uint16_t data16;
+ status_t err = buf.nextUint16(&data16);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ print("DATA HEADER", "target pkg", static_cast<uint32_t>(data16), "");
- for (uint32_t j = 0; j < N; ++j) {
- NEXT(buf, i, o);
- if (i == 0) {
- print("", "padding", i, o, "");
- } else {
- String8 type;
- const uint32_t numeric_type = (j + 1) << 16;
- const uint32_t res_id = numeric_package | numeric_type;
- if (resource_metadata(am, res_id, NULL, &type, NULL) < 0) {
- // printe done from resource_metadata
- return -1;
- }
- print("", "type offset", i, o, "absolute offset 0x%02x, %s",
- i + IDMAP_HEADER_SIZE, type.string());
- types.add(numeric_type);
- }
+ err = buf.nextUint16(&data16);
+ if (err != NO_ERROR) {
+ return err;
}
+ print("", "types count", static_cast<uint32_t>(data16), "");
- return 0;
- }
+ uint32_t typeCount = static_cast<uint32_t>(data16);
+ while (typeCount > 0) {
+ typeCount--;
+
+ err = buf.nextUint16(&data16);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ const uint32_t targetTypeId = static_cast<uint32_t>(data16);
+ print("DATA BLOCK", "target type", targetTypeId, "");
- int parse_data_block(const IdmapBuffer& buf, const AssetManager& am, size_t numeric_type)
- {
- uint32_t i, o, n, id_offset;
- const uint32_t numeric_package = package_id(am);
-
- NEXT(buf, i, o);
- print("DATA BLOCK", "entry count", i, o, "");
- n = i;
-
- NEXT(buf, i, o);
- print("", "entry offset", i, o, "");
- id_offset = i;
-
- for ( ; n > 0; --n) {
- String8 type, name;
-
- NEXT(buf, i, o);
- if (i == 0) {
- print("", "padding", i, o, "");
- } else {
- uint32_t res_id = numeric_package | numeric_type | id_offset;
- if (resource_metadata(am, res_id, NULL, &type, &name) < 0) {
- // printe done from resource_metadata
- return -1;
+ err = buf.nextUint16(&data16);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ print("", "overlay type", static_cast<uint32_t>(data16), "");
+
+ err = buf.nextUint16(&data16);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ const uint32_t entryCount = static_cast<uint32_t>(data16);
+ print("", "entry count", entryCount, "");
+
+ err = buf.nextUint16(&data16);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ const uint32_t entryOffset = static_cast<uint32_t>(data16);
+ print("", "entry offset", entryOffset, "");
+
+ for (uint32_t i = 0; i < entryCount; i++) {
+ uint32_t data32;
+ err = buf.nextUint32(&data32);
+ if (err != NO_ERROR) {
+ return err;
}
- print("", "entry", i, o, "%s/%s", type.string(), name.string());
+
+ uint32_t resID = (packageId << 24) | (targetTypeId << 16) | (entryOffset + i);
+ String8 type;
+ String8 name;
+ err = resource_metadata(am, resID, NULL, &type, &name);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ print("", "entry", data32, "%s/%s", type.string(), name.string());
}
- ++id_offset;
}
- return 0;
+ return NO_ERROR;
}
}
-int idmap_inspect(const char *idmap_path)
-{
+int idmap_inspect(const char *idmap_path) {
IdmapBuffer buf;
if (buf.init(idmap_path) < 0) {
// printe done from IdmapBuffer::init
return EXIT_FAILURE;
}
AssetManager am;
- if (parse_idmap_header(buf, am) < 0) {
+ if (parse_idmap_header(buf, am) != NO_ERROR) {
// printe done from parse_idmap_header
return EXIT_FAILURE;
}
- Vector<uint32_t> types;
- if (parse_data_header(buf, am, types) < 0) {
+ if (parse_data(buf, am) != NO_ERROR) {
// printe done from parse_data_header
return EXIT_FAILURE;
}
- const size_t N = types.size();
- for (size_t i = 0; i < N; ++i) {
- if (parse_data_block(buf, am, types.itemAt(i)) < 0) {
- // printe done from parse_data_block
- return EXIT_FAILURE;
- }
- }
return EXIT_SUCCESS;
}
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index c5fc941..1153f38 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -119,7 +119,8 @@ namespace {
int parse_manifest(const void *data, size_t size, const char *target_package_name)
{
- ResXMLTree parser(data, size);
+ ResXMLTree parser;
+ parser.setTo(data, size);
if (parser.getError() != NO_ERROR) {
ALOGD("%s failed to init xml parser, error=0x%08x\n", __FUNCTION__, parser.getError());
return -1;
diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java
index 92c6a51..6a8fb05 100644
--- a/cmds/media/src/com/android/commands/media/Media.java
+++ b/cmds/media/src/com/android/commands/media/Media.java
@@ -17,12 +17,19 @@
package com.android.commands.media;
-import android.app.PendingIntent;
+import android.app.ActivityManager;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.media.IAudioService;
-import android.media.IRemoteControlDisplay;
+import android.content.pm.ParceledListSlice;
+import android.media.MediaMetadata;
+import android.media.session.ISessionController;
+import android.media.session.ISessionControllerCallback;
+import android.media.session.ISessionManager;
+import android.media.session.MediaController;
+import android.media.session.ParcelableVolumeInfo;
+import android.media.session.PlaybackState;
import android.os.Bundle;
+import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -30,16 +37,17 @@ import android.util.AndroidException;
import android.view.InputDevice;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+
import com.android.internal.os.BaseCommand;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
+import java.util.List;
public class Media extends BaseCommand {
-
- private IAudioService mAudioService;
+ private ISessionManager mSessionService;
/**
* Command-line entry point.
@@ -54,29 +62,35 @@ public class Media extends BaseCommand {
out.println(
"usage: media [subcommand] [options]\n" +
" media dispatch KEY\n" +
- " media remote-display\n" +
+ " media list-sessions\n" +
+ " media monitor <tag>\n" +
"\n" +
- "media dispatch: dispatch a media key to the current media client.\n" +
+ "media dispatch: dispatch a media key to the system.\n" +
" KEY may be: play, pause, play-pause, mute, headsethook,\n" +
- " stop, next, previous, rewind, recordm fast-forword.\n" +
- "media remote-display: monitor remote display updates.\n"
+ " stop, next, previous, rewind, record, fast-forword.\n" +
+ "media list-sessions: print a list of the current sessions.\n" +
+ "media monitor: monitor updates to the specified session.\n" +
+ " Use the tag from list-sessions.\n"
);
}
public void onRun() throws Exception {
- mAudioService = IAudioService.Stub.asInterface(ServiceManager.checkService(
- Context.AUDIO_SERVICE));
- if (mAudioService == null) {
+ mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService(
+ Context.MEDIA_SESSION_SERVICE));
+ if (mSessionService == null) {
System.err.println(NO_SYSTEM_ERROR_CODE);
- throw new AndroidException("Can't connect to audio service; is the system running?");
+ throw new AndroidException(
+ "Can't connect to media session service; is the system running?");
}
String op = nextArgRequired();
if (op.equals("dispatch")) {
runDispatch();
- } else if (op.equals("remote-display")) {
- runRemoteDisplay();
+ } else if (op.equals("list-sessions")) {
+ runListSessions();
+ } else if (op.equals("monitor")) {
+ runMonitor();
} else {
showError("Error: unknown command '" + op + "'");
return;
@@ -85,11 +99,42 @@ public class Media extends BaseCommand {
private void sendMediaKey(KeyEvent event) {
try {
- mAudioService.dispatchMediaKeyEvent(event);
+ mSessionService.dispatchMediaKeyEvent(event, false);
} catch (RemoteException e) {
}
}
+ private void runMonitor() throws Exception {
+ String id = nextArgRequired();
+ if (id == null) {
+ showError("Error: must include a session id");
+ return;
+ }
+ boolean success = false;
+ try {
+ List<IBinder> sessions = mSessionService
+ .getSessions(null, ActivityManager.getCurrentUser());
+ for (IBinder session : sessions) {
+ ISessionController controller = ISessionController.Stub.asInterface(session);
+ try {
+ if (controller != null && id.equals(controller.getTag())) {
+ ControllerMonitor monitor = new ControllerMonitor(controller);
+ monitor.run();
+ success = true;
+ break;
+ }
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("***Error monitoring session*** " + e.getMessage());
+ }
+ if (!success) {
+ System.out.println("No session found with id " + id);
+ }
+ }
+
private void runDispatch() throws Exception {
String cmd = nextArgRequired();
int keycode;
@@ -127,65 +172,80 @@ public class Media extends BaseCommand {
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_KEYBOARD));
}
- class RemoteDisplayMonitor extends IRemoteControlDisplay.Stub {
- RemoteDisplayMonitor() {
+ class ControllerMonitor extends ISessionControllerCallback.Stub {
+ private final ISessionController mController;
+
+ public ControllerMonitor(ISessionController controller) {
+ mController = controller;
}
+ @Override
+ public void onSessionDestroyed() {
+ System.out.println("onSessionDestroyed. Enter q to quit.");
+
+ }
@Override
- public void setCurrentClientId(int clientGeneration, PendingIntent clientMediaIntent,
- boolean clearing) {
- System.out.println("New client: id=" + clientGeneration
- + " intent=" + clientMediaIntent + " clearing=" + clearing);
+ public void onEvent(String event, Bundle extras) {
+ System.out.println("onSessionEvent event=" + event + ", extras=" + extras);
}
@Override
- public void setEnabled(boolean enabled) {
- System.out.println("New enable state= " + (enabled ? "enabled" : "disabled"));
+ public void onPlaybackStateChanged(PlaybackState state) {
+ System.out.println("onPlaybackStateChanged " + state);
}
@Override
- public void setPlaybackState(int generationId, int state, long stateChangeTimeMs,
- long currentPosMs, float speed) {
- System.out.println("New state: id=" + generationId + " state=" + state
- + " time=" + stateChangeTimeMs + " pos=" + currentPosMs + " speed=" + speed);
+ public void onMetadataChanged(MediaMetadata metadata) {
+ String mmString = metadata == null ? null : "title=" + metadata
+ .getDescription();
+ System.out.println("onMetadataChanged " + mmString);
}
@Override
- public void setTransportControlInfo(int generationId, int transportControlFlags,
- int posCapabilities) {
- System.out.println("New control info: id=" + generationId
- + " flags=0x" + Integer.toHexString(transportControlFlags)
- + " cap=0x" + Integer.toHexString(posCapabilities));
+ public void onQueueChanged(ParceledListSlice queue) throws RemoteException {
+ System.out.println("onQueueChanged, "
+ + (queue == null ? "null queue" : " size=" + queue.getList().size()));
}
@Override
- public void setMetadata(int generationId, Bundle metadata) {
- System.out.println("New metadata: id=" + generationId
- + " data=" + metadata);
+ public void onQueueTitleChanged(CharSequence title) throws RemoteException {
+ System.out.println("onQueueTitleChange " + title);
}
@Override
- public void setArtwork(int generationId, Bitmap artwork) {
- System.out.println("New artwork: id=" + generationId
- + " art=" + artwork);
+ public void onExtrasChanged(Bundle extras) throws RemoteException {
+ System.out.println("onExtrasChanged " + extras);
}
@Override
- public void setAllMetadata(int generationId, Bundle metadata, Bitmap artwork) {
- System.out.println("New metadata+artwork: id=" + generationId
- + " data=" + metadata + " art=" + artwork);
+ public void onVolumeInfoChanged(ParcelableVolumeInfo info) throws RemoteException {
+ System.out.println("onVolumeInfoChanged " + info);
}
void printUsageMessage() {
- System.out.println("Monitoring remote control displays... available commands:");
+ try {
+ System.out.println("V2Monitoring session " + mController.getTag()
+ + "... available commands: play, pause, next, previous");
+ } catch (RemoteException e) {
+ System.out.println("Error trying to monitor session!");
+ }
System.out.println("(q)uit: finish monitoring");
}
void run() throws RemoteException {
printUsageMessage();
-
- mAudioService.registerRemoteControlDisplay(this, 0, 0);
+ HandlerThread cbThread = new HandlerThread("MediaCb") {
+ @Override
+ protected void onLooperPrepared() {
+ try {
+ mController.registerCallbackListener(ControllerMonitor.this);
+ } catch (RemoteException e) {
+ System.out.println("Error registering monitor callback");
+ }
+ }
+ };
+ cbThread.start();
try {
InputStreamReader converter = new InputStreamReader(System.in);
@@ -198,6 +258,14 @@ public class Media extends BaseCommand {
addNewline = false;
} else if ("q".equals(line) || "quit".equals(line)) {
break;
+ } else if ("play".equals(line)) {
+ mController.play();
+ } else if ("pause".equals(line)) {
+ mController.pause();
+ } else if ("next".equals(line)) {
+ mController.next();
+ } else if ("previous".equals(line)) {
+ mController.previous();
} else {
System.out.println("Invalid command: " + line);
}
@@ -209,17 +277,38 @@ public class Media extends BaseCommand {
printUsageMessage();
}
}
-
} catch (IOException e) {
e.printStackTrace();
} finally {
- mAudioService.unregisterRemoteControlDisplay(this);
+ cbThread.getLooper().quit();
+ try {
+ mController.unregisterCallbackListener(this);
+ } catch (Exception e) {
+ // ignoring
+ }
}
}
}
- private void runRemoteDisplay() throws Exception {
- RemoteDisplayMonitor monitor = new RemoteDisplayMonitor();
- monitor.run();
+ private void runListSessions() {
+ System.out.println("Sessions:");
+ try {
+ List<IBinder> sessions = mSessionService
+ .getSessions(null, ActivityManager.getCurrentUser());
+ for (IBinder session : sessions) {
+
+ ISessionController controller = ISessionController.Stub.asInterface(session);
+ if (controller != null) {
+ try {
+ System.out.println(" tag=" + controller.getTag()
+ + ", package=" + controller.getPackageName());
+ } catch (RemoteException e) {
+ // ignore
+ }
+ }
+ }
+ } catch (Exception e) {
+ System.out.println("***Error listing sessions***");
+ }
}
}
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 75b0a82..5e9d8f7 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -18,16 +18,23 @@ package com.android.commands.pm;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.PackageInstallObserver;
import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
+import android.content.Intent;
+import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
-import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageInstallObserver;
+import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
@@ -39,30 +46,43 @@ import android.content.res.AssetManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
+import android.os.Bundle;
import android.os.IUserManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.content.PackageHelper;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.SizedInputStream;
+
+import libcore.io.IoUtils;
import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.security.InvalidAlgorithmParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.WeakHashMap;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import com.android.internal.content.PackageHelper;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
public final class Pm {
+ private static final String TAG = "Pm";
+
IPackageManager mPm;
+ IPackageInstaller mInstaller;
IUserManager mUm;
private WeakHashMap<String, Resources> mResourceCache
@@ -76,10 +96,18 @@ public final class Pm {
"Error: Could not access the Package Manager. Is the system running?";
public static void main(String[] args) {
- new Pm().run(args);
+ try {
+ new Pm().run(args);
+ } catch (Exception e) {
+ Log.e(TAG, "Error", e);
+ System.err.println("Error: " + e);
+ if (e instanceof RemoteException) {
+ System.err.println(PM_NOT_RUNNING_ERR);
+ }
+ }
}
- public void run(String[] args) {
+ public void run(String[] args) throws IOException, RemoteException {
boolean validCommand = false;
if (args.length < 1) {
showUsage();
@@ -92,6 +120,7 @@ public final class Pm {
System.err.println(PM_NOT_RUNNING_ERR);
return;
}
+ mInstaller = mPm.getPackageInstaller();
mArgs = args;
String op = args[0];
@@ -117,6 +146,31 @@ public final class Pm {
return;
}
+ if ("install-create".equals(op)) {
+ runInstallCreate();
+ return;
+ }
+
+ if ("install-write".equals(op)) {
+ runInstallWrite();
+ return;
+ }
+
+ if ("install-commit".equals(op)) {
+ runInstallCommit();
+ return;
+ }
+
+ if ("install-abandon".equals(op) || "install-destroy".equals(op)) {
+ runInstallAbandon();
+ return;
+ }
+
+ if ("set-installer".equals(op)) {
+ runSetInstaller();
+ return;
+ }
+
if ("uninstall".equals(op)) {
runUninstall();
return;
@@ -147,13 +201,13 @@ public final class Pm {
return;
}
- if ("block".equals(op)) {
- runSetBlockedSetting(true);
+ if ("hide".equals(op)) {
+ runSetHiddenSetting(true);
return;
}
- if ("unblock".equals(op)) {
- runSetBlockedSetting(false);
+ if ("unhide".equals(op)) {
+ runSetHiddenSetting(false);
return;
}
@@ -202,6 +256,11 @@ public final class Pm {
return;
}
+ if ("force-dex-opt".equals(op)) {
+ runForceDexOpt();
+ return;
+ }
+
try {
if (args.length == 1) {
if (args[0].equalsIgnoreCase("-l")) {
@@ -698,14 +757,23 @@ public final class Pm {
ActivityManager.dumpPackageStateStatic(FileDescriptor.out, pkg);
}
- class PackageInstallObserver extends IPackageInstallObserver.Stub {
+ class LocalPackageInstallObserver extends PackageInstallObserver {
boolean finished;
int result;
+ String extraPermission;
+ String extraPackage;
- public void packageInstalled(String name, int status) {
- synchronized( this) {
+ @Override
+ public void onPackageInstalled(String name, int status, String msg, Bundle extras) {
+ synchronized (this) {
finished = true;
result = status;
+ if (status == PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION) {
+ extraPermission = extras.getString(
+ PackageManager.EXTRA_FAILURE_EXISTING_PERMISSION);
+ extraPackage = extras.getString(
+ PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
+ }
notifyAll();
}
}
@@ -715,7 +783,8 @@ public final class Pm {
* Converts a failure code into a string by using reflection to find a matching constant
* in PackageManager.
*/
- private String installFailureToString(int result) {
+ private String installFailureToString(LocalPackageInstallObserver obs) {
+ final int result = obs.result;
Field[] fields = PackageManager.class.getFields();
for (Field f: fields) {
if (f.getType() == int.class) {
@@ -730,7 +799,16 @@ public final class Pm {
// get the int value and compare it to result.
try {
if (result == f.getInt(null)) {
- return fieldName;
+ StringBuilder sb = new StringBuilder(64);
+ sb.append(fieldName);
+ if (obs.extraPermission != null) {
+ sb.append(" perm=");
+ sb.append(obs.extraPermission);
+ }
+ if (obs.extraPackage != null) {
+ sb.append(" pkg=" + obs.extraPackage);
+ }
+ return sb.toString();
}
} catch (IllegalAccessException e) {
// this shouldn't happen since we only look for public static fields.
@@ -787,18 +865,12 @@ public final class Pm {
}
private void runInstall() {
- int installFlags = PackageManager.INSTALL_ALL_USERS;
+ int installFlags = 0;
+ int userId = UserHandle.USER_ALL;
String installerPackageName = null;
String opt;
- String algo = null;
- byte[] iv = null;
- byte[] key = null;
-
- String macAlgo = null;
- byte[] macKey = null;
- byte[] tag = null;
String originatingUriString = null;
String referrer = null;
String abi = null;
@@ -824,42 +896,6 @@ public final class Pm {
installFlags |= PackageManager.INSTALL_INTERNAL;
} else if (opt.equals("-d")) {
installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
- } else if (opt.equals("--algo")) {
- algo = nextOptionData();
- if (algo == null) {
- System.err.println("Error: must supply argument for --algo");
- return;
- }
- } else if (opt.equals("--iv")) {
- iv = hexToBytes(nextOptionData());
- if (iv == null) {
- System.err.println("Error: must supply argument for --iv");
- return;
- }
- } else if (opt.equals("--key")) {
- key = hexToBytes(nextOptionData());
- if (key == null) {
- System.err.println("Error: must supply argument for --key");
- return;
- }
- } else if (opt.equals("--macalgo")) {
- macAlgo = nextOptionData();
- if (macAlgo == null) {
- System.err.println("Error: must supply argument for --macalgo");
- return;
- }
- } else if (opt.equals("--mackey")) {
- macKey = hexToBytes(nextOptionData());
- if (macKey == null) {
- System.err.println("Error: must supply argument for --mackey");
- return;
- }
- } else if (opt.equals("--tag")) {
- tag = hexToBytes(nextOptionData());
- if (tag == null) {
- System.err.println("Error: must supply argument for --tag");
- return;
- }
} else if (opt.equals("--originating-uri")) {
originatingUriString = nextOptionData();
if (originatingUriString == null) {
@@ -873,70 +909,20 @@ public final class Pm {
return;
}
} else if (opt.equals("--abi")) {
- abi = nextOptionData();
- if (abi == null) {
- System.err.println("Error: must supply argument for --abi");
- return;
- }
+ abi = checkAbiArgument(nextOptionData());
+ } else if (opt.equals("--user")) {
+ userId = Integer.parseInt(nextOptionData());
} else {
System.err.println("Error: Unknown option: " + opt);
return;
}
}
- if (abi != null) {
- final String[] supportedAbis = Build.SUPPORTED_ABIS;
- boolean matched = false;
- for (String supportedAbi : supportedAbis) {
- if (supportedAbi.equals(abi)) {
- matched = true;
- break;
- }
- }
-
- if (!matched) {
- System.err.println("Error: abi " + abi + " not supported on this device.");
- return;
- }
- }
-
- final ContainerEncryptionParams encryptionParams;
- if (algo != null || iv != null || key != null || macAlgo != null || macKey != null
- || tag != null) {
- if (algo == null || iv == null || key == null) {
- System.err.println("Error: all of --algo, --iv, and --key must be specified");
- return;
- }
-
- if (macAlgo != null || macKey != null || tag != null) {
- if (macAlgo == null || macKey == null || tag == null) {
- System.err.println("Error: all of --macalgo, --mackey, and --tag must "
- + "be specified");
- return;
- }
- }
-
- try {
- final SecretKey encKey = new SecretKeySpec(key, "RAW");
-
- final SecretKey macSecretKey;
- if (macKey == null || macKey.length == 0) {
- macSecretKey = null;
- } else {
- macSecretKey = new SecretKeySpec(macKey, "RAW");
- }
-
- encryptionParams = new ContainerEncryptionParams(algo, new IvParameterSpec(iv),
- encKey, macAlgo, null, macSecretKey, tag, -1, -1, -1);
- } catch (InvalidAlgorithmParameterException e) {
- e.printStackTrace();
- return;
- }
- } else {
- encryptionParams = null;
+ if (userId == UserHandle.USER_ALL) {
+ userId = UserHandle.USER_OWNER;
+ installFlags |= PackageManager.INSTALL_ALL_USERS;
}
- final Uri apkURI;
final Uri verificationURI;
final Uri originatingURI;
final Uri referrerURI;
@@ -956,9 +942,7 @@ public final class Pm {
// Populate apkURI, must be present
final String apkFilePath = nextArg();
System.err.println("\tpkg: " + apkFilePath);
- if (apkFilePath != null) {
- apkURI = Uri.fromFile(new File(apkFilePath));
- } else {
+ if (apkFilePath == null) {
System.err.println("Error: no package specified");
return;
}
@@ -972,14 +956,13 @@ public final class Pm {
verificationURI = null;
}
- PackageInstallObserver obs = new PackageInstallObserver();
+ LocalPackageInstallObserver obs = new LocalPackageInstallObserver();
try {
VerificationParams verificationParams = new VerificationParams(verificationURI,
originatingURI, referrerURI, VerificationParams.NO_UID, null);
- mPm.installPackageWithVerificationEncryptionAndAbiOverride(apkURI, obs,
- installFlags, installerPackageName, verificationParams,
- encryptionParams, abi);
+ mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags,
+ installerPackageName, verificationParams, abi, userId);
synchronized (obs) {
while (!obs.finished) {
@@ -992,7 +975,7 @@ public final class Pm {
System.out.println("Success");
} else {
System.err.println("Failure ["
- + installFailureToString(obs.result)
+ + installFailureToString(obs)
+ "]");
}
}
@@ -1002,39 +985,200 @@ public final class Pm {
}
}
- /**
- * Convert a string containing hex-encoded bytes to a byte array.
- *
- * @param input String containing hex-encoded bytes
- * @return input as an array of bytes
- */
- private byte[] hexToBytes(String input) {
- if (input == null) {
- return null;
+ private void runInstallCreate() throws RemoteException {
+ int userId = UserHandle.USER_ALL;
+ String installerPackageName = null;
+
+ final SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
+
+ String opt;
+ while ((opt = nextOption()) != null) {
+ if (opt.equals("-l")) {
+ params.installFlags |= PackageManager.INSTALL_FORWARD_LOCK;
+ } else if (opt.equals("-r")) {
+ params.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
+ } else if (opt.equals("-i")) {
+ installerPackageName = nextArg();
+ if (installerPackageName == null) {
+ throw new IllegalArgumentException("Missing installer package");
+ }
+ } else if (opt.equals("-t")) {
+ params.installFlags |= PackageManager.INSTALL_ALLOW_TEST;
+ } else if (opt.equals("-s")) {
+ params.installFlags |= PackageManager.INSTALL_EXTERNAL;
+ } else if (opt.equals("-f")) {
+ params.installFlags |= PackageManager.INSTALL_INTERNAL;
+ } else if (opt.equals("-d")) {
+ params.installFlags |= PackageManager.INSTALL_ALLOW_DOWNGRADE;
+ } else if (opt.equals("--originating-uri")) {
+ params.originatingUri = Uri.parse(nextOptionData());
+ } else if (opt.equals("--referrer")) {
+ params.referrerUri = Uri.parse(nextOptionData());
+ } else if (opt.equals("-p")) {
+ params.mode = SessionParams.MODE_INHERIT_EXISTING;
+ params.appPackageName = nextOptionData();
+ if (params.appPackageName == null) {
+ throw new IllegalArgumentException("Missing inherit package name");
+ }
+ } else if (opt.equals("-S")) {
+ params.setSize(Long.parseLong(nextOptionData()));
+ } else if (opt.equals("--abi")) {
+ params.abiOverride = checkAbiArgument(nextOptionData());
+ } else if (opt.equals("--user")) {
+ userId = Integer.parseInt(nextOptionData());
+ } else {
+ throw new IllegalArgumentException("Unknown option " + opt);
+ }
}
- final int inputLength = input.length();
- if ((inputLength % 2) != 0) {
- System.err.print("Invalid length; must be multiple of 2");
- return null;
+ if (userId == UserHandle.USER_ALL) {
+ userId = UserHandle.USER_OWNER;
+ params.installFlags |= PackageManager.INSTALL_ALL_USERS;
+ }
+
+ final int sessionId = mInstaller.createSession(params, installerPackageName, userId);
+
+ // NOTE: adb depends on parsing this string
+ System.out.println("Success: created install session [" + sessionId + "]");
+ }
+
+ private void runInstallWrite() throws IOException, RemoteException {
+ long sizeBytes = -1;
+
+ String opt;
+ while ((opt = nextOption()) != null) {
+ if (opt.equals("-S")) {
+ sizeBytes = Long.parseLong(nextOptionData());
+ } else {
+ throw new IllegalArgumentException("Unknown option: " + opt);
+ }
+ }
+
+ final int sessionId = Integer.parseInt(nextArg());
+ final String splitName = nextArg();
+
+ String path = nextArg();
+ if ("-".equals(path)) {
+ path = null;
+ } else if (path != null) {
+ final File file = new File(path);
+ if (file.isFile()) {
+ sizeBytes = file.length();
+ }
}
- final int byteLength = inputLength / 2;
- final byte[] output = new byte[byteLength];
+ final SessionInfo info = mInstaller.getSessionInfo(sessionId);
- int inputIndex = 0;
- int byteIndex = 0;
- while (inputIndex < inputLength) {
- output[byteIndex++] = (byte) Integer.parseInt(
- input.substring(inputIndex, inputIndex + 2), 16);
- inputIndex += 2;
+ PackageInstaller.Session session = null;
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
+
+ if (path != null) {
+ in = new FileInputStream(path);
+ } else {
+ in = new SizedInputStream(System.in, sizeBytes);
+ }
+ out = session.openWrite(splitName, 0, sizeBytes);
+
+ int total = 0;
+ byte[] buffer = new byte[65536];
+ int c;
+ while ((c = in.read(buffer)) != -1) {
+ total += c;
+ out.write(buffer, 0, c);
+
+ if (info.sizeBytes > 0) {
+ final float fraction = ((float) c / (float) info.sizeBytes);
+ session.addProgress(fraction);
+ }
+ }
+ session.fsync(out);
+
+ System.out.println("Success: streamed " + total + " bytes");
+ } finally {
+ IoUtils.closeQuietly(out);
+ IoUtils.closeQuietly(in);
+ IoUtils.closeQuietly(session);
}
+ }
- return output;
+ private void runInstallCommit() throws RemoteException {
+ final int sessionId = Integer.parseInt(nextArg());
+
+ PackageInstaller.Session session = null;
+ try {
+ session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
+
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ session.commit(receiver.getIntentSender());
+
+ final Intent result = receiver.getResult();
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == PackageInstaller.STATUS_SUCCESS) {
+ System.out.println("Success");
+ } else {
+ Log.e(TAG, "Failure details: " + result.getExtras());
+ System.out.println("Failure ["
+ + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
+ return;
+ }
+ } finally {
+ IoUtils.closeQuietly(session);
+ }
+ }
+
+ private void runInstallAbandon() throws RemoteException {
+ final int sessionId = Integer.parseInt(nextArg());
+
+ PackageInstaller.Session session = null;
+ try {
+ session = new PackageInstaller.Session(mInstaller.openSession(sessionId));
+ session.abandon();
+ System.out.println("Success");
+ } finally {
+ IoUtils.closeQuietly(session);
+ }
+ }
+
+ private void runSetInstaller() throws RemoteException {
+ final String targetPackage = nextArg();
+ final String installerPackageName = nextArg();
+
+ if (targetPackage == null || installerPackageName == null) {
+ throw new IllegalArgumentException(
+ "must provide both target and installer package names");
+ }
+
+ mPm.setInstallerPackageName(targetPackage, installerPackageName);
+ System.out.println("Success");
}
public void runCreateUser() {
String name;
+ int userId = -1;
+ int flags = 0;
+ String opt;
+ while ((opt = nextOption()) != null) {
+ if ("--profileOf".equals(opt)) {
+ String optionData = nextOptionData();
+ if (optionData == null || !isNumber(optionData)) {
+ System.err.println("Error: no USER_ID specified");
+ showUsage();
+ return;
+ } else {
+ userId = Integer.parseInt(optionData);
+ }
+ } else if ("--managed".equals(opt)) {
+ flags |= UserInfo.FLAG_MANAGED_PROFILE;
+ } else {
+ System.err.println("Error: unknown option " + opt);
+ showUsage();
+ return;
+ }
+ }
String arg = nextArg();
if (arg == null) {
System.err.println("Error: no user name specified.");
@@ -1042,7 +1186,12 @@ public final class Pm {
}
name = arg;
try {
- final UserInfo info = mUm.createUser(name, 0);
+ UserInfo info = null;
+ if (userId < 0) {
+ info = mUm.createUser(name, flags);
+ } else {
+ info = mUm.createProfileForUser(name, flags, userId);
+ }
if (info != null) {
System.out.println("Success: created user id " + info.id);
} else {
@@ -1082,13 +1231,16 @@ public final class Pm {
public void runListUsers() {
try {
+ IActivityManager am = ActivityManagerNative.getDefault();
+
List<UserInfo> users = mUm.getUsers(false);
if (users == null) {
System.err.println("Error: couldn't get users");
} else {
System.out.println("Users:");
for (int i = 0; i < users.size(); i++) {
- System.out.println("\t" + users.get(i).toString());
+ String running = am.isUserRunning(users.get(i).id, false) ? " running" : "";
+ System.out.println("\t" + users.get(i).toString() + running);
}
}
} catch (RemoteException e) {
@@ -1101,26 +1253,32 @@ public final class Pm {
System.out.println("Maximum supported users: " + UserManager.getMaxSupportedUsers());
}
- class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
- boolean finished;
- boolean result;
-
- public void packageDeleted(String packageName, int returnCode) {
- synchronized (this) {
- finished = true;
- result = returnCode == PackageManager.DELETE_SUCCEEDED;
- notifyAll();
- }
+ public void runForceDexOpt() {
+ final String packageName = nextArg();
+ try {
+ mPm.forceDexOpt(packageName);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
}
}
- private void runUninstall() {
- int unInstallFlags = PackageManager.DELETE_ALL_USERS;
+ private void runUninstall() throws RemoteException {
+ int flags = 0;
+ int userId = UserHandle.USER_ALL;
String opt;
while ((opt=nextOption()) != null) {
if (opt.equals("-k")) {
- unInstallFlags |= PackageManager.DELETE_KEEP_DATA;
+ flags |= PackageManager.DELETE_KEEP_DATA;
+ } else if (opt.equals("--user")) {
+ String param = nextArg();
+ if (isNumber(param)) {
+ userId = Integer.parseInt(param);
+ } else {
+ showUsage();
+ System.err.println("Error: Invalid user: " + param);
+ return;
+ }
} else {
System.err.println("Error: Unknown option: " + opt);
return;
@@ -1133,32 +1291,46 @@ public final class Pm {
showUsage();
return;
}
- boolean result = deletePackage(pkg, unInstallFlags);
- if (result) {
- System.out.println("Success");
+
+ if (userId == UserHandle.USER_ALL) {
+ userId = UserHandle.USER_OWNER;
+ flags |= PackageManager.DELETE_ALL_USERS;
} else {
- System.out.println("Failure");
+ PackageInfo info;
+ try {
+ info = mPm.getPackageInfo(pkg, 0, userId);
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(PM_NOT_RUNNING_ERR);
+ return;
+ }
+ if (info == null) {
+ System.err.println("Failure - not installed for " + userId);
+ return;
+ }
+ final boolean isSystem =
+ (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ // If we are being asked to delete a system app for just one
+ // user set flag so it disables rather than reverting to system
+ // version of the app.
+ if (isSystem) {
+ flags |= PackageManager.DELETE_SYSTEM_APP;
+ }
}
- }
- private boolean deletePackage(String pkg, int unInstallFlags) {
- PackageDeleteObserver obs = new PackageDeleteObserver();
- try {
- mPm.deletePackageAsUser(pkg, obs, UserHandle.USER_OWNER, unInstallFlags);
+ final LocalIntentReceiver receiver = new LocalIntentReceiver();
+ mInstaller.uninstall(pkg, flags, receiver.getIntentSender(), userId);
- synchronized (obs) {
- while (!obs.finished) {
- try {
- obs.wait();
- } catch (InterruptedException e) {
- }
- }
- }
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(PM_NOT_RUNNING_ERR);
+ final Intent result = receiver.getResult();
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status == PackageInstaller.STATUS_SUCCESS) {
+ System.out.println("Success");
+ } else {
+ Log.e(TAG, "Failure details: " + result.getExtras());
+ System.out.println("Failure ["
+ + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]");
}
- return obs.result;
}
static class ClearDataObserver extends IPackageDataObserver.Stub {
@@ -1173,7 +1345,6 @@ public final class Pm {
notifyAll();
}
}
-
}
private void runClear() {
@@ -1290,7 +1461,7 @@ public final class Pm {
}
}
- private void runSetBlockedSetting(boolean state) {
+ private void runSetHiddenSetting(boolean state) {
int userId = 0;
String option = nextOption();
if (option != null && option.equals("--user")) {
@@ -1311,9 +1482,9 @@ public final class Pm {
return;
}
try {
- mPm.setApplicationBlockedSettingAsUser(pkg, state, userId);
- System.err.println("Package " + pkg + " new blocked state: "
- + mPm.getApplicationBlockedSettingAsUser(pkg, userId));
+ mPm.setApplicationHiddenSettingAsUser(pkg, state, userId);
+ System.err.println("Package " + pkg + " new hidden state: "
+ + mPm.getApplicationHiddenSettingAsUser(pkg, userId));
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(PM_NOT_RUNNING_ERR);
@@ -1456,6 +1627,12 @@ public final class Pm {
if (info != null && info.applicationInfo != null) {
System.out.print("package:");
System.out.println(info.applicationInfo.sourceDir);
+ if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) {
+ for (String splitSourceDir : info.applicationInfo.splitSourceDirs) {
+ System.out.print("package:");
+ System.out.println(splitSourceDir);
+ }
+ }
}
} catch (RemoteException e) {
System.err.println(e.toString());
@@ -1481,6 +1658,54 @@ public final class Pm {
}
}
+ private static String checkAbiArgument(String abi) {
+ if (TextUtils.isEmpty(abi)) {
+ throw new IllegalArgumentException("Missing ABI argument");
+ }
+
+ if ("-".equals(abi)) {
+ return abi;
+ }
+
+ final String[] supportedAbis = Build.SUPPORTED_ABIS;
+ for (String supportedAbi : supportedAbis) {
+ if (supportedAbi.equals(abi)) {
+ return abi;
+ }
+ }
+
+ throw new IllegalArgumentException("ABI " + abi + " not supported on this device");
+ }
+
+ private static class LocalIntentReceiver {
+ private final SynchronousQueue<Intent> mResult = new SynchronousQueue<>();
+
+ private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {
+ @Override
+ public int send(int code, Intent intent, String resolvedType,
+ IIntentReceiver finishedReceiver, String requiredPermission) {
+ try {
+ mResult.offer(intent, 5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ return 0;
+ }
+ };
+
+ public IntentSender getIntentSender() {
+ return new IntentSender((IIntentSender) mLocalSender);
+ }
+
+ public Intent getResult() {
+ try {
+ return mResult.take();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
private String nextOption() {
if (mNextArg >= mArgs.length) {
return null;
@@ -1537,24 +1762,27 @@ public final class Pm {
System.err.println(" pm list users");
System.err.println(" pm path PACKAGE");
System.err.println(" pm dump PACKAGE");
- System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f]");
- System.err.println(" [--algo <algorithm name> --key <key-in-hex> --iv <IV-in-hex>]");
- System.err.println(" [--originating-uri <URI>] [--referrer <URI>] PATH");
- System.err.println(" pm uninstall [-k] PACKAGE");
+ System.err.println(" pm install [-lrtsfd] [-i PACKAGE] [PATH]");
+ System.err.println(" pm install-create [-lrtsfdp] [-i PACKAGE] [-S BYTES]");
+ System.err.println(" pm install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH]");
+ System.err.println(" pm install-commit SESSION_ID");
+ System.err.println(" pm install-abandon SESSION_ID");
+ System.err.println(" pm uninstall [-k] [--user USER_ID] PACKAGE");
+ System.err.println(" pm set-installer PACKAGE INSTALLER");
System.err.println(" pm clear [--user USER_ID] PACKAGE");
System.err.println(" pm enable [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm disable [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm disable-user [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT");
- System.err.println(" pm block [--user USER_ID] PACKAGE_OR_COMPONENT");
- System.err.println(" pm unblock [--user USER_ID] PACKAGE_OR_COMPONENT");
+ System.err.println(" pm hide [--user USER_ID] PACKAGE_OR_COMPONENT");
+ System.err.println(" pm unhide [--user USER_ID] PACKAGE_OR_COMPONENT");
System.err.println(" pm grant PACKAGE PERMISSION");
System.err.println(" pm revoke PACKAGE PERMISSION");
System.err.println(" pm set-install-location [0/auto] [1/internal] [2/external]");
System.err.println(" pm get-install-location");
System.err.println(" pm set-permission-enforced PERMISSION [true|false]");
System.err.println(" pm trim-caches DESIRED_FREE_SPACE");
- System.err.println(" pm create-user USER_NAME");
+ System.err.println(" pm create-user [--profileOf USER_ID] [--managed] USER_NAME");
System.err.println(" pm remove-user USER_ID");
System.err.println(" pm get-max-users");
System.err.println("");
@@ -1589,16 +1817,28 @@ public final class Pm {
System.err.println("");
System.err.println("pm path: print the path to the .apk of the given PACKAGE.");
System.err.println("");
- System.err.println("pm dump: print system state associated w ith the given PACKAGE.");
+ System.err.println("pm dump: print system state associated with the given PACKAGE.");
+ System.err.println("");
+ System.err.println("pm install: install a single legacy package");
+ System.err.println("pm install-create: create an install session");
+ System.err.println(" -l: forward lock application");
+ System.err.println(" -r: replace existing application");
+ System.err.println(" -t: allow test packages");
+ System.err.println(" -i: specify the installer package name");
+ System.err.println(" -s: install application on sdcard");
+ System.err.println(" -f: install application on internal flash");
+ System.err.println(" -d: allow version code downgrade");
+ System.err.println(" -p: partial application install");
+ System.err.println(" -S: size in bytes of entire session");
System.err.println("");
- System.err.println("pm install: installs a package to the system. Options:");
- System.err.println(" -l: install the package with FORWARD_LOCK.");
- System.err.println(" -r: reinstall an exisiting app, keeping its data.");
- System.err.println(" -t: allow test .apks to be installed.");
- System.err.println(" -i: specify the installer package name.");
- System.err.println(" -s: install package on sdcard.");
- System.err.println(" -f: install package on internal flash.");
- System.err.println(" -d: allow version code downgrade.");
+ System.err.println("pm install-write: write a package into existing session; path may");
+ System.err.println(" be '-' to read from stdin");
+ System.err.println(" -S: size in bytes of package, required for stdin");
+ System.err.println("");
+ System.err.println("pm install-commit: perform install of fully staged session");
+ System.err.println("pm install-abandon: abandon session");
+ System.err.println("");
+ System.err.println("pm set-installer: set installer package name");
System.err.println("");
System.err.println("pm uninstall: removes a package from the system. Options:");
System.err.println(" -k: keep the data and cache directories around after package removal.");
@@ -1632,5 +1872,6 @@ public final class Pm {
System.err.println("");
System.err.println("pm remove-user: remove the user with the given USER_IDENTIFIER,");
System.err.println(" deleting all data associated with that user");
+ System.err.println("");
}
}
diff --git a/cmds/screencap/Android.mk b/cmds/screencap/Android.mk
index ca8008b..5c11b75 100644
--- a/cmds/screencap/Android.mk
+++ b/cmds/screencap/Android.mk
@@ -16,11 +16,4 @@ 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)
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 2b365d8..1ddbecb 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -54,13 +54,13 @@ static void usage(const char* pname)
);
}
-static SkBitmap::Config flinger2skia(PixelFormat f)
+static SkColorType flinger2skia(PixelFormat f)
{
switch (f) {
case PIXEL_FORMAT_RGB_565:
- return SkBitmap::kRGB_565_Config;
+ return kRGB_565_SkColorType;
default:
- return SkBitmap::kARGB_8888_Config;
+ return kN32_SkColorType;
}
}
@@ -159,7 +159,7 @@ int main(int argc, char** argv)
ScreenshotClient screenshot;
sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
- if (display != NULL && screenshot.update(display) == NO_ERROR) {
+ if (display != NULL && screenshot.update(display, Rect(), false) == NO_ERROR) {
base = screenshot.getPixels();
w = screenshot.getWidth();
h = screenshot.getHeight();
@@ -192,9 +192,10 @@ int main(int argc, char** argv)
if (base) {
if (png) {
+ const SkImageInfo info = SkImageInfo::Make(w, h, flinger2skia(f),
+ kPremul_SkAlphaType);
SkBitmap b;
- b.setConfig(flinger2skia(f), w, h, s*bytesPerPixel(f));
- b.setPixels((void*)base);
+ b.installPixels(info, const_cast<void*>(base), s*bytesPerPixel(f));
SkDynamicMemoryWStream stream;
SkImageEncoder::EncodeStream(&stream, b,
SkImageEncoder::kPNG_Type, SkImageEncoder::kDefaultQuality);
diff --git a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
index dce0a75..e6847a9 100644
--- a/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
+++ b/cmds/settings/src/com/android/commands/settings/SettingsCmd.java
@@ -20,6 +20,7 @@ import android.app.ActivityManagerNative;
import android.app.IActivityManager;
import android.app.IActivityManager.ContentProviderHolder;
import android.content.IContentProvider;
+import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -33,7 +34,8 @@ public final class SettingsCmd {
enum CommandVerb {
UNSPECIFIED,
GET,
- PUT
+ PUT,
+ DELETE
}
static String[] mArgs;
@@ -74,6 +76,8 @@ public final class SettingsCmd {
mVerb = CommandVerb.GET;
} else if ("put".equalsIgnoreCase(arg)) {
mVerb = CommandVerb.PUT;
+ } else if ("delete".equalsIgnoreCase(arg)) {
+ mVerb = CommandVerb.DELETE;
} else {
// invalid
System.err.println("Invalid command: " + arg);
@@ -87,7 +91,7 @@ public final class SettingsCmd {
break; // invalid
}
mTable = arg.toLowerCase();
- } else if (mVerb == CommandVerb.GET) {
+ } else if (mVerb == CommandVerb.GET || mVerb == CommandVerb.DELETE) {
mKey = arg;
if (mNextArg >= mArgs.length) {
valid = true;
@@ -136,6 +140,10 @@ public final class SettingsCmd {
case PUT:
putForUser(provider, mUser, mTable, mKey, mValue);
break;
+ case DELETE:
+ System.out.println("Deleted "
+ + deleteForUser(provider, mUser, mTable, mKey) + " rows");
+ break;
default:
System.err.println("Unspecified command");
break;
@@ -211,9 +219,31 @@ public final class SettingsCmd {
}
}
+ int deleteForUser(IContentProvider provider, int userHandle,
+ final String table, final String key) {
+ Uri targetUri;
+ if ("system".equals(table)) targetUri = Settings.System.getUriFor(key);
+ else if ("secure".equals(table)) targetUri = Settings.Secure.getUriFor(key);
+ else if ("global".equals(table)) targetUri = Settings.Global.getUriFor(key);
+ else {
+ System.err.println("Invalid table; no delete performed");
+ throw new IllegalArgumentException("Invalid table " + table);
+ }
+
+ int num = 0;
+ try {
+ num = provider.delete(null, targetUri, null, null);
+ } catch (RemoteException e) {
+ System.err.println("Can't clear key " + key + " in " + table + " for user "
+ + userHandle);
+ }
+ return num;
+ }
+
private static void printUsage() {
System.err.println("usage: settings [--user NUM] get namespace key");
System.err.println(" settings [--user NUM] put namespace key value");
+ System.err.println(" settings [--user NUM] delete namespace key");
System.err.println("\n'namespace' is one of {system, secure, global}, case-insensitive");
System.err.println("If '--user NUM' is not given, the operations are performed on the owner user.");
}
diff --git a/cmds/svc/src/com/android/commands/svc/DataCommand.java b/cmds/svc/src/com/android/commands/svc/DataCommand.java
index 72cb86d..406e33b 100644
--- a/cmds/svc/src/com/android/commands/svc/DataCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/DataCommand.java
@@ -36,9 +36,7 @@ public class DataCommand extends Svc.Command {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc data [enable|disable]\n"
- + " Turn mobile data on or off.\n\n"
- + " svc data prefer\n"
- + " Set mobile as the preferred data network\n";
+ + " Turn mobile data on or off.\n\n";
}
public void run(String[] args) {
@@ -51,15 +49,6 @@ public class DataCommand extends Svc.Command {
} else if ("disable".equals(args[1])) {
flag = false;
validCommand = true;
- } else if ("prefer".equals(args[1])) {
- IConnectivityManager connMgr =
- IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
- try {
- connMgr.setNetworkPreference(ConnectivityManager.TYPE_MOBILE);
- } catch (RemoteException e) {
- System.err.println("Failed to set preferred network: " + e);
- }
- return;
}
if (validCommand) {
ITelephony phoneMgr
@@ -78,4 +67,4 @@ public class DataCommand extends Svc.Command {
}
System.err.println(longHelp());
}
-} \ No newline at end of file
+}
diff --git a/cmds/svc/src/com/android/commands/svc/WifiCommand.java b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
index d29e8b2..39f0e35 100644
--- a/cmds/svc/src/com/android/commands/svc/WifiCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/WifiCommand.java
@@ -36,9 +36,7 @@ public class WifiCommand extends Svc.Command {
return shortHelp() + "\n"
+ "\n"
+ "usage: svc wifi [enable|disable]\n"
- + " Turn Wi-Fi on or off.\n\n"
- + " svc wifi prefer\n"
- + " Set Wi-Fi as the preferred data network\n";
+ + " Turn Wi-Fi on or off.\n\n";
}
public void run(String[] args) {
@@ -51,15 +49,6 @@ public class WifiCommand extends Svc.Command {
} else if ("disable".equals(args[1])) {
flag = false;
validCommand = true;
- } else if ("prefer".equals(args[1])) {
- IConnectivityManager connMgr =
- IConnectivityManager.Stub.asInterface(ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
- try {
- connMgr.setNetworkPreference(ConnectivityManager.TYPE_WIFI);
- } catch (RemoteException e) {
- System.err.println("Failed to set preferred network: " + e);
- }
- return;
}
if (validCommand) {
IWifiManager wifiMgr
@@ -75,4 +64,4 @@ public class WifiCommand extends Svc.Command {
}
System.err.println(longHelp());
}
-} \ No newline at end of file
+}