diff options
115 files changed, 2092 insertions, 1314 deletions
diff --git a/api/current.txt b/api/current.txt index d281f136d526..e46dbeb74db0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -15910,7 +15910,7 @@ package android.os { method public static void resetThreadGcInvocationCount(); method public static deprecated int setAllocationLimit(int); method public static deprecated int setGlobalAllocationLimit(int); - method public static void startAllocCounting(); + method public static deprecated void startAllocCounting(); method public static void startMethodTracing(); method public static void startMethodTracing(java.lang.String); method public static void startMethodTracing(java.lang.String, int); @@ -22276,19 +22276,19 @@ package android.text.format { method public static java.text.DateFormat getMediumDateFormat(android.content.Context); method public static java.text.DateFormat getTimeFormat(android.content.Context); method public static boolean is24HourFormat(android.content.Context); - field public static final char AM_PM = 97; // 0x0061 'a' - field public static final char CAPITAL_AM_PM = 65; // 0x0041 'A' - field public static final char DATE = 100; // 0x0064 'd' - field public static final char DAY = 69; // 0x0045 'E' - field public static final char HOUR = 104; // 0x0068 'h' - field public static final char HOUR_OF_DAY = 107; // 0x006b 'k' - field public static final char MINUTE = 109; // 0x006d 'm' - field public static final char MONTH = 77; // 0x004d 'M' - field public static final char QUOTE = 39; // 0x0027 '\'' - field public static final char SECONDS = 115; // 0x0073 's' - field public static final char STANDALONE_MONTH = 76; // 0x004c 'L' - field public static final char TIME_ZONE = 122; // 0x007a 'z' - field public static final char YEAR = 121; // 0x0079 'y' + field public static final deprecated char AM_PM = 97; // 0x0061 'a' + field public static final deprecated char CAPITAL_AM_PM = 65; // 0x0041 'A' + field public static final deprecated char DATE = 100; // 0x0064 'd' + field public static final deprecated char DAY = 69; // 0x0045 'E' + field public static final deprecated char HOUR = 104; // 0x0068 'h' + field public static final deprecated char HOUR_OF_DAY = 107; // 0x006b 'k' + field public static final deprecated char MINUTE = 109; // 0x006d 'm' + field public static final deprecated char MONTH = 77; // 0x004d 'M' + field public static final deprecated char QUOTE = 39; // 0x0027 '\'' + field public static final deprecated char SECONDS = 115; // 0x0073 's' + field public static final deprecated char STANDALONE_MONTH = 76; // 0x004c 'L' + field public static final deprecated char TIME_ZONE = 122; // 0x007a 'z' + field public static final deprecated char YEAR = 121; // 0x0079 'y' } public class DateUtils { @@ -29496,8 +29496,8 @@ package android.widget { method public void setFormat12Hour(java.lang.CharSequence); method public void setFormat24Hour(java.lang.CharSequence); method public void setTimeZone(java.lang.String); - field public static final java.lang.CharSequence DEFAULT_FORMAT_12_HOUR; - field public static final java.lang.CharSequence DEFAULT_FORMAT_24_HOUR; + field public static final deprecated java.lang.CharSequence DEFAULT_FORMAT_12_HOUR; + field public static final deprecated java.lang.CharSequence DEFAULT_FORMAT_24_HOUR; } public class TextSwitcher extends android.widget.ViewSwitcher { @@ -41332,8 +41332,8 @@ package java.util.zip { public class ZipFile { ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException; - ctor public ZipFile(java.io.File, int) throws java.io.IOException; ctor public ZipFile(java.lang.String) throws java.io.IOException; + ctor public ZipFile(java.io.File, int) throws java.io.IOException; method public void close() throws java.io.IOException; method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries(); method public java.util.zip.ZipEntry getEntry(java.lang.String); diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index 6fe358c7ee54..0668be606a7e 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -13,7 +13,9 @@ #include <cutils/process_name.h> #include <cutils/memory.h> #include <android_runtime/AndroidRuntime.h> +#include <sys/personality.h> +#include <stdlib.h> #include <stdio.h> #include <unistd.h> @@ -128,8 +130,32 @@ static void setArgv0(const char *argv0, const char *newArgv0) strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0)); } -int main(int argc, const char* const argv[]) +int main(int argc, char* const argv[]) { +#ifdef __arm__ + /* + * b/7188322 - Temporarily revert to the compat memory layout + * to avoid breaking third party apps. + * + * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE. + * + * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466 + * changes the kernel mapping from bottom up to top-down. + * This breaks some programs which improperly embed + * an out of date copy of Android's linker. + */ + if (getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) { + int current = personality(0xFFFFFFFF); + if ((current & ADDR_COMPAT_LAYOUT) == 0) { + personality(current | ADDR_COMPAT_LAYOUT); + setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1); + execv("/system/bin/app_process", argv); + return -1; + } + } + unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP"); +#endif + // These are global variables in ProcessState.cpp mArgC = argc; mArgV = argv; diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java index 787fbdb89062..ae39d24500e5 100644 --- a/cmds/content/src/com/android/commands/content/Content.java +++ b/cmds/content/src/com/android/commands/content/Content.java @@ -96,7 +96,7 @@ public class Content { + " [--projection <PROJECTION>] [--where <WHERE>] [--sort <SORT_ORDER>]\n" + " <PROJECTION> is a list of colon separated column names and is formatted:\n" + " <COLUMN_NAME>[:<COLUMN_NAME>...]\n" - + " <SORT_OREDER> is the order in which rows in the result should be sorted.\n" + + " <SORT_ORDER> is the order in which rows in the result should be sorted.\n" + " Example:\n" + " # Select \"name\" and \"value\" columns from secure settings where \"name\" is " + "equal to \"new_setting\" and sort the result by name in ascending order.\n" diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 2a547102eb46..09d6f89c4b88 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -14,7 +14,7 @@ ** limitations under the License. */ -#include <linux/capability.h> +#include <sys/capability.h> #include "installd.h" #include <diskusage/dirsize.h> #include <selinux/android.h> @@ -28,7 +28,7 @@ dir_rec_t android_app_lib_dir; dir_rec_t android_media_dir; dir_rec_array_t android_system_dirs; -int install(const char *pkgname, uid_t uid, gid_t gid) +int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) { char pkgdir[PKG_PATH_MAX]; char libsymlink[PKG_PATH_MAX]; @@ -91,7 +91,7 @@ int install(const char *pkgname, uid_t uid, gid_t gid) return -1; } - if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) { + if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) { ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); unlink(libsymlink); unlink(pkgdir); @@ -184,7 +184,7 @@ int delete_user_data(const char *pkgname, uid_t persona) return delete_dir_contents(pkgdir, 0, "lib"); } -int make_user_data(const char *pkgname, uid_t uid, uid_t persona) +int make_user_data(const char *pkgname, uid_t uid, uid_t persona, const char* seinfo) { char pkgdir[PKG_PATH_MAX]; char applibdir[PKG_PATH_MAX]; @@ -245,7 +245,7 @@ int make_user_data(const char *pkgname, uid_t uid, uid_t persona) return -1; } - if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) { + if (selinux_android_setfilecon2(pkgdir, pkgname, seinfo, uid) < 0) { ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno)); unlink(libsymlink); unlink(pkgdir); @@ -317,7 +317,7 @@ int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy) uid = (uid_t) s.st_uid % PER_USER_RANGE; /* Create the directory for the target */ make_user_data(name, uid + target_persona * PER_USER_RANGE, - target_persona); + target_persona, NULL); } } closedir(d); diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index 21d674a03bb6..281aaabc6591 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -14,7 +14,7 @@ ** limitations under the License. */ -#include <linux/capability.h> +#include <sys/capability.h> #include <linux/prctl.h> #include "installd.h" @@ -31,7 +31,7 @@ static int do_ping(char **arg, char reply[REPLY_MAX]) static int do_install(char **arg, char reply[REPLY_MAX]) { - return install(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */ + return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */ } static int do_dexopt(char **arg, char reply[REPLY_MAX]) @@ -103,7 +103,8 @@ static int do_rm_user_data(char **arg, char reply[REPLY_MAX]) static int do_mk_user_data(char **arg, char reply[REPLY_MAX]) { - return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, userid */ + return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); + /* pkgname, uid, userid, seinfo */ } static int do_rm_user(char **arg, char reply[REPLY_MAX]) @@ -134,7 +135,7 @@ struct cmdinfo { struct cmdinfo cmds[] = { { "ping", 0, do_ping }, - { "install", 3, do_install }, + { "install", 4, do_install }, { "dexopt", 3, do_dexopt }, { "movedex", 2, do_move_dex }, { "rmdex", 1, do_rm_dex }, @@ -147,7 +148,7 @@ struct cmdinfo cmds[] = { { "rmuserdata", 2, do_rm_user_data }, { "movefiles", 0, do_movefiles }, { "linklib", 3, do_linklib }, - { "mkuserdata", 3, do_mk_user_data }, + { "mkuserdata", 4, do_mk_user_data }, { "rmuser", 1, do_rm_user }, { "cloneuserdata", 3, do_clone_user_data }, }; diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index 0500c23fa6a4..04498efab6e3 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -192,12 +192,12 @@ int ensure_media_user_dirs(userid_t userid); /* commands.c */ -int install(const char *pkgname, uid_t uid, gid_t gid); +int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo); int uninstall(const char *pkgname, uid_t persona); int renamepkg(const char *oldpkgname, const char *newpkgname); int fix_uid(const char *pkgname, uid_t uid, gid_t gid); int delete_user_data(const char *pkgname, uid_t persona); -int make_user_data(const char *pkgname, uid_t uid, uid_t persona); +int make_user_data(const char *pkgname, uid_t uid, uid_t persona, const char* seinfo); int delete_persona(uid_t persona); int clone_persona_data(uid_t src_persona, uid_t target_persona, int copy); int delete_cache(const char *pkgname, uid_t persona); diff --git a/cmds/interrupter/Android.mk b/cmds/interrupter/Android.mk new file mode 100644 index 000000000000..e324627517ec --- /dev/null +++ b/cmds/interrupter/Android.mk @@ -0,0 +1,21 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + interrupter.c +LOCAL_MODULE := interrupter +LOCAL_MODULE_TAGS := eng tests +LOCAL_LDFLAGS := -ldl + +include $(BUILD_SHARED_LIBRARY) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := \ + interrupter.c +LOCAL_MODULE := interrupter +LOCAL_MODULE_TAGS := eng tests +LOCAL_LDFLAGS := -ldl + +include $(BUILD_HOST_SHARED_LIBRARY)
\ No newline at end of file diff --git a/cmds/interrupter/interrupter.c b/cmds/interrupter/interrupter.c new file mode 100644 index 000000000000..ae555150c969 --- /dev/null +++ b/cmds/interrupter/interrupter.c @@ -0,0 +1,53 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * The probability of a syscall failing from 0.0 to 1.0 + */ +#define PROBABILITY 0.9 + + + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +/* for various intercepted calls */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <fcntl.h> + +/* For builds on glibc */ +#define __USE_GNU +#include <dlfcn.h> + +#include "interrupter.h" + +static int probability = PROBABILITY * RAND_MAX; + +static int maybe_interrupt() { + if (rand() < probability) { + return 1; + } + return 0; +} + +DEFINE_INTERCEPT(read, ssize_t, int, void*, size_t); +DEFINE_INTERCEPT(write, ssize_t, int, const void*, size_t); +DEFINE_INTERCEPT(accept, int, int, struct sockaddr*, socklen_t*); +DEFINE_INTERCEPT(creat, int, const char*, mode_t); diff --git a/cmds/interrupter/interrupter.h b/cmds/interrupter/interrupter.h new file mode 100644 index 000000000000..9ad0277eebbe --- /dev/null +++ b/cmds/interrupter/interrupter.h @@ -0,0 +1,79 @@ +/* + * Copyright 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define CONCATENATE(arg1, arg2) CONCATENATE1(arg1, arg2) +#define CONCATENATE1(arg1, arg2) CONCATENATE2(arg1, arg2) +#define CONCATENATE2(arg1, arg2) arg1##arg2 + +#define INTERRUPTER(sym) \ + if (real_##sym == NULL) \ + __init_##sym(); \ + if (maybe_interrupt()) { \ + errno = EINTR; \ + return -1; \ + } + +#define CALL_FUNCTION_1(sym, ret, type1) \ +ret (*real_##sym)(type1) = NULL; \ +ret sym(type1 arg1) { \ + INTERRUPTER(sym) \ + return real_##sym(arg1); \ +} + +#define CALL_FUNCTION_2(sym, ret, type1, type2) \ +ret (*real_##sym)(type1, type2) = NULL; \ +ret sym(type1 arg1, type2 arg2) { \ + INTERRUPTER(sym) \ + return real_##sym(arg1, arg2); \ +} + +#define CALL_FUNCTION_3(sym, ret, type1, type2, type3) \ +ret (*real_##sym)(type1, type2, type3) = NULL; \ +ret sym(type1 arg1, type2 arg2, type3 arg3) { \ + INTERRUPTER(sym) \ + return real_##sym(arg1, arg2, arg3); \ +} + +#define CALL_FUNCTION_4(sym, ret, type1, type2, type3, type4) \ +ret (*real_##sym)(type1, type2, type3, type4) = NULL; \ +ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + INTERRUPTER(sym) \ + return real_##sym(arg1, arg2, arg3, arg4); \ +} + +#define CALL_FUNCTION_5(sym, ret, type1, type2, type3, type4, type5) \ +ret (*real_##sym)(type1, type2, type3, type4, type5) = NULL; \ +ret sym(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ + INTERRUPTER(sym) \ + return real_##sym(arg1, arg2, arg3, arg4, arg5); \ +} + +#define DEFINE_INTERCEPT_N(N, sym, ret, ...) \ +static void __init_##sym(void); \ +CONCATENATE(CALL_FUNCTION_, N)(sym, ret, __VA_ARGS__) \ +static void __init_##sym(void) { \ + real_##sym = dlsym(RTLD_NEXT, #sym); \ + if (real_##sym == NULL) { \ + fprintf(stderr, "Error hooking " #sym ": %s\n", dlerror()); \ + } \ +} + +#define INTERCEPT_NARG(...) INTERCEPT_NARG_N(__VA_ARGS__, INTERCEPT_RSEQ_N()) +#define INTERCEPT_NARG_N(...) INTERCEPT_ARG_N(__VA_ARGS__) +#define INTERCEPT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N +#define INTERCEPT_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0 + +#define DEFINE_INTERCEPT(sym, ret, ...) DEFINE_INTERCEPT_N(INTERCEPT_NARG(__VA_ARGS__), sym, ret, __VA_ARGS__) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index d8808173497e..22fd9a9d3686 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -4492,6 +4492,8 @@ public final class ActivityThread { + "snatched provider from the jaws of death"); } prc.removePending = false; + // There is a race! It fails to remove the message, which + // will be handled in completeRemoveProvider(). mH.removeMessages(H.REMOVE_PROVIDER, prc); } else { unstableDelta = 0; @@ -4671,6 +4673,11 @@ public final class ActivityThread { return; } + // More complicated race!! Some client managed to acquire the + // provider and release it before the removal was completed. + // Continue the removal, and abort the next remove message. + prc.removePending = false; + final IBinder jBinder = prc.holder.provider.asBinder(); ProviderRefCount existingPrc = mProviderRefCountMap.get(jBinder); if (existingPrc == prc) { diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 6fdf3b47b85f..6fdf3b47b85f 100755..100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 6367e160490e..6367e160490e 100755..100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index 4cc22b4ae909..4cc22b4ae909 100755..100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index 793d79858c6c..793d79858c6c 100755..100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java diff --git a/core/java/android/bluetooth/BluetoothInputDevice.java b/core/java/android/bluetooth/BluetoothInputDevice.java index db7e424d40ee..db7e424d40ee 100755..100644 --- a/core/java/android/bluetooth/BluetoothInputDevice.java +++ b/core/java/android/bluetooth/BluetoothInputDevice.java diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java index b5280e533778..b5280e533778 100755..100644 --- a/core/java/android/bluetooth/BluetoothPbap.java +++ b/core/java/android/bluetooth/BluetoothPbap.java diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 1920efa52f87..1920efa52f87 100755..100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java diff --git a/core/java/android/bluetooth/IBluetoothInputDevice.aidl b/core/java/android/bluetooth/IBluetoothInputDevice.aidl index 1ebb9ca6eb12..1ebb9ca6eb12 100755..100644 --- a/core/java/android/bluetooth/IBluetoothInputDevice.aidl +++ b/core/java/android/bluetooth/IBluetoothInputDevice.aidl diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl index ed8777c51526..ed8777c51526 100755..100644 --- a/core/java/android/bluetooth/IBluetoothManager.aidl +++ b/core/java/android/bluetooth/IBluetoothManager.aidl diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 32cc7fd5aa1f..02401dc5416b 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -398,6 +398,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public String[] resourceDirs; /** + * String retrieved from the seinfo tag found in selinux policy. This value + * is useful in setting an SELinux security context on the process as well + * as its data directory. + * + * {@hide} + */ + public String seinfo; + + /** * Paths to all shared libraries this application is linked against. This * field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving @@ -477,6 +486,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (resourceDirs != null) { pw.println(prefix + "resourceDirs=" + resourceDirs); } + if (seinfo != null) { + pw.println(prefix + "seinfo=" + seinfo); + } pw.println(prefix + "dataDir=" + dataDir); if (sharedLibraryFiles != null) { pw.println(prefix + "sharedLibraryFiles=" + sharedLibraryFiles); @@ -544,6 +556,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { publicSourceDir = orig.publicSourceDir; nativeLibraryDir = orig.nativeLibraryDir; resourceDirs = orig.resourceDirs; + seinfo = orig.seinfo; sharedLibraryFiles = orig.sharedLibraryFiles; dataDir = orig.dataDir; uid = orig.uid; @@ -583,6 +596,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeString(publicSourceDir); dest.writeString(nativeLibraryDir); dest.writeStringArray(resourceDirs); + dest.writeString(seinfo); dest.writeStringArray(sharedLibraryFiles); dest.writeString(dataDir); dest.writeInt(uid); @@ -621,6 +635,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { publicSourceDir = source.readString(); nativeLibraryDir = source.readString(); resourceDirs = source.readStringArray(); + seinfo = source.readString(); sharedLibraryFiles = source.readStringArray(); dataDir = source.readString(); uid = source.readInt(); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index b316f230a944..0404a842a943 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -232,11 +232,13 @@ public class Resources { } /** - * Return the character sequence associated with a particular resource ID for a particular - * numerical quantity. - * - * <p>See <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String - * Resources</a> for more on quantity strings. + * Returns the character sequence necessary for grammatically correct pluralization + * of the given resource ID for the given quantity. + * Note that the character sequence is selected based solely on grammatical necessity, + * and that such rules differ between languages. Do not assume you know which string + * will be returned for a given quantity. See + * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a> + * for more detail. * * @param id The desired resource identifier, as generated by the aapt * tool. This integer encodes the package, type, and resource @@ -344,14 +346,17 @@ public class Resources { } /** - * Return the string value associated with a particular resource ID for a particular - * numerical quantity, substituting the format arguments as defined in - * {@link java.util.Formatter} and {@link java.lang.String#format}. It will be - * stripped of any styled text information. - * {@more} - * - * <p>See <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String - * Resources</a> for more on quantity strings. + * Formats the string necessary for grammatically correct pluralization + * of the given resource ID for the given quantity, using the given arguments. + * Note that the string is selected based solely on grammatical necessity, + * and that such rules differ between languages. Do not assume you know which string + * will be returned for a given quantity. See + * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a> + * for more detail. + * + * <p>Substitution of format arguments works as if using + * {@link java.util.Formatter} and {@link java.lang.String#format}. + * The resulting string will be stripped of any styled text information. * * @param id The desired resource identifier, as generated by the aapt * tool. This integer encodes the package, type, and resource @@ -372,11 +377,13 @@ public class Resources { } /** - * Return the string value associated with a particular resource ID for a particular - * numerical quantity. - * - * <p>See <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String - * Resources</a> for more on quantity strings. + * Returns the string necessary for grammatically correct pluralization + * of the given resource ID for the given quantity. + * Note that the string is selected based solely on grammatical necessity, + * and that such rules differ between languages. Do not assume you know which string + * will be returned for a given quantity. See + * <a href="{@docRoot}guide/topics/resources/string-resource.html#Plurals">String Resources</a> + * for more detail. * * @param id The desired resource identifier, as generated by the aapt * tool. This integer encodes the package, type, and resource diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index c0a894b6e66e..2a2f7cf81f84 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -23,8 +23,8 @@ import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; import java.security.KeyManagementException; +import java.security.PrivateKey; import java.security.cert.X509Certificate; -import java.security.interfaces.ECPrivateKey; import javax.net.SocketFactory; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -89,7 +89,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { private TrustManager[] mTrustManagers = null; private KeyManager[] mKeyManagers = null; private byte[] mNpnProtocols = null; - private ECPrivateKey mChannelIdPrivateKey = null; + private PrivateKey mChannelIdPrivateKey = null; private final int mHandshakeTimeoutMillis; private final SSLClientSessionCache mSessionCache; @@ -321,7 +321,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { } /** - * Sets the {@link ECPrivateKey} to be used for TLS Channel ID by connections made by this + * Sets the private key to be used for TLS Channel ID by connections made by this * factory. * * @param privateKey private key (enables TLS Channel ID) or {@code null} for no key (disables @@ -330,7 +330,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * * @hide */ - public void setChannelIdPrivateKey(ECPrivateKey privateKey) { + public void setChannelIdPrivateKey(PrivateKey privateKey) { mChannelIdPrivateKey = privateKey; } diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index e50c94813a74..2e77237451ce 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -45,7 +45,7 @@ import dalvik.system.VMDebug; /** - * Provides various debugging functions for Android applications, including + * Provides various debugging methods for Android applications, including * tracing and allocation counts. * <p><strong>Logging Trace Files</strong></p> * <p>Debug can create log files that give details about an application, such as @@ -130,7 +130,7 @@ public final class Debug public int otherSharedDirty; /** @hide */ - public static final int NUM_OTHER_STATS = 9; + public static final int NUM_OTHER_STATS = 10; private int[] otherStats = new int[NUM_OTHER_STATS*3]; @@ -177,15 +177,16 @@ public final class Debug /* @hide */ public static String getOtherLabel(int which) { switch (which) { - case 0: return "Cursor"; - case 1: return "Ashmem"; - case 2: return "Other dev"; - case 3: return ".so mmap"; - case 4: return ".jar mmap"; - case 5: return ".apk mmap"; - case 6: return ".ttf mmap"; - case 7: return ".dex mmap"; - case 8: return "Other mmap"; + case 0: return "Stack"; + case 1: return "Cursor"; + case 2: return "Ashmem"; + case 3: return "Other dev"; + case 4: return ".so mmap"; + case 5: return ".jar mmap"; + case 6: return ".apk mmap"; + case 7: return ".ttf mmap"; + case 8: return ".dex mmap"; + case 9: return "Other mmap"; default: return "????"; } } @@ -554,16 +555,19 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** * Start counting the number and aggregate size of memory allocations. * - * <p>The {@link #startAllocCounting() start} function resets the counts and enables counting. - * The {@link #stopAllocCounting() stop} function disables the counting so that the analysis - * code doesn't cause additional allocations. The various <code>get</code> functions return - * the specified value. And the various <code>reset</code> functions reset the specified + * <p>The {@link #startAllocCounting() start} method resets the counts and enables counting. + * The {@link #stopAllocCounting() stop} method disables the counting so that the analysis + * code doesn't cause additional allocations. The various <code>get</code> methods return + * the specified value. And the various <code>reset</code> methods reset the specified * count.</p> * - * <p>Counts are kept for the system as a whole and for each thread. + * <p>Counts are kept for the system as a whole (global) and for each thread. * The per-thread counts for threads other than the current thread * are not cleared by the "reset" or "start" calls.</p> + * + * @deprecated Accurate counting is a burden on the runtime and may be removed. */ + @Deprecated public static void startAllocCounting() { VMDebug.startAllocCounting(); } @@ -577,211 +581,269 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo VMDebug.stopAllocCounting(); } + /** + * Returns the global count of objects allocated by the runtime between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + */ public static int getGlobalAllocCount() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); } + + /** + * Clears the global count of objects allocated. + * @see #getGlobalAllocCount() + */ + public static void resetGlobalAllocCount() { + VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); + } + + /** + * Returns the global size, in bytes, of objects allocated by the runtime between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + */ public static int getGlobalAllocSize() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); } + + /** + * Clears the global size of objects allocated. + * @see #getGlobalAllocCountSize() + */ + public static void resetGlobalAllocSize() { + VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); + } + + /** + * Returns the global count of objects freed by the runtime between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + */ public static int getGlobalFreedCount() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); } + + /** + * Clears the global count of objects freed. + * @see #getGlobalFreedCount() + */ + public static void resetGlobalFreedCount() { + VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); + } + + /** + * Returns the global size, in bytes, of objects freed by the runtime between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + */ public static int getGlobalFreedSize() { return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); } + + /** + * Clears the global size of objects freed. + * @see #getGlobalFreedSize() + */ + public static void resetGlobalFreedSize() { + VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); + } + + /** + * Returns the number of non-concurrent GC invocations between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + */ + public static int getGlobalGcInvocationCount() { + return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); + } + + /** + * Clears the count of non-concurrent GC invocations. + * @see #getGlobalGcInvocationCount() + */ + public static void resetGlobalGcInvocationCount() { + VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); + } + + /** + * Returns the number of classes successfully initialized (ie those that executed without + * throwing an exception) between a {@link #startAllocCounting() start} and + * {@link #stopAllocCounting() stop}. + */ public static int getGlobalClassInitCount() { - /* number of classes that have been successfully initialized */ return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); } + + /** + * Clears the count of classes initialized. + * @see #getGlobalClassInitCount() + */ + public static void resetGlobalClassInitCount() { + VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); + } + + /** + * Returns the time spent successfully initializing classes between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + */ public static int getGlobalClassInitTime() { /* cumulative elapsed time for class initialization, in usec */ return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); } /** - * Returns the global count of external allocation requests. The - * external allocation tracking feature was removed in Honeycomb. - * This method exists for compatibility and always returns 0. - * - * @deprecated This method is now obsolete. + * Clears the count of time spent initializing classes. + * @see #getGlobalClassInitTime() */ - @Deprecated - public static int getGlobalExternalAllocCount() { - return 0; + public static void resetGlobalClassInitTime() { + VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); } /** - * Returns the global count of bytes externally allocated. The - * external allocation tracking feature was removed in Honeycomb. * This method exists for compatibility and always returns 0. - * * @deprecated This method is now obsolete. */ @Deprecated - public static int getGlobalExternalAllocSize() { + public static int getGlobalExternalAllocCount() { return 0; } /** - * Returns the global count of freed external allocation requests. - * The external allocation tracking feature was removed in - * Honeycomb. This method exists for compatibility and always - * returns 0. - * + * This method exists for compatibility and has no effect. * @deprecated This method is now obsolete. */ @Deprecated - public static int getGlobalExternalFreedCount() { - return 0; - } + public static void resetGlobalExternalAllocSize() {} /** - * Returns the global count of freed bytes from external - * allocation requests. The external allocation tracking feature - * was removed in Honeycomb. This method exists for compatibility - * and always returns 0. - * + * This method exists for compatibility and has no effect. * @deprecated This method is now obsolete. */ @Deprecated - public static int getGlobalExternalFreedSize() { - return 0; - } - - public static int getGlobalGcInvocationCount() { - return VMDebug.getAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); - } - public static int getThreadAllocCount() { - return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); - } - public static int getThreadAllocSize() { - return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); - } + public static void resetGlobalExternalAllocCount() {} /** - * Returns the count of external allocation requests made by the - * current thread. The external allocation tracking feature was - * removed in Honeycomb. This method exists for compatibility and - * always returns 0. - * + * This method exists for compatibility and always returns 0. * @deprecated This method is now obsolete. */ @Deprecated - public static int getThreadExternalAllocCount() { + public static int getGlobalExternalAllocSize() { return 0; } /** - * Returns the global count of bytes externally allocated. The - * external allocation tracking feature was removed in Honeycomb. * This method exists for compatibility and always returns 0. - * * @deprecated This method is now obsolete. */ @Deprecated - public static int getThreadExternalAllocSize() { + public static int getGlobalExternalFreedCount() { return 0; } - public static int getThreadGcInvocationCount() { - return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); - } - - public static void resetGlobalAllocCount() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_OBJECTS); - } - public static void resetGlobalAllocSize() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_ALLOCATED_BYTES); - } - public static void resetGlobalFreedCount() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_OBJECTS); - } - public static void resetGlobalFreedSize() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_FREED_BYTES); - } - public static void resetGlobalClassInitCount() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_COUNT); - } - public static void resetGlobalClassInitTime() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_CLASS_INIT_TIME); - } - /** - * Resets the global count of external allocation requests. The - * external allocation tracking feature was removed in Honeycomb. * This method exists for compatibility and has no effect. - * * @deprecated This method is now obsolete. */ @Deprecated - public static void resetGlobalExternalAllocCount() {} + public static void resetGlobalExternalFreedCount() {} /** - * Resets the global count of bytes externally allocated. The - * external allocation tracking feature was removed in Honeycomb. * This method exists for compatibility and has no effect. - * * @deprecated This method is now obsolete. */ @Deprecated - public static void resetGlobalExternalAllocSize() {} + public static int getGlobalExternalFreedSize() { + return 0; + } /** - * Resets the global count of freed external allocations. The - * external allocation tracking feature was removed in Honeycomb. * This method exists for compatibility and has no effect. - * * @deprecated This method is now obsolete. */ @Deprecated - public static void resetGlobalExternalFreedCount() {} + public static void resetGlobalExternalFreedSize() {} /** - * Resets the global count counter of freed bytes from external - * allocations. The external allocation tracking feature was - * removed in Honeycomb. This method exists for compatibility and - * has no effect. - * - * @deprecated This method is now obsolete. + * Returns the thread-local count of objects allocated by the runtime between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. */ - @Deprecated - public static void resetGlobalExternalFreedSize() {} - - public static void resetGlobalGcInvocationCount() { - VMDebug.resetAllocCount(VMDebug.KIND_GLOBAL_GC_INVOCATIONS); + public static int getThreadAllocCount() { + return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); } + + /** + * Clears the thread-local count of objects allocated. + * @see #getThreadAllocCount() + */ public static void resetThreadAllocCount() { VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_OBJECTS); } + + /** + * Returns the thread-local size of objects allocated by the runtime between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + * @return The allocated size in bytes. + */ + public static int getThreadAllocSize() { + return VMDebug.getAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); + } + + /** + * Clears the thread-local count of objects allocated. + * @see #getThreadAllocSize() + */ public static void resetThreadAllocSize() { VMDebug.resetAllocCount(VMDebug.KIND_THREAD_ALLOCATED_BYTES); } /** - * Resets the count of external allocation requests made by the - * current thread. The external allocation tracking feature was - * removed in Honeycomb. This method exists for compatibility and - * has no effect. - * + * This method exists for compatibility and has no effect. + * @deprecated This method is now obsolete. + */ + @Deprecated + public static int getThreadExternalAllocCount() { + return 0; + } + + /** + * This method exists for compatibility and has no effect. * @deprecated This method is now obsolete. */ @Deprecated public static void resetThreadExternalAllocCount() {} /** - * Resets the count of bytes externally allocated by the current - * thread. The external allocation tracking feature was removed - * in Honeycomb. This method exists for compatibility and has no - * effect. - * + * This method exists for compatibility and has no effect. + * @deprecated This method is now obsolete. + */ + @Deprecated + public static int getThreadExternalAllocSize() { + return 0; + } + + /** + * This method exists for compatibility and has no effect. * @deprecated This method is now obsolete. */ @Deprecated public static void resetThreadExternalAllocSize() {} + /** + * Returns the number of thread-local non-concurrent GC invocations between a + * {@link #startAllocCounting() start} and {@link #stopAllocCounting() stop}. + */ + public static int getThreadGcInvocationCount() { + return VMDebug.getAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); + } + + /** + * Clears the thread-local count of non-concurrent GC invocations. + * @see #getThreadGcInvocationCount() + */ public static void resetThreadGcInvocationCount() { VMDebug.resetAllocCount(VMDebug.KIND_THREAD_GC_INVOCATIONS); } + + /** + * Clears all the global and thread-local memory allocation counters. + * @see #startAllocCounting() + */ public static void resetAllCounts() { VMDebug.resetAllocCount(VMDebug.KIND_ALL_COUNTS); } @@ -1380,7 +1442,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo } /** - * @return a String describing the immediate caller of the calling function. + * @return a String describing the immediate caller of the calling method. * {@hide} */ public static String getCaller() { diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java index 651693a970f4..c36564373853 100644 --- a/core/java/android/security/IKeystoreService.java +++ b/core/java/android/security/IKeystoreService.java @@ -148,6 +148,10 @@ public interface IKeystoreService extends IInterface { for (int i = 0; i < size; i++) { _result[i] = _reply.readString(); } + int _ret = _reply.readInt(); + if (_ret != 1) { + return null; + } } finally { _reply.recycle(); _data.recycle(); @@ -401,6 +405,45 @@ public interface IKeystoreService extends IInterface { } return _result; } + + @Override + public int duplicate(String srcKey, int srcUid, String destKey, int destUid) + throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + int _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(srcKey); + _data.writeInt(srcUid); + _data.writeString(destKey); + _data.writeInt(destUid); + mRemote.transact(Stub.TRANSACTION_duplicate, _data, _reply, 0); + _reply.readException(); + _result = _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + + @Override + public int is_hardware_backed() throws RemoteException { + Parcel _data = Parcel.obtain(); + Parcel _reply = Parcel.obtain(); + int _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + mRemote.transact(Stub.TRANSACTION_is_hardware_backed, _data, _reply, 0); + _reply.readException(); + _result = _reply.readInt(); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } } private static final String DESCRIPTOR = "android.security.keystore"; @@ -425,6 +468,8 @@ public interface IKeystoreService extends IInterface { static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17; static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18; static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19; + static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20; + static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21; /** * Cast an IBinder object into an IKeystoreService interface, generating @@ -509,4 +554,9 @@ public interface IKeystoreService extends IInterface { public int ungrant(String name, int granteeUid) throws RemoteException; public long getmtime(String name) throws RemoteException; + + public int duplicate(String srcKey, int srcUid, String destKey, int destUid) + throws RemoteException; + + public int is_hardware_backed() throws RemoteException; } diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index cc676deece2e..50b1a2962a1b 100644 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -34,178 +34,82 @@ import java.text.SimpleDateFormat; import libcore.icu.LocaleData; /** - Utility class for producing strings with formatted date/time. - - <p> - Most callers should avoid supplying their own format strings to this - class' {@code format} methods and rely on the correctly localized ones - supplied by the system. This class' factory methods return - appropriately-localized {@link java.text.DateFormat} instances, suitable - for both formatting and parsing dates. For the canonical documentation - of format strings, see {@link java.text.SimpleDateFormat}. - </p> - <p> - The format methods in this class takes as inputs a format string and a representation of a date/time. - The format string controls how the output is generated. - This class only supports a subset of the full Unicode specification. - Use {@link java.text.SimpleDateFormat} if you need more. - Formatting characters may be repeated in order to get more detailed representations - of that field. For instance, the format character 'M' is used to - represent the month. Depending on how many times that character is repeated - you get a different representation. - </p> - <p> - For the month of September:<br/> - M -> 9<br/> - MM -> 09<br/> - MMM -> Sep<br/> - MMMM -> September - </p> - <p> - The effects of the duplication vary depending on the nature of the field. - See the notes on the individual field formatters for details. For purely numeric - fields such as <code>HOUR</code> adding more copies of the designator will - zero-pad the value to that number of characters. - </p> - <p> - For 7 minutes past the hour:<br/> - m -> 7<br/> - mm -> 07<br/> - mmm -> 007<br/> - mmmm -> 0007 - </p> - <p> - Examples for April 6, 1970 at 3:23am:<br/> - "MM/dd/yy h:mmaa" -> "04/06/70 3:23am"<br/> - "MMM dd, yyyy h:mmaa" -> "Apr 6, 1970 3:23am"<br/> - "MMMM dd, yyyy h:mmaa" -> "April 6, 1970 3:23am"<br/> - "E, MMMM dd, yyyy h:mmaa" -> "Mon, April 6, 1970 3:23am&<br/> - "EEEE, MMMM dd, yyyy h:mmaa" -> "Monday, April 6, 1970 3:23am"<br/> - "'Noteworthy day: 'M/d/yy" -> "Noteworthy day: 4/6/70" + * Utility class for producing strings with formatted date/time. + * + * <p>Most callers should avoid supplying their own format strings to this + * class' {@code format} methods and rely on the correctly localized ones + * supplied by the system. This class' factory methods return + * appropriately-localized {@link java.text.DateFormat} instances, suitable + * for both formatting and parsing dates. For the canonical documentation + * of format strings, see {@link java.text.SimpleDateFormat}. + * + * <p>The {@code format} methods in this class implement a subset of Unicode + * <a href="http://www.unicode.org/reports/tr35/#Date_Format_Patterns">UTS #35</a> patterns. + * The subset currently supported by this class includes the following format characters: + * {@code acdEHhLKkLMmsyz}. Up to API level 17, only {@code adEhkMmszy} were supported. + * Note that this class incorrectly implements {@code k} as if it were {@code H} for backwards + * compatibility. + * + * <p>See {@link java.text.SimpleDateFormat} for more documentation + * about patterns, or if you need a more complete or correct implementation. + * Note that the non-{@code format} methods in this class are implemented by + * {@code SimpleDateFormat}. */ - public class DateFormat { - /** - Text in the format string that should be copied verbatim rather that - interpreted as formatting codes must be surrounded by the <code>QUOTE</code> - character. If you need to embed a literal <code>QUOTE</code> character in - the output text then use two in a row. - */ + /** @deprecated Use a literal {@code '} instead. */ + @Deprecated public static final char QUOTE = '\''; - - /** - This designator indicates whether the <code>HOUR</code> field is before - or after noon. The output is lower-case. - - Examples: - a -> a or p - aa -> am or pm - */ + + /** @deprecated Use a literal {@code 'a'} instead. */ + @Deprecated public static final char AM_PM = 'a'; - /** - This designator indicates whether the <code>HOUR</code> field is before - or after noon. The output is capitalized. - - Examples: - A -> A or P - AA -> AM or PM - */ + /** @deprecated Use a literal {@code 'a'} instead; 'A' was always equivalent to 'a'. */ + @Deprecated public static final char CAPITAL_AM_PM = 'A'; - /** - This designator indicates the day of the month. - - Examples for the 9th of the month: - d -> 9 - dd -> 09 - */ + /** @deprecated Use a literal {@code 'd'} instead. */ + @Deprecated public static final char DATE = 'd'; - /** - This designator indicates the name of the day of the week. - - Examples for Sunday: - E -> Sun - EEEE -> Sunday - */ + /** @deprecated Use a literal {@code 'E'} instead. */ + @Deprecated public static final char DAY = 'E'; - /** - This designator indicates the hour of the day in 12 hour format. - - Examples for 3pm: - h -> 3 - hh -> 03 - */ + /** @deprecated Use a literal {@code 'h'} instead. */ + @Deprecated public static final char HOUR = 'h'; /** - This designator indicates the hour of the day in 24 hour format. - - Example for 3pm: - k -> 15 - - Examples for midnight: - k -> 0 - kk -> 00 + * @deprecated Use a literal {@code 'H'} (for compatibility with {@link SimpleDateFormat} + * and Unicode) or {@code 'k'} (for compatibility with Android releases up to and including + * Jelly Bean MR-1) instead. Note that the two are incompatible. */ + @Deprecated public static final char HOUR_OF_DAY = 'k'; - /** - This designator indicates the minute of the hour. - - Examples for 7 minutes past the hour: - m -> 7 - mm -> 07 - */ + /** @deprecated Use a literal {@code 'm'} instead. */ + @Deprecated public static final char MINUTE = 'm'; - /** - This designator indicates the month of the year. See also - {@link #STANDALONE_MONTH}. - - Examples for September: - M -> 9 - MM -> 09 - MMM -> Sep - MMMM -> September - */ + /** @deprecated Use a literal {@code 'M'} instead. */ + @Deprecated public static final char MONTH = 'M'; - /** - This designator indicates the standalone month of the year, - necessary in some format strings in some languages. For - example, Russian distinguishes between the "June" in - "June" and that in "June 2010". - */ + /** @deprecated Use a literal {@code 'L'} instead. */ + @Deprecated public static final char STANDALONE_MONTH = 'L'; - /** - This designator indicates the seconds of the minute. - - Examples for 7 seconds past the minute: - s -> 7 - ss -> 07 - */ + /** @deprecated Use a literal {@code 's'} instead. */ + @Deprecated public static final char SECONDS = 's'; - /** - This designator indicates the offset of the timezone from GMT. - - Example for US/Pacific timezone: - z -> -0800 - zz -> PST - */ + /** @deprecated Use a literal {@code 'z'} instead. */ + @Deprecated public static final char TIME_ZONE = 'z'; - /** - This designator indicates the year. - - Examples for 2006 - y -> 06 - yyyy -> 2006 - */ + /** @deprecated Use a literal {@code 'y'} instead. */ + @Deprecated public static final char YEAR = 'y'; @@ -233,8 +137,7 @@ public class DateFormat { } java.text.DateFormat natural = - java.text.DateFormat.getTimeInstance( - java.text.DateFormat.LONG, locale); + java.text.DateFormat.getTimeInstance(java.text.DateFormat.LONG, locale); if (natural instanceof SimpleDateFormat) { SimpleDateFormat sdf = (SimpleDateFormat) natural; @@ -267,13 +170,22 @@ public class DateFormat { * @return the {@link java.text.DateFormat} object that properly formats the time. */ public static java.text.DateFormat getTimeFormat(Context context) { + return new java.text.SimpleDateFormat(getTimeFormatString(context)); + } + + /** + * Returns a String pattern that can be used to format the time according + * to the current locale and the user's 12-/24-hour clock preference. + * @param context the application context + * @hide + */ + public static String getTimeFormatString(Context context) { LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); - boolean is24 = is24HourFormat(context); - return new java.text.SimpleDateFormat(is24 ? d.timeFormat24 : d.timeFormat12); + return is24HourFormat(context) ? d.timeFormat24 : d.timeFormat12; } /** - * Returns a {@link java.text.DateFormat} object that can format the date + * Returns a {@link java.text.DateFormat} object that can format the date * in short form (such as 12/31/1999) according * to the current locale and the user's date-order preference. * @param context the application context @@ -298,7 +210,6 @@ public class DateFormat { public static java.text.DateFormat getDateFormatForSetting(Context context, String value) { String format = getDateFormatStringForSetting(context, value); - return new java.text.SimpleDateFormat(format); } @@ -342,10 +253,10 @@ public class DateFormat { value = context.getString(R.string.numeric_date_format); return value; } - + /** * Returns a {@link java.text.DateFormat} object that can format the date - * in long form (such as December 31, 1999) for the current locale. + * in long form (such as {@code Monday, January 3, 2000}) for the current locale. * @param context the application context * @return the {@link java.text.DateFormat} object that formats the date in long form. */ @@ -355,7 +266,7 @@ public class DateFormat { /** * Returns a {@link java.text.DateFormat} object that can format the date - * in medium form (such as Dec. 31, 1999) for the current locale. + * in medium form (such as {@code Jan 3, 2000}) for the current locale. * @param context the application context * @return the {@link java.text.DateFormat} object that formats the date in long form. */ @@ -365,13 +276,13 @@ public class DateFormat { /** * Gets the current date format stored as a char array. The array will contain - * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order + * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order * specified by the user's format preference. Note that this order is * only appropriate for all-numeric dates; spelled-out (MEDIUM and LONG) * dates will generally contain other punctuation, spaces, or words, * not just the day, month, and year, and not necessarily in the same * order returned here. - */ + */ public static char[] getDateFormatOrder(Context context) { char[] order = new char[] {DATE, MONTH, YEAR}; String value = getDateFormatString(context); @@ -401,7 +312,7 @@ public class DateFormat { } return order; } - + private static String getDateFormatString(Context context) { String value = Settings.System.getString(context.getContentResolver(), Settings.System.DATE_FORMAT); @@ -410,7 +321,7 @@ public class DateFormat { } /** - * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a + * Given a format string and a time in milliseconds since Jan 1, 1970 GMT, returns a * CharSequence containing the requested date. * @param inFormat the format string, as described in {@link android.text.format.DateFormat} * @param inTimeInMillis in milliseconds since Jan 1, 1970 GMT @@ -428,22 +339,20 @@ public class DateFormat { * @return a {@link CharSequence} containing the requested text */ public static CharSequence format(CharSequence inFormat, Date inDate) { - Calendar c = new GregorianCalendar(); - + Calendar c = new GregorianCalendar(); c.setTime(inDate); - return format(inFormat, c); } /** * Indicates whether the specified format string contains seconds. - * + * * Always returns false if the input format is null. - * + * * @param inFormat the format string, as described in {@link android.text.format.DateFormat} - * + * * @return true if the format string contains {@link #SECONDS}, false otherwise - * + * * @hide */ public static boolean hasSeconds(CharSequence inFormat) { @@ -498,24 +407,23 @@ public class DateFormat { } /** - * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence + * Given a format string and a {@link java.util.Calendar} object, returns a CharSequence * containing the requested date. * @param inFormat the format string, as described in {@link android.text.format.DateFormat} * @param inDate the date to format * @return a {@link CharSequence} containing the requested text */ public static CharSequence format(CharSequence inFormat, Calendar inDate) { - SpannableStringBuilder s = new SpannableStringBuilder(inFormat); - int c; - int count; + SpannableStringBuilder s = new SpannableStringBuilder(inFormat); + int count; + + LocaleData localeData = LocaleData.get(Locale.getDefault()); int len = inFormat.length(); for (int i = 0; i < len; i += count) { - int temp; - count = 1; - c = s.charAt(i); + int c = s.charAt(i); if (c == QUOTE) { count = appendQuotedText(s, i, len); @@ -528,102 +436,105 @@ public class DateFormat { } String replacement; - switch (c) { - case AM_PM: - replacement = DateUtils.getAMPMString(inDate.get(Calendar.AM_PM)); - break; - - case CAPITAL_AM_PM: - //FIXME: this is the same as AM_PM? no capital? - replacement = DateUtils.getAMPMString(inDate.get(Calendar.AM_PM)); + case 'A': + case 'a': + replacement = localeData.amPm[inDate.get(Calendar.AM_PM) - Calendar.AM]; break; - - case DATE: + case 'd': replacement = zeroPad(inDate.get(Calendar.DATE), count); break; - - case DAY: - temp = inDate.get(Calendar.DAY_OF_WEEK); - replacement = DateUtils.getDayOfWeekString(temp, - count < 4 ? - DateUtils.LENGTH_MEDIUM : - DateUtils.LENGTH_LONG); + case 'c': + case 'E': + replacement = getDayOfWeekString(localeData, + inDate.get(Calendar.DAY_OF_WEEK), count, c); break; - - case HOUR: - temp = inDate.get(Calendar.HOUR); - - if (0 == temp) - temp = 12; - - replacement = zeroPad(temp, count); + case 'K': // hour in am/pm (0-11) + case 'h': // hour in am/pm (1-12) + { + int hour = inDate.get(Calendar.HOUR); + if (c == 'h' && hour == 0) { + hour = 12; + } + replacement = zeroPad(hour, count); + } + break; + case 'H': // hour in day (0-23) + case 'k': // hour in day (1-24) [but see note below] + { + int hour = inDate.get(Calendar.HOUR_OF_DAY); + // Historically on Android 'k' was interpreted as 'H', which wasn't + // implemented, so pretty much all callers that want to format 24-hour + // times are abusing 'k'. http://b/8359981. + if (false && c == 'k' && hour == 0) { + hour = 24; + } + replacement = zeroPad(hour, count); + } break; - - case HOUR_OF_DAY: - replacement = zeroPad(inDate.get(Calendar.HOUR_OF_DAY), count); + case 'L': + case 'M': + replacement = getMonthString(localeData, + inDate.get(Calendar.MONTH), count, c); break; - - case MINUTE: + case 'm': replacement = zeroPad(inDate.get(Calendar.MINUTE), count); break; - - case MONTH: - case STANDALONE_MONTH: - replacement = getMonthString(inDate, count, c); - break; - - case SECONDS: + case 's': replacement = zeroPad(inDate.get(Calendar.SECOND), count); break; - - case TIME_ZONE: - replacement = getTimeZoneString(inDate, count); + case 'y': + replacement = getYearString(inDate.get(Calendar.YEAR), count); break; - - case YEAR: - replacement = getYearString(inDate, count); + case 'z': + replacement = getTimeZoneString(inDate, count); break; - default: replacement = null; break; } - + if (replacement != null) { s.replace(i, i + count, replacement); count = replacement.length(); // CARE: count is used in the for loop above len = s.length(); } } - - if (inFormat instanceof Spanned) + + if (inFormat instanceof Spanned) { return new SpannedString(s); - else + } else { return s.toString(); + } } - - private static String getMonthString(Calendar inDate, int count, int kind) { - boolean standalone = (kind == STANDALONE_MONTH); - int month = inDate.get(Calendar.MONTH); - - if (count >= 4) { - return standalone - ? DateUtils.getStandaloneMonthString(month, DateUtils.LENGTH_LONG) - : DateUtils.getMonthString(month, DateUtils.LENGTH_LONG); + + private static String getDayOfWeekString(LocaleData ld, int day, int count, int kind) { + boolean standalone = (kind == 'c'); + if (count == 5) { + return standalone ? ld.tinyStandAloneWeekdayNames[day] : ld.tinyWeekdayNames[day]; + } else if (count == 4) { + return standalone ? ld.longStandAloneWeekdayNames[day] : ld.longWeekdayNames[day]; + } else { + return standalone ? ld.shortStandAloneWeekdayNames[day] : ld.shortWeekdayNames[day]; + } + } + + private static String getMonthString(LocaleData ld, int month, int count, int kind) { + boolean standalone = (kind == 'L'); + if (count == 5) { + return standalone ? ld.tinyStandAloneMonthNames[month] : ld.tinyMonthNames[month]; + } else if (count == 4) { + return standalone ? ld.longStandAloneMonthNames[month] : ld.longMonthNames[month]; } else if (count == 3) { - return standalone - ? DateUtils.getStandaloneMonthString(month, DateUtils.LENGTH_MEDIUM) - : DateUtils.getMonthString(month, DateUtils.LENGTH_MEDIUM); + return standalone ? ld.shortStandAloneMonthNames[month] : ld.shortMonthNames[month]; } else { // Calendar.JANUARY == 0, so add 1 to month. return zeroPad(month+1, count); } } - + private static String getTimeZoneString(Calendar inDate, int count) { TimeZone tz = inDate.getTimeZone(); - if (count < 2) { // FIXME: shouldn't this be <= 2 ? return formatZoneOffset(inDate.get(Calendar.DST_OFFSET) + inDate.get(Calendar.ZONE_OFFSET), @@ -652,13 +563,12 @@ public class DateFormat { tb.append(zeroPad(minutes, 2)); return tb.toString(); } - - private static String getYearString(Calendar inDate, int count) { - int year = inDate.get(Calendar.YEAR); + + private static String getYearString(int year, int count) { return (count <= 2) ? zeroPad(year % 100, 2) : String.format(Locale.getDefault(), "%d", year); } - + private static int appendQuotedText(SpannableStringBuilder s, int i, int len) { if (i + 1 < len && s.charAt(i + 1) == QUOTE) { s.delete(i, i + 1); diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 8920b2482429..5a88cf69cdad 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -39,7 +39,6 @@ public class DateUtils { private static final Object sLock = new Object(); private static Configuration sLastConfig; - private static java.text.DateFormat sStatusTimeFormat; private static String sElapsedFormatMMSS; private static String sElapsedFormatHMMSS; @@ -95,14 +94,14 @@ public class DateUtils // translated. /** * This is not actually the preferred 24-hour date format in all locales. - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static final String HOUR_MINUTE_24 = "%H:%M"; public static final String MONTH_FORMAT = "%B"; /** * This is not actually a useful month name in all locales. - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static final String ABBREV_MONTH_FORMAT = "%b"; @@ -118,7 +117,7 @@ public class DateUtils // The index is constructed from a bit-wise OR of the boolean values: // {showTime, showYear, showWeekDay}. For example, if showYear and // showWeekDay are both true, then the index would be 3. - /** @deprecated do not use. */ + /** @deprecated Do not use. */ public static final int sameYearTable[] = { com.android.internal.R.string.same_year_md1_md2, com.android.internal.R.string.same_year_wday1_md1_wday2_md2, @@ -145,7 +144,7 @@ public class DateUtils // The index is constructed from a bit-wise OR of the boolean values: // {showTime, showYear, showWeekDay}. For example, if showYear and // showWeekDay are both true, then the index would be 3. - /** @deprecated do not use. */ + /** @deprecated Do not use. */ public static final int sameMonthTable[] = { com.android.internal.R.string.same_month_md1_md2, com.android.internal.R.string.same_month_wday1_md1_wday2_md2, @@ -172,7 +171,7 @@ public class DateUtils * * @more <p> * e.g. "Sunday" or "January" - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static final int LENGTH_LONG = 10; @@ -183,7 +182,7 @@ public class DateUtils * * @more <p> * e.g. "Sun" or "Jan" - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static final int LENGTH_MEDIUM = 20; @@ -195,7 +194,7 @@ public class DateUtils * <p>e.g. "Su" or "Jan" * <p>In most languages, the results returned for LENGTH_SHORT will be the same as * the results returned for {@link #LENGTH_MEDIUM}. - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static final int LENGTH_SHORT = 30; @@ -204,7 +203,7 @@ public class DateUtils * Request an even shorter abbreviated version of the name. * Do not use this. Currently this will always return the same result * as {@link #LENGTH_SHORT}. - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static final int LENGTH_SHORTER = 40; @@ -216,7 +215,7 @@ public class DateUtils * <p>e.g. "S", "T", "T" or "J" * <p>In some languages, the results returned for LENGTH_SHORTEST will be the same as * the results returned for {@link #LENGTH_SHORT}. - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static final int LENGTH_SHORTEST = 50; @@ -232,7 +231,7 @@ public class DateUtils * Undefined lengths will return {@link #LENGTH_MEDIUM} * but may return something different in the future. * @throws IndexOutOfBoundsException if the dayOfWeek is out of bounds. - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static String getDayOfWeekString(int dayOfWeek, int abbrev) { @@ -254,7 +253,7 @@ public class DateUtils * @param ampm Either {@link Calendar#AM Calendar.AM} or {@link Calendar#PM Calendar.PM}. * @throws IndexOutOfBoundsException if the ampm is out of bounds. * @return Localized version of "AM" or "PM". - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static String getAMPMString(int ampm) { @@ -270,14 +269,10 @@ public class DateUtils * Undefined lengths will return {@link #LENGTH_MEDIUM} * but may return something different in the future. * @return Localized month of the year. - * @deprecated use {@link java.text.SimpleDateFormat} instead. + * @deprecated Use {@link java.text.SimpleDateFormat} instead. */ @Deprecated public static String getMonthString(int month, int abbrev) { - // Note that here we use d.shortMonthNames for MEDIUM, SHORT and SHORTER. - // This is a shortcut to not spam the translators with too many variations - // of the same string. If we find that in a language the distinction - // is necessary, we can can add more without changing this API. LocaleData d = LocaleData.get(Locale.getDefault()); String[] names; switch (abbrev) { @@ -292,41 +287,6 @@ public class DateUtils } /** - * Return a localized string for the month of the year, for - * contexts where the month is not formatted together with - * a day of the month. - * - * @param month One of {@link Calendar#JANUARY Calendar.JANUARY}, - * {@link Calendar#FEBRUARY Calendar.FEBRUARY}, etc. - * @param abbrev One of {@link #LENGTH_LONG}, {@link #LENGTH_MEDIUM}, - * or {@link #LENGTH_SHORTEST}. - * Undefined lengths will return {@link #LENGTH_MEDIUM} - * but may return something different in the future. - * @return Localized month of the year. - * @hide Pending API council approval - * @deprecated use {@link java.text.SimpleDateFormat} instead. - */ - @Deprecated - public static String getStandaloneMonthString(int month, int abbrev) { - // Note that here we use d.shortMonthNames for MEDIUM, SHORT and SHORTER. - // This is a shortcut to not spam the translators with too many variations - // of the same string. If we find that in a language the distinction - // is necessary, we can can add more without changing this API. - LocaleData d = LocaleData.get(Locale.getDefault()); - String[] names; - switch (abbrev) { - case LENGTH_LONG: names = d.longStandAloneMonthNames; - break; - case LENGTH_MEDIUM: names = d.shortMonthNames; break; - case LENGTH_SHORT: names = d.shortMonthNames; break; - case LENGTH_SHORTER: names = d.shortMonthNames; break; - case LENGTH_SHORTEST: names = d.tinyMonthNames; break; - default: names = d.shortMonthNames; break; - } - return names[month]; - } - - /** * Returns a string describing the elapsed time since startTime. * @param startTime some time in the past. * @return a String object containing the elapsed time. @@ -429,20 +389,7 @@ public class DateUtils } } } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) { - count = getNumberOfDaysPassed(time, now); - if (past) { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_num_days_ago; - } else { - resId = com.android.internal.R.plurals.num_days_ago; - } - } else { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_in_num_days; - } else { - resId = com.android.internal.R.plurals.in_num_days; - } - } + return getRelativeDayString(r, time, now); } else { // We know that we won't be showing the time, so it is safe to pass // in a null context. @@ -454,24 +401,6 @@ public class DateUtils } /** - * Returns the number of days passed between two dates. - * - * @param date1 first date - * @param date2 second date - * @return number of days passed between to dates. - */ - private synchronized static long getNumberOfDaysPassed(long date1, long date2) { - if (sThenTime == null) { - sThenTime = new Time(); - } - sThenTime.set(date1); - int day1 = Time.getJulianDay(date1, sThenTime.gmtoff); - sThenTime.set(date2); - int day2 = Time.getJulianDay(date2, sThenTime.gmtoff); - return Math.abs(day2 - day1); - } - - /** * Return string describing the elapsed time since startTime formatted like * "[relative time/date], [time]". * <p> @@ -529,28 +458,29 @@ public class DateUtils * today this function returns "Today", if the day was a week ago it returns "7 days ago", and * if the day is in 2 weeks it returns "in 14 days". * - * @param r the resources to get the strings from + * @param r the resources * @param day the relative day to describe in UTC milliseconds * @param today the current time in UTC milliseconds - * @return a formatting string */ private static final String getRelativeDayString(Resources r, long day, long today) { + Locale locale = r.getConfiguration().locale; + if (locale == null) { + locale = Locale.getDefault(); + } + + // TODO: use TimeZone.getOffset instead. Time startTime = new Time(); startTime.set(day); + int startDay = Time.getJulianDay(day, startTime.gmtoff); + Time currentTime = new Time(); currentTime.set(today); - - int startDay = Time.getJulianDay(day, startTime.gmtoff); int currentDay = Time.getJulianDay(today, currentTime.gmtoff); int days = Math.abs(currentDay - startDay); boolean past = (today > day); // TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2). - Locale locale = r.getConfiguration().locale; - if (locale == null) { - locale = Locale.getDefault(); - } if (days == 1) { if (past) { return LocaleData.get(locale).yesterday; @@ -583,25 +513,12 @@ public class DateUtils Configuration cfg = r.getConfiguration(); if (sLastConfig == null || !sLastConfig.equals(cfg)) { sLastConfig = cfg; - sStatusTimeFormat = java.text.DateFormat.getTimeInstance(java.text.DateFormat.SHORT); sElapsedFormatMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_mm_ss); sElapsedFormatHMMSS = r.getString(com.android.internal.R.string.elapsed_time_short_format_h_mm_ss); } } /** - * Format a time so it appears like it would in the status bar clock. - * @deprecated use {@link #DateFormat.getTimeFormat(Context)} instead. - * @hide - */ - public static final CharSequence timeString(long millis) { - synchronized (sLock) { - initFormatStringsLocked(); - return sStatusTimeFormat.format(millis); - } - } - - /** * Return given duration in a human-friendly format. For example, "4 * minutes" or "1 second". Returns only largest meaningful unit of time, * from seconds up to hours. @@ -715,18 +632,6 @@ public class DateUtils } /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static Calendar newCalendar(boolean zulu) - { - if (zulu) - return Calendar.getInstance(TimeZone.getTimeZone("GMT")); - - return Calendar.getInstance(); - } - - /** * @return true if the supplied when is today else false */ public static boolean isToday(long when) { @@ -744,127 +649,6 @@ public class DateUtils } /** - * @hide - * @deprecated use {@link android.text.format.Time} - * Return true if this date string is local time - */ - public static boolean isUTC(String s) - { - if (s.length() == 16 && s.charAt(15) == 'Z') { - return true; - } - if (s.length() == 9 && s.charAt(8) == 'Z') { - // XXX not sure if this case possible/valid - return true; - } - return false; - } - - /** - * Return a string containing the date and time in RFC2445 format. - * Ensures that the time is written in UTC. The Calendar class doesn't - * really help out with this, so this is slower than it ought to be. - * - * @param cal the date and time to write - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static String writeDateTime(Calendar cal) - { - TimeZone tz = TimeZone.getTimeZone("GMT"); - GregorianCalendar c = new GregorianCalendar(tz); - c.setTimeInMillis(cal.getTimeInMillis()); - return writeDateTime(c, true); - } - - /** - * Return a string containing the date and time in RFC2445 format. - * - * @param cal the date and time to write - * @param zulu If the calendar is in UTC, pass true, and a Z will - * be written at the end as per RFC2445. Otherwise, the time is - * considered in localtime. - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static String writeDateTime(Calendar cal, boolean zulu) - { - StringBuilder sb = new StringBuilder(); - sb.ensureCapacity(16); - if (zulu) { - sb.setLength(16); - sb.setCharAt(15, 'Z'); - } else { - sb.setLength(15); - } - return writeDateTime(cal, sb); - } - - /** - * Return a string containing the date and time in RFC2445 format. - * - * @param cal the date and time to write - * @param sb a StringBuilder to use. It is assumed that setLength - * has already been called on sb to the appropriate length - * which is sb.setLength(zulu ? 16 : 15) - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static String writeDateTime(Calendar cal, StringBuilder sb) - { - int n; - - n = cal.get(Calendar.YEAR); - sb.setCharAt(3, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(2, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(1, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(0, (char)('0'+n%10)); - - n = cal.get(Calendar.MONTH) + 1; - sb.setCharAt(5, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(4, (char)('0'+n%10)); - - n = cal.get(Calendar.DAY_OF_MONTH); - sb.setCharAt(7, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(6, (char)('0'+n%10)); - - sb.setCharAt(8, 'T'); - - n = cal.get(Calendar.HOUR_OF_DAY); - sb.setCharAt(10, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(9, (char)('0'+n%10)); - - n = cal.get(Calendar.MINUTE); - sb.setCharAt(12, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(11, (char)('0'+n%10)); - - n = cal.get(Calendar.SECOND); - sb.setCharAt(14, (char)('0'+n%10)); - n /= 10; - sb.setCharAt(13, (char)('0'+n%10)); - - return sb.toString(); - } - - /** - * @hide - * @deprecated use {@link android.text.format.Time} - */ - public static void assign(Calendar lval, Calendar rval) - { - // there should be a faster way. - lval.clear(); - lval.setTimeInMillis(rval.getTimeInMillis()); - } - - /** * Formats a date or a time range according to the local conventions. * <p> * Note that this is a convenience method. Using it involves creating an @@ -1096,30 +880,34 @@ public class DateUtils // computation below that'd otherwise be thrown out. boolean isInstant = (startMillis == endMillis); - Time startDate; + Calendar startCalendar, endCalendar; + Time startDate = new Time(); if (timeZone != null) { - startDate = new Time(timeZone); + startCalendar = Calendar.getInstance(TimeZone.getTimeZone(timeZone)); } else if (useUTC) { - startDate = new Time(Time.TIMEZONE_UTC); + startCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); } else { - startDate = new Time(); + startCalendar = Calendar.getInstance(); } - startDate.set(startMillis); + startCalendar.setTimeInMillis(startMillis); + setTimeFromCalendar(startDate, startCalendar); - Time endDate; + Time endDate = new Time(); int dayDistance; if (isInstant) { endDate = startDate; dayDistance = 0; } else { if (timeZone != null) { - endDate = new Time(timeZone); + endCalendar = Calendar.getInstance(TimeZone.getTimeZone(timeZone)); } else if (useUTC) { - endDate = new Time(Time.TIMEZONE_UTC); + endCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); } else { - endDate = new Time(); + endCalendar = Calendar.getInstance(); } - endDate.set(endMillis); + endCalendar.setTimeInMillis(endMillis); + setTimeFromCalendar(endDate, endCalendar); + int startJulianDay = Time.getJulianDay(startMillis, startDate.gmtoff); int endJulianDay = Time.getJulianDay(endMillis, endDate.gmtoff); dayDistance = endJulianDay - startJulianDay; @@ -1462,6 +1250,20 @@ public class DateUtils return formatter.format(fullFormat, timeString, startWeekDayString, dateString); } + private static void setTimeFromCalendar(Time t, Calendar c) { + t.hour = c.get(Calendar.HOUR_OF_DAY); + t.minute = c.get(Calendar.MINUTE); + t.month = c.get(Calendar.MONTH); + t.monthDay = c.get(Calendar.DAY_OF_MONTH); + t.second = c.get(Calendar.SECOND); + t.weekDay = c.get(Calendar.DAY_OF_WEEK) - 1; + t.year = c.get(Calendar.YEAR); + t.yearDay = c.get(Calendar.DAY_OF_YEAR); + t.isDst = (c.get(Calendar.DST_OFFSET) != 0) ? 1 : 0; + t.gmtoff = c.get(Calendar.ZONE_OFFSET) + c.get(Calendar.DST_OFFSET); + t.timezone = c.getTimeZone().getID(); + } + /** * Formats a date or a time according to the local conventions. There are * lots of options that allow the caller to control, for example, if the diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index 121c6f2f9324..9c98b98dedf4 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -95,16 +95,12 @@ public final class Formatter { } /** - * Returns a string in the canonical IP format ###.###.###.### from a packed integer containing - * the IP address. The IP address is expected to be in little-endian format (LSB first). That - * is, 0x01020304 will return "4.3.2.1". + * Returns a string in the canonical IPv4 format ###.###.###.### from a packed integer + * containing the IP address. The IPv4 address is expected to be in little-endian + * format (LSB first). That is, 0x01020304 will return "4.3.2.1". * - * @param ipv4Address the IP address as a packed integer with LSB first. - * @return string with canonical IP address format. - * - * @deprecated this method doesn't support IPv6 addresses. Prefer {@link - * java.net.InetAddress#getHostAddress()}, which supports both IPv4 and - * IPv6 addresses. + * @deprecated Use {@link java.net.InetAddress#getHostAddress()}, which supports both IPv4 and + * IPv6 addresses. This method does not support IPv6 addresses. */ @Deprecated public static String formatIpAddress(int ipv4Address) { diff --git a/core/java/android/util/FloatMath.java b/core/java/android/util/FloatMath.java index 955622396aac..0ffd5bd61098 100644 --- a/core/java/android/util/FloatMath.java +++ b/core/java/android/util/FloatMath.java @@ -17,12 +17,10 @@ package android.util; /** - * Math routines similar to those found in {@link java.lang.Math}. Performs - * computations on {@code float} values directly without incurring the overhead - * of conversions to and from {@code double}. - * - * <p>On one platform, {@code FloatMath.sqrt(100)} executes in one third of the - * time required by {@code java.lang.Math.sqrt(100)}.</p> + * Math routines similar to those found in {@link java.lang.Math}. On + * versions of Android with a JIT, these are significantly slower than + * the equivalent {@code Math} functions, which should be used in preference + * to these. */ public class FloatMath { diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java index 366abd36294d..7e8fee56ea95 100644 --- a/core/java/android/util/SparseArray.java +++ b/core/java/android/util/SparseArray.java @@ -118,7 +118,7 @@ public class SparseArray<E> implements Cloneable { mGarbage = true; } } - + private void gc() { // Log.e("SparseArray", "gc start with " + mSize); @@ -214,7 +214,7 @@ public class SparseArray<E> implements Cloneable { /** * Given an index in the range <code>0...size()-1</code>, returns * the key from the <code>index</code>th key-value mapping that this - * SparseArray stores. + * SparseArray stores. */ public int keyAt(int index) { if (mGarbage) { @@ -223,11 +223,11 @@ public class SparseArray<E> implements Cloneable { return mKeys[index]; } - + /** * Given an index in the range <code>0...size()-1</code>, returns * the value from the <code>index</code>th key-value mapping that this - * SparseArray stores. + * SparseArray stores. */ @SuppressWarnings("unchecked") public E valueAt(int index) { @@ -241,7 +241,7 @@ public class SparseArray<E> implements Cloneable { /** * Given an index in the range <code>0...size()-1</code>, sets a new * value for the <code>index</code>th key-value mapping that this - * SparseArray stores. + * SparseArray stores. */ public void setValueAt(int index, E value) { if (mGarbage) { @@ -250,7 +250,7 @@ public class SparseArray<E> implements Cloneable { mValues[index] = value; } - + /** * Returns the index for which {@link #keyAt} would return the * specified key, or a negative number if the specified @@ -268,9 +268,11 @@ public class SparseArray<E> implements Cloneable { * Returns an index for which {@link #valueAt} would return the * specified key, or a negative number if no keys map to the * specified value. - * Beware that this is a linear search, unlike lookups by key, + * <p>Beware that this is a linear search, unlike lookups by key, * and that multiple keys can map to the same value and this will * find only one of them. + * <p>Note also that unlike most collections' {@code indexOf} methods, + * this method compares values using {@code ==} rather than {@code equals}. */ public int indexOfValue(E value) { if (mGarbage) { @@ -332,7 +334,7 @@ public class SparseArray<E> implements Cloneable { mValues[pos] = value; mSize = pos + 1; } - + private static int binarySearch(int[] a, int start, int len, int key) { int high = start + len, low = start - 1, guess; diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java index c3a1a17d88a1..023dfa8dafe4 100644 --- a/core/java/android/webkit/BrowserFrame.java +++ b/core/java/android/webkit/BrowserFrame.java @@ -1324,7 +1324,7 @@ class BrowserFrame extends Handler { private native void nativeSslCertErrorCancel(int handle, int certError); native void nativeSslClientCert(int handle, - int ctx, + long ctx, byte[][] asn1DerEncodedCertificateChain); native void nativeSslClientCert(int handle, diff --git a/core/java/android/webkit/ClientCertRequestHandler.java b/core/java/android/webkit/ClientCertRequestHandler.java index dac151054198..f5a60f6e871d 100644 --- a/core/java/android/webkit/ClientCertRequestHandler.java +++ b/core/java/android/webkit/ClientCertRequestHandler.java @@ -75,7 +75,7 @@ public final class ClientCertRequestHandler extends Handler { /** * Proceed with the specified private key bytes and client certificate chain. */ - private void setSslClientCertFromCtx(final int ctx, final byte[][] chainBytes) { + private void setSslClientCertFromCtx(final long ctx, final byte[][] chainBytes) { post(new Runnable() { public void run() { mBrowserFrame.nativeSslClientCert(mHandle, ctx, chainBytes); diff --git a/core/java/android/webkit/HTML5Audio.java b/core/java/android/webkit/HTML5Audio.java index fc5df2d5f59c..684ec073ce45 100644 --- a/core/java/android/webkit/HTML5Audio.java +++ b/core/java/android/webkit/HTML5Audio.java @@ -54,14 +54,15 @@ class HTML5Audio extends Handler // The private status of the view that created this player private IsPrivateBrowsingEnabledGetter mIsPrivateBrowsingEnabledGetter; - private static int IDLE = 0; - private static int INITIALIZED = 1; - private static int PREPARED = 2; - private static int STARTED = 4; - private static int COMPLETE = 5; - private static int PAUSED = 6; - private static int STOPPED = -2; - private static int ERROR = -1; + private static int IDLE = 0; + private static int INITIALIZED = 1; + private static int PREPARED = 2; + private static int STARTED = 4; + private static int COMPLETE = 5; + private static int PAUSED = 6; + private static int PAUSED_TRANSITORILY = 7; + private static int STOPPED = -2; + private static int ERROR = -1; private int mState = IDLE; @@ -247,7 +248,7 @@ class HTML5Audio extends Handler // resume playback if (mMediaPlayer == null) { resetMediaPlayer(); - } else if (mState != ERROR && !mMediaPlayer.isPlaying()) { + } else if (mState == PAUSED_TRANSITORILY && !mMediaPlayer.isPlaying()) { mMediaPlayer.start(); mState = STARTED; } @@ -265,7 +266,9 @@ class HTML5Audio extends Handler case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: // Lost focus for a short time, but we have to stop // playback. - if (mState != ERROR && mMediaPlayer.isPlaying()) pause(); + if (mState != ERROR && mMediaPlayer.isPlaying()) { + pause(PAUSED_TRANSITORILY); + } break; } } @@ -298,12 +301,16 @@ class HTML5Audio extends Handler } private void pause() { + pause(PAUSED); + } + + private void pause(int state) { if (mState == STARTED) { if (mTimer != null) { mTimer.purge(); } mMediaPlayer.pause(); - mState = PAUSED; + mState = state; } } diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java index 7154f9580590..4db9f6c27342 100644 --- a/core/java/android/webkit/WebViewClassic.java +++ b/core/java/android/webkit/WebViewClassic.java @@ -5416,7 +5416,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc ClipData clipData = cm.getPrimaryClip(); if (clipData != null) { ClipData.Item clipItem = clipData.getItemAt(0); - CharSequence pasteText = clipItem.getText(); + CharSequence pasteText = clipItem.coerceToText(mContext); if (mInputConnection != null) { mInputConnection.replaceSelection(pasteText); } @@ -8368,8 +8368,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc mListBoxDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { + if (mWebViewCore != null) { mWebViewCore.sendMessage( EventHub.SINGLE_LISTBOX_CHOICE, -2, 0); + } mListBoxDialog = null; } }); diff --git a/core/java/android/widget/DigitalClock.java b/core/java/android/widget/DigitalClock.java index c6b6dd68f182..b6c1e5b9532f 100644 --- a/core/java/android/widget/DigitalClock.java +++ b/core/java/android/widget/DigitalClock.java @@ -39,8 +39,6 @@ public class DigitalClock extends TextView { // proportional fonts don't shake rendering Calendar mCalendar; - private final static String m12 = "h:mm:ss aa"; - private final static String m24 = "k:mm:ss"; @SuppressWarnings("FieldCanBeLocal") // We must keep a reference to this observer private FormatChangeObserver mFormatChangeObserver; @@ -102,19 +100,8 @@ public class DigitalClock extends TextView { mTickerStopped = true; } - /** - * Pulls 12/24 mode from system settings - */ - private boolean get24HourMode() { - return android.text.format.DateFormat.is24HourFormat(getContext()); - } - private void setFormat() { - if (get24HourMode()) { - mFormat = m24; - } else { - mFormat = m12; - } + mFormat = DateFormat.getTimeFormatString(getContext()); } private class FormatChangeObserver extends ContentObserver { diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index 290d9b5b4a52..2f08253e0721 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -36,21 +36,24 @@ import com.android.internal.R; import java.util.Calendar; import java.util.TimeZone; +import libcore.icu.LocaleData; + import static android.view.ViewDebug.ExportedProperty; import static android.widget.RemoteViews.*; /** * <p><code>TextClock</code> can display the current date and/or time as * a formatted string.</p> - * + * * <p>This view honors the 24-hour format system setting. As such, it is * possible and recommended to provide two different formatting patterns: * one to display the date/time in 24-hour mode and one to display the - * date/time in 12-hour mode.</p> - * + * date/time in 12-hour mode. Most callers will want to use the defaults, + * though, which will be appropriate for the user's locale.</p> + * * <p>It is possible to determine whether the system is currently in * 24-hour mode by calling {@link #is24HourModeEnabled()}.</p> - * + * * <p>The rules used by this widget to decide how to format the date and * time are the following:</p> * <ul> @@ -58,22 +61,24 @@ import static android.widget.RemoteViews.*; * <ul> * <li>Use the value returned by {@link #getFormat24Hour()} when non-null</li> * <li>Otherwise, use the value returned by {@link #getFormat12Hour()} when non-null</li> - * <li>Otherwise, use {@link #DEFAULT_FORMAT_24_HOUR}</li> + * <li>Otherwise, use a default value appropriate for the user's locale, such as {@code h:mm a}</li> * </ul> * </li> * <li>In 12-hour mode: * <ul> * <li>Use the value returned by {@link #getFormat12Hour()} when non-null</li> * <li>Otherwise, use the value returned by {@link #getFormat24Hour()} when non-null</li> - * <li>Otherwise, use {@link #DEFAULT_FORMAT_12_HOUR}</li> + * <li>Otherwise, use a default value appropriate for the user's locale, such as {@code HH:mm}</li> * </ul> * </li> * </ul> - * + * * <p>The {@link CharSequence} instances used as formatting patterns when calling either * {@link #setFormat24Hour(CharSequence)} or {@link #setFormat12Hour(CharSequence)} can - * contain styling information. To do so, use a {@link android.text.Spanned} object.</p> - * + * contain styling information. To do so, use a {@link android.text.Spanned} object. + * Note that if you customize these strings, it is your responsibility to supply strings + * appropriate for formatting dates and/or times in the user's locale.</p> + * * @attr ref android.R.styleable#TextClock_format12Hour * @attr ref android.R.styleable#TextClock_format24Hour * @attr ref android.R.styleable#TextClock_timeZone @@ -81,32 +86,34 @@ import static android.widget.RemoteViews.*; @RemoteView public class TextClock extends TextView { /** - * The default formatting pattern in 12-hour mode. This pattenr is used + * The default formatting pattern in 12-hour mode. This pattern is used * if {@link #setFormat12Hour(CharSequence)} is called with a null pattern * or if no pattern was specified when creating an instance of this class. - * + * * This default pattern shows only the time, hours and minutes, and an am/pm * indicator. * * @see #setFormat12Hour(CharSequence) * @see #getFormat12Hour() + * @deprecated Let the system use locale-appropriate defaults instead. */ - public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm aa"; + public static final CharSequence DEFAULT_FORMAT_12_HOUR = "h:mm a"; /** - * The default formatting pattern in 24-hour mode. This pattenr is used + * The default formatting pattern in 24-hour mode. This pattern is used * if {@link #setFormat24Hour(CharSequence)} is called with a null pattern * or if no pattern was specified when creating an instance of this class. * * This default pattern shows only the time, hours and minutes. - * - * @see #setFormat24Hour(CharSequence) - * @see #getFormat24Hour() + * + * @see #setFormat24Hour(CharSequence) + * @see #getFormat24Hour() + * @deprecated Let the system use locale-appropriate defaults instead. */ - public static final CharSequence DEFAULT_FORMAT_24_HOUR = "k:mm"; + public static final CharSequence DEFAULT_FORMAT_24_HOUR = "H:mm"; - private CharSequence mFormat12 = DEFAULT_FORMAT_12_HOUR; - private CharSequence mFormat24 = DEFAULT_FORMAT_24_HOUR; + private CharSequence mFormat12; + private CharSequence mFormat24; @ExportedProperty private CharSequence mFormat; @@ -158,7 +165,7 @@ public class TextClock extends TextView { * Creates a new clock using the default patterns * {@link #DEFAULT_FORMAT_24_HOUR} and {@link #DEFAULT_FORMAT_12_HOUR} * respectively for the 24-hour and 12-hour modes. - * + * * @param context The Context the view is running in, through which it can * access the current theme, resources, etc. */ @@ -171,7 +178,7 @@ public class TextClock extends TextView { /** * Creates a new clock inflated from XML. This object's properties are * intialized from the attributes specified in XML. - * + * * This constructor uses a default style of 0, so the only attribute values * applied are those in the Context's Theme and the given AttributeSet. * @@ -201,14 +208,8 @@ public class TextClock extends TextView { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TextClock, defStyle, 0); try { - CharSequence format; - - format = a.getText(R.styleable.TextClock_format12Hour); - mFormat12 = format == null ? DEFAULT_FORMAT_12_HOUR : format; - - format = a.getText(R.styleable.TextClock_format24Hour); - mFormat24 = format == null ? DEFAULT_FORMAT_24_HOUR : format; - + mFormat12 = a.getText(R.styleable.TextClock_format12Hour); + mFormat24 = a.getText(R.styleable.TextClock_format24Hour); mTimeZone = a.getString(R.styleable.TextClock_timeZone); } finally { a.recycle(); @@ -218,6 +219,16 @@ public class TextClock extends TextView { } private void init() { + if (mFormat12 == null || mFormat24 == null) { + LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale); + if (mFormat12 == null) { + mFormat12 = ld.timeFormat12; + } + if (mFormat24 == null) { + mFormat24 = ld.timeFormat24; + } + } + createTime(mTimeZone); // Wait until onAttachedToWindow() to handle the ticker chooseFormat(false); @@ -235,11 +246,11 @@ public class TextClock extends TextView { * Returns the formatting pattern used to display the date and/or time * in 12-hour mode. The formatting pattern syntax is described in * {@link DateFormat}. - * + * * @return A {@link CharSequence} or null. - * - * @see #setFormat12Hour(CharSequence) - * @see #is24HourModeEnabled() + * + * @see #setFormat12Hour(CharSequence) + * @see #is24HourModeEnabled() */ @ExportedProperty public CharSequence getFormat12Hour() { @@ -257,12 +268,12 @@ public class TextClock extends TextView { * {@link #DEFAULT_FORMAT_12_HOUR} will be used instead. * * @param format A date/time formatting pattern as described in {@link DateFormat} - * + * * @see #getFormat12Hour() * @see #is24HourModeEnabled() * @see #DEFAULT_FORMAT_12_HOUR * @see DateFormat - * + * * @attr ref android.R.styleable#TextClock_format12Hour */ @RemotableViewMethod @@ -292,7 +303,7 @@ public class TextClock extends TextView { * Specifies the formatting pattern used to display the date and/or time * in 24-hour mode. The formatting pattern syntax is described in * {@link DateFormat}. - * + * * If this pattern is set to null, {@link #getFormat12Hour()} will be used * even in 24-hour mode. If both 24-hour and 12-hour formatting patterns * are set to null, {@link #DEFAULT_FORMAT_24_HOUR} and @@ -301,7 +312,7 @@ public class TextClock extends TextView { * @param format A date/time formatting pattern as described in {@link DateFormat} * * @see #getFormat24Hour() - * @see #is24HourModeEnabled() + * @see #is24HourModeEnabled() * @see #DEFAULT_FORMAT_24_HOUR * @see DateFormat * @@ -317,22 +328,22 @@ public class TextClock extends TextView { /** * Indicates whether the system is currently using the 24-hour mode. - * + * * When the system is in 24-hour mode, this view will use the pattern * returned by {@link #getFormat24Hour()}. In 12-hour mode, the pattern * returned by {@link #getFormat12Hour()} is used instead. - * + * * If either one of the formats is null, the other format is used. If * both formats are null, the default values {@link #DEFAULT_FORMAT_12_HOUR} * and {@link #DEFAULT_FORMAT_24_HOUR} are used instead. - * + * * @return true if time should be displayed in 24-hour format, false if it * should be displayed in 12-hour format. - * + * * @see #setFormat12Hour(CharSequence) - * @see #getFormat12Hour() + * @see #getFormat12Hour() * @see #setFormat24Hour(CharSequence) - * @see #getFormat24Hour() + * @see #getFormat24Hour() */ public boolean is24HourModeEnabled() { return DateFormat.is24HourFormat(getContext()); @@ -340,13 +351,13 @@ public class TextClock extends TextView { /** * Indicates which time zone is currently used by this view. - * + * * @return The ID of the current time zone or null if the default time zone, * as set by the user, must be used * * @see TimeZone * @see java.util.TimeZone#getAvailableIDs() - * @see #setTimeZone(String) + * @see #setTimeZone(String) */ public String getTimeZone() { return mTimeZone; @@ -378,7 +389,7 @@ public class TextClock extends TextView { /** * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()} * depending on whether the user has selected 24-hour format. - * + * * Calling this method does not schedule or unschedule the time ticker. */ private void chooseFormat() { @@ -388,17 +399,19 @@ public class TextClock extends TextView { /** * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()} * depending on whether the user has selected 24-hour format. - * + * * @param handleTicker true if calling this method should schedule/unschedule the * time ticker, false otherwise */ private void chooseFormat(boolean handleTicker) { final boolean format24Requested = is24HourModeEnabled(); + LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale); + if (format24Requested) { - mFormat = abc(mFormat24, mFormat12, DEFAULT_FORMAT_24_HOUR); + mFormat = abc(mFormat24, mFormat12, ld.timeFormat24); } else { - mFormat = abc(mFormat12, mFormat24, DEFAULT_FORMAT_12_HOUR); + mFormat = abc(mFormat12, mFormat24, ld.timeFormat12); } boolean hadSeconds = mHasSeconds; diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java index eed3e67918e8..eb2d1fe3e79a 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/core/java/com/android/internal/backup/LocalTransport.java @@ -27,6 +27,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.SELinux; import android.util.Log; import com.android.org.bouncycastle.util.encoders.Base64; @@ -64,6 +65,10 @@ public class LocalTransport extends IBackupTransport.Stub { public LocalTransport(Context context) { mContext = context; + mDataDir.mkdirs(); + if (!SELinux.restorecon(mDataDir)) { + Log.e(TAG, "SELinux restorecon failed for " + mDataDir); + } } public Intent configurationIntent() { diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 9b95be162361..d8f20c179dc0 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -11,10 +11,6 @@ else LOCAL_CFLAGS += -DPACKED="" endif -ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),) - LOCAL_CFLAGS += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX) -endif - ifeq ($(USE_OPENGL_RENDERER),true) LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER endif diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp index 42d408d23ce6..f5eaf94b15d2 100644 --- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp +++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp @@ -2,16 +2,16 @@ ** ** Copyright 2006, 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 +** 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 +** 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 +** 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. */ @@ -23,20 +23,17 @@ #include <android_runtime/AndroidRuntime.h> #include <utils/Log.h> +#include <utils/String8.h> #include <fcntl.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> -#if defined(__arm__) -extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, - size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); - -extern "C" void free_malloc_leak_info(uint8_t* info); -#endif +extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, + size_t* infoSize, size_t* totalMemory, size_t* backtraceSize); -#define MAPS_FILE_SIZE 65 * 1024 +extern "C" void free_malloc_leak_info(uint8_t* info); struct Header { size_t mapSize; @@ -48,96 +45,57 @@ struct Header { namespace android { +static void ReadFile(const char* path, String8& s) { + int fd = open(path, O_RDONLY); + if (fd != -1) { + char bytes[1024]; + ssize_t byteCount; + while ((byteCount = TEMP_FAILURE_RETRY(read(fd, bytes, sizeof(bytes)))) > 0) { + s.append(bytes, byteCount); + } + close(fd); + } +} + /* - * Retrieve the native heap information and the info from /proc/<self>/maps, + * Retrieve the native heap information and the info from /proc/self/maps, * copy them into a byte[] with a "struct Header" that holds data offsets, * and return the array. */ -static jbyteArray getLeakInfo(JNIEnv *env, jobject clazz) -{ -#if defined(__arm__) - // get the info in /proc/[pid]/map +static jbyteArray DdmHandleNativeHeap_getLeakInfo(JNIEnv* env, jobject) { Header header; memset(&header, 0, sizeof(header)); - pid_t pid = getpid(); - - char path[FILENAME_MAX]; - sprintf(path, "/proc/%d/maps", pid); - - struct stat sb; - int ret = stat(path, &sb); - - uint8_t* mapsFile = NULL; - if (ret == 0) { - mapsFile = (uint8_t*)malloc(MAPS_FILE_SIZE); - int fd = open(path, O_RDONLY); - - if (mapsFile != NULL && fd != -1) { - int amount = 0; - do { - uint8_t* ptr = mapsFile + header.mapSize; - amount = read(fd, ptr, MAPS_FILE_SIZE); - if (amount <= 0) { - if (errno != EINTR) - break; - else - continue; - } - header.mapSize += amount; - } while (header.mapSize < MAPS_FILE_SIZE); - - ALOGD("**** read %d bytes from '%s'", (int) header.mapSize, path); - } - } + String8 maps; + ReadFile("/proc/self/maps", maps); + header.mapSize = maps.size(); uint8_t* allocBytes; - get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize, - &header.totalMemory, &header.backtraceSize); + get_malloc_leak_info(&allocBytes, &header.allocSize, &header.allocInfoSize, + &header.totalMemory, &header.backtraceSize); - jbyte* bytes = NULL; - jbyte* ptr = NULL; - jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize); - if (array == NULL) { - goto done; - } - - bytes = env->GetByteArrayElements(array, NULL); - ptr = bytes; - -// ALOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d", -// header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory); + ALOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d", + header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory); - memcpy(ptr, &header, sizeof(header)); - ptr += sizeof(header); - - if (header.mapSize > 0 && mapsFile != NULL) { - memcpy(ptr, mapsFile, header.mapSize); - ptr += header.mapSize; + jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize); + if (array != NULL) { + env->SetByteArrayRegion(array, 0, + sizeof(header), reinterpret_cast<jbyte*>(&header)); + env->SetByteArrayRegion(array, sizeof(header), + maps.size(), reinterpret_cast<const jbyte*>(maps.string())); + env->SetByteArrayRegion(array, sizeof(header) + maps.size(), + header.allocSize, reinterpret_cast<jbyte*>(allocBytes)); } - - memcpy(ptr, allocBytes, header.allocSize); - env->ReleaseByteArrayElements(array, bytes, 0); -done: - if (mapsFile != NULL) { - free(mapsFile); - } - // free the info up! free_malloc_leak_info(allocBytes); - return array; -#else - return NULL; -#endif } static JNINativeMethod method_table[] = { - { "getLeakInfo", "()[B", (void*)getLeakInfo }, + { "getLeakInfo", "()[B", (void*) DdmHandleNativeHeap_getLeakInfo }, }; -int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env) -{ +int register_android_ddm_DdmHandleNativeHeap(JNIEnv* env) { return AndroidRuntime::registerNativeMethods(env, "android/ddm/DdmHandleNativeHeap", method_table, NELEM(method_table)); } diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 6e21a1123e7b..2883c102dada 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -43,6 +43,7 @@ enum { HEAP_UNKNOWN, HEAP_DALVIK, HEAP_NATIVE, + HEAP_STACK, HEAP_CURSOR, HEAP_ASHMEM, HEAP_UNKNOWN_DEV, @@ -109,7 +110,7 @@ static jlong android_os_Debug_getNativeHeapAllocatedSize(JNIEnv *env, jobject cl static jlong android_os_Debug_getNativeHeapFreeSize(JNIEnv *env, jobject clazz) { -#ifdef HAVE_MALLOC_H +#ifdef HAVE_MALLOC_H struct mallinfo info = mallinfo(); return (jlong) info.fordblks; #else @@ -164,6 +165,8 @@ static void read_mapinfo(FILE *fp, stats_t* stats) whichHeap = HEAP_NATIVE; } else if (strstr(name, "/dev/ashmem/dalvik-") == name) { whichHeap = HEAP_DALVIK; + } else if (strstr(name, "[stack") == name) { + whichHeap = HEAP_STACK; } else if (strstr(name, "/dev/ashmem/CursorWindow") == name) { whichHeap = HEAP_CURSOR; } else if (strstr(name, "/dev/ashmem/") == name) { @@ -191,7 +194,7 @@ static void read_mapinfo(FILE *fp, stats_t* stats) //ALOGI("native=%d dalvik=%d sqlite=%d: %s\n", isNativeHeap, isDalvikHeap, // isSqliteHeap, line); - + while (true) { if (fgets(line, 1024, fp) == 0) { done = true; @@ -233,7 +236,7 @@ static void load_maps(int pid, stats_t* stats) { char tmp[128]; FILE *fp; - + sprintf(tmp, "/proc/%d/smaps", pid); fp = fopen(tmp, "r"); if (fp == 0) return; @@ -247,7 +250,7 @@ static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, { stats_t stats[_NUM_HEAP]; memset(&stats, 0, sizeof(stats)); - + load_maps(pid, stats); for (int i=_NUM_CORE_HEAP; i<_NUM_HEAP; i++) { @@ -261,9 +264,9 @@ static void android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, env->SetIntField(object, stat_fields[i].privateDirty_field, stats[i].privateDirty); env->SetIntField(object, stat_fields[i].sharedDirty_field, stats[i].sharedDirty); } - + jintArray otherIntArray = (jintArray)env->GetObjectField(object, otherStats_field); - + jint* otherArray = (jint*)env->GetPrimitiveArrayCritical(otherIntArray, 0); if (otherArray == NULL) { return; @@ -328,7 +331,7 @@ static jint read_binder_stat(const char* stat) char compare[128]; int len = snprintf(compare, 128, "proc %d", getpid()); - + // loop until we have the block that represents this process do { if (fgets(line, 1024, fp) == 0) { @@ -336,15 +339,15 @@ static jint read_binder_stat(const char* stat) } } while (strncmp(compare, line, len)); - // now that we have this process, read until we find the stat that we are looking for + // now that we have this process, read until we find the stat that we are looking for len = snprintf(compare, 128, " %s: ", stat); - + do { if (fgets(line, 1024, fp) == 0) { return -1; } } while (strncmp(compare, line, len)); - + // we have the line, now increment the line ptr to the value char* ptr = line + len; return atoi(ptr); @@ -510,7 +513,7 @@ static void android_os_Debug_dumpNativeHeap(JNIEnv* env, jobject clazz, jobject fileDescriptor) { if (fileDescriptor == NULL) { - jniThrowNullPointerException(env, NULL); + jniThrowNullPointerException(env, "fd == null"); return; } int origFd = jniGetFDFromFileDescriptor(env, fileDescriptor); @@ -547,7 +550,7 @@ static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject claz jint pid, jstring fileName) { if (fileName == NULL) { - jniThrowNullPointerException(env, NULL); + jniThrowNullPointerException(env, "file == null"); return; } const jchar* str = env->GetStringCritical(fileName, 0); @@ -611,6 +614,19 @@ int register_android_os_Debug(JNIEnv *env) { jclass clazz = env->FindClass("android/os/Debug$MemoryInfo"); + // Sanity check the number of other statistics expected in Java matches here. + jfieldID numOtherStats_field = env->GetStaticFieldID(clazz, "NUM_OTHER_STATS", "I"); + jint numOtherStats = env->GetStaticIntField(clazz, numOtherStats_field); + int expectedNumOtherStats = _NUM_HEAP - _NUM_CORE_HEAP; + if (numOtherStats != expectedNumOtherStats) { + jniThrowExceptionFmt(env, "java/lang/RuntimeException", + "android.os.Debug.Meminfo.NUM_OTHER_STATS=%d expected %d", + numOtherStats, expectedNumOtherStats); + return JNI_ERR; + } + + otherStats_field = env->GetFieldID(clazz, "otherStats", "[I"); + for (int i=0; i<_NUM_CORE_HEAP; i++) { stat_fields[i].pss_field = env->GetFieldID(clazz, stat_field_names[i].pss_name, "I"); @@ -620,8 +636,6 @@ int register_android_os_Debug(JNIEnv *env) env->GetFieldID(clazz, stat_field_names[i].sharedDirty_name, "I"); } - otherStats_field = env->GetFieldID(clazz, "otherStats", "[I"); - return jniRegisterNativeMethods(env, "android/os/Debug", gMethods, NELEM(gMethods)); } diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp index b12fdfc9999b..0a97f3922113 100644 --- a/core/jni/android_os_SELinux.cpp +++ b/core/jni/android_os_SELinux.cpp @@ -23,428 +23,407 @@ #include "selinux/selinux.h" #include "selinux/android.h" #include <errno.h> +#include <ScopedLocalRef.h> +#include <ScopedUtfChars.h> +#include <UniquePtr.h> namespace android { - static jboolean isSELinuxDisabled = true; - - static void throw_NullPointerException(JNIEnv *env, const char* msg) { - jclass clazz; - clazz = env->FindClass("java/lang/NullPointerException"); - env->ThrowNew(clazz, msg); - } +struct SecurityContext_Delete { + void operator()(security_context_t p) const { + freecon(p); + } +}; +typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext; - /* - * Function: isSELinuxEnabled - * Purpose: checks whether SELinux is enabled/disbaled - * Parameters: none - * Return value : true (enabled) or false (disabled) - * Exceptions: none - */ - static jboolean isSELinuxEnabled(JNIEnv *env, jobject classz) { +static jboolean isSELinuxDisabled = true; +/* + * Function: isSELinuxEnabled + * Purpose: checks whether SELinux is enabled/disbaled + * Parameters: none + * Return value : true (enabled) or false (disabled) + * Exceptions: none + */ +static jboolean isSELinuxEnabled(JNIEnv *env, jobject) { return !isSELinuxDisabled; - } - - /* - * Function: isSELinuxEnforced - * Purpose: return the current SELinux enforce mode - * Parameters: none - * Return value: true (enforcing) or false (permissive) - * Exceptions: none - */ - static jboolean isSELinuxEnforced(JNIEnv *env, jobject clazz) { +} + +/* + * Function: isSELinuxEnforced + * Purpose: return the current SELinux enforce mode + * Parameters: none + * Return value: true (enforcing) or false (permissive) + * Exceptions: none + */ +static jboolean isSELinuxEnforced(JNIEnv *env, jobject) { return (security_getenforce() == 1) ? true : false; - } +} - /* - * Function: setSELinuxEnforce - * Purpose: set the SE Linux enforcing mode - * Parameters: true (enforcing) or false (permissive) - * Return value: true (success) or false (fail) - * Exceptions: none - */ - static jboolean setSELinuxEnforce(JNIEnv *env, jobject clazz, jboolean value) { - if (isSELinuxDisabled) - return false; +/* + * Function: setSELinuxEnforce + * Purpose: set the SE Linux enforcing mode + * Parameters: true (enforcing) or false (permissive) + * Return value: true (success) or false (fail) + * Exceptions: none + */ +static jboolean setSELinuxEnforce(JNIEnv *env, jobject, jboolean value) { + if (isSELinuxDisabled) { + return false; + } - int enforce = (value) ? 1 : 0; + int enforce = value ? 1 : 0; return (security_setenforce(enforce) != -1) ? true : false; - } - - /* - * Function: getPeerCon - * Purpose: retrieves security context of peer socket - * Parameters: - * fileDescriptor: peer socket file as a FileDescriptor object - * Returns: jstring representing the security_context of socket or NULL if error - * Exceptions: NullPointerException if fileDescriptor object is NULL - */ - static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) { - if (isSELinuxDisabled) - return NULL; +} - if (fileDescriptor == NULL) { - throw_NullPointerException(env, "Trying to check security context of a null peer socket."); - return NULL; +/* + * Function: getPeerCon + * Purpose: retrieves security context of peer socket + * Parameters: + * fileDescriptor: peer socket file as a FileDescriptor object + * Returns: jstring representing the security_context of socket or NULL if error + * Exceptions: NullPointerException if fileDescriptor object is NULL + */ +static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) { + if (isSELinuxDisabled) { + return NULL; } - security_context_t context = NULL; - jstring securityString = NULL; + if (fileDescriptor == NULL) { + jniThrowNullPointerException(env, + "Trying to check security context of a null peer socket."); + return NULL; + } int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); - if (env->ExceptionOccurred() != NULL) { - ALOGE("There was an issue with retrieving the file descriptor"); - goto bail; + ALOGE("getPeerCon => getFD for %p failed", fileDescriptor); + return NULL; } - if (getpeercon(fd, &context) == -1) - goto bail; - - ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context); + security_context_t tmp; + int ret = getpeercon(fd, &tmp); + Unique_SecurityContext context(tmp); - securityString = env->NewStringUTF(context); - - bail: - if (context != NULL) - freecon(context); - - return securityString; - } - - /* - * Function: setFSCreateCon - * Purpose: set security context used for creating a new file system object - * Parameters: - * context: security_context_t representing the new context of a file system object, - * set to NULL to return to the default policy behavior - * Returns: true on success, false on error - * Exception: none - */ - static jboolean setFSCreateCon(JNIEnv *env, jobject clazz, jstring context) { - if (isSELinuxDisabled) - return false; - - char * securityContext = NULL; - const char *constant_securityContext = NULL; + ScopedLocalRef<jstring> contextStr(env, NULL); + if (ret != -1) { + contextStr.reset(env->NewStringUTF(context.get())); + } - if (context != NULL) { - constant_securityContext = env->GetStringUTFChars(context, NULL); + ALOGV("getPeerCon(%d) => %s", fd, contextStr.get()); + return contextStr.release(); +} - // GetStringUTFChars returns const char * yet setfscreatecon needs char * - securityContext = const_cast<char *>(constant_securityContext); +/* + * Function: setFSCreateCon + * Purpose: set security context used for creating a new file system object + * Parameters: + * context: security_context_t representing the new context of a file system object, + * set to NULL to return to the default policy behavior + * Returns: true on success, false on error + * Exception: none + */ +static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) { + if (isSELinuxDisabled) { + return false; } - int ret; - if ((ret = setfscreatecon(securityContext)) == -1) - goto bail; + UniquePtr<ScopedUtfChars> context; + const char* context_c_str = NULL; + if (contextStr != NULL) { + context.reset(new ScopedUtfChars(env, contextStr)); + context_c_str = context->c_str(); + if (context_c_str == NULL) { + return false; + } + } - ALOGV("setFSCreateCon: set new security context to '%s' ", context == NULL ? "default", context); + int ret = setfscreatecon(const_cast<char *>(context_c_str)); - bail: - if (constant_securityContext != NULL) - env->ReleaseStringUTFChars(context, constant_securityContext); + ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret); return (ret == 0) ? true : false; - } - - /* - * Function: setFileCon - * Purpose: set the security context of a file object - * Parameters: - * path: the location of the file system object - * con: the new security context of the file system object - * Returns: true on success, false on error - * Exception: NullPointerException is thrown if either path or context strign are NULL - */ - static jboolean setFileCon(JNIEnv *env, jobject clazz, jstring path, jstring con) { - if (isSELinuxDisabled) - return false; +} - if (path == NULL) { - throw_NullPointerException(env, "Trying to change the security context of a NULL file object."); - return false; +/* + * Function: setFileCon + * Purpose: set the security context of a file object + * Parameters: + * path: the location of the file system object + * context: the new security context of the file system object + * Returns: true on success, false on error + * Exception: NullPointerException is thrown if either path or context strign are NULL + */ +static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) { + if (isSELinuxDisabled) { + return false; } - if (con == NULL) { - throw_NullPointerException(env, "Trying to set the security context of a file object with NULL."); - return false; + ScopedUtfChars path(env, pathStr); + if (path.c_str() == NULL) { + return false; } - const char *objectPath = env->GetStringUTFChars(path, NULL); - const char *constant_con = env->GetStringUTFChars(con, NULL); + ScopedUtfChars context(env, contextStr); + if (context.c_str() == NULL) { + return false; + } // GetStringUTFChars returns const char * yet setfilecon needs char * - char *newCon = const_cast<char *>(constant_con); - - int ret; - if ((ret = setfilecon(objectPath, newCon)) == -1) - goto bail; - - ALOGV("setFileCon: Succesfully set security context '%s' for '%s'", newCon, objectPath); + char *tmp = const_cast<char *>(context.c_str()); + int ret = setfilecon(path.c_str(), tmp); - bail: - env->ReleaseStringUTFChars(path, objectPath); - env->ReleaseStringUTFChars(con, constant_con); + ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret); return (ret == 0) ? true : false; - } - - /* - * Function: getFileCon - * Purpose: retrieves the context associated with the given path in the file system - * Parameters: - * path: given path in the file system - * Returns: - * string representing the security context string of the file object - * the string may be NULL if an error occured - * Exceptions: NullPointerException if the path object is null - */ - static jstring getFileCon(JNIEnv *env, jobject clazz, jstring path) { - if (isSELinuxDisabled) - return NULL; +} - if (path == NULL) { - throw_NullPointerException(env, "Trying to check security context of a null path."); - return NULL; +/* + * Function: getFileCon + * Purpose: retrieves the context associated with the given path in the file system + * Parameters: + * path: given path in the file system + * Returns: + * string representing the security context string of the file object + * the string may be NULL if an error occured + * Exceptions: NullPointerException if the path object is null + */ +static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) { + if (isSELinuxDisabled) { + return NULL; } - const char *objectPath = env->GetStringUTFChars(path, NULL); - - security_context_t context = NULL; - jstring securityString = NULL; + ScopedUtfChars path(env, pathStr); + if (path.c_str() == NULL) { + return NULL; + } - if (getfilecon(objectPath, &context) == -1) - goto bail; + security_context_t tmp; + int ret = getfilecon(path.c_str(), &tmp); + Unique_SecurityContext context(tmp); - ALOGV("getFileCon: Successfully retrived context '%s' for file '%s'", context, objectPath); + ScopedLocalRef<jstring> securityString(env, NULL); + if (ret != -1) { + securityString.reset(env->NewStringUTF(context.get())); + } - securityString = env->NewStringUTF(context); + ALOGV("getFileCon(%s) => %s", path.c_str(), context.get()); + return securityString.release(); +} - bail: - if (context != NULL) - freecon(context); +/* + * Function: getCon + * Purpose: Get the context of the current process. + * Parameters: none + * Returns: a jstring representing the security context of the process, + * the jstring may be NULL if there was an error + * Exceptions: none + */ +static jstring getCon(JNIEnv *env, jobject) { + if (isSELinuxDisabled) { + return NULL; + } - env->ReleaseStringUTFChars(path, objectPath); + security_context_t tmp; + int ret = getcon(&tmp); + Unique_SecurityContext context(tmp); - return securityString; - } + ScopedLocalRef<jstring> securityString(env, NULL); + if (ret != -1) { + securityString.reset(env->NewStringUTF(context.get())); + } - /* - * Function: getCon - * Purpose: Get the context of the current process. - * Parameters: none - * Returns: a jstring representing the security context of the process, - * the jstring may be NULL if there was an error - * Exceptions: none - */ - static jstring getCon(JNIEnv *env, jobject clazz) { - if (isSELinuxDisabled) - return NULL; + ALOGV("getCon() => %s", context.get()); + return securityString.release(); +} - security_context_t context = NULL; - jstring securityString = NULL; +/* + * Function: getPidCon + * Purpose: Get the context of a process identified by its pid + * Parameters: + * pid: a jint representing the process + * Returns: a jstring representing the security context of the pid, + * the jstring may be NULL if there was an error + * Exceptions: none + */ +static jstring getPidCon(JNIEnv *env, jobject, jint pid) { + if (isSELinuxDisabled) { + return NULL; + } - if (getcon(&context) == -1) - goto bail; + security_context_t tmp; + int ret = getpidcon(static_cast<pid_t>(pid), &tmp); + Unique_SecurityContext context(tmp); - ALOGV("getCon: Successfully retrieved context '%s'", context); + ScopedLocalRef<jstring> securityString(env, NULL); + if (ret != -1) { + securityString.reset(env->NewStringUTF(context.get())); + } - securityString = env->NewStringUTF(context); + ALOGV("getPidCon(%d) => %s", pid, context.get()); + return securityString.release(); +} - bail: - if (context != NULL) - freecon(context); +/* + * Function: getBooleanNames + * Purpose: Gets a list of the SELinux boolean names. + * Parameters: None + * Returns: an array of strings containing the SELinux boolean names. + * returns NULL string on error + * Exceptions: None + */ +static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv) { + if (isSELinuxDisabled) { + return NULL; + } - return securityString; - } + char **list; + int len; + if (security_get_boolean_names(&list, &len) == -1) { + return NULL; + } - /* - * Function: getPidCon - * Purpose: Get the context of a process identified by its pid - * Parameters: - * pid: a jint representing the process - * Returns: a jstring representing the security context of the pid, - * the jstring may be NULL if there was an error - * Exceptions: none - */ - static jstring getPidCon(JNIEnv *env, jobject clazz, jint pid) { - if (isSELinuxDisabled) - return NULL; + jclass stringClass = env->FindClass("java/lang/String"); + jobjectArray stringArray = env->NewObjectArray(len, stringClass, NULL); + for (int i = 0; i < len; i++) { + ScopedLocalRef<jstring> obj(env, env->NewStringUTF(list[i])); + env->SetObjectArrayElement(stringArray, i, obj.get()); + free(list[i]); + } + free(list); - security_context_t context = NULL; - jstring securityString = NULL; + return stringArray; +} - pid_t checkPid = (pid_t)pid; +/* + * Function: getBooleanValue + * Purpose: Gets the value for the given SELinux boolean name. + * Parameters: + * String: The name of the SELinux boolean. + * Returns: a boolean: (true) boolean is set or (false) it is not. + * Exceptions: None + */ +static jboolean getBooleanValue(JNIEnv *env, jobject, jstring nameStr) { + if (isSELinuxDisabled) { + return false; + } - if (getpidcon(checkPid, &context) == -1) - goto bail; + if (nameStr == NULL) { + return false; + } - ALOGV("getPidCon: Successfully retrived context '%s' for pid '%d'", context, checkPid); + ScopedUtfChars name(env, nameStr); + int ret = security_get_boolean_active(name.c_str()); - securityString = env->NewStringUTF(context); + ALOGV("getBooleanValue(%s) => %d", name.c_str(), ret); + return (ret == 1) ? true : false; +} - bail: - if (context != NULL) - freecon(context); +/* + * Function: setBooleanNames + * Purpose: Sets the value for the given SELinux boolean name. + * Parameters: + * String: The name of the SELinux boolean. + * Boolean: The new value of the SELinux boolean. + * Returns: a boolean indicating whether or not the operation succeeded. + * Exceptions: None + */ +static jboolean setBooleanValue(JNIEnv *env, jobject, jstring nameStr, jboolean value) { + if (isSELinuxDisabled) { + return false; + } - return securityString; - } - - /* - * Function: getBooleanNames - * Purpose: Gets a list of the SELinux boolean names. - * Parameters: None - * Returns: an array of strings containing the SELinux boolean names. - * returns NULL string on error - * Exceptions: None - */ - static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv clazz) { - if (isSELinuxDisabled) - return NULL; + if (nameStr == NULL) { + return false; + } - char **list; - int i, len, ret; - jclass stringClass; - jobjectArray stringArray = NULL; - - if (security_get_boolean_names(&list, &len) == -1) - return NULL; - - stringClass = env->FindClass("java/lang/String"); - stringArray = env->NewObjectArray(len, stringClass, env->NewStringUTF("")); - for (i = 0; i < len; i++) { - jstring obj; - obj = env->NewStringUTF(list[i]); - env->SetObjectArrayElement(stringArray, i, obj); - env->DeleteLocalRef(obj); - free(list[i]); + ScopedUtfChars name(env, nameStr); + int ret = security_set_boolean(name.c_str(), value ? 1 : 0); + if (ret) { + return false; } - free(list); - return stringArray; - } - - /* - * Function: getBooleanValue - * Purpose: Gets the value for the given SELinux boolean name. - * Parameters: - * String: The name of the SELinux boolean. - * Returns: a boolean: (true) boolean is set or (false) it is not. - * Exceptions: None - */ - static jboolean getBooleanValue(JNIEnv *env, jobject clazz, jstring name) { - if (isSELinuxDisabled) - return false; - - const char *boolean_name; - int ret; - - if (name == NULL) - return false; - boolean_name = env->GetStringUTFChars(name, NULL); - ret = security_get_boolean_active(boolean_name); - env->ReleaseStringUTFChars(name, boolean_name); - return (ret == 1) ? true : false; - } - - /* - * Function: setBooleanNames - * Purpose: Sets the value for the given SELinux boolean name. - * Parameters: - * String: The name of the SELinux boolean. - * Boolean: The new value of the SELinux boolean. - * Returns: a boolean indicating whether or not the operation succeeded. - * Exceptions: None - */ - static jboolean setBooleanValue(JNIEnv *env, jobject clazz, jstring name, jboolean value) { - if (isSELinuxDisabled) - return false; - - const char *boolean_name = NULL; - int ret; - - if (name == NULL) - return false; - boolean_name = env->GetStringUTFChars(name, NULL); - ret = security_set_boolean(boolean_name, (value) ? 1 : 0); - env->ReleaseStringUTFChars(name, boolean_name); - if (ret) - return false; - - if (security_commit_booleans() == -1) - return false; + if (security_commit_booleans() == -1) { + return false; + } return true; - } +} - /* - * Function: checkSELinuxAccess - * Purpose: Check permissions between two security contexts. - * Parameters: scon: subject security context as a string - * tcon: object security context as a string - * tclass: object's security class name as a string - * perm: permission name as a string - * Returns: boolean: (true) if permission was granted, (false) otherwise - * Exceptions: None - */ - static jboolean checkSELinuxAccess(JNIEnv *env, jobject clazz, jstring scon, jstring tcon, jstring tclass, jstring perm) { - if (isSELinuxDisabled) - return true; +/* + * Function: checkSELinuxAccess + * Purpose: Check permissions between two security contexts. + * Parameters: subjectContextStr: subject security context as a string + * objectContextStr: object security context as a string + * objectClassStr: object's security class name as a string + * permissionStr: permission name as a string + * Returns: boolean: (true) if permission was granted, (false) otherwise + * Exceptions: None + */ +static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr, + jstring objectContextStr, jstring objectClassStr, jstring permissionStr) { + if (isSELinuxDisabled) { + return true; + } - int accessGranted = -1; + ScopedUtfChars subjectContext(env, subjectContextStr); + if (subjectContext.c_str() == NULL) { + return false; + } - const char *const_scon, *const_tcon, *mytclass, *myperm; - char *myscon, *mytcon; + ScopedUtfChars objectContext(env, objectContextStr); + if (objectContext.c_str() == NULL) { + return false; + } - if (scon == NULL || tcon == NULL || tclass == NULL || perm == NULL) - goto bail; + ScopedUtfChars objectClass(env, objectClassStr); + if (objectClass.c_str() == NULL) { + return false; + } - const_scon = env->GetStringUTFChars(scon, NULL); - const_tcon = env->GetStringUTFChars(tcon, NULL); - mytclass = env->GetStringUTFChars(tclass, NULL); - myperm = env->GetStringUTFChars(perm, NULL); + ScopedUtfChars permission(env, permissionStr); + if (permission.c_str() == NULL) { + return false; + } - // selinux_check_access needs char* for some - myscon = const_cast<char *>(const_scon); - mytcon = const_cast<char *>(const_tcon); + char *tmp1 = const_cast<char *>(subjectContext.c_str()); + char *tmp2 = const_cast<char *>(objectContext.c_str()); + int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(), + NULL); - accessGranted = selinux_check_access(myscon, mytcon, mytclass, myperm, NULL); + ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(), + objectClass.c_str(), permission.c_str(), accessGranted); - ALOGV("selinux_check_access returned %d", accessGranted); + return (accessGranted == 0) ? true : false; +} - env->ReleaseStringUTFChars(scon, const_scon); - env->ReleaseStringUTFChars(tcon, const_tcon); - env->ReleaseStringUTFChars(tclass, mytclass); - env->ReleaseStringUTFChars(perm, myperm); +/* + * Function: native_restorecon + * Purpose: restore default SELinux security context + * Parameters: pathname: the pathname for the file to be relabeled + * Returns: boolean: (true) file label successfully restored, (false) otherwise + * Exceptions: none + */ +static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) { + if (isSELinuxDisabled) { + return true; + } - bail: - return (accessGranted == 0) ? true : false; - } - - /* - * Function: native_restorecon - * Purpose: restore default SELinux security context - * Parameters: pathname: the pathname for the file to be relabeled - * Returns: boolean: (true) file label successfully restored, (false) otherwise - * Exceptions: none - */ - static jboolean native_restorecon(JNIEnv *env, jobject clazz, jstring pathname) { - if (isSELinuxDisabled) - return true; - - const char *file = const_cast<char *>(env->GetStringUTFChars(pathname, NULL)); - int ret = selinux_android_restorecon(file); - env->ReleaseStringUTFChars(pathname, file); - return (ret == 0); - } + ScopedUtfChars pathname(env, pathnameStr); + if (pathname.c_str() == NULL) { + ALOGV("restorecon(%p) => threw exception", pathname); + return false; + } - /* - * JNI registration. - */ - static JNINativeMethod method_table[] = { + int ret = selinux_android_restorecon(pathname.c_str()); + ALOGV("restorecon(%s) => %d", pathname.c_str(), ret); + return (ret == 0); +} +/* + * JNI registration. + */ +static JNINativeMethod method_table[] = { /* name, signature, funcPtr */ { "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess }, { "getBooleanNames" , "()[Ljava/lang/String;" , (void*)getBooleanNames }, @@ -460,25 +439,25 @@ namespace android { { "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon }, { "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon }, { "setSELinuxEnforce" , "(Z)Z" , (void*)setSELinuxEnforce}, - }; +}; - static int log_callback(int type, const char *fmt, ...) { +static int log_callback(int type, const char *fmt, ...) { va_list ap; va_start(ap, fmt); LOG_PRI_VA(ANDROID_LOG_ERROR, "SELinux", fmt, ap); va_end(ap); return 0; - } +} - int register_android_os_SELinux(JNIEnv *env) { +int register_android_os_SELinux(JNIEnv *env) { union selinux_callback cb; cb.func_log = log_callback; selinux_set_callback(SELINUX_CB_LOG, cb); isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false; - return AndroidRuntime::registerNativeMethods( - env, "android/os/SELinux", - method_table, NELEM(method_table)); - } + return AndroidRuntime::registerNativeMethods(env, "android/os/SELinux", method_table, + NELEM(method_table)); +} + } diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp index 7e5dedecbdc6..83d6df171a54 100644 --- a/core/jni/com_android_internal_os_ZygoteInit.cpp +++ b/core/jni/com_android_internal_os_ZygoteInit.cpp @@ -27,12 +27,8 @@ #include <JNIHelp.h> #include "android_runtime/AndroidRuntime.h" -#include <linux/capability.h> -#include <linux/prctl.h> +#include <sys/capability.h> #include <sys/prctl.h> -extern "C" int capget(cap_user_header_t hdrp, cap_user_data_t datap); -extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap); - namespace android { diff --git a/core/res/res/values-mcc286/config.xml b/core/res/res/values-mcc286/config.xml index d99d0516eb21..d99d0516eb21 100755..100644 --- a/core/res/res/values-mcc286/config.xml +++ b/core/res/res/values-mcc286/config.xml diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 8e66a77606b0..cc6131c5c7fa 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3050,12 +3050,12 @@ <!-- Specifies the formatting pattern used to show the time and/or date in 12-hour mode. Please refer to {@link android.text.format.DateFormat} for a complete description of accepted formatting patterns. - The default pattern is "h:mm aa". --> + The default pattern is a locale-appropriate equivalent of "h:mm a". --> <attr name="format12Hour" format="string"/> <!-- Specifies the formatting pattern used to show the time and/or date in 24-hour mode. Please refer to {@link android.text.format.DateFormat} for a complete description of accepted formatting patterns. - The default pattern is "k:mm". --> + The default pattern is a locale-appropriate equivalent of "H:mm". --> <attr name="format24Hour" format="string"/> <!-- Specifies the time zone to use. When this attribute is specified, the TextClock will ignore the time zone of the system. To use the user's diff --git a/core/res/res/xml/apns.xml b/core/res/res/xml/apns.xml index 8c7245c5d01b..249b598a4653 100644 --- a/core/res/res/xml/apns.xml +++ b/core/res/res/xml/apns.xml @@ -20,6 +20,6 @@ <!-- If you edit this version, also edit the version in the partner-supplied apns-conf.xml configuration file --> -<apns version="7"> +<apns version="8"> </apns> diff --git a/core/res/res/xml/kg_password_kbd_numeric.xml b/core/res/res/xml/kg_password_kbd_numeric.xml index 93b32af2de92..93b32af2de92 100755..100644 --- a/core/res/res/xml/kg_password_kbd_numeric.xml +++ b/core/res/res/xml/kg_password_kbd_numeric.xml diff --git a/core/tests/coretests/src/android/text/format/DateUtilsTest.java b/core/tests/coretests/src/android/text/format/DateUtilsTest.java index cf42bb1c003a..c5f6236fe153 100644 --- a/core/tests/coretests/src/android/text/format/DateUtilsTest.java +++ b/core/tests/coretests/src/android/text/format/DateUtilsTest.java @@ -21,8 +21,9 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; public class DateUtilsTest extends TestCase { + // This test is not in CTS because formatDuration is @hidden. @SmallTest - public void testFormatDurationSeconds() throws Exception { + public void test_formatDuration_seconds() throws Exception { assertEquals("0 seconds", DateUtils.formatDuration(0)); assertEquals("0 seconds", DateUtils.formatDuration(1)); assertEquals("0 seconds", DateUtils.formatDuration(499)); @@ -31,16 +32,18 @@ public class DateUtilsTest extends TestCase { assertEquals("2 seconds", DateUtils.formatDuration(1500)); } + // This test is not in CTS because formatDuration is @hidden. @SmallTest - public void testFormatDurationMinutes() throws Exception { + public void test_formatDuration_Minutes() throws Exception { assertEquals("59 seconds", DateUtils.formatDuration(59000)); assertEquals("60 seconds", DateUtils.formatDuration(59500)); assertEquals("1 minute", DateUtils.formatDuration(60000)); assertEquals("2 minutes", DateUtils.formatDuration(120000)); } + // This test is not in CTS because formatDuration is @hidden. @SmallTest - public void testFormatDurationHours() throws Exception { + public void test_formatDuration_Hours() throws Exception { assertEquals("59 minutes", DateUtils.formatDuration(3540000)); assertEquals("1 hour", DateUtils.formatDuration(3600000)); assertEquals("48 hours", DateUtils.formatDuration(172800000)); diff --git a/core/tests/coretests/src/android/webkit/WebkitTest.java b/core/tests/coretests/src/android/webkit/WebkitTest.java index 17b4088f0996..4685e3cf08d7 100644 --- a/core/tests/coretests/src/android/webkit/WebkitTest.java +++ b/core/tests/coretests/src/android/webkit/WebkitTest.java @@ -52,7 +52,7 @@ public class WebkitTest extends AndroidTestCase { date.setTime(time); c.setTime(date); index = dateSorter.getIndex(time); - Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd kk:mm:ss", c).toString() + + Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd HH:mm:ss", c).toString() + " " + index + " " + dateSorter.getLabel(index)); } } diff --git a/data/sounds/AudioPackage10.mk b/data/sounds/AudioPackage10.mk index b40e38552920..b40e38552920 100755..100644 --- a/data/sounds/AudioPackage10.mk +++ b/data/sounds/AudioPackage10.mk diff --git a/data/sounds/AudioPackage8.mk b/data/sounds/AudioPackage8.mk index 93c43da5d075..93c43da5d075 100755..100644 --- a/data/sounds/AudioPackage8.mk +++ b/data/sounds/AudioPackage8.mk diff --git a/data/sounds/AudioPackage9.mk b/data/sounds/AudioPackage9.mk index 73e4fd31d971..73e4fd31d971 100755..100644 --- a/data/sounds/AudioPackage9.mk +++ b/data/sounds/AudioPackage9.mk diff --git a/data/sounds/alarms/ogg/Krypton.ogg b/data/sounds/alarms/ogg/Krypton.ogg Binary files differindex 48f956bc1b7a..48f956bc1b7a 100755..100644 --- a/data/sounds/alarms/ogg/Krypton.ogg +++ b/data/sounds/alarms/ogg/Krypton.ogg diff --git a/data/sounds/alarms/wav/Argon.wav b/data/sounds/alarms/wav/Argon.wav Binary files differindex 56e57fc0e2ba..56e57fc0e2ba 100755..100644 --- a/data/sounds/alarms/wav/Argon.wav +++ b/data/sounds/alarms/wav/Argon.wav diff --git a/data/sounds/alarms/wav/Carbon.wav b/data/sounds/alarms/wav/Carbon.wav Binary files differindex 2b855e1b5777..2b855e1b5777 100755..100644 --- a/data/sounds/alarms/wav/Carbon.wav +++ b/data/sounds/alarms/wav/Carbon.wav diff --git a/data/sounds/alarms/wav/Osmium.wav b/data/sounds/alarms/wav/Osmium.wav Binary files differindex 2dcc47f8c75f..2dcc47f8c75f 100755..100644 --- a/data/sounds/alarms/wav/Osmium.wav +++ b/data/sounds/alarms/wav/Osmium.wav diff --git a/data/sounds/alarms/wav/Platinum.wav b/data/sounds/alarms/wav/Platinum.wav Binary files differindex 08ea03e2b6f7..08ea03e2b6f7 100755..100644 --- a/data/sounds/alarms/wav/Platinum.wav +++ b/data/sounds/alarms/wav/Platinum.wav diff --git a/data/sounds/alarms/wav/Promethium.wav b/data/sounds/alarms/wav/Promethium.wav Binary files differindex 08ea03e2b6f7..08ea03e2b6f7 100755..100644 --- a/data/sounds/alarms/wav/Promethium.wav +++ b/data/sounds/alarms/wav/Promethium.wav diff --git a/docs/html/google/play/billing/v2/billing_integrate.jd b/docs/html/google/play/billing/v2/billing_integrate.jd index 7b748a399b66..7b748a399b66 100755..100644 --- a/docs/html/google/play/billing/v2/billing_integrate.jd +++ b/docs/html/google/play/billing/v2/billing_integrate.jd diff --git a/docs/html/images/ui/notifications/custom_message.png b/docs/html/images/ui/notifications/custom_message.png Binary files differindex 00b763239c40..00b763239c40 100755..100644 --- a/docs/html/images/ui/notifications/custom_message.png +++ b/docs/html/images/ui/notifications/custom_message.png diff --git a/docs/html/images/ui/notifications/notifications_window.png b/docs/html/images/ui/notifications/notifications_window.png Binary files differindex 0354ee92bda4..0354ee92bda4 100755..100644 --- a/docs/html/images/ui/notifications/notifications_window.png +++ b/docs/html/images/ui/notifications/notifications_window.png diff --git a/docs/html/images/ui/notifications/status_bar.png b/docs/html/images/ui/notifications/status_bar.png Binary files differindex f0240a5f0b52..f0240a5f0b52 100755..100644 --- a/docs/html/images/ui/notifications/status_bar.png +++ b/docs/html/images/ui/notifications/status_bar.png diff --git a/docs/html/training/animation/anim_card_flip.mp4 b/docs/html/training/animation/anim_card_flip.mp4 Binary files differindex e885f987c413..e885f987c413 100755..100644 --- a/docs/html/training/animation/anim_card_flip.mp4 +++ b/docs/html/training/animation/anim_card_flip.mp4 diff --git a/docs/html/training/animation/anim_card_flip.ogv b/docs/html/training/animation/anim_card_flip.ogv Binary files differindex 33cd86c23e09..33cd86c23e09 100755..100644 --- a/docs/html/training/animation/anim_card_flip.ogv +++ b/docs/html/training/animation/anim_card_flip.ogv diff --git a/docs/html/training/animation/anim_card_flip.webm b/docs/html/training/animation/anim_card_flip.webm Binary files differindex a670d7831c8a..a670d7831c8a 100755..100644 --- a/docs/html/training/animation/anim_card_flip.webm +++ b/docs/html/training/animation/anim_card_flip.webm diff --git a/docs/html/training/animation/anim_screenslide.mp4 b/docs/html/training/animation/anim_screenslide.mp4 Binary files differindex 3e6502642e64..3e6502642e64 100755..100644 --- a/docs/html/training/animation/anim_screenslide.mp4 +++ b/docs/html/training/animation/anim_screenslide.mp4 diff --git a/docs/html/training/animation/anim_screenslide.ogv b/docs/html/training/animation/anim_screenslide.ogv Binary files differindex c45ebd44db53..c45ebd44db53 100755..100644 --- a/docs/html/training/animation/anim_screenslide.ogv +++ b/docs/html/training/animation/anim_screenslide.ogv diff --git a/docs/html/training/animation/anim_screenslide.webm b/docs/html/training/animation/anim_screenslide.webm Binary files differindex c72adbcb1384..c72adbcb1384 100755..100644 --- a/docs/html/training/animation/anim_screenslide.webm +++ b/docs/html/training/animation/anim_screenslide.webm diff --git a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java index 79a763024c93..83faf356f2d5 100644 --- a/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java +++ b/keystore/java/android/security/AndroidKeyPairGeneratorSpec.java @@ -28,10 +28,28 @@ import java.util.Date; import javax.security.auth.x500.X500Principal; /** - * This provides the required parameters needed for initializing the KeyPair - * generator that works with - * <a href="{@docRoot}guide/topics/security/keystore.html">Android KeyStore - * facility</a>. + * This provides the required parameters needed for initializing the + * {@code KeyPairGenerator} that works with <a href="{@docRoot} + * guide/topics/security/keystore.html">Android KeyStore facility</a>. The + * Android KeyStore facility is accessed through a + * {@link java.security.KeyPairGenerator} API using the + * {@code AndroidKeyPairGenerator} provider. The {@code context} passed in may + * be used to pop up some UI to ask the user to unlock or initialize the Android + * keystore facility. + * <p> + * After generation, the {@code keyStoreAlias} is used with the + * {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)} + * interface to retrieve the {@link PrivateKey} and its associated + * {@link Certificate} chain. + * <p> + * The KeyPair generator will create a self-signed certificate with the subject + * as its X.509v3 Subject Distinguished Name and as its X.509v3 Issuer + * Distinguished Name along with the other parameters specified with the + * {@link Builder}. + * <p> + * The self-signed certificate may be replaced at a later time by a certificate + * signed by a real Certificate Authority. + * * @hide */ public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec { @@ -74,6 +92,7 @@ public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec { * period * @throws IllegalArgumentException when any argument is {@code null} or * {@code endDate} is before {@code startDate}. + * @hide should be built with AndroidKeyPairGeneratorSpecBuilder */ public AndroidKeyPairGeneratorSpec(Context context, String keyStoreAlias, X500Principal subjectDN, BigInteger serialNumber, Date startDate, Date endDate) { @@ -142,4 +161,121 @@ public class AndroidKeyPairGeneratorSpec implements AlgorithmParameterSpec { Date getEndDate() { return mEndDate; } + + /** + * Builder class for {@link AndroidKeyPairGeneratorSpec} objects. + * <p> + * This will build a parameter spec for use with the <a href="{@docRoot} + * guide/topics/security/keystore.html">Android KeyStore facility</a>. + * <p> + * The required fields must be filled in with the builder. + * <p> + * Example: + * + * <pre class="prettyprint"> + * Calendar start = new Calendar(); + * Calendar end = new Calendar(); + * end.add(1, Calendar.YEAR); + * + * AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(mContext) + * .setAlias("myKey") + * .setSubject(new X500Principal("CN=myKey")) + * .setSerial(BigInteger.valueOf(1337)) + * .setStartDate(start.getTime()) + * .setEndDate(end.getTime()) + * .build(); + * </pre> + */ + public static class Builder { + private final Context mContext; + + private String mKeystoreAlias; + + private X500Principal mSubjectDN; + + private BigInteger mSerialNumber; + + private Date mStartDate; + + private Date mEndDate; + + public Builder(Context context) { + if (context == null) { + throw new NullPointerException("context == null"); + } + mContext = context; + } + + /** + * Sets the alias to be used to retrieve the key later from a + * {@link java.security.KeyStore} instance using the + * {@code AndroidKeyStore} provider. + */ + public Builder setAlias(String alias) { + if (alias == null) { + throw new NullPointerException("alias == null"); + } + mKeystoreAlias = alias; + return this; + } + + /** + * Sets the subject used for the self-signed certificate of the + * generated key pair. + */ + public Builder setSubject(X500Principal subject) { + if (subject == null) { + throw new NullPointerException("subject == null"); + } + mSubjectDN = subject; + return this; + } + + /** + * Sets the serial number used for the self-signed certificate of the + * generated key pair. + */ + public Builder setSerialNumber(BigInteger serialNumber) { + if (serialNumber == null) { + throw new NullPointerException("serialNumber == null"); + } + mSerialNumber = serialNumber; + return this; + } + + /** + * Sets the start of the validity period for the self-signed certificate + * of the generated key pair. + */ + public Builder setStartDate(Date startDate) { + if (startDate == null) { + throw new NullPointerException("startDate == null"); + } + mStartDate = startDate; + return this; + } + + /** + * Sets the end of the validity period for the self-signed certificate + * of the generated key pair. + */ + public Builder setEndDate(Date endDate) { + if (endDate == null) { + throw new NullPointerException("endDate == null"); + } + mEndDate = endDate; + return this; + } + + /** + * Builds the instance of the {@code AndroidKeyPairGeneratorSpec}. + * + * @throws IllegalArgumentException if a required field is missing + * @return built instance of {@code AndroidKeyPairGeneratorSpec} + */ + public AndroidKeyPairGeneratorSpec build() { + return new AndroidKeyPairGeneratorSpec(mContext, mKeystoreAlias, mSubjectDN, + mSerialNumber, mStartDate, mEndDate); + } + } } diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java index 65d7b8ff0bec..8a9826bd6176 100644 --- a/keystore/java/android/security/AndroidKeyStore.java +++ b/keystore/java/android/security/AndroidKeyStore.java @@ -453,17 +453,19 @@ public class AndroidKeyStore extends KeyStoreSpi { * convention. */ final String[] certAliases = mKeyStore.saw(Credentials.USER_CERTIFICATE); - for (String alias : certAliases) { - final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias); - if (certBytes == null) { - continue; - } + if (certAliases != null) { + for (String alias : certAliases) { + final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias); + if (certBytes == null) { + continue; + } - final Certificate c = toCertificate(certBytes); - nonCaEntries.add(alias); + final Certificate c = toCertificate(certBytes); + nonCaEntries.add(alias); - if (cert.equals(c)) { - return alias; + if (cert.equals(c)) { + return alias; + } } } @@ -472,19 +474,22 @@ public class AndroidKeyStore extends KeyStoreSpi { * PrivateKeyEntry we looked at above. */ final String[] caAliases = mKeyStore.saw(Credentials.CA_CERTIFICATE); - for (String alias : caAliases) { - if (nonCaEntries.contains(alias)) { - continue; - } + if (certAliases != null) { + for (String alias : caAliases) { + if (nonCaEntries.contains(alias)) { + continue; + } - final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias); - if (certBytes == null) { - continue; - } + final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias); + if (certBytes == null) { + continue; + } - final Certificate c = toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias)); - if (cert.equals(c)) { - return alias; + final Certificate c = + toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias)); + if (cert.equals(c)) { + return alias; + } } } diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java index d8109ce2df99..166849dd8cc1 100644 --- a/keystore/java/android/security/Credentials.java +++ b/keystore/java/android/security/Credentials.java @@ -49,6 +49,8 @@ public class Credentials { public static final String INSTALL_ACTION = "android.credentials.INSTALL"; + public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER"; + public static final String UNLOCK_ACTION = "com.android.credentials.UNLOCK"; /** Key prefix for CA certificates. */ @@ -83,6 +85,12 @@ public class Credentials { public static final String EXTENSION_PFX = ".pfx"; /** + * Intent extra: install the certificate bundle as this UID instead of + * system. + */ + public static final String EXTRA_INSTALL_AS_UID = "install_as_uid"; + + /** * Intent extra: name for the user's private key. */ public static final String EXTRA_USER_PRIVATE_KEY_NAME = "user_private_key_name"; diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 4b6931744821..20374724dd24 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -87,42 +87,58 @@ public class KeyStore { } } - public boolean put(String key, byte[] value) { + public boolean put(String key, byte[] value, int uid) { try { - return mBinder.insert(key, value, -1) == NO_ERROR; + return mBinder.insert(key, value, uid) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } } - public boolean delete(String key) { + public boolean put(String key, byte[] value) { + return put(key, value, -1); + } + + public boolean delete(String key, int uid) { try { - return mBinder.del(key, -1) == NO_ERROR; + return mBinder.del(key, uid) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } } - public boolean contains(String key) { + public boolean delete(String key) { + return delete(key, -1); + } + + public boolean contains(String key, int uid) { try { - return mBinder.exist(key, -1) == NO_ERROR; + return mBinder.exist(key, uid) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } } - public String[] saw(String prefix) { + public boolean contains(String key) { + return contains(key, -1); + } + + public String[] saw(String prefix, int uid) { try { - return mBinder.saw(prefix, -1); + return mBinder.saw(prefix, uid); } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return null; } } + public String[] saw(String prefix) { + return saw(prefix, -1); + } + public boolean reset() { try { return mBinder.reset() == NO_ERROR; @@ -169,24 +185,32 @@ public class KeyStore { } } - public boolean generate(String key) { + public boolean generate(String key, int uid) { try { - return mBinder.generate(key, -1) == NO_ERROR; + return mBinder.generate(key, uid) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } } - public boolean importKey(String keyName, byte[] key) { + public boolean generate(String key) { + return generate(key, -1); + } + + public boolean importKey(String keyName, byte[] key, int uid) { try { - return mBinder.import_key(keyName, key, -1) == NO_ERROR; + return mBinder.import_key(keyName, key, uid) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } } + public boolean importKey(String keyName, byte[] key) { + return importKey(keyName, key, -1); + } + public byte[] getPubkey(String key) { try { return mBinder.get_pubkey(key); @@ -196,15 +220,19 @@ public class KeyStore { } } - public boolean delKey(String key) { + public boolean delKey(String key, int uid) { try { - return mBinder.del_key(key, -1) == NO_ERROR; + return mBinder.del_key(key, uid) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } } + public boolean delKey(String key) { + return delKey(key, -1); + } + public byte[] sign(String key, byte[] data) { try { return mBinder.sign(key, data); @@ -259,6 +287,24 @@ public class KeyStore { } } + public boolean duplicate(String srcKey, int srcUid, String destKey, int destUid) { + try { + return mBinder.duplicate(srcKey, srcUid, destKey, destUid) == NO_ERROR; + } catch (RemoteException e) { + Log.w(TAG, "Cannot connect to keystore", e); + return false; + } + } + + public boolean isHardwareBacked() { + try { + return mBinder.is_hardware_backed() == NO_ERROR; + } catch (RemoteException e) { + Log.w(TAG, "Cannot connect to keystore", e); + return false; + } + } + public int getLastError() { return mError; } diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java index e6a3750e1d0a..3d275cd72d0b 100644 --- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java +++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorSpecTest.java @@ -53,6 +53,26 @@ public class AndroidKeyPairGeneratorSpecTest extends AndroidTestCase { assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate()); } + public void testBuilder_Success() throws Exception { + AndroidKeyPairGeneratorSpec spec = new AndroidKeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setSubject(TEST_DN_1) + .setSerialNumber(SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .build(); + + assertEquals("Context should be the one specified", getContext(), spec.getContext()); + + assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias()); + + assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN()); + + assertEquals("startDate should be the one specified", NOW, spec.getStartDate()); + + assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate()); + } + public void testConstructor_NullContext_Failure() throws Exception { try { new AndroidKeyPairGeneratorSpec(null, TEST_ALIAS_1, TEST_DN_1, SERIAL_1, NOW, diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java index cd031b479f92..69007c43f978 100644 --- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java +++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java @@ -67,7 +67,9 @@ public class AndroidKeyPairGeneratorTest extends AndroidTestCase { assertTrue(mAndroidKeyStore.password("1111")); assertTrue(mAndroidKeyStore.isUnlocked()); - assertEquals(0, mAndroidKeyStore.saw("").length); + String[] aliases = mAndroidKeyStore.saw(""); + assertNotNull(aliases); + assertEquals(0, aliases.length); mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME); } diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java index 07a2d7b9a828..1de1eaf5bd50 100644 --- a/keystore/tests/src/android/security/KeyStoreTest.java +++ b/keystore/tests/src/android/security/KeyStoreTest.java @@ -17,6 +17,7 @@ package android.security; import android.app.Activity; +import android.os.Process; import android.security.KeyStore; import android.test.ActivityUnitTestCase; import android.test.AssertionFailedError; @@ -128,7 +129,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { super.tearDown(); } - public void teststate() throws Exception { + public void testState() throws Exception { assertEquals(KeyStore.State.UNINITIALIZED, mKeyStore.state()); } @@ -154,6 +155,24 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME))); } + public void testPut_grantedUid_Wifi() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + mKeyStore.password(TEST_PASSWD); + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testPut_ungrantedUid_Bluetooth() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + mKeyStore.password(TEST_PASSWD); + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + } + public void testI18n() throws Exception { assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE)); assertFalse(mKeyStore.contains(TEST_I18N_KEY)); @@ -167,22 +186,64 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.password(TEST_PASSWD); assertFalse(mKeyStore.delete(TEST_KEYNAME)); - mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE); + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE)); assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME))); assertTrue(mKeyStore.delete(TEST_KEYNAME)); assertNull(mKeyStore.get(TEST_KEYNAME)); } + public void testDelete_grantedUid_Wifi() throws Exception { + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID)); + mKeyStore.password(TEST_PASSWD); + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID)); + + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertTrue(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testDelete_ungrantedUid_Bluetooth() throws Exception { + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID)); + mKeyStore.password(TEST_PASSWD); + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID)); + + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + } + public void testContains() throws Exception { assertFalse(mKeyStore.contains(TEST_KEYNAME)); - mKeyStore.password(TEST_PASSWD); + assertTrue(mKeyStore.password(TEST_PASSWD)); assertFalse(mKeyStore.contains(TEST_KEYNAME)); - mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE); + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE)); assertTrue(mKeyStore.contains(TEST_KEYNAME)); } + public void testContains_grantedUid_Wifi() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + + assertTrue(mKeyStore.password(TEST_PASSWD)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testContains_grantedUid_Bluetooth() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + + assertTrue(mKeyStore.password(TEST_PASSWD)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + } + public void testSaw() throws Exception { String[] emptyResult = mKeyStore.saw(TEST_KEYNAME); assertNotNull(emptyResult); @@ -198,6 +259,48 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { new HashSet(Arrays.asList(results))); } + public void testSaw_ungrantedUid_Bluetooth() throws Exception { + String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID); + assertNull(results1); + + mKeyStore.password(TEST_PASSWD); + mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE); + mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE); + + String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID); + assertNull(results2); + } + + public void testSaw_grantedUid_Wifi() throws Exception { + String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID); + assertNotNull(results1); + assertEquals(0, results1.length); + + mKeyStore.password(TEST_PASSWD); + mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID); + mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID); + + String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID); + assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()), + TEST_KEYNAME2.substring(TEST_KEYNAME.length()))), + new HashSet(Arrays.asList(results2))); + } + + public void testSaw_grantedUid_Vpn() throws Exception { + String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID); + assertNotNull(results1); + assertEquals(0, results1.length); + + mKeyStore.password(TEST_PASSWD); + mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID); + mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID); + + String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID); + assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()), + TEST_KEYNAME2.substring(TEST_KEYNAME.length()))), + new HashSet(Arrays.asList(results2))); + } + public void testLock() throws Exception { assertFalse(mKeyStore.lock()); @@ -239,17 +342,57 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { } public void testGenerate_Success() throws Exception { - mKeyStore.password(TEST_PASSWD); + assertTrue(mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to generate key when unlocked", mKeyStore.generate(TEST_KEYNAME)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testGenerate_grantedUid_Wifi_Success() throws Exception { + assertTrue(mKeyStore.password(TEST_PASSWD)); + + assertTrue("Should be able to generate key when unlocked", + mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + } + + public void testGenerate_ungrantedUid_Bluetooth_Failure() throws Exception { + assertTrue(mKeyStore.password(TEST_PASSWD)); + + assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); } public void testImport_Success() throws Exception { - mKeyStore.password(TEST_PASSWD); + assertTrue(mKeyStore.password(TEST_PASSWD)); assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testImport_grantedUid_Wifi_Success() throws Exception { + assertTrue(mKeyStore.password(TEST_PASSWD)); + + assertTrue("Should be able to import key when unlocked", + mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + } + + public void testImport_ungrantedUid_Bluetooth_Failure() throws Exception { + assertTrue(mKeyStore.password(TEST_PASSWD)); + + assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); } public void testImport_Failure_BadEncoding() throws Exception { @@ -257,12 +400,15 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { assertFalse("Invalid DER-encoded key should not be imported", mKeyStore.importKey(TEST_KEYNAME, TEST_DATA)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); } public void testSign_Success() throws Exception { mKeyStore.password(TEST_PASSWD); assertTrue(mKeyStore.generate(TEST_KEYNAME)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA); assertNotNull("Signature should not be null", signature); @@ -272,6 +418,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.password(TEST_PASSWD); assertTrue(mKeyStore.generate(TEST_KEYNAME)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA); assertNotNull("Signature should not be null", signature); @@ -406,6 +553,62 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> { mKeyStore.ungrant(TEST_KEYNAME, 0)); } + public void testDuplicate_grantedUid_Wifi_Success() throws Exception { + assertTrue(mKeyStore.password(TEST_PASSWD)); + + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + + assertTrue(mKeyStore.generate(TEST_KEYNAME)); + + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + + // source doesn't exist + assertFalse(mKeyStore.duplicate(TEST_KEYNAME1, -1, TEST_KEYNAME1, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID)); + + // Copy from current UID to granted UID + assertTrue(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME1, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME1)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID)); + assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME1, Process.WIFI_UID)); + + // Copy from granted UID to same granted UID + assertTrue(mKeyStore.duplicate(TEST_KEYNAME1, Process.WIFI_UID, TEST_KEYNAME2, + Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME2, Process.WIFI_UID)); + assertFalse(mKeyStore.duplicate(TEST_KEYNAME1, Process.WIFI_UID, TEST_KEYNAME2, + Process.WIFI_UID)); + + assertTrue(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, -1)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME1)); + assertTrue(mKeyStore.contains(TEST_KEYNAME2)); + assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, -1)); + } + + public void testDuplicate_ungrantedUid_Bluetooth_Failure() throws Exception { + assertTrue(mKeyStore.password(TEST_PASSWD)); + + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + + assertTrue(mKeyStore.generate(TEST_KEYNAME)); + + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + + assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.duplicate(TEST_KEYNAME, Process.BLUETOOTH_UID, TEST_KEYNAME2, + Process.BLUETOOTH_UID)); + + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + } + /** * The amount of time to allow before and after expected time for variance * in timing tests. diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp index e80b325e6e32..e80b325e6e32 100755..100644 --- a/libs/hwui/Dither.cpp +++ b/libs/hwui/Dither.cpp diff --git a/libs/hwui/Dither.h b/libs/hwui/Dither.h index 34cf9bf6a4b7..34cf9bf6a4b7 100755..100644 --- a/libs/hwui/Dither.h +++ b/libs/hwui/Dither.h diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java index 8eb933247472..756638c0f6f8 100644 --- a/media/java/android/media/ThumbnailUtils.java +++ b/media/java/android/media/ThumbnailUtils.java @@ -48,7 +48,7 @@ public class ThumbnailUtils { /* Maximum pixels size for created bitmap. */ private static final int MAX_NUM_PIXELS_THUMBNAIL = 512 * 384; - private static final int MAX_NUM_PIXELS_MICRO_THUMBNAIL = 128 * 128; + private static final int MAX_NUM_PIXELS_MICRO_THUMBNAIL = 160 * 120; private static final int UNCONSTRAINED = -1; /* Options used internally. */ diff --git a/media/jni/mediaeditor/VideoBrowserMain.c b/media/jni/mediaeditor/VideoBrowserMain.c index c6c6000ce6bc..c6c6000ce6bc 100755..100644 --- a/media/jni/mediaeditor/VideoBrowserMain.c +++ b/media/jni/mediaeditor/VideoBrowserMain.c diff --git a/media/tests/EffectsTest/Android.mk b/media/tests/EffectsTest/Android.mk index 25b4fe495914..25b4fe495914 100755..100644 --- a/media/tests/EffectsTest/Android.mk +++ b/media/tests/EffectsTest/Android.mk diff --git a/media/tests/EffectsTest/AndroidManifest.xml b/media/tests/EffectsTest/AndroidManifest.xml index 9b59891fb279..9b59891fb279 100755..100644 --- a/media/tests/EffectsTest/AndroidManifest.xml +++ b/media/tests/EffectsTest/AndroidManifest.xml diff --git a/media/tests/EffectsTest/res/drawable/icon.png b/media/tests/EffectsTest/res/drawable/icon.png Binary files differindex 64e3601c234d..64e3601c234d 100755..100644 --- a/media/tests/EffectsTest/res/drawable/icon.png +++ b/media/tests/EffectsTest/res/drawable/icon.png diff --git a/media/tests/EffectsTest/res/drawable/stop.png b/media/tests/EffectsTest/res/drawable/stop.png Binary files differindex 83f012ca2b56..83f012ca2b56 100755..100644 --- a/media/tests/EffectsTest/res/drawable/stop.png +++ b/media/tests/EffectsTest/res/drawable/stop.png diff --git a/media/tests/EffectsTest/res/layout/bassboosttest.xml b/media/tests/EffectsTest/res/layout/bassboosttest.xml index ac912c84d107..ac912c84d107 100755..100644 --- a/media/tests/EffectsTest/res/layout/bassboosttest.xml +++ b/media/tests/EffectsTest/res/layout/bassboosttest.xml diff --git a/media/tests/EffectsTest/res/layout/effectstest.xml b/media/tests/EffectsTest/res/layout/effectstest.xml index 9af4eb6ef22a..9af4eb6ef22a 100755..100644 --- a/media/tests/EffectsTest/res/layout/effectstest.xml +++ b/media/tests/EffectsTest/res/layout/effectstest.xml diff --git a/media/tests/EffectsTest/res/layout/envreverbtest.xml b/media/tests/EffectsTest/res/layout/envreverbtest.xml index 01c324080294..01c324080294 100755..100644 --- a/media/tests/EffectsTest/res/layout/envreverbtest.xml +++ b/media/tests/EffectsTest/res/layout/envreverbtest.xml diff --git a/media/tests/EffectsTest/res/layout/equalizertest.xml b/media/tests/EffectsTest/res/layout/equalizertest.xml index 5ef035da676d..5ef035da676d 100755..100644 --- a/media/tests/EffectsTest/res/layout/equalizertest.xml +++ b/media/tests/EffectsTest/res/layout/equalizertest.xml diff --git a/media/tests/EffectsTest/res/layout/presetreverbtest.xml b/media/tests/EffectsTest/res/layout/presetreverbtest.xml index cd7fbd3a6d50..cd7fbd3a6d50 100755..100644 --- a/media/tests/EffectsTest/res/layout/presetreverbtest.xml +++ b/media/tests/EffectsTest/res/layout/presetreverbtest.xml diff --git a/media/tests/EffectsTest/res/layout/virtualizertest.xml b/media/tests/EffectsTest/res/layout/virtualizertest.xml index 1fafeab3abdb..1fafeab3abdb 100755..100644 --- a/media/tests/EffectsTest/res/layout/virtualizertest.xml +++ b/media/tests/EffectsTest/res/layout/virtualizertest.xml diff --git a/media/tests/EffectsTest/res/layout/visualizertest.xml b/media/tests/EffectsTest/res/layout/visualizertest.xml index 50ac7bbd8cd0..50ac7bbd8cd0 100755..100644 --- a/media/tests/EffectsTest/res/layout/visualizertest.xml +++ b/media/tests/EffectsTest/res/layout/visualizertest.xml diff --git a/media/tests/EffectsTest/res/values/strings.xml b/media/tests/EffectsTest/res/values/strings.xml index 2a8518417565..2a8518417565 100755..100644 --- a/media/tests/EffectsTest/res/values/strings.xml +++ b/media/tests/EffectsTest/res/values/strings.xml diff --git a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java index 1a10d6422184..1a10d6422184 100755..100644 --- a/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java +++ b/media/tests/EffectsTest/src/com/android/effectstest/BassBoostTest.java diff --git a/media/tests/EffectsTest/src/com/android/effectstest/EffectParameter.java b/media/tests/EffectsTest/src/com/android/effectstest/EffectParameter.java index 95077e79b272..95077e79b272 100755..100644 --- a/media/tests/EffectsTest/src/com/android/effectstest/EffectParameter.java +++ b/media/tests/EffectsTest/src/com/android/effectstest/EffectParameter.java diff --git a/media/tests/EffectsTest/src/com/android/effectstest/EffectsTest.java b/media/tests/EffectsTest/src/com/android/effectstest/EffectsTest.java index 70202463a79e..70202463a79e 100755..100644 --- a/media/tests/EffectsTest/src/com/android/effectstest/EffectsTest.java +++ b/media/tests/EffectsTest/src/com/android/effectstest/EffectsTest.java diff --git a/media/tests/EffectsTest/src/com/android/effectstest/EnvReverbTest.java b/media/tests/EffectsTest/src/com/android/effectstest/EnvReverbTest.java index 594e8446faa7..594e8446faa7 100755..100644 --- a/media/tests/EffectsTest/src/com/android/effectstest/EnvReverbTest.java +++ b/media/tests/EffectsTest/src/com/android/effectstest/EnvReverbTest.java diff --git a/media/tests/EffectsTest/src/com/android/effectstest/EqualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/EqualizerTest.java index f30a26f39c64..f30a26f39c64 100755..100644 --- a/media/tests/EffectsTest/src/com/android/effectstest/EqualizerTest.java +++ b/media/tests/EffectsTest/src/com/android/effectstest/EqualizerTest.java diff --git a/media/tests/EffectsTest/src/com/android/effectstest/PresetReverbTest.java b/media/tests/EffectsTest/src/com/android/effectstest/PresetReverbTest.java index 91d79483ea93..91d79483ea93 100755..100644 --- a/media/tests/EffectsTest/src/com/android/effectstest/PresetReverbTest.java +++ b/media/tests/EffectsTest/src/com/android/effectstest/PresetReverbTest.java diff --git a/media/tests/EffectsTest/src/com/android/effectstest/VirtualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/VirtualizerTest.java index bb32e6fa7603..bb32e6fa7603 100755..100644 --- a/media/tests/EffectsTest/src/com/android/effectstest/VirtualizerTest.java +++ b/media/tests/EffectsTest/src/com/android/effectstest/VirtualizerTest.java diff --git a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java index 60583e0adf72..60583e0adf72 100755..100644 --- a/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java +++ b/media/tests/EffectsTest/src/com/android/effectstest/VisualizerTest.java diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java index 9da883a7f4c7..8d0fe75543c6 100644 --- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java +++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java @@ -378,6 +378,7 @@ public class ImageWallpaper extends WallpaperService { if (DEBUG) { Log.d(TAG, "Redrawing wallpaper"); } + if (mIsHwAccelerated) { if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) { drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels); @@ -640,13 +641,26 @@ public class ImageWallpaper extends WallpaperService { } mEglContext = createContext(mEgl, mEglDisplay, mEglConfig); + + int[] maxSize = new int[1]; + Rect frame = surfaceHolder.getSurfaceFrame(); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0); + if(frame.width() > maxSize[0] || frame.height() > maxSize[0]) { + mEgl.eglDestroyContext(mEglDisplay, mEglContext); + mEgl.eglTerminate(mEglDisplay); + Log.e(GL_LOG_TAG, "requested texture size " + + frame.width() + "x" + frame.height() + " exceeds the support maximum of " + + maxSize[0] + "x" + maxSize[0]); + return false; + } mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, surfaceHolder, null); if (mEglSurface == null || mEglSurface == EGL_NO_SURFACE) { int error = mEgl.eglGetError(); - if (error == EGL_BAD_NATIVE_WINDOW) { - Log.e(GL_LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); + if (error == EGL_BAD_NATIVE_WINDOW || error == EGL_BAD_ALLOC) { + Log.e(GL_LOG_TAG, "createWindowSurface returned " + + GLUtils.getEGLErrorString(error) + "."); return false; } throw new RuntimeException("createWindowSurface failed " + diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java index 0f894a154f39..0f894a154f39 100755..100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/GestureRecorder.java diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 30af333f7669..7d7e7a328965 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -415,6 +415,7 @@ public class PhoneStatusBar extends BaseStatusBar { mSystemIconArea = (LinearLayout) mStatusBarView.findViewById(R.id.system_icon_area); mStatusIcons = (LinearLayout)mStatusBarView.findViewById(R.id.statusIcons); mNotificationIcons = (IconMerger)mStatusBarView.findViewById(R.id.notificationIcons); + mMoreIcon = mStatusBarView.findViewById(R.id.moreIcon); mNotificationIcons.setOverflowIndicator(mMoreIcon); mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents); mTickerView = mStatusBarView.findViewById(R.id.ticker); diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index 3dc77d49feab..3dc77d49feab 100755..100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index fb515ac1e722..0f4262a1f7a6 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -1523,6 +1523,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { return null; } + WindowManager wm = null; + View view = null; + try { Context context = mContext; if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName @@ -1582,8 +1585,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; params.setTitle("Starting " + packageName); - WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); - View view = win.getDecorView(); + wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); + view = win.getDecorView(); if (win.isFloating()) { // Whoops, there is no way to display an animation/preview @@ -1613,6 +1616,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { // failure loading resources because we are loading from an app // on external storage that has been unmounted. Log.w(TAG, appToken + " failed creating starting window", e); + } finally { + if (view != null && view.getParent() == null) { + Log.w(TAG, "view not successfully added to wm, removing view"); + wm.removeViewImmediate(view); + } } return null; diff --git a/preloaded-classes b/preloaded-classes index 10c5c9e704c9..126dd15fe5aa 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -199,16 +199,14 @@ android.app.backup.BackupHelperDispatcher$Header android.app.backup.FileBackupHelperBase android.app.backup.FullBackup android.appwidget.AppWidgetManager -android.bluetooth.BluetoothAudioGateway android.bluetooth.BluetoothSocket -android.bluetooth.HeadsetBase android.bluetooth.IBluetooth android.bluetooth.IBluetooth$Stub android.bluetooth.IBluetoothA2dp android.bluetooth.IBluetoothA2dp$Stub android.content.AbstractThreadedSyncAdapter android.content.AbstractThreadedSyncAdapter$ISyncAdapterImpl -undroid.content.AbstractThreadedSyncAdapter$SyncThread +android.content.AbstractThreadedSyncAdapter$SyncThread android.content.BroadcastReceiver android.content.BroadcastReceiver$PendingResult android.content.ComponentCallbacks @@ -737,9 +735,6 @@ android.provider.Settings$NameValueTable android.provider.Settings$Secure android.provider.Settings$System android.renderscript.RenderScript -android.server.BluetoothA2dpService -android.server.BluetoothEventLoop -android.server.BluetoothService android.telephony.PhoneNumberUtils android.telephony.TelephonyManager android.text.AndroidBidi @@ -844,7 +839,6 @@ android.util.EventLog$Event android.util.FinitePool android.util.FloatMath android.util.FloatProperty -android.util.LocaleUtil android.util.Log android.util.Log$1 android.util.Log$TerribleFailureHandler @@ -1022,7 +1016,6 @@ android.view.ViewRootImpl$ConsumeBatchedInputRunnable android.view.ViewRootImpl$InputMethodCallback android.view.ViewRootImpl$InvalidateOnAnimationRunnable android.view.ViewRootImpl$QueuedInputEvent -android.view.ViewRootImpl$ResizedInfo android.view.ViewRootImpl$RunQueue android.view.ViewRootImpl$RunQueue$HandlerAction android.view.ViewRootImpl$TrackballAxis @@ -1042,7 +1035,6 @@ android.view.ViewTreeObserver$OnScrollChangedListener android.view.ViewTreeObserver$OnTouchModeChangeListener android.view.Window android.view.Window$Callback -android.view.Window$LocalWindowManager android.view.WindowLeaked android.view.WindowManager android.view.WindowManager$LayoutParams @@ -1050,7 +1042,6 @@ android.view.WindowManager$LayoutParams$1 android.view.WindowManagerGlobal android.view.WindowManagerGlobal$1 android.view.WindowManagerImpl -android.view.WindowManagerImpl$CompatModeWrapper android.view.accessibility.AccessibilityEvent android.view.accessibility.AccessibilityEventSource android.view.accessibility.AccessibilityManager @@ -1843,7 +1834,6 @@ java.text.CharacterIterator java.text.DateFormat java.text.DateFormatSymbols java.text.DecimalFormat -java.text.DecimalFormat$1 java.text.DecimalFormatSymbols java.text.FieldPosition java.text.Format @@ -1995,7 +1985,6 @@ java.util.concurrent.Executors$FinalizableDelegatedExecutorService java.util.concurrent.Future java.util.concurrent.FutureTask java.util.concurrent.FutureTask$WaitNode -java.util.concurrent.FutureTask$Sync java.util.concurrent.LinkedBlockingQueue java.util.concurrent.LinkedBlockingQueue$Node java.util.concurrent.RejectedExecutionHandler @@ -2015,7 +2004,6 @@ java.util.concurrent.TimeUnit$7 java.util.concurrent.atomic.AtomicBoolean java.util.concurrent.atomic.AtomicInteger java.util.concurrent.atomic.AtomicReference -java.util.concurrent.atomic.UnsafeAccess java.util.concurrent.locks.AbstractOwnableSynchronizer java.util.concurrent.locks.AbstractQueuedSynchronizer java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject @@ -2034,7 +2022,6 @@ java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock java.util.concurrent.locks.ReentrantReadWriteLock$Sync java.util.concurrent.locks.ReentrantReadWriteLock$Sync$ThreadLocalHoldCounter java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock -java.util.concurrent.locks.UnsafeAccess java.util.jar.Attributes java.util.jar.Attributes$Name java.util.jar.InitManifest @@ -2111,7 +2098,6 @@ javax.net.ssl.X509ExtendedKeyManager javax.net.ssl.X509KeyManager javax.net.ssl.X509TrustManager javax.security.auth.x500.X500Principal -libcore.icu.ErrorCode libcore.icu.ICU libcore.icu.LocaleData libcore.icu.NativeBreakIterator @@ -2122,7 +2108,7 @@ libcore.icu.NativeDecimalFormat$FieldPositionIterator libcore.icu.NativeIDN libcore.icu.NativeNormalizer libcore.icu.NativePluralRules -libcore.icu.TimeZones +libcore.icu.TimeZoneNames libcore.internal.StringPool libcore.io.AsynchronousCloseMonitor libcore.io.Base64 diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 7ac314b8a7a9..b0561df5aaf7 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -63,6 +63,7 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; +import android.os.SELinux; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; @@ -743,6 +744,9 @@ class BackupManagerService extends IBackupManager.Stub { // correct directory. mBaseStateDir = new File(Environment.getSecureDataDirectory(), "backup"); mBaseStateDir.mkdirs(); + if (!SELinux.restorecon(mBaseStateDir)) { + Slog.e(TAG, "SELinux restorecon failed on " + mBaseStateDir); + } mDataDir = Environment.getDownloadCacheDirectory(); mPasswordHashFile = new File(mBaseStateDir, "pwhash"); @@ -2133,6 +2137,10 @@ class BackupManagerService extends IBackupManager.Stub { ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE); + if (!SELinux.restorecon(mBackupDataName)) { + Slog.e(TAG, "SELinux restorecon failed on " + mBackupDataName); + } + mNewState = ParcelFileDescriptor.open(mNewStateName, ParcelFileDescriptor.MODE_READ_WRITE | ParcelFileDescriptor.MODE_CREATE | @@ -3795,7 +3803,7 @@ class BackupManagerService extends IBackupManager.Stub { b.append(String.format(" %9d ", info.size)); Date stamp = new Date(info.mtime); - b.append(new SimpleDateFormat("MMM dd kk:mm:ss ").format(stamp)); + b.append(new SimpleDateFormat("MMM dd HH:mm:ss ").format(stamp)); b.append(info.packageName); b.append(" :: "); @@ -4572,6 +4580,10 @@ class BackupManagerService extends IBackupManager.Stub { ParcelFileDescriptor.MODE_CREATE | ParcelFileDescriptor.MODE_TRUNCATE); + if (!SELinux.restorecon(mBackupDataName)) { + Slog.e(TAG, "SElinux restorecon failed for " + mBackupDataName); + } + if (mTransport.getRestoreData(mBackupData) != BackupConstants.TRANSPORT_OK) { // Transport-level failure, so we wind everything up and // terminate the restore operation. diff --git a/services/java/com/android/server/BluetoothManagerService.java b/services/java/com/android/server/BluetoothManagerService.java index 5a2088ce01c7..5a2088ce01c7 100755..100644 --- a/services/java/com/android/server/BluetoothManagerService.java +++ b/services/java/com/android/server/BluetoothManagerService.java diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 2e0c977d2ec5..ce83a4578669 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -1577,7 +1577,7 @@ class MountService extends IMountService.Stub boolean mounted = false; try { mounted = Environment.MEDIA_MOUNTED.equals(getVolumeState(primary.getPath())); - } catch (IllegalStateException e) { + } catch (IllegalArgumentException e) { } if (!mounted) { diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java index b2a8ad834dc4..1663106964dc 100644 --- a/services/java/com/android/server/Watchdog.java +++ b/services/java/com/android/server/Watchdog.java @@ -29,6 +29,7 @@ import android.content.IntentFilter; import android.os.BatteryManager; import android.os.Debug; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.Process; import android.os.ServiceManager; @@ -114,6 +115,10 @@ public class Watchdog extends Thread { * Used for scheduling monitor callbacks and checking memory usage. */ final class HeartbeatHandler extends Handler { + HeartbeatHandler(Looper looper) { + super(looper); + } + @Override public void handleMessage(Message msg) { switch (msg.what) { @@ -183,7 +188,9 @@ public class Watchdog extends Thread { private Watchdog() { super("watchdog"); - mHandler = new HeartbeatHandler(); + // Explicitly bind the HeartbeatHandler to run on the ServerThread, so + // that it can't get accidentally bound to another thread. + mHandler = new HeartbeatHandler(Looper.getMainLooper()); } public void init(Context context, BatteryService battery, diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 6e81e9d0cb93..c6efe15b9ced 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -2171,7 +2171,7 @@ public final class ActivityManagerService extends ActivityManagerNative // the PID of the new process, or else throw a RuntimeException. Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", app.processName, uid, uid, gids, debugFlags, mountExternal, - app.info.targetSdkVersion, null, null); + app.info.targetSdkVersion, app.info.seinfo, null); BatteryStatsImpl bs = app.batteryStats.getBatteryStats(); synchronized (bs) { diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java index 71a6a0188230..6a071ef03f9e 100644 --- a/services/java/com/android/server/pm/Installer.java +++ b/services/java/com/android/server/pm/Installer.java @@ -188,7 +188,7 @@ public final class Installer { } } - public int install(String name, int uid, int gid) { + public int install(String name, int uid, int gid, String seinfo) { StringBuilder builder = new StringBuilder("install"); builder.append(' '); builder.append(name); @@ -196,6 +196,8 @@ public final class Installer { builder.append(uid); builder.append(' '); builder.append(gid); + builder.append(' '); + builder.append(seinfo != null ? seinfo : "!"); return execute(builder.toString()); } @@ -263,7 +265,7 @@ public final class Installer { return execute(builder.toString()); } - public int createUserData(String name, int uid, int userId) { + public int createUserData(String name, int uid, int userId, String seinfo) { StringBuilder builder = new StringBuilder("mkuserdata"); builder.append(' '); builder.append(name); @@ -271,6 +273,8 @@ public final class Installer { builder.append(uid); builder.append(' '); builder.append(userId); + builder.append(' '); + builder.append(seinfo != null ? seinfo : "!"); return execute(builder.toString()); } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 2238f17621f1..b8324eeb2b60 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -352,6 +352,9 @@ public class PackageManagerService extends IPackageManager.Stub { final HashMap<String, FeatureInfo> mAvailableFeatures = new HashMap<String, FeatureInfo>(); + // If mac_permissions.xml was found for seinfo labeling. + boolean mFoundPolicyFile; + // All available activities, for your resolving pleasure. final ActivityIntentResolver mActivities = new ActivityIntentResolver(); @@ -1020,6 +1023,8 @@ public class PackageManagerService extends IPackageManager.Stub { readPermissions(); + mFoundPolicyFile = SELinuxMMAC.readInstallPolicy(); + mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false), mSdkVersion, mOnlyCore); long startTime = SystemClock.uptimeMillis(); @@ -3582,16 +3587,16 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private int createDataDirsLI(String packageName, int uid) { + private int createDataDirsLI(String packageName, int uid, String seinfo) { int[] users = sUserManager.getUserIds(); - int res = mInstaller.install(packageName, uid, uid); + int res = mInstaller.install(packageName, uid, uid, seinfo); if (res < 0) { return res; } for (int user : users) { if (user != 0) { res = mInstaller.createUserData(packageName, - UserHandle.getUid(user, uid), user); + UserHandle.getUid(user, uid), user, seinfo); if (res < 0) { return res; } @@ -3847,6 +3852,10 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } + if (mFoundPolicyFile) { + SELinuxMMAC.assignSeinfoValue(pkg); + } + pkg.applicationInfo.uid = pkgSetting.appId; pkg.mExtras = pkgSetting; @@ -3985,7 +3994,8 @@ public class PackageManagerService extends IPackageManager.Stub { recovered = true; // And now re-install the app. - ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid); + ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid, + pkg.applicationInfo.seinfo); if (ret == -1) { // Ack should not happen! msg = prefix + pkg.packageName @@ -4031,7 +4041,8 @@ public class PackageManagerService extends IPackageManager.Stub { Log.v(TAG, "Want this data dir: " + dataPath); } //invoke installer to do the actual installation - int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid); + int ret = createDataDirsLI(pkgName, pkg.applicationInfo.uid, + pkg.applicationInfo.seinfo); if (ret < 0) { // Error from installer mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/java/com/android/server/pm/SELinuxMMAC.java new file mode 100644 index 000000000000..4bbdb5e26668 --- /dev/null +++ b/services/java/com/android/server/pm/SELinuxMMAC.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageParser; +import android.content.pm.Signature; +import android.os.Environment; +import android.util.Slog; +import android.util.Xml; + +import com.android.internal.util.XmlUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; + +import java.util.HashMap; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +/** + * Centralized access to SELinux MMAC (middleware MAC) implementation. + * {@hide} + */ +public final class SELinuxMMAC { + + private static final String TAG = "SELinuxMMAC"; + + private static final boolean DEBUG_POLICY = false; + private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false; + + // Signature seinfo values read from policy. + private static final HashMap<Signature, String> sSigSeinfo = + new HashMap<Signature, String>(); + + // Package name seinfo values read from policy. + private static final HashMap<String, String> sPackageSeinfo = + new HashMap<String, String>(); + + // Locations of potential install policy files. + private static final File[] INSTALL_POLICY_FILE = { + new File(Environment.getDataDirectory(), "system/mac_permissions.xml"), + new File(Environment.getRootDirectory(), "etc/security/mac_permissions.xml"), + null}; + + private static void flushInstallPolicy() { + sSigSeinfo.clear(); + sPackageSeinfo.clear(); + } + + /** + * Parses an MMAC install policy from a predefined list of locations. + * @param none + * @return boolean indicating whether an install policy was correctly parsed. + */ + public static boolean readInstallPolicy() { + + return readInstallPolicy(INSTALL_POLICY_FILE); + } + + /** + * Parses an MMAC install policy given as an argument. + * @param File object representing the path of the policy. + * @return boolean indicating whether the install policy was correctly parsed. + */ + public static boolean readInstallPolicy(File policyFile) { + + return readInstallPolicy(new File[]{policyFile,null}); + } + + private static boolean readInstallPolicy(File[] policyFiles) { + + FileReader policyFile = null; + int i = 0; + while (policyFile == null && policyFiles != null && policyFiles[i] != null) { + try { + policyFile = new FileReader(policyFiles[i]); + break; + } catch (FileNotFoundException e) { + Slog.d(TAG,"Couldn't find install policy " + policyFiles[i].getPath()); + } + i++; + } + + if (policyFile == null) { + Slog.d(TAG, "No policy file found. All seinfo values will be null."); + return false; + } + + Slog.d(TAG, "Using install policy file " + policyFiles[i].getPath()); + + flushInstallPolicy(); + + try { + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(policyFile); + + XmlUtils.beginDocument(parser, "policy"); + while (true) { + XmlUtils.nextElement(parser); + if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { + break; + } + + String tagName = parser.getName(); + if ("signer".equals(tagName)) { + String cert = parser.getAttributeValue(null, "signature"); + if (cert == null) { + Slog.w(TAG, "<signer> without signature at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + Signature signature; + try { + signature = new Signature(cert); + } catch (IllegalArgumentException e) { + Slog.w(TAG, "<signer> with bad signature at " + + parser.getPositionDescription(), e); + XmlUtils.skipCurrentTag(parser); + continue; + } + String seinfo = readSeinfoTag(parser); + if (seinfo != null) { + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "<signer> tag: (" + cert + ") assigned seinfo=" + + seinfo); + + sSigSeinfo.put(signature, seinfo); + } + } else if ("default".equals(tagName)) { + String seinfo = readSeinfoTag(parser); + if (seinfo != null) { + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "<default> tag assigned seinfo=" + seinfo); + + // The 'null' signature is the default seinfo value + sSigSeinfo.put(null, seinfo); + } + } else if ("package".equals(tagName)) { + String pkgName = parser.getAttributeValue(null, "name"); + if (pkgName == null) { + Slog.w(TAG, "<package> without name at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + continue; + } + String seinfo = readSeinfoTag(parser); + if (seinfo != null) { + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "<package> tag: (" + pkgName + + ") assigned seinfo=" + seinfo); + + sPackageSeinfo.put(pkgName, seinfo); + } + } else { + XmlUtils.skipCurrentTag(parser); + continue; + } + } + } catch (XmlPullParserException e) { + Slog.w(TAG, "Got execption parsing ", e); + } catch (IOException e) { + Slog.w(TAG, "Got execption parsing ", e); + } + try { + policyFile.close(); + } catch (IOException e) { + //omit + } + return true; + } + + private static String readSeinfoTag(XmlPullParser parser) throws + IOException, XmlPullParserException { + + int type; + int outerDepth = parser.getDepth(); + String seinfo = null; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if ("seinfo".equals(tagName)) { + String seinfoValue = parser.getAttributeValue(null, "value"); + if (validateValue(seinfoValue)) { + seinfo = seinfoValue; + } else { + Slog.w(TAG, "<seinfo> without valid value at " + + parser.getPositionDescription()); + } + } + XmlUtils.skipCurrentTag(parser); + } + return seinfo; + } + + /** + * General validation routine for tag values. + * Returns a boolean indicating if the passed string + * contains only letters or underscores. + */ + private static boolean validateValue(String name) { + if (name == null) + return false; + + final int N = name.length(); + if (N == 0) + return false; + + for (int i = 0; i < N; i++) { + final char c = name.charAt(i); + if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && (c != '_')) { + return false; + } + } + return true; + } + + /** + * Labels a package based on an seinfo tag from install policy. + * The label is attached to the ApplicationInfo instance of the package. + * @param PackageParser.Package object representing the package + * to labeled. + * @return String holding the value of the seinfo label that was assigned. + * Value may be null which indicates no seinfo label was assigned. + */ + public static void assignSeinfoValue(PackageParser.Package pkg) { + + /* + * Non system installed apps should be treated the same. This + * means that any post-loaded apk will be assigned the default + * tag, if one exists in the policy, else null, without respect + * to the signing key. + */ + if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) || + ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) { + + // We just want one of the signatures to match. + for (Signature s : pkg.mSignatures) { + if (s == null) + continue; + + if (sSigSeinfo.containsKey(s)) { + String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(s); + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "package (" + pkg.packageName + + ") labeled with seinfo=" + seinfo); + + return; + } + } + + // Check for seinfo labeled by package. + if (sPackageSeinfo.containsKey(pkg.packageName)) { + String seinfo = pkg.applicationInfo.seinfo = sPackageSeinfo.get(pkg.packageName); + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "package (" + pkg.packageName + + ") labeled with seinfo=" + seinfo); + return; + } + } + + // If we have a default seinfo value then great, otherwise + // we set a null object and that is what we started with. + String seinfo = pkg.applicationInfo.seinfo = sSigSeinfo.get(null); + if (DEBUG_POLICY_INSTALL) + Slog.i(TAG, "package (" + pkg.packageName + + ") labeled with seinfo=" + (seinfo == null ? "null" : seinfo)); + } +} diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 06f11bc9a4da..b744bc335b46 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -1359,6 +1359,7 @@ final class Settings { // userId - application-specific user id // debugFlag - 0 or 1 if the package is debuggable. // dataPath - path to package's data path + // seinfo - seinfo label for the app (assigned at install time) // // NOTE: We prefer not to expose all ApplicationInfo flags for now. // @@ -1372,6 +1373,8 @@ final class Settings { sb.append((int)ai.uid); sb.append(isDebug ? " 1 " : " 0 "); sb.append(dataPath); + sb.append(" "); + sb.append(ai.seinfo); sb.append("\n"); str.write(sb.toString().getBytes()); } @@ -2337,7 +2340,8 @@ final class Settings { ps.setInstalled((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0, userHandle); // Need to create a data directory for all apps under this user. installer.createUserData(ps.name, - UserHandle.getUid(userHandle, ps.appId), userHandle); + UserHandle.getUid(userHandle, ps.appId), userHandle, + ps.pkg.applicationInfo.seinfo); } readDefaultPreferredAppsLPw(userHandle); writePackageRestrictionsLPr(userHandle); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 0466c15473f5..d6dfff40844d 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -1514,7 +1514,11 @@ public class WindowManagerService extends IWindowManager.Stub pos++; } if (pos >= N) { - // All is good! + // Z order is good. + // The IM target window may be changed, so update the mTargetAppToken. + if (imWin != null) { + imWin.mTargetAppToken = mInputMethodTarget.mAppToken; + } return false; } } @@ -9457,9 +9461,31 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_ORIENTATION && winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING) Slog.i( TAG, "Resizing " + win + " WITH DRAW PENDING"); - win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets, - winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING, - configChanged ? win.mConfiguration : null); + final boolean reportDraw + = winAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING; + final Configuration newConfig = configChanged ? win.mConfiguration : null; + if (win.mClient instanceof IWindow.Stub) { + // Simulate one-way call if win.mClient is a local object. + final IWindow client = win.mClient; + final Rect frame = win.mFrame; + final Rect contentInsets = win.mLastContentInsets; + final Rect visibleInsets = win.mLastVisibleInsets; + mH.post(new Runnable() { + @Override + public void run() { + try { + client.resized(frame, contentInsets, visibleInsets, + reportDraw, newConfig); + } catch (RemoteException e) { + // Actually, it's not a remote call. + // RemoteException mustn't be raised. + } + } + }); + } else { + win.mClient.resized(win.mFrame, win.mLastContentInsets, win.mLastVisibleInsets, + reportDraw, newConfig); + } win.mContentInsetsChanged = false; win.mVisibleInsetsChanged = false; winAnimator.mSurfaceResized = false; diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index 0f531b7a6b34..3cf48a0e183f 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -111,9 +111,9 @@ public class PackageManagerSettingsTests extends AndroidTestCase { private void writePackagesList() { writeFile(new File(getContext().getFilesDir(), "system/packages.list"), - ( "com.google.app1 11000 0 /data/data/com.google.app1" - + "com.google.app2 11001 0 /data/data/com.google.app2" - + "com.android.app3 11030 0 /data/data/com.android.app3") + ( "com.google.app1 11000 0 /data/data/com.google.app1 seinfo1" + + "com.google.app2 11001 0 /data/data/com.google.app2 seinfo2" + + "com.android.app3 11030 0 /data/data/com.android.app3 seinfo3") .getBytes()); } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java index 03057777ab38..532148e00dec 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java @@ -1731,6 +1731,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub { //Ignore more client requests break; case PEER_CONNECTION_USER_ACCEPT: + //Stop discovery to avoid failure due to channel switch + mWifiNative.p2pStopFind(); if (mSavedPeerConfig.wps.setup == WpsInfo.PBC) { mWifiNative.startWpsPbc(mGroup.getInterface(), null); } else { |