summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt1
-rw-r--r--cmds/installd/Android.mk6
-rw-r--r--cmds/installd/commands.c40
-rw-r--r--core/java/android/app/Application.java11
-rw-r--r--core/java/android/app/ApplicationThreadNative.java1
-rwxr-xr-x[-rw-r--r--]core/java/android/app/admin/DevicePolicyManager.java6
-rw-r--r--core/java/android/os/SELinux.java105
-rw-r--r--core/java/android/widget/Gallery.java8
-rw-r--r--core/java/android/widget/GridView.java7
-rw-r--r--core/java/android/widget/SimpleExpandableListAdapter.java52
-rw-r--r--core/java/com/android/internal/os/ProcessStats.java4
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuPresenter.java2
-rw-r--r--core/jni/Android.mk7
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android_os_SELinux.cpp502
-rw-r--r--core/res/res/layout/transient_notification.xml1
-rw-r--r--core/tests/coretests/apks/install_complete_package_info/Android.mk11
-rw-r--r--core/tests/coretests/apks/install_complete_package_info/AndroidManifest.xml54
-rw-r--r--core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestActivity.java24
-rw-r--r--core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestProvider.java57
-rw-r--r--core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestReceiver.java57
-rw-r--r--core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestService.java30
-rwxr-xr-xcore/tests/coretests/src/android/content/pm/PackageManagerTests.java89
-rw-r--r--core/tests/coretests/src/android/os/SELinuxTest.java45
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/Android.mk2
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/res/drawable-nodpi/default_wallpaper.jpg (renamed from core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg)bin399 -> 399 bytes
-rwxr-xr-xcore/tests/overlaytests/runtests.sh44
-rw-r--r--libs/androidfw/ResourceTypes.cpp36
-rw-r--r--media/java/android/media/MediaFile.java1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/ImageWallpaper.java8
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java4
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java1
-rw-r--r--services/java/com/android/server/MountService.java1
-rw-r--r--services/java/com/android/server/PowerManagerService.java2
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java4
-rw-r--r--services/java/com/android/server/pm/Settings.java2
-rw-r--r--services/java/com/android/server/pm/ShutdownThread.java15
-rw-r--r--telephony/java/android/telephony/cdma/CdmaCellLocation.java32
-rw-r--r--telephony/java/com/android/internal/telephony/Connection.java12
-rw-r--r--telephony/java/com/android/internal/telephony/cat/CommandDetails.java5
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CdmaConnection.java10
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GSMPhone.java2
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmConnection.java21
-rw-r--r--tools/aapt/AaptAssets.cpp2
-rw-r--r--tools/aapt/Android.mk4
-rw-r--r--tools/aapt/Bundle.h4
-rw-r--r--tools/aapt/Main.cpp5
-rw-r--r--tools/aapt/ResourceTable.cpp19
-rw-r--r--tools/layoutlib/bridge/.classpath2
-rw-r--r--tools/layoutlib/bridge/tests/.classpath2
-rwxr-xr-xtools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java787
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/Log.java16
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java54
55 files changed, 2138 insertions, 89 deletions
diff --git a/api/current.txt b/api/current.txt
index 4a23046..308e4d4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20254,6 +20254,7 @@ package android.telephony.cdma {
public class CdmaCellLocation extends android.telephony.CellLocation {
ctor public CdmaCellLocation();
ctor public CdmaCellLocation(android.os.Bundle);
+ method public static double convertQuartSecToDecDegrees(int);
method public void fillInNotifierBundle(android.os.Bundle);
method public int getBaseStationId();
method public int getBaseStationLatitude();
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index f277339..3e722ea 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -34,6 +34,12 @@ LOCAL_SHARED_LIBRARIES := \
LOCAL_STATIC_LIBRARIES := \
libdiskusage
+ifeq ($(HAVE_SELINUX),true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_CFLAGS := -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
LOCAL_MODULE := installd
LOCAL_MODULE_TAGS := optional
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 96a6438..1bb4935 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -17,6 +17,10 @@
#include "installd.h"
#include <diskusage/dirsize.h>
+#ifdef HAVE_SELINUX
+#include <selinux/android.h>
+#endif
+
/* Directory records that are used in execution of commands. */
dir_rec_t android_data_dir;
dir_rec_t android_asec_dir;
@@ -72,12 +76,31 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
return -errno;
}
+#ifdef HAVE_SELINUX
+ if (selinux_android_setfilecon(libdir, pkgname, AID_SYSTEM) < 0) {
+ LOGE("cannot setfilecon dir '%s': %s\n", libdir, strerror(errno));
+ unlink(libdir);
+ unlink(pkgdir);
+ return -errno;
+ }
+#endif
+
if (chown(pkgdir, uid, gid) < 0) {
ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
unlink(libdir);
unlink(pkgdir);
return -errno;
}
+
+#ifdef HAVE_SELINUX
+ if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
+ LOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(libdir);
+ unlink(pkgdir);
+ return -errno;
+ }
+#endif
+
return 0;
}
@@ -175,6 +198,15 @@ int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
unlink(pkgdir);
return -errno;
}
+
+#ifdef HAVE_SELINUX
+ if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
+ LOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(pkgdir);
+ return -errno;
+ }
+#endif
+
return 0;
}
@@ -366,12 +398,18 @@ int protect(char *pkgname, gid_t gid)
ALOGE("failed to chgrp '%s': %s\n", pkgpath, strerror(errno));
return -1;
}
-
if (chmod(pkgpath, S_IRUSR|S_IWUSR|S_IRGRP) < 0) {
ALOGE("failed to chmod '%s': %s\n", pkgpath, strerror(errno));
return -1;
}
+#ifdef HAVE_SELINUX
+ if (selinux_android_setfilecon(pkgpath, pkgname, s.st_uid) < 0) {
+ LOGE("cannot setfilecon dir '%s': %s\n", pkgpath, strerror(errno));
+ return -1;
+ }
+#endif
+
return 0;
}
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index dd9ea26..3a67cec 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -64,11 +64,12 @@ public class Application extends ContextWrapper implements ComponentCallbacks2 {
}
/**
- * Called when the application is starting, before any other application
- * objects have been created. Implementations should be as quick as
- * possible (for example using lazy initialization of state) since the time
- * spent in this function directly impacts the performance of starting the
- * first activity, service, or receiver in a process.
+ * Called when the application is starting, before any activity, service,
+ * or receiver objects (excluding content providers) have been created.
+ * Implementations should be as quick as possible (for example using
+ * lazy initialization of state) since the time spent in this function
+ * directly impacts the performance of starting the first activity,
+ * service, or receiver in a process.
* If you override this method, be sure to call super.onCreate().
*/
public void onCreate() {
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 3e726e0..8e6278d 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -385,6 +385,7 @@ public abstract class ApplicationThreadNative extends Binder
case SCHEDULE_LOW_MEMORY_TRANSACTION:
{
+ data.enforceInterface(IApplicationThread.descriptor);
scheduleLowMemory();
return true;
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 4ed0766..0b58396 100644..100755
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1008,13 +1008,15 @@ public class DevicePolicyManager {
/**
* Ask the user date be wiped. This will cause the device to reboot,
* erasing all user data while next booting up. External storage such
- * as SD cards will not be erased.
+ * as SD cards will be also erased if the flag {@link #WIPE_EXTERNAL_STORAGE}
+ * is set.
*
* <p>The calling device admin must have requested
* {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA} to be able to call
* this method; if it has not, a security exception will be thrown.
*
- * @param flags Bit mask of additional options: currently must be 0.
+ * @param flags Bit mask of additional options: currently 0 and
+ * {@link #WIPE_EXTERNAL_STORAGE} are supported.
*/
public void wipeData(int flags) {
if (mService != null) {
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
new file mode 100644
index 0000000..90cfa37
--- /dev/null
+++ b/core/java/android/os/SELinux.java
@@ -0,0 +1,105 @@
+package android.os;
+
+import java.io.FileDescriptor;
+
+/**
+ * This class provides access to the centralized jni bindings for
+ * SELinux interaction.
+ * {@hide}
+ */
+public class SELinux {
+
+ /**
+ * Determine whether SELinux is disabled or enabled.
+ * @return a boolean indicating whether SELinux is enabled.
+ */
+ public static final native boolean isSELinuxEnabled();
+
+ /**
+ * Determine whether SELinux is permissive or enforcing.
+ * @return a boolean indicating whether SELinux is enforcing.
+ */
+ public static final native boolean isSELinuxEnforced();
+
+ /**
+ * Set whether SELinux is permissive or enforcing.
+ * @param boolean representing whether to set SELinux to enforcing
+ * @return a boolean representing whether the desired mode was set
+ */
+ public static final native boolean setSELinuxEnforce(boolean value);
+
+ /**
+ * Sets the security context for newly created file objects.
+ * @param context a security context given as a String.
+ * @return a boolean indicating whether the operation succeeded.
+ */
+ public static final native boolean setFSCreateContext(String context);
+
+ /**
+ * Change the security context of an existing file object.
+ * @param path representing the path of file object to relabel.
+ * @param con new security context given as a String.
+ * @return a boolean indicating whether the operation succeeded.
+ */
+ public static final native boolean setFileContext(String path, String context);
+
+ /**
+ * Get the security context of a file object.
+ * @param path the pathname of the file object.
+ * @return a security context given as a String.
+ */
+ public static final native String getFileContext(String path);
+
+ /**
+ * Get the security context of a peer socket.
+ * @param fd FileDescriptor class of the peer socket.
+ * @return a String representing the peer socket security context.
+ */
+ public static final native String getPeerContext(FileDescriptor fd);
+
+ /**
+ * Gets the security context of the current process.
+ * @return a String representing the security context of the current process.
+ */
+ public static final native String getContext();
+
+ /**
+ * Gets the security context of a given process id.
+ * Use of this function is discouraged for Binder transactions.
+ * Use Binder.getCallingSecctx() instead.
+ * @param pid an int representing the process id to check.
+ * @return a String representing the security context of the given pid.
+ */
+ public static final native String getPidContext(int pid);
+
+ /**
+ * Gets a list of the SELinux boolean names.
+ * @return an array of strings containing the SELinux boolean names.
+ */
+ public static final native String[] getBooleanNames();
+
+ /**
+ * Gets the value for the given SELinux boolean name.
+ * @param String The name of the SELinux boolean.
+ * @return a boolean indicating whether the SELinux boolean is set.
+ */
+ public static final native boolean getBooleanValue(String name);
+
+ /**
+ * Sets the value for the given SELinux boolean name.
+ * @param String The name of the SELinux boolean.
+ * @param Boolean The new value of the SELinux boolean.
+ * @return a boolean indicating whether or not the operation succeeded.
+ */
+ public static final native boolean setBooleanValue(String name, boolean value);
+
+ /**
+ * Check permissions between two security contexts.
+ * @param scon The source or subject security context.
+ * @param tcon The target or object security context.
+ * @param tclass The object security class name.
+ * @param perm The permission name.
+ * @return a boolean indicating whether permission was granted.
+ */
+ public static final native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm);
+}
diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java
index e4e7239..72e429c 100644
--- a/core/java/android/widget/Gallery.java
+++ b/core/java/android/widget/Gallery.java
@@ -1195,15 +1195,15 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList
case KeyEvent.KEYCODE_DPAD_LEFT:
if (movePrevious()) {
playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT);
+ return true;
}
- return true;
-
+ break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (moveNext()) {
playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT);
+ return true;
}
- return true;
-
+ break;
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
mReceivedInvokeKeyDown = true;
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 8975109..ada7dd1 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -2207,8 +2207,13 @@ public class GridView extends AbsListView {
int height = view.getHeight();
if (height > 0) {
final int numColumns = mNumColumns;
- final int whichRow = mFirstPosition / numColumns;
final int rowCount = (mItemCount + numColumns - 1) / numColumns;
+ // In case of stackFromBottom the calculation of whichRow needs
+ // to take into account that counting from the top the first row
+ // might not be entirely filled.
+ final int oddItemsOnFirstRow = isStackFromBottom() ? ((rowCount * numColumns) -
+ mItemCount) : 0;
+ final int whichRow = (mFirstPosition + oddItemsOnFirstRow) / numColumns;
return Math.max(whichRow * 100 - (top * 100) / height +
(int) ((float) mScrollY / getHeight() * rowCount * 100), 0);
}
diff --git a/core/java/android/widget/SimpleExpandableListAdapter.java b/core/java/android/widget/SimpleExpandableListAdapter.java
index 015c169..f514374 100644
--- a/core/java/android/widget/SimpleExpandableListAdapter.java
+++ b/core/java/android/widget/SimpleExpandableListAdapter.java
@@ -38,6 +38,8 @@ import java.util.Map;
*/
public class SimpleExpandableListAdapter extends BaseExpandableListAdapter {
private List<? extends Map<String, ?>> mGroupData;
+ // Keeps track of if a group is currently expanded or not
+ private boolean[] mIsGroupExpanded;
private int mExpandedGroupLayout;
private int mCollapsedGroupLayout;
private String[] mGroupFrom;
@@ -196,6 +198,8 @@ public class SimpleExpandableListAdapter extends BaseExpandableListAdapter {
int childLayout, int lastChildLayout, String[] childFrom,
int[] childTo) {
mGroupData = groupData;
+ // Initially all groups are not expanded
+ mIsGroupExpanded = new boolean[groupData.size()];
mExpandedGroupLayout = expandedGroupLayout;
mCollapsedGroupLayout = collapsedGroupLayout;
mGroupFrom = groupFrom;
@@ -298,4 +302,52 @@ public class SimpleExpandableListAdapter extends BaseExpandableListAdapter {
return true;
}
+ /**
+ * {@inheritDoc}
+ * @return 1 for the last child in a group, 0 for the other children.
+ */
+ @Override
+ public int getChildType(int groupPosition, int childPosition) {
+ final int childrenInGroup = getChildrenCount(groupPosition);
+ return childPosition == childrenInGroup - 1 ? 1 : 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return 2, one type for the last child in a group, one for the other children.
+ */
+ @Override
+ public int getChildTypeCount() {
+ return 2;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return 1 for an expanded group view, 0 for a collapsed one.
+ */
+ @Override
+ public int getGroupType(int groupPosition) {
+ return mIsGroupExpanded[groupPosition] ? 1 : 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @return 2, one for a collapsed group view, one for an expanded one.
+ */
+ @Override
+ public int getGroupTypeCount() {
+ return 2;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onGroupCollapsed(int groupPosition) {
+ mIsGroupExpanded[groupPosition] = false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void onGroupExpanded(int groupPosition) {
+ mIsGroupExpanded[groupPosition] = true;
+ }
}
diff --git a/core/java/com/android/internal/os/ProcessStats.java b/core/java/com/android/internal/os/ProcessStats.java
index 1923b86..b1bb8c1 100644
--- a/core/java/com/android/internal/os/ProcessStats.java
+++ b/core/java/com/android/internal/os/ProcessStats.java
@@ -154,7 +154,7 @@ public class ProcessStats {
private boolean mFirst = true;
- private byte[] mBuffer = new byte[256];
+ private byte[] mBuffer = new byte[4096];
/**
* The time in microseconds that the CPU has been running at each speed.
@@ -556,7 +556,7 @@ public class ProcessStats {
private long[] getCpuSpeedTimes(long[] out) {
long[] tempTimes = out;
long[] tempSpeeds = mCpuSpeeds;
- final int MAX_SPEEDS = 20;
+ final int MAX_SPEEDS = 60;
if (out == null) {
tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
tempSpeeds = new long[MAX_SPEEDS];
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 73324c0..cf6029e 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -278,7 +278,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter
*/
public boolean showOverflowMenu() {
if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
- mPostedOpenRunnable == null) {
+ mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) {
OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
mPostedOpenRunnable = new OpenOverflowRunnable(popup);
// Post this for later; we might still need a layout for the anchor to be right.
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c24f6c6..b5a2f98 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -66,6 +66,7 @@ LOCAL_SRC_FILES:= \
android_os_MessageQueue.cpp \
android_os_ParcelFileDescriptor.cpp \
android_os_Parcel.cpp \
+ android_os_SELinux.cpp \
android_os_StatFs.cpp \
android_os_SystemClock.cpp \
android_os_SystemProperties.cpp \
@@ -218,6 +219,12 @@ LOCAL_SHARED_LIBRARIES := \
libharfbuzz \
libz
+ifeq ($(HAVE_SELINUX),true)
+LOCAL_C_INCLUDES += external/libselinux/include
+LOCAL_SHARED_LIBRARIES += libselinux
+LOCAL_CFLAGS += -DHAVE_SELINUX
+endif # HAVE_SELINUX
+
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
endif
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 241a905..7a23747 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -133,6 +133,7 @@ extern int register_android_os_Debug(JNIEnv* env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
extern int register_android_os_ParcelFileDescriptor(JNIEnv *env);
+extern int register_android_os_SELinux(JNIEnv* env);
extern int register_android_os_StatFs(JNIEnv *env);
extern int register_android_os_SystemProperties(JNIEnv *env);
extern int register_android_os_SystemClock(JNIEnv* env);
@@ -1146,6 +1147,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_os_FileUtils),
REG_JNI(register_android_os_MessageQueue),
REG_JNI(register_android_os_ParcelFileDescriptor),
+ REG_JNI(register_android_os_SELinux),
REG_JNI(register_android_os_StatFs),
REG_JNI(register_android_os_Trace),
REG_JNI(register_android_os_UEventObserver),
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
new file mode 100644
index 0000000..eb99d2b
--- /dev/null
+++ b/core/jni/android_os_SELinux.cpp
@@ -0,0 +1,502 @@
+#define LOG_TAG "SELinuxJNI"
+#include <utils/Log.h>
+
+#include "JNIHelp.h"
+#include "jni.h"
+#include "android_runtime/AndroidRuntime.h"
+#ifdef HAVE_SELINUX
+#include "selinux/selinux.h"
+#endif
+#include <errno.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);
+ }
+
+ /*
+ * 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) {
+
+ 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) {
+#ifdef HAVE_SELINUX
+ return (security_getenforce() == 1) ? true : false;
+#else
+ return false;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return false;
+
+ int enforce = (value) ? 1 : 0;
+
+ return (security_setenforce(enforce) != -1) ? true : false;
+#else
+ return false;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return NULL;
+
+ if (fileDescriptor == NULL) {
+ throw_NullPointerException(env, "Trying to check security context of a null peer socket.");
+ return NULL;
+ }
+
+ security_context_t context = NULL;
+ jstring securityString = NULL;
+
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
+
+ if (env->ExceptionOccurred() != NULL) {
+ LOGE("There was an issue with retrieving the file descriptor");
+ goto bail;
+ }
+
+ if (getpeercon(fd, &context) == -1)
+ goto bail;
+
+ LOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context);
+
+ securityString = env->NewStringUTF(context);
+
+ bail:
+ if (context != NULL)
+ freecon(context);
+
+ return securityString;
+#else
+ return NULL;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return false;
+
+ char * securityContext = NULL;
+ const char *constant_securityContext = NULL;
+
+ if (context != NULL) {
+ constant_securityContext = env->GetStringUTFChars(context, NULL);
+
+ // GetStringUTFChars returns const char * yet setfscreatecon needs char *
+ securityContext = const_cast<char *>(constant_securityContext);
+ }
+
+ int ret;
+ if ((ret = setfscreatecon(securityContext)) == -1)
+ goto bail;
+
+ LOGV("setFSCreateCon: set new security context to '%s' ", context == NULL ? "default", context);
+
+ bail:
+ if (constant_securityContext != NULL)
+ env->ReleaseStringUTFChars(context, constant_securityContext);
+
+ return (ret == 0) ? true : false;
+#else
+ return false;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return false;
+
+ if (path == NULL) {
+ throw_NullPointerException(env, "Trying to change the security context of a NULL file object.");
+ return false;
+ }
+
+ if (con == NULL) {
+ throw_NullPointerException(env, "Trying to set the security context of a file object with NULL.");
+ return false;
+ }
+
+ const char *objectPath = env->GetStringUTFChars(path, NULL);
+ const char *constant_con = env->GetStringUTFChars(con, NULL);
+
+ // 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;
+
+ LOGV("setFileCon: Succesfully set security context '%s' for '%s'", newCon, objectPath);
+
+ bail:
+ env->ReleaseStringUTFChars(path, objectPath);
+ env->ReleaseStringUTFChars(con, constant_con);
+ return (ret == 0) ? true : false;
+#else
+ return false;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return NULL;
+
+ if (path == NULL) {
+ throw_NullPointerException(env, "Trying to check security context of a null path.");
+ return NULL;
+ }
+
+ const char *objectPath = env->GetStringUTFChars(path, NULL);
+
+ security_context_t context = NULL;
+ jstring securityString = NULL;
+
+ if (getfilecon(objectPath, &context) == -1)
+ goto bail;
+
+ LOGV("getFileCon: Successfully retrived context '%s' for file '%s'", context, objectPath);
+
+ securityString = env->NewStringUTF(context);
+
+ bail:
+ if (context != NULL)
+ freecon(context);
+
+ env->ReleaseStringUTFChars(path, objectPath);
+
+ return securityString;
+#else
+ return NULL;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return NULL;
+
+ security_context_t context = NULL;
+ jstring securityString = NULL;
+
+ if (getcon(&context) == -1)
+ goto bail;
+
+ LOGV("getCon: Successfully retrieved context '%s'", context);
+
+ securityString = env->NewStringUTF(context);
+
+ bail:
+ if (context != NULL)
+ freecon(context);
+
+ return securityString;
+#else
+ return NULL;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return NULL;
+
+ security_context_t context = NULL;
+ jstring securityString = NULL;
+
+ pid_t checkPid = (pid_t)pid;
+
+ if (getpidcon(checkPid, &context) == -1)
+ goto bail;
+
+ LOGV("getPidCon: Successfully retrived context '%s' for pid '%d'", context, checkPid);
+
+ securityString = env->NewStringUTF(context);
+
+ bail:
+ if (context != NULL)
+ freecon(context);
+
+ return securityString;
+#else
+ return NULL;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return NULL;
+
+ 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]);
+ }
+ free(list);
+
+ return stringArray;
+#else
+ return NULL;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ 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;
+#else
+ return false;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ 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;
+
+ return true;
+#else
+ return false;
+#endif
+ }
+
+ /*
+ * 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) {
+#ifdef HAVE_SELINUX
+ if (isSELinuxDisabled)
+ return true;
+
+ int accessGranted = -1;
+
+ const char *const_scon, *const_tcon, *mytclass, *myperm;
+ char *myscon, *mytcon;
+
+ if (scon == NULL || tcon == NULL || tclass == NULL || perm == NULL)
+ goto bail;
+
+ const_scon = env->GetStringUTFChars(scon, NULL);
+ const_tcon = env->GetStringUTFChars(tcon, NULL);
+ mytclass = env->GetStringUTFChars(tclass, NULL);
+ myperm = env->GetStringUTFChars(perm, NULL);
+
+ // selinux_check_access needs char* for some
+ myscon = const_cast<char *>(const_scon);
+ mytcon = const_cast<char *>(const_tcon);
+
+ accessGranted = selinux_check_access(myscon, mytcon, mytclass, myperm, NULL);
+
+ LOGV("selinux_check_access returned %d", accessGranted);
+
+ env->ReleaseStringUTFChars(scon, const_scon);
+ env->ReleaseStringUTFChars(tcon, const_tcon);
+ env->ReleaseStringUTFChars(tclass, mytclass);
+ env->ReleaseStringUTFChars(perm, myperm);
+
+ bail:
+ return (accessGranted == 0) ? true : false;
+
+#else
+ return true;
+#endif
+ }
+
+ /*
+ * 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 },
+ { "getBooleanValue" , "(Ljava/lang/String;)Z" , (void*)getBooleanValue },
+ { "getContext" , "()Ljava/lang/String;" , (void*)getCon },
+ { "getFileContext" , "(Ljava/lang/String;)Ljava/lang/String;" , (void*)getFileCon },
+ { "getPeerContext" , "(Ljava/io/FileDescriptor;)Ljava/lang/String;" , (void*)getPeerCon },
+ { "getPidContext" , "(I)Ljava/lang/String;" , (void*)getPidCon },
+ { "isSELinuxEnforced" , "()Z" , (void*)isSELinuxEnforced},
+ { "isSELinuxEnabled" , "()Z" , (void*)isSELinuxEnabled },
+ { "setBooleanValue" , "(Ljava/lang/String;Z)Z" , (void*)setBooleanValue },
+ { "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, ...) {
+ 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) {
+#ifdef HAVE_SELINUX
+ union selinux_callback cb;
+ cb.func_log = log_callback;
+ selinux_set_callback(SELINUX_CB_LOG, cb);
+
+ isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
+
+#endif
+ return AndroidRuntime::registerNativeMethods(
+ env, "android/os/SELinux",
+ method_table, NELEM(method_table));
+ }
+}
diff --git a/core/res/res/layout/transient_notification.xml b/core/res/res/layout/transient_notification.xml
index 21d58aa..5523807 100644
--- a/core/res/res/layout/transient_notification.xml
+++ b/core/res/res/layout/transient_notification.xml
@@ -29,6 +29,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:layout_gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.Small"
android:textColor="@color/bright_foreground_dark"
android:shadowColor="#BB000000"
diff --git a/core/tests/coretests/apks/install_complete_package_info/Android.mk b/core/tests/coretests/apks/install_complete_package_info/Android.mk
new file mode 100644
index 0000000..1edccb4
--- /dev/null
+++ b/core/tests/coretests/apks/install_complete_package_info/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := FrameworkCoreTests_install_complete_package_info
+
+include $(BUILD_PACKAGE)
+
diff --git a/core/tests/coretests/apks/install_complete_package_info/AndroidManifest.xml b/core/tests/coretests/apks/install_complete_package_info/AndroidManifest.xml
new file mode 100644
index 0000000..4b01736
--- /dev/null
+++ b/core/tests/coretests/apks/install_complete_package_info/AndroidManifest.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.install_complete_package_info">
+
+<!--
+ This manifest declares at least one of each of the components that
+ can be retrieved by PackageManager.getInstalledPackages.
+ All the implementing classes are empty implementations
+-->
+
+ <uses-feature
+ android:name="com.android.frameworks.coretests.nonexistent" />
+ <uses-configuration
+ android:reqFiveWayNav="false" />
+
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.frameworks.coretests"
+ android:label="Frameworks Core Tests" />
+
+ <permission
+ android:label="test permission"
+ android:name="test_permission"
+ android:protectionLevel="normal" />
+
+ <application
+ android:hasCode="true">
+ <activity
+ android:name="com.android.frameworks.coretests.TestActivity">
+ </activity>
+ <provider
+ android:name="com.android.frameworks.coretests.TestProvider"
+ android:authorities="com.android.frameworks.coretests.testprovider" />
+ <receiver
+ android:name="com.android.frameworks.coretests.TestReceiver" />
+ <service
+ android:name="com.android.frameworks.coretests.TestService" />
+ </application>
+</manifest>
diff --git a/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestActivity.java b/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestActivity.java
new file mode 100644
index 0000000..10d0551
--- /dev/null
+++ b/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestActivity.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.frameworks.coretests;
+
+import android.app.Activity;
+
+public class TestActivity extends Activity {
+
+}
diff --git a/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestProvider.java b/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestProvider.java
new file mode 100644
index 0000000..59f9f10
--- /dev/null
+++ b/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestProvider.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.frameworks.coretests;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class TestProvider extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestReceiver.java b/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestReceiver.java
new file mode 100644
index 0000000..21f6263
--- /dev/null
+++ b/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestReceiver.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.frameworks.coretests;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+public class TestReceiver extends ContentProvider {
+
+ @Override
+ public boolean onCreate() {
+ return false;
+ }
+
+ @Override
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ @Override
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ @Override
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ @Override
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestService.java b/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestService.java
new file mode 100644
index 0000000..b330e75
--- /dev/null
+++ b/core/tests/coretests/apks/install_complete_package_info/src/com/android/frameworks/coretests/TestService.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.frameworks.coretests;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class TestService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 77e4986..6e1b9d6 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -23,6 +23,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
@@ -50,6 +51,8 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.List;
+
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
public static final String TAG="PackageManagerTests";
@@ -3162,6 +3165,92 @@ public class PackageManagerTests extends AndroidTestCase {
assertNotNull("Verifier device identity should not be null", id);
}
+ public void testGetInstalledPackages() {
+ List<PackageInfo> packages = getPm().getInstalledPackages(0);
+ assertNotNull("installed packages cannot be null", packages);
+ assertTrue("installed packages cannot be empty", packages.size() > 0);
+ }
+
+ public void testGetUnInstalledPackages() {
+ List<PackageInfo> packages = getPm().getInstalledPackages(
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ assertNotNull("installed packages cannot be null", packages);
+ assertTrue("installed packages cannot be empty", packages.size() > 0);
+ }
+
+ /**
+ * Test that getInstalledPackages returns all the data specified in
+ * flags.
+ */
+ public void testGetInstalledPackagesAll() {
+ int flags = PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
+ | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
+ | PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
+ | PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
+ | PackageManager.GET_SIGNATURES | PackageManager.GET_UNINSTALLED_PACKAGES;
+
+ List<PackageInfo> packages = getPm().getInstalledPackages(flags);
+ assertNotNull("installed packages cannot be null", packages);
+ assertTrue("installed packages cannot be empty", packages.size() > 0);
+
+ PackageInfo packageInfo = null;
+
+ // Find the package with all components specified in the AndroidManifest
+ // to ensure no null values
+ for (PackageInfo pi : packages) {
+ if ("com.android.frameworks.coretests.install_complete_package_info"
+ .equals(pi.packageName)) {
+ packageInfo = pi;
+ break;
+ }
+ }
+ assertNotNull("activities should not be null", packageInfo.activities);
+ assertNotNull("configPreferences should not be null", packageInfo.configPreferences);
+ assertNotNull("instrumentation should not be null", packageInfo.instrumentation);
+ assertNotNull("permissions should not be null", packageInfo.permissions);
+ assertNotNull("providers should not be null", packageInfo.providers);
+ assertNotNull("receivers should not be null", packageInfo.receivers);
+ assertNotNull("services should not be null", packageInfo.services);
+ assertNotNull("signatures should not be null", packageInfo.signatures);
+ }
+
+ /**
+ * Test that getInstalledPackages returns all the data specified in
+ * flags when the GET_UNINSTALLED_PACKAGES flag is set.
+ */
+ public void testGetUnInstalledPackagesAll() {
+ int flags = PackageManager.GET_UNINSTALLED_PACKAGES
+ | PackageManager.GET_ACTIVITIES | PackageManager.GET_GIDS
+ | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_INSTRUMENTATION
+ | PackageManager.GET_PERMISSIONS | PackageManager.GET_PROVIDERS
+ | PackageManager.GET_RECEIVERS | PackageManager.GET_SERVICES
+ | PackageManager.GET_SIGNATURES | PackageManager.GET_UNINSTALLED_PACKAGES;
+
+ List<PackageInfo> packages = getPm().getInstalledPackages(flags);
+ assertNotNull("installed packages cannot be null", packages);
+ assertTrue("installed packages cannot be empty", packages.size() > 0);
+
+ PackageInfo packageInfo = null;
+
+ // Find the package with all components specified in the AndroidManifest
+ // to ensure no null values
+ for (PackageInfo pi : packages) {
+ if ("com.android.frameworks.coretests.install_complete_package_info"
+ .equals(pi.packageName)) {
+ packageInfo = pi;
+ break;
+ }
+ }
+ assertNotNull("activities should not be null", packageInfo.activities);
+ assertNotNull("configPreferences should not be null", packageInfo.configPreferences);
+ assertNotNull("instrumentation should not be null", packageInfo.instrumentation);
+ assertNotNull("permissions should not be null", packageInfo.permissions);
+ assertNotNull("providers should not be null", packageInfo.providers);
+ assertNotNull("receivers should not be null", packageInfo.receivers);
+ assertNotNull("services should not be null", packageInfo.services);
+ assertNotNull("signatures should not be null", packageInfo.signatures);
+ }
+
/*---------- Recommended install location tests ----*/
/*
* TODO's
diff --git a/core/tests/coretests/src/android/os/SELinuxTest.java b/core/tests/coretests/src/android/os/SELinuxTest.java
new file mode 100644
index 0000000..9b63a6b
--- /dev/null
+++ b/core/tests/coretests/src/android/os/SELinuxTest.java
@@ -0,0 +1,45 @@
+package android.os;
+
+import android.os.Process;
+import android.os.SELinux;
+import android.test.AndroidTestCase;
+import static junit.framework.Assert.assertEquals;
+
+public class SELinuxTest extends AndroidTestCase {
+
+ public void testgetFileCon() {
+ if(SELinux.isSELinuxEnabled() == false)
+ return;
+
+ String ctx = SELinux.getFileContext("/system/bin/toolbox");
+ assertEquals(ctx, "u:object_r:system_file:s0");
+ }
+
+ public void testgetCon() {
+ if(SELinux.isSELinuxEnabled() == false)
+ return;
+
+ String mycon = SELinux.getContext();
+ assertEquals(mycon, "u:r:untrusted_app:s0:c33");
+ }
+
+ public void testgetPidCon() {
+ if(SELinux.isSELinuxEnabled() == false)
+ return;
+
+ String mycon = SELinux.getPidContext(Process.myPid());
+ assertEquals(mycon, "u:r:untrusted_app:s0:c33");
+ }
+
+ public void testcheckSELinuxAccess() {
+ if(SELinux.isSELinuxEnabled() == false)
+ return;
+
+ String mycon = SELinux.getContext();
+ boolean ret;
+ ret = SELinux.checkSELinuxAccess(mycon, mycon, "process", "fork");
+ assertEquals(ret,"true");
+ ret = SELinux.checkSELinuxAccess(mycon, mycon, "memprotect", "mmap_zero");
+ assertEquals(ret,"true");
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
index cf32c9f..b1327f7 100644
--- a/core/tests/overlaytests/OverlayTestOverlay/Android.mk
+++ b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
@@ -9,6 +9,4 @@ LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := com.android.overlaytest.overlay
-LOCAL_AAPT_FLAGS := -o
-
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg b/core/tests/overlaytests/OverlayTestOverlay/res/drawable-nodpi/default_wallpaper.jpg
index 0d944d0..0d944d0 100644
--- a/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/drawable-nodpi/default_wallpaper.jpg
Binary files differ
diff --git a/core/tests/overlaytests/runtests.sh b/core/tests/overlaytests/runtests.sh
index 0ad9efb..0a721ad40 100755
--- a/core/tests/overlaytests/runtests.sh
+++ b/core/tests/overlaytests/runtests.sh
@@ -18,7 +18,6 @@ function atexit()
log=$(mktemp)
trap "atexit" EXIT
-failures=0
function compile_module()
{
@@ -38,6 +37,37 @@ function wait_for_boot_completed()
$adb wait-for-device logcat | grep -m 1 -e 'PowerManagerService.*bootCompleted' >/dev/null
}
+function mkdir_if_needed()
+{
+ local path="$1"
+
+ if [[ "${path:0:1}" != "/" ]]; then
+ echo "mkdir_if_needed: error: path '$path' does not begin with /" | tee -a $log
+ exit 1
+ fi
+
+ local basename=$(basename "$path")
+ local dirname=$(dirname "$path")
+ local t=$($adb shell ls -l $dirname | tr -d '\r' | grep -e "${basename}$" | grep -oe '^.')
+
+ case "$t" in
+ d) # File exists, and is a directory ...
+ # do nothing
+ ;;
+ l) # ... (or symbolic link possibly to a directory).
+ # do nothing
+ ;;
+ "") # File does not exist.
+ mkdir_if_needed "$dirname"
+ $adb shell mkdir "$path"
+ ;;
+ *) # File exists, but is not a directory.
+ echo "mkdir_if_needed: file '$path' exists, but is not a directory" | tee -a $log
+ exit 1
+ ;;
+ esac
+}
+
function disable_overlay()
{
echo "Disabling overlay"
@@ -48,6 +78,8 @@ function disable_overlay()
function enable_overlay()
{
echo "Enabling overlay"
+ mkdir_if_needed "/system/vendor"
+ mkdir_if_needed "/vendor/overlay/framework"
$adb shell ln -s /data/app/com.android.overlaytest.overlay.apk /vendor/overlay/framework/framework-res.apk
}
@@ -59,13 +91,21 @@ function instrument()
$adb shell am instrument -w -e class $class com.android.overlaytest/android.test.InstrumentationTestRunner | tee -a $log
}
+function remount()
+{
+ echo "Remounting file system writable"
+ $adb remount | tee -a $log
+}
+
function sync()
{
echo "Syncing to device"
- $adb remount | tee -a $log
$adb sync data | tee -a $log
}
+# some commands require write access, remount once and for all
+remount
+
# build and sync
compile_module "$PWD/OverlayTest/Android.mk"
compile_module "$PWD/OverlayTestOverlay/Android.mk"
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index f3a1d9a..8cce191 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -5159,7 +5159,8 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui
const uint32_t pkg_id = pkg->package->id << 24;
for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
- ssize_t offset = -1;
+ ssize_t first = -1;
+ ssize_t last = -1;
const Type* typeConfigs = pkg->getType(typeIndex);
ssize_t mapIndex = map.add();
if (mapIndex < 0) {
@@ -5167,12 +5168,14 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui
}
Vector<uint32_t>& vector = map.editItemAt(mapIndex);
for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
- uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+ uint32_t resID = pkg_id
| (0x00ff0000 & ((typeIndex+1)<<16))
| (0x0000ffff & (entryIndex));
resource_name resName;
if (!this->getResourceName(resID, &resName)) {
ALOGW("idmap: resource 0x%08x has spec but lacks values, skipping\n", resID);
+ // add dummy value, or trimming leading/trailing zeroes later will fail
+ vector.push(0);
continue;
}
@@ -5185,13 +5188,13 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui
overlayPackage.string(),
overlayPackage.size());
if (overlayResID != 0) {
- // overlay package has package ID == 0, use original package's ID instead
- overlayResID |= pkg_id;
+ overlayResID = pkg_id | (0x00ffffff & overlayResID);
+ last = Res_GETENTRY(resID);
+ if (first == -1) {
+ first = Res_GETENTRY(resID);
+ }
}
vector.push(overlayResID);
- if (overlayResID != 0 && offset == -1) {
- offset = Res_GETENTRY(resID);
- }
#if 0
if (overlayResID != 0) {
ALOGD("%s/%s 0x%08x -> 0x%08x\n",
@@ -5202,13 +5205,16 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui
#endif
}
- if (offset != -1) {
- // shave off leading and trailing entries which lack overlay values
- vector.removeItemsAt(0, offset);
- vector.insertAt((uint32_t)offset, 0, 1);
- while (vector.top() == 0) {
- vector.pop();
+ if (first != -1) {
+ // shave off trailing entries which lack overlay values
+ const size_t last_past_one = last + 1;
+ if (last_past_one < vector.size()) {
+ vector.removeItemsAt(last_past_one, vector.size() - last_past_one);
}
+ // shave off leading entries which lack overlay values
+ vector.removeItemsAt(0, first);
+ // store offset to first overlaid resource ID of this type
+ vector.insertAt((uint32_t)first, 0, 1);
// reserve space for number and offset of entries, and the actual entries
*outSize += (2 + vector.size()) * sizeof(uint32_t);
} else {
@@ -5246,6 +5252,10 @@ status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, ui
if (N == 0) {
continue;
}
+ if (N == 1) { // vector expected to hold (offset) + (N > 0 entries)
+ ALOGW("idmap: type %d supposedly has entries, but no entries found\n", i);
+ return UNKNOWN_ERROR;
+ }
*data++ = htodl(N - 1); // do not count the offset (which is vector's first element)
for (size_t j = 0; j < N; ++j) {
const uint32_t& overlayResID = vector.itemAt(j);
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index c9bec18..d21ada4 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -172,6 +172,7 @@ public class MediaFile {
static {
addFileType("MP3", FILE_TYPE_MP3, "audio/mpeg", MtpConstants.FORMAT_MP3);
+ addFileType("MPGA", FILE_TYPE_MP3, "audio/mpeg", MtpConstants.FORMAT_MP3);
addFileType("M4A", FILE_TYPE_M4A, "audio/mp4", MtpConstants.FORMAT_MPEG);
addFileType("WAV", FILE_TYPE_WAV, "audio/x-wav", MtpConstants.FORMAT_WAV);
addFileType("AMR", FILE_TYPE_AMR, "audio/amr");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b0939de..bcd0add 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1540,6 +1540,12 @@ public class DatabaseHelper extends SQLiteOpenHelper {
SystemProperties.get("ro.com.android.dataroaming",
"false")) ? 1 : 0);
+ // Mobile Data default, based on build
+ loadSetting(stmt, Settings.Secure.MOBILE_DATA,
+ "true".equalsIgnoreCase(
+ SystemProperties.get("ro.com.android.mobiledata",
+ "true")) ? 1 : 0);
+
loadBooleanSetting(stmt, Settings.Secure.INSTALL_NON_MARKET_APPS,
R.bool.def_install_non_market_apps);
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 96f83c6..b0a7c4b 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -294,6 +294,13 @@ public class ImageWallpaper extends WallpaperService {
updateWallpaperLocked();
}
+ if (mBackground == null) {
+ // If we somehow got to this point after we have last flushed
+ // the wallpaper, well we really need it to draw again. So
+ // seems like we need to reload it. Ouch.
+ updateWallpaperLocked();
+ }
+
SurfaceHolder sh = getSurfaceHolder();
final Rect frame = sh.getSurfaceFrame();
final int dw = frame.width();
@@ -315,7 +322,6 @@ public class ImageWallpaper extends WallpaperService {
mLastXTranslation = xPixels;
mLastYTranslation = yPixels;
-
if (mIsHwAccelerated) {
if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) {
drawWallpaperWithCanvas(sh, availw, availh, xPixels, yPixels);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 47703c6..0aa3018 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1666,7 +1666,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
*/
private void restorePanelState(SparseArray<Parcelable> icicles) {
PanelFeatureState st;
- for (int curFeatureId = icicles.size() - 1; curFeatureId >= 0; curFeatureId--) {
+ int curFeatureId;
+ for (int i = icicles.size() - 1; i >= 0; i--) {
+ curFeatureId = icicles.keyAt(i);
st = getPanelState(curFeatureId, false /* required */);
if (st == null) {
// The panel must not have been required, and is currently not around, skip it
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 0f5ad66..4ea3d90 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -1691,6 +1691,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Note: we can only do the wipe via ExternalStorageFormatter if the volume is not emulated.
if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
+ intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
mWakeLock.acquire(10000);
mContext.startService(intent);
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 1482d22..04267a3 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1221,6 +1221,7 @@ class MountService extends IMountService.Stub
for(MountServiceBinderListener bl : mListeners) {
if (bl.mListener == listener) {
mListeners.remove(mListeners.indexOf(bl));
+ listener.asBinder().unlinkToDeath(bl, 0);
return;
}
}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 4390e55..0a9905e 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1165,6 +1165,8 @@ public class PowerManagerService extends IPowerManager.Stub
? "SCREEN_BRIGHT_BIT " : "")
+ (((state & SCREEN_ON_BIT) != 0)
? "SCREEN_ON_BIT " : "")
+ + (((state & BUTTON_BRIGHT_BIT) != 0)
+ ? "BUTTON_BRIGHT_BIT " : "")
+ (((state & BATTERY_LOW_BIT) != 0)
? "BATTERY_LOW_BIT " : "");
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index eaecd4c..7e733c6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -83,7 +83,7 @@ class ServerThread extends Thread {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
SystemClock.uptimeMillis());
- Looper.prepare();
+ Looper.prepareMainLooper();
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 63455ee..c808930 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1820,7 +1820,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (cr.binding != null && cr.binding.service != null
&& cr.binding.service.app != null
&& cr.binding.service.app.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cr.binding.service.app, oomAdj,
+ updateLruProcessInternalLocked(cr.binding.service.app, false,
updateActivityTime, i+1);
}
}
@@ -1828,7 +1828,7 @@ public final class ActivityManagerService extends ActivityManagerNative
for (int j=app.conProviders.size()-1; j>=0; j--) {
ContentProviderRecord cpr = app.conProviders.get(j).provider;
if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq) {
- updateLruProcessInternalLocked(cpr.proc, oomAdj,
+ updateLruProcessInternalLocked(cpr.proc, false,
updateActivityTime, i+1);
}
}
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 91cd458..b26e853 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1241,7 +1241,7 @@ final class Settings {
// Avoid any application that has a space in its path
// or that is handled by the system.
- if (dataPath.indexOf(" ") >= 0 || ai.uid <= Process.FIRST_APPLICATION_UID)
+ if (dataPath.indexOf(" ") >= 0 || ai.uid < Process.FIRST_APPLICATION_UID)
continue;
// we store on each line the following information for now:
diff --git a/services/java/com/android/server/pm/ShutdownThread.java b/services/java/com/android/server/pm/ShutdownThread.java
index 69406c8..3675d41 100644
--- a/services/java/com/android/server/pm/ShutdownThread.java
+++ b/services/java/com/android/server/pm/ShutdownThread.java
@@ -84,6 +84,8 @@ public final class ShutdownThread extends Thread {
private PowerManager.WakeLock mCpuWakeLock;
private PowerManager.WakeLock mScreenWakeLock;
private Handler mHandler;
+
+ private static AlertDialog sConfirmDialog;
private ShutdownThread() {
}
@@ -124,7 +126,10 @@ public final class ShutdownThread extends Thread {
if (confirm) {
final CloseDialogReceiver closer = new CloseDialogReceiver(context);
- final AlertDialog dialog = new AlertDialog.Builder(context)
+ if (sConfirmDialog != null) {
+ sConfirmDialog.dismiss();
+ }
+ sConfirmDialog = new AlertDialog.Builder(context)
.setTitle(mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_title
: com.android.internal.R.string.power_off)
@@ -136,10 +141,10 @@ public final class ShutdownThread extends Thread {
})
.setNegativeButton(com.android.internal.R.string.no, null)
.create();
- closer.dialog = dialog;
- dialog.setOnDismissListener(closer);
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- dialog.show();
+ closer.dialog = sConfirmDialog;
+ sConfirmDialog.setOnDismissListener(closer);
+ sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
+ sConfirmDialog.show();
} else {
beginShutdownSequence(context);
}
diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java
index 84db830..6cfae6a 100644
--- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java
+++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java
@@ -81,14 +81,26 @@ public class CdmaCellLocation extends CellLocation {
}
/**
- * @return cdma base station latitude, Integer.MAX_VALUE if unknown
+ * Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+ * (http://www.3gpp2.org/public_html/specs/C.S0005-A_v6.0.pdf)
+ * It is represented in units of 0.25 seconds and ranges from -1296000
+ * to 1296000, both values inclusive (corresponding to a range of -90
+ * to +90 degrees). Integer.MAX_VALUE is considered invalid value.
+ *
+ * @return cdma base station latitude in units of 0.25 seconds, Integer.MAX_VALUE if unknown
*/
public int getBaseStationLatitude() {
return this.mBaseStationLatitude;
}
/**
- * @return cdma base station longitude, Integer.MAX_VALUE if unknown
+ * Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
+ * (http://www.3gpp2.org/public_html/specs/C.S0005-A_v6.0.pdf)
+ * It is represented in units of 0.25 seconds and ranges from -2592000
+ * to 2592000, both values inclusive (corresponding to a range of -180
+ * to +180 degrees). Integer.MAX_VALUE is considered invalid value.
+ *
+ * @return cdma base station longitude in units of 0.25 seconds, Integer.MAX_VALUE if unknown
*/
public int getBaseStationLongitude() {
return this.mBaseStationLongitude;
@@ -215,6 +227,22 @@ public class CdmaCellLocation extends CellLocation {
this.mNetworkId == -1);
}
+ /**
+ * Converts latitude or longitude from 0.25 seconds (as defined in the
+ * 3GPP2 C.S0005-A v6.0 standard) to decimal degrees
+ *
+ * @param quartSec latitude or longitude in 0.25 seconds units
+ * @return latitude or longitude in decimal degrees units
+ * @throws IllegalArgumentException if value is less than -2592000,
+ * greater than 2592000, or is not a number.
+ */
+ public static double convertQuartSecToDecDegrees(int quartSec) {
+ if(Double.isNaN(quartSec) || quartSec < -2592000 || quartSec > 2592000){
+ // Invalid value
+ throw new IllegalArgumentException("Invalid coordiante value:" + quartSec);
+ }
+ return ((double)quartSec) / (3600 * 4);
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index 07f90cd..021602f 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -28,6 +28,10 @@ public abstract class Connection {
public static int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network
public static int PRESENTATION_PAYPHONE = 4; // show pay phone info
+ //Caller Name Display
+ protected String cnapName;
+ protected int cnapNamePresentation = PRESENTATION_ALLOWED;
+
private static String LOG_TAG = "TelephonyConnection";
public enum DisconnectCause {
@@ -84,11 +88,11 @@ public abstract class Connection {
public abstract String getAddress();
/**
- * Gets CDMA CNAP name associated with connection.
+ * Gets CNAP name associated with connection.
* @return cnap name or null if unavailable
*/
public String getCnapName() {
- return null;
+ return cnapName;
}
/**
@@ -100,12 +104,12 @@ public abstract class Connection {
}
/**
- * Gets CDMA CNAP presentation associated with connection.
+ * Gets CNAP presentation associated with connection.
* @return cnap name or null if unavailable
*/
public int getCnapNamePresentation() {
- return 0;
+ return cnapNamePresentation;
};
/**
diff --git a/telephony/java/com/android/internal/telephony/cat/CommandDetails.java b/telephony/java/com/android/internal/telephony/cat/CommandDetails.java
index 8579535..3e7f722 100644
--- a/telephony/java/com/android/internal/telephony/cat/CommandDetails.java
+++ b/telephony/java/com/android/internal/telephony/cat/CommandDetails.java
@@ -48,13 +48,14 @@ class CommandDetails extends ValueObject implements Parcelable {
}
public CommandDetails(Parcel in) {
- compRequired = true;
+ compRequired = in.readInt() != 0;
commandNumber = in.readInt();
typeOfCommand = in.readInt();
commandQualifier = in.readInt();
}
public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(compRequired ? 1 : 0);
dest.writeInt(commandNumber);
dest.writeInt(typeOfCommand);
dest.writeInt(commandQualifier);
@@ -111,4 +112,4 @@ class ItemsIconId extends ValueObject {
ComprehensionTlvTag getTag() {
return ComprehensionTlvTag.ITEM_ICON_ID_LIST;
}
-} \ No newline at end of file
+}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index 98ad3b1..6985979 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -51,7 +51,6 @@ public class CdmaConnection extends Connection {
String postDialString; // outgoing calls only
boolean isIncoming;
boolean disconnected;
- String cnapName;
int index; // index in CdmaCallTracker.connections[], -1 if unassigned
/*
@@ -77,7 +76,6 @@ public class CdmaConnection extends Connection {
DisconnectCause cause = DisconnectCause.NOT_DISCONNECTED;
PostDialState postDialState = PostDialState.NOT_STARTED;
int numberPresentation = Connection.PRESENTATION_ALLOWED;
- int cnapNamePresentation = Connection.PRESENTATION_ALLOWED;
Handler h;
@@ -230,14 +228,6 @@ public class CdmaConnection extends Connection {
return address;
}
- public String getCnapName() {
- return cnapName;
- }
-
- public int getCnapNamePresentation() {
- return cnapNamePresentation;
- }
-
public CdmaCall getCall() {
return parent;
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 6e9cd51..484bab0 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1232,7 +1232,7 @@ public class GSMPhone extends PhoneBase {
// If the radio shuts off or resets while one of these
// is pending, we need to clean up.
- for (int i = 0, s = mPendingMMIs.size() ; i < s; i++) {
+ for (int i = mPendingMMIs.size() - 1; i >= 0; i--) {
if (mPendingMMIs.get(i).isPendingUSSD()) {
mPendingMMIs.get(i).onUssdFinishedError();
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
index f7c6025..9e32e8d 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
@@ -26,6 +26,7 @@ import android.os.SystemClock;
import android.util.Log;
import android.telephony.PhoneNumberUtils;
import android.telephony.ServiceState;
+import android.text.TextUtils;
import com.android.internal.telephony.*;
@@ -125,6 +126,8 @@ public class GsmConnection extends Connection {
isIncoming = dc.isMT;
createTime = System.currentTimeMillis();
+ cnapName = dc.name;
+ cnapNamePresentation = dc.namePresentation;
numberPresentation = dc.numberPresentation;
uusInfo = dc.uusInfo;
@@ -151,6 +154,9 @@ public class GsmConnection extends Connection {
index = -1;
isIncoming = false;
+ cnapName = null;
+ cnapNamePresentation = Connection.PRESENTATION_ALLOWED;
+ numberPresentation = Connection.PRESENTATION_ALLOWED;
createTime = System.currentTimeMillis();
this.parent = parent;
@@ -437,6 +443,21 @@ public class GsmConnection extends Connection {
changed = true;
}
+ // A null cnapName should be the same as ""
+ if (TextUtils.isEmpty(dc.name)) {
+ if (!TextUtils.isEmpty(cnapName)) {
+ changed = true;
+ cnapName = "";
+ }
+ } else if (!dc.name.equals(cnapName)) {
+ changed = true;
+ cnapName = dc.name;
+ }
+
+ if (Phone.DEBUG_PHONE) log("--dssds----"+cnapName);
+ cnapNamePresentation = dc.namePresentation;
+ numberPresentation = dc.numberPresentation;
+
if (newParent != parent) {
if (parent != null) {
parent.detach(this);
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index f2fa3f5..46b8a27 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -58,7 +58,7 @@ static bool validateFileName(const char* fileName)
// The default to use if no other ignore pattern is defined.
const char * const gDefaultIgnoreAssets =
- "!.svn:!.git:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*.scc:*~";
+ "!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~";
// The ignore pattern that can be passed via --ignore-assets in Main.cpp
const char * gUserIgnoreAssets = NULL;
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index d0a81dc..482f43e 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -29,6 +29,10 @@ LOCAL_SRC_FILES := \
LOCAL_CFLAGS += -Wno-format-y2k
+ifeq (darwin,$(HOST_OS))
+LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
+endif
+
LOCAL_C_INCLUDES += external/expat/lib
LOCAL_C_INCLUDES += external/libpng
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index daeadc0..d7cb61a 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -53,7 +53,6 @@ public:
mWantUTF16(false), mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
- mIsOverlayPackage(false),
mAutoAddOverlay(false), mGenDependencies(false),
mAssetSourceDir(NULL),
mCrunchedOutputDir(NULL), mProguardFile(NULL),
@@ -107,8 +106,6 @@ public:
void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; }
void setInstrumentationPackageNameOverride(const char * val) { mInstrumentationPackageNameOverride = val; }
- bool getIsOverlayPackage() const { return mIsOverlayPackage; }
- void setIsOverlayPackage(bool val) { mIsOverlayPackage = val; }
bool getAutoAddOverlay() { return mAutoAddOverlay; }
void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; }
bool getGenDependencies() { return mGenDependencies; }
@@ -250,7 +247,6 @@ private:
const char* mOutputAPKFile;
const char* mManifestPackageNameOverride;
const char* mInstrumentationPackageNameOverride;
- bool mIsOverlayPackage;
bool mAutoAddOverlay;
bool mGenDependencies;
const char* mAssetSourceDir;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 9f05c6a..9570c66 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -69,7 +69,6 @@ void usage(void)
" [-F apk-file] [-J R-file-dir] \\\n"
" [--product product1,product2,...] \\\n"
" [-c CONFIGS] [--preferred-configurations CONFIGS] \\\n"
- " [-o] \\\n"
" [raw-files-dir [raw-files-dir] ...]\n"
"\n"
" Package the android resources. It will read assets and resources that are\n"
@@ -110,7 +109,6 @@ void usage(void)
" -j specify a jar or zip file containing classes to include\n"
" -k junk path of file(s) added\n"
" -m make package directories under location specified by -J\n"
- " -o create overlay package (ie only resources; expects <overlay-package> in manifest)\n"
#if 0
" -p pseudolocalize the default configuration\n"
#endif
@@ -296,9 +294,6 @@ int main(int argc, char* const argv[])
case 'm':
bundle.setMakePackageDirs(true);
break;
- case 'o':
- bundle.setIsOverlayPackage(true);
- break;
#if 0
case 'p':
bundle.setPseudolocalize(true);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 0195727..d98fe65 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2749,6 +2749,12 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
const bool filterable = (typeName != mipmap16);
const size_t N = t != NULL ? t->getOrderedConfigs().size() : 0;
+
+ // Until a non-NO_ENTRY value has been written for a resource,
+ // that resource is invalid; validResources[i] represents
+ // the item at t->getOrderedConfigs().itemAt(i).
+ Vector<bool> validResources;
+ validResources.insertAt(false, 0, N);
// First write the typeSpec chunk, containing information about
// each resource entry in this type.
@@ -2885,6 +2891,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
if (amt < 0) {
return amt;
}
+ validResources.editItemAt(ei) = true;
} else {
index[ei] = htodl(ResTable_type::NO_ENTRY);
}
@@ -2895,6 +2902,14 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<AaptFile>& dest)
(((uint8_t*)data->editData()) + typeStart);
tHeader->header.size = htodl(data->getSize()-typeStart);
}
+
+ for (size_t i = 0; i < N; ++i) {
+ if (!validResources[i]) {
+ sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
+ fprintf(stderr, "warning: no entries written for %s/%s\n",
+ String8(typeName).string(), String8(c->getName()).string());
+ }
+ }
}
// Fill in the rest of the package information.
@@ -3723,9 +3738,7 @@ sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
{
sp<Package> p = mPackages.valueFor(package);
if (p == NULL) {
- if (mBundle->getIsOverlayPackage()) {
- p = new Package(package, 0x00);
- } else if (mIsAppPackage) {
+ if (mIsAppPackage) {
if (mHaveAppPackage) {
fprintf(stderr, "Adding multiple application package resources; only one is allowed.\n"
"Use -x to create extended resources.\n");
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index 9fb000e..a5db7b1 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -3,7 +3,7 @@
<classpathentry excluding="org/kxml2/io/" kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
- <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/ninepatch/ninepatch-prebuilt.jar"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/tools-common/tools-common-prebuilt.jar"/>
diff --git a/tools/layoutlib/bridge/tests/.classpath b/tools/layoutlib/bridge/tests/.classpath
index 027bc67..2b32e09 100644
--- a/tools/layoutlib/bridge/tests/.classpath
+++ b/tools/layoutlib/bridge/tests/.classpath
@@ -4,7 +4,7 @@
<classpathentry kind="src" path="res"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/layoutlib_bridge"/>
- <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilts/misc/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
<classpathentry kind="output" path="bin"/>
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
new file mode 100755
index 0000000..c988c70
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java
@@ -0,0 +1,787 @@
+/*
+ * 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.tools.layoutlib.create;
+
+import com.android.tools.layoutlib.annotations.VisibleForTesting;
+import com.android.tools.layoutlib.annotations.VisibleForTesting.Visibility;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+import org.objectweb.asm.signature.SignatureReader;
+import org.objectweb.asm.signature.SignatureVisitor;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * Analyzes the input JAR using the ASM java bytecode manipulation library
+ * to list the classes and their dependencies. A "dependency" is a class
+ * used by another class.
+ */
+public class DependencyFinder {
+
+ // Note: a bunch of stuff has package-level access for unit tests. Consider it private.
+
+ /** Output logger. */
+ private final Log mLog;
+
+ /**
+ * Creates a new analyzer.
+ *
+ * @param log The log output.
+ */
+ public DependencyFinder(Log log) {
+ mLog = log;
+ }
+
+ /**
+ * Starts the analysis using parameters from the constructor.
+ *
+ * @param osJarPath The input source JARs to parse.
+ * @return A pair: [0]: map { class FQCN => set of FQCN class dependencies }.
+ * [1]: map { missing class FQCN => set of FQCN class that uses it. }
+ */
+ public List<Map<String, Set<String>>> findDeps(List<String> osJarPath) throws IOException {
+
+ Map<String, ClassReader> zipClasses = parseZip(osJarPath);
+ mLog.info("Found %d classes in input JAR%s.",
+ zipClasses.size(),
+ osJarPath.size() > 1 ? "s" : "");
+
+ Map<String, Set<String>> deps = findClassesDeps(zipClasses);
+
+ Map<String, Set<String>> missing = findMissingClasses(deps, zipClasses.keySet());
+
+ List<Map<String, Set<String>>> result = new ArrayList<Map<String,Set<String>>>(2);
+ result.add(deps);
+ result.add(missing);
+ return result;
+ }
+
+ /**
+ * Prints dependencies to the current logger, found stuff and missing stuff.
+ */
+ public void printAllDeps(List<Map<String, Set<String>>> result) {
+ assert result.size() == 2;
+ Map<String, Set<String>> deps = result.get(0);
+ Map<String, Set<String>> missing = result.get(1);
+
+ // Print all dependences found in the format:
+ // +Found: <FQCN from zip>
+ // uses: FQCN
+
+ mLog.info("++++++ %d Entries found in source JARs", deps.size());
+ mLog.info("");
+
+ for (Entry<String, Set<String>> entry : deps.entrySet()) {
+ mLog.info( "+Found : %s", entry.getKey());
+ for (String dep : entry.getValue()) {
+ mLog.info(" uses: %s", dep);
+ }
+
+ mLog.info("");
+ }
+
+
+ // Now print all missing dependences in the format:
+ // -Missing <FQCN>:
+ // used by: <FQCN>
+
+ mLog.info("");
+ mLog.info("------ %d Entries missing from source JARs", missing.size());
+ mLog.info("");
+
+ for (Entry<String, Set<String>> entry : missing.entrySet()) {
+ mLog.info( "-Missing : %s", entry.getKey());
+ for (String dep : entry.getValue()) {
+ mLog.info(" used by: %s", dep);
+ }
+
+ mLog.info("");
+ }
+ }
+
+ /**
+ * Prints only a summary of the missing dependencies to the current logger.
+ */
+ public void printMissingDeps(List<Map<String, Set<String>>> result) {
+ assert result.size() == 2;
+ @SuppressWarnings("unused") Map<String, Set<String>> deps = result.get(0);
+ Map<String, Set<String>> missing = result.get(1);
+
+ for (String fqcn : missing.keySet()) {
+ mLog.info("%s", fqcn);
+ }
+ }
+
+ // ----------------
+
+ /**
+ * Parses a JAR file and returns a list of all classes founds using a map
+ * class name => ASM ClassReader. Class names are in the form "android.view.View".
+ */
+ Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException {
+ TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>();
+
+ for (String jarPath : jarPathList) {
+ ZipFile zip = new ZipFile(jarPath);
+ Enumeration<? extends ZipEntry> entries = zip.entries();
+ ZipEntry entry;
+ while (entries.hasMoreElements()) {
+ entry = entries.nextElement();
+ if (entry.getName().endsWith(".class")) {
+ ClassReader cr = new ClassReader(zip.getInputStream(entry));
+ String className = classReaderToClassName(cr);
+ classes.put(className, cr);
+ }
+ }
+ }
+
+ return classes;
+ }
+
+ /**
+ * Utility that returns the fully qualified binary class name for a ClassReader.
+ * E.g. it returns something like android.view.View.
+ */
+ static String classReaderToClassName(ClassReader classReader) {
+ if (classReader == null) {
+ return null;
+ } else {
+ return classReader.getClassName().replace('/', '.');
+ }
+ }
+
+ /**
+ * Utility that returns the fully qualified binary class name from a path-like FQCN.
+ * E.g. it returns android.view.View from android/view/View.
+ */
+ static String internalToBinaryClassName(String className) {
+ if (className == null) {
+ return null;
+ } else {
+ return className.replace('/', '.');
+ }
+ }
+
+ /**
+ * Finds all dependencies for all classes in keepClasses which are also
+ * listed in zipClasses. Returns a map of all the dependencies found.
+ */
+ Map<String, Set<String>> findClassesDeps(Map<String, ClassReader> zipClasses) {
+
+ // The dependencies that we'll collect.
+ // It's a map Class name => uses class names.
+ Map<String, Set<String>> dependencyMap = new TreeMap<String, Set<String>>();
+
+ DependencyVisitor visitor = getVisitor();
+
+ int count = 0;
+ try {
+ for (Entry<String, ClassReader> entry : zipClasses.entrySet()) {
+ String name = entry.getKey();
+
+ TreeSet<String> set = new TreeSet<String>();
+ dependencyMap.put(name, set);
+ visitor.setDependencySet(set);
+
+ ClassReader cr = entry.getValue();
+ cr.accept(visitor, 0 /* flags */);
+
+ visitor.setDependencySet(null);
+
+ mLog.debugNoln("Visited %d classes\r", ++count);
+ }
+ } finally {
+ mLog.debugNoln("\n");
+ }
+
+ return dependencyMap;
+ }
+
+ /**
+ * Computes which classes FQCN were found as dependencies that are NOT listed
+ * in the original JAR classes.
+ *
+ * @param deps The map { FQCN => dependencies[] } returned by {@link #findClassesDeps(Map)}.
+ * @param zipClasses The set of all classes FQCN found in the JAR files.
+ * @return A map { FQCN not found in the zipClasses => classes using it }
+ */
+ private Map<String, Set<String>> findMissingClasses(
+ Map<String, Set<String>> deps,
+ Set<String> zipClasses) {
+ Map<String, Set<String>> missing = new TreeMap<String, Set<String>>();
+
+ for (Entry<String, Set<String>> entry : deps.entrySet()) {
+ String name = entry.getKey();
+
+ for (String dep : entry.getValue()) {
+ if (!zipClasses.contains(dep)) {
+ // This dependency doesn't exist in the zip classes.
+ Set<String> set = missing.get(dep);
+ if (set == null) {
+ set = new TreeSet<String>();
+ missing.put(dep, set);
+ }
+ set.add(name);
+ }
+ }
+
+ }
+
+ return missing;
+ }
+
+
+ // ----------------------------------
+
+ /**
+ * Instantiates a new DependencyVisitor. Useful for unit tests.
+ */
+ @VisibleForTesting(visibility=Visibility.PRIVATE)
+ DependencyVisitor getVisitor() {
+ return new DependencyVisitor();
+ }
+
+ /**
+ * Visitor to collect all the type dependencies from a class.
+ */
+ public class DependencyVisitor extends ClassVisitor {
+
+ private Set<String> mCurrentDepSet;
+
+ /**
+ * Creates a new visitor that will find all the dependencies for the visited class.
+ */
+ public DependencyVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+ /**
+ * Sets the {@link Set} where to record direct dependencies for this class.
+ * This will change before each {@link ClassReader#accept(ClassVisitor, int)} call.
+ */
+ public void setDependencySet(Set<String> set) {
+ mCurrentDepSet = set;
+ }
+
+ /**
+ * Considers the given class name as a dependency.
+ */
+ public void considerName(String className) {
+ if (className == null) {
+ return;
+ }
+
+ className = internalToBinaryClassName(className);
+
+ try {
+ // exclude classes that are part of the default JRE (the one executing this program)
+ if (getClass().getClassLoader().loadClass(className) != null) {
+ return;
+ }
+ } catch (ClassNotFoundException e) {
+ // ignore
+ }
+
+ // Add it to the dependency set for the currently visited class, as needed.
+ assert mCurrentDepSet != null;
+ if (mCurrentDepSet != null) {
+ mCurrentDepSet.add(className);
+ }
+ }
+
+ /**
+ * Considers this array of names using considerName().
+ */
+ public void considerNames(String[] classNames) {
+ if (classNames != null) {
+ for (String className : classNames) {
+ considerName(className);
+ }
+ }
+ }
+
+ /**
+ * Considers this signature or type signature by invoking the {@link SignatureVisitor}
+ * on it.
+ */
+ public void considerSignature(String signature) {
+ if (signature != null) {
+ SignatureReader sr = new SignatureReader(signature);
+ // SignatureReader.accept will call accessType so we don't really have
+ // to differentiate where the signature comes from.
+ sr.accept(new MySignatureVisitor());
+ }
+ }
+
+ /**
+ * Considers this {@link Type}. For arrays, the element type is considered.
+ * If the type is an object, it's internal name is considered.
+ */
+ public void considerType(Type t) {
+ if (t != null) {
+ if (t.getSort() == Type.ARRAY) {
+ t = t.getElementType();
+ }
+ if (t.getSort() == Type.OBJECT) {
+ considerName(t.getInternalName());
+ }
+ }
+ }
+
+ /**
+ * Considers a descriptor string. The descriptor is converted to a {@link Type}
+ * and then considerType() is invoked.
+ */
+ public boolean considerDesc(String desc) {
+ if (desc != null) {
+ try {
+ if (desc.length() > 0 && desc.charAt(0) == '(') {
+ // This is a method descriptor with arguments and a return type.
+ Type t = Type.getReturnType(desc);
+ considerType(t);
+
+ for (Type arg : Type.getArgumentTypes(desc)) {
+ considerType(arg);
+ }
+
+ } else {
+ Type t = Type.getType(desc);
+ considerType(t);
+ }
+ return true;
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // ignore, not a valid type.
+ }
+ }
+ return false;
+ }
+
+
+ // ---------------------------------------------------
+ // --- ClassVisitor, FieldVisitor
+ // ---------------------------------------------------
+
+ // Visits a class header
+ @Override
+ public void visit(int version, int access, String name,
+ String signature, String superName, String[] interfaces) {
+ // signature is the signature of this class. May be null if the class is not a generic
+ // one, and does not extend or implement generic classes or interfaces.
+
+ if (signature != null) {
+ considerSignature(signature);
+ }
+
+ // superName is the internal of name of the super class (see getInternalName).
+ // For interfaces, the super class is Object. May be null but only for the Object class.
+ considerName(superName);
+
+ // interfaces is the internal names of the class's interfaces (see getInternalName).
+ // May be null.
+ considerNames(interfaces);
+ }
+
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ // desc is the class descriptor of the annotation class.
+ considerDesc(desc);
+ return new MyAnnotationVisitor();
+ }
+
+ @Override
+ public void visitAttribute(Attribute attr) {
+ // pass
+ }
+
+ // Visits the end of a class
+ @Override
+ public void visitEnd() {
+ // pass
+ }
+
+ private class MyFieldVisitor extends FieldVisitor {
+
+ public MyFieldVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ // desc is the class descriptor of the annotation class.
+ considerDesc(desc);
+ return new MyAnnotationVisitor();
+ }
+
+ @Override
+ public void visitAttribute(Attribute attr) {
+ // pass
+ }
+
+ // Visits the end of a class
+ @Override
+ public void visitEnd() {
+ // pass
+ }
+ }
+
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc,
+ String signature, Object value) {
+ // desc is the field's descriptor (see Type).
+ considerDesc(desc);
+
+ // signature is the field's signature. May be null if the field's type does not use
+ // generic types.
+ considerSignature(signature);
+
+ return new MyFieldVisitor();
+ }
+
+ @Override
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ // name is the internal name of an inner class (see getInternalName).
+ // Note: outerName/innerName seems to be null when we're reading the
+ // _Original_ClassName classes generated by layoutlib_create.
+ if (outerName != null) {
+ considerName(name);
+ }
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+ // desc is the method's descriptor (see Type).
+ considerDesc(desc);
+ // signature is the method's signature. May be null if the method parameters, return
+ // type and exceptions do not use generic types.
+ considerSignature(signature);
+
+ return new MyMethodVisitor();
+ }
+
+ @Override
+ public void visitOuterClass(String owner, String name, String desc) {
+ // pass
+ }
+
+ @Override
+ public void visitSource(String source, String debug) {
+ // pass
+ }
+
+
+ // ---------------------------------------------------
+ // --- MethodVisitor
+ // ---------------------------------------------------
+
+ private class MyMethodVisitor extends MethodVisitor {
+
+ public MyMethodVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+
+ @Override
+ public AnnotationVisitor visitAnnotationDefault() {
+ return new MyAnnotationVisitor();
+ }
+
+ @Override
+ public void visitCode() {
+ // pass
+ }
+
+ // field instruction
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ // name is the field's name.
+ // desc is the field's descriptor (see Type).
+ considerDesc(desc);
+ }
+
+ @Override
+ public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
+ // pass
+ }
+
+ @Override
+ public void visitIincInsn(int var, int increment) {
+ // pass -- an IINC instruction
+ }
+
+ @Override
+ public void visitInsn(int opcode) {
+ // pass -- a zero operand instruction
+ }
+
+ @Override
+ public void visitIntInsn(int opcode, int operand) {
+ // pass -- a single int operand instruction
+ }
+
+ @Override
+ public void visitJumpInsn(int opcode, Label label) {
+ // pass -- a jump instruction
+ }
+
+ @Override
+ public void visitLabel(Label label) {
+ // pass -- a label target
+ }
+
+ // instruction to load a constant from the stack
+ @Override
+ public void visitLdcInsn(Object cst) {
+ if (cst instanceof Type) {
+ considerType((Type) cst);
+ }
+ }
+
+ @Override
+ public void visitLineNumber(int line, Label start) {
+ // pass
+ }
+
+ @Override
+ public void visitLocalVariable(String name, String desc,
+ String signature, Label start, Label end, int index) {
+ // desc is the type descriptor of this local variable.
+ considerDesc(desc);
+ // signature is the type signature of this local variable. May be null if the local
+ // variable type does not use generic types.
+ considerSignature(signature);
+ }
+
+ @Override
+ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+ // pass -- a lookup switch instruction
+ }
+
+ @Override
+ public void visitMaxs(int maxStack, int maxLocals) {
+ // pass
+ }
+
+ // instruction that invokes a method
+ @Override
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+
+ // owner is the internal name of the method's owner class
+ if (!considerDesc(owner) && owner.indexOf('/') != -1) {
+ considerName(owner);
+ }
+ // desc is the method's descriptor (see Type).
+ considerDesc(desc);
+ }
+
+ // instruction multianewarray, whatever that is
+ @Override
+ public void visitMultiANewArrayInsn(String desc, int dims) {
+
+ // desc an array type descriptor.
+ considerDesc(desc);
+ }
+
+ @Override
+ public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
+ boolean visible) {
+ // desc is the class descriptor of the annotation class.
+ considerDesc(desc);
+ return new MyAnnotationVisitor();
+ }
+
+ @Override
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
+ // pass -- table switch instruction
+
+ }
+
+ @Override
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+ // type is the internal name of the type of exceptions handled by the handler,
+ // or null to catch any exceptions (for "finally" blocks).
+ considerName(type);
+ }
+
+ // type instruction
+ @Override
+ public void visitTypeInsn(int opcode, String type) {
+ // type is the operand of the instruction to be visited. This operand must be the
+ // internal name of an object or array class.
+ considerName(type);
+ }
+
+ @Override
+ public void visitVarInsn(int opcode, int var) {
+ // pass -- local variable instruction
+ }
+ }
+
+ private class MySignatureVisitor extends SignatureVisitor {
+
+ public MySignatureVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+ // ---------------------------------------------------
+ // --- SignatureVisitor
+ // ---------------------------------------------------
+
+ private String mCurrentSignatureClass = null;
+
+ // Starts the visit of a signature corresponding to a class or interface type
+ @Override
+ public void visitClassType(String name) {
+ mCurrentSignatureClass = name;
+ considerName(name);
+ }
+
+ // Visits an inner class
+ @Override
+ public void visitInnerClassType(String name) {
+ if (mCurrentSignatureClass != null) {
+ mCurrentSignatureClass += "$" + name;
+ considerName(mCurrentSignatureClass);
+ }
+ }
+
+ @Override
+ public SignatureVisitor visitArrayType() {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public void visitBaseType(char descriptor) {
+ // pass -- a primitive type, ignored
+ }
+
+ @Override
+ public SignatureVisitor visitClassBound() {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public SignatureVisitor visitExceptionType() {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public void visitFormalTypeParameter(String name) {
+ // pass
+ }
+
+ @Override
+ public SignatureVisitor visitInterface() {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public SignatureVisitor visitInterfaceBound() {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public SignatureVisitor visitParameterType() {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public SignatureVisitor visitReturnType() {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public SignatureVisitor visitSuperclass() {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public SignatureVisitor visitTypeArgument(char wildcard) {
+ return new MySignatureVisitor();
+ }
+
+ @Override
+ public void visitTypeVariable(String name) {
+ // pass
+ }
+
+ @Override
+ public void visitTypeArgument() {
+ // pass
+ }
+ }
+
+
+ // ---------------------------------------------------
+ // --- AnnotationVisitor
+ // ---------------------------------------------------
+
+ private class MyAnnotationVisitor extends AnnotationVisitor {
+
+ public MyAnnotationVisitor() {
+ super(Opcodes.ASM4);
+ }
+
+ // Visits a primitive value of an annotation
+ @Override
+ public void visit(String name, Object value) {
+ // value is the actual value, whose type must be Byte, Boolean, Character, Short,
+ // Integer, Long, Float, Double, String or Type
+ if (value instanceof Type) {
+ considerType((Type) value);
+ }
+ }
+
+ @Override
+ public AnnotationVisitor visitAnnotation(String name, String desc) {
+ // desc is the class descriptor of the nested annotation class.
+ considerDesc(desc);
+ return new MyAnnotationVisitor();
+ }
+
+ @Override
+ public AnnotationVisitor visitArray(String name) {
+ return new MyAnnotationVisitor();
+ }
+
+ @Override
+ public void visitEnum(String name, String desc, String value) {
+ // desc is the class descriptor of the enumeration class.
+ considerDesc(desc);
+ }
+ }
+ }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Log.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Log.java
index 8efd871..c3ba591 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Log.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Log.java
@@ -33,11 +33,19 @@ public class Log {
}
}
+ /** Similar to debug() but doesn't do a \n automatically. */
+ public void debugNoln(String format, Object... args) {
+ if (mVerbose) {
+ String s = String.format(format, args);
+ System.out.print(s);
+ }
+ }
+
public void info(String format, Object... args) {
String s = String.format(format, args);
outPrintln(s);
}
-
+
public void error(String format, Object... args) {
String s = String.format(format, args);
errPrintln(s);
@@ -50,15 +58,15 @@ public class Log {
pw.flush();
error(format + "\n" + sw.toString(), args);
}
-
+
/** for unit testing */
protected void errPrintln(String msg) {
System.err.println(msg);
}
-
+
/** for unit testing */
protected void outPrintln(String msg) {
System.out.println(msg);
}
-
+
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index 4b7a348..9cd74db 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -18,6 +18,8 @@ package com.android.tools.layoutlib.create;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
@@ -47,6 +49,8 @@ public class Main {
public static class Options {
public boolean generatePublicAccess = true;
+ public boolean listAllDeps = false;
+ public boolean listOnlyMissingDeps = false;
}
public static final Options sOptions = new Options();
@@ -60,16 +64,29 @@ public class Main {
if (!processArgs(log, args, osJarPath, osDestJar)) {
log.error("Usage: layoutlib_create [-v] [-p] output.jar input.jar ...");
+ log.error("Usage: layoutlib_create [-v] [--list-deps|--missing-deps] input.jar ...");
System.exit(1);
}
- log.info("Output: %1$s", osDestJar[0]);
+ if (sOptions.listAllDeps || sOptions.listOnlyMissingDeps) {
+ System.exit(listDeps(osJarPath, log));
+
+ } else {
+ System.exit(createLayoutLib(osDestJar[0], osJarPath, log));
+ }
+
+
+ System.exit(1);
+ }
+
+ private static int createLayoutLib(String osDestJar, ArrayList<String> osJarPath, Log log) {
+ log.info("Output: %1$s", osDestJar);
for (String path : osJarPath) {
log.info("Input : %1$s", path);
}
try {
- AsmGenerator agen = new AsmGenerator(log, osDestJar[0], new CreateInfo());
+ AsmGenerator agen = new AsmGenerator(log, osDestJar, new CreateInfo());
AsmAnalyzer aa = new AsmAnalyzer(log, osJarPath, agen,
new String[] { // derived from
@@ -116,17 +133,33 @@ public class Main {
for (String path : osJarPath) {
log.info("- Input JAR : %1$s", path);
}
- System.exit(1);
+ return 1;
}
- System.exit(0);
+ return 0;
} catch (IOException e) {
log.exception(e, "Failed to load jar");
} catch (LogAbortException e) {
e.error(log);
}
- System.exit(1);
+ return 1;
+ }
+
+ private static int listDeps(ArrayList<String> osJarPath, Log log) {
+ DependencyFinder df = new DependencyFinder(log);
+ try {
+ List<Map<String, Set<String>>> result = df.findDeps(osJarPath);
+ if (sOptions.listAllDeps) {
+ df.printAllDeps(result);
+ } else if (sOptions.listOnlyMissingDeps) {
+ df.printMissingDeps(result);
+ }
+ } catch (IOException e) {
+ log.exception(e, "Failed to load jar");
+ }
+
+ return 0;
}
/**
@@ -138,14 +171,21 @@ public class Main {
*/
private static boolean processArgs(Log log, String[] args,
ArrayList<String> osJarPath, String[] osDestJar) {
+ boolean needs_dest = true;
for (int i = 0; i < args.length; i++) {
String s = args[i];
if (s.equals("-v")) {
log.setVerbose(true);
} else if (s.equals("-p")) {
sOptions.generatePublicAccess = false;
+ } else if (s.equals("--list-deps")) {
+ sOptions.listAllDeps = true;
+ needs_dest = false;
+ } else if (s.equals("--missing-deps")) {
+ sOptions.listOnlyMissingDeps = true;
+ needs_dest = false;
} else if (!s.startsWith("-")) {
- if (osDestJar[0] == null) {
+ if (needs_dest && osDestJar[0] == null) {
osDestJar[0] = s;
} else {
osJarPath.add(s);
@@ -160,7 +200,7 @@ public class Main {
log.error("Missing parameter: path to input jar");
return false;
}
- if (osDestJar[0] == null) {
+ if (needs_dest && osDestJar[0] == null) {
log.error("Missing parameter: path to output jar");
return false;
}