summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/system-current.txt9
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java32
-rw-r--r--core/java/android/provider/Browser.java21
-rw-r--r--core/java/android/webkit/WebViewFactory.java38
-rw-r--r--core/java/android/widget/Editor.java13
-rw-r--r--core/res/AndroidManifest.xml8
-rw-r--r--core/res/res/values/strings.xml6
-rw-r--r--libs/hwui/Android.common.mk1
-rw-r--r--libs/hwui/DeferredDisplayList.h2
-rw-r--r--libs/hwui/tests/Android.mk13
-rw-r--r--libs/hwui/unit_tests/Android.mk34
-rw-r--r--libs/hwui/unit_tests/ClipAreaTests.cpp (renamed from libs/hwui/tests/ClipAreaTests.cpp)0
-rw-r--r--libs/hwui/unit_tests/LinearAllocatorTests.cpp108
-rwxr-xr-xlibs/hwui/unit_tests/how_to_run.txt4
-rw-r--r--libs/hwui/unit_tests/main.cpp22
-rw-r--r--libs/hwui/utils/LinearAllocator.cpp272
-rw-r--r--libs/hwui/utils/LinearAllocator.h142
-rw-r--r--preloaded-classes5
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java45
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java117
20 files changed, 792 insertions, 100 deletions
diff --git a/api/system-current.txt b/api/system-current.txt
index 16ffc3199a77..137bb19c4a60 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -41589,10 +41589,19 @@ package android.webkit {
ctor public WebViewFactory();
method public static android.content.pm.PackageInfo getLoadedPackageInfo();
method public static java.lang.String getWebViewPackageName();
+ method public static int loadWebViewNativeLibraryFromPackage(java.lang.String);
method public static void onWebViewUpdateInstalled();
method public static void prepareWebViewInSystemServer();
method public static void prepareWebViewInZygote();
field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize";
+ field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
+ field public static final int LIBLOAD_FAILED_JNI_CALL = 7; // 0x7
+ field public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4; // 0x4
+ field public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6; // 0x6
+ field public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5; // 0x5
+ field public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3; // 0x3
+ field public static final int LIBLOAD_SUCCESS = 0; // 0x0
+ field public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1; // 0x1
}
public abstract interface WebViewFactoryProvider {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a20aa6687069..47133d417912 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2651,14 +2651,12 @@ public class DevicePolicyManager {
/**
* @hide
- * Sets the given package as the device owner. The package must already be installed and there
- * shouldn't be an existing device owner registered, for this call to succeed. Also, this
- * method must be called before the device is provisioned.
+ * Sets the given package as the device owner.
+ * Same as {@link #setDeviceOwner(String, String)} but without setting a device owner name.
* @param packageName the package name of the application to be registered as the device owner.
* @return whether the package was successfully registered as the device owner.
* @throws IllegalArgumentException if the package name is null or invalid
- * @throws IllegalStateException if a device owner is already registered or the device has
- * already been provisioned.
+ * @throws IllegalStateException If the preconditions mentioned are not met.
*/
public boolean setDeviceOwner(String packageName) throws IllegalArgumentException,
IllegalStateException {
@@ -2667,15 +2665,17 @@ public class DevicePolicyManager {
/**
* @hide
- * Sets the given package as the device owner. The package must already be installed and there
- * shouldn't be an existing device owner registered, for this call to succeed. Also, this
- * method must be called before the device is provisioned.
+ * Sets the given package as the device owner. The package must already be installed. There
+ * must not already be a device owner.
+ * Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call
+ * this method.
+ * Calling this after the setup phase of the primary user has completed is allowed only if
+ * the caller is the shell uid, and there are no additional users and no accounts.
* @param packageName the package name of the application to be registered as the device owner.
* @param ownerName the human readable name of the institution that owns this device.
* @return whether the package was successfully registered as the device owner.
* @throws IllegalArgumentException if the package name is null or invalid
- * @throws IllegalStateException if a device owner is already registered or the device has
- * already been provisioned.
+ * @throws IllegalStateException If the preconditions mentioned are not met.
*/
public boolean setDeviceOwner(String packageName, String ownerName)
throws IllegalArgumentException, IllegalStateException {
@@ -2961,14 +2961,18 @@ public class DevicePolicyManager {
/**
* @hide
* Sets the given component as the profile owner of the given user profile. The package must
- * already be installed and there shouldn't be an existing profile owner registered for this
- * user. Only the system can call this API if the user has already completed setup.
+ * already be installed. There must not already be a profile owner for this user.
+ * Only apps with the MANAGE_PROFILE_AND_DEVICE_OWNERS permission and the shell uid can call
+ * this method.
+ * Calling this after the setup phase of the specified user has completed is allowed only if:
+ * - the caller is SYSTEM_UID.
+ * - or the caller is the shell uid, and there are no accounts on the specified user.
* @param admin the component name to be registered as profile owner.
* @param ownerName the human readable name of the organisation associated with this DPM.
* @param userHandle the userId to set the profile owner for.
* @return whether the component was successfully registered as the profile owner.
- * @throws IllegalArgumentException if admin is null, the package isn't installed, or
- * the user has already been set up.
+ * @throws IllegalArgumentException if admin is null, the package isn't installed, or the
+ * preconditions mentioned are not met.
*/
public boolean setProfileOwner(ComponentName admin, String ownerName, int userHandle)
throws IllegalArgumentException {
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index 69a05c4f0b19..bae06b80f5ca 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -16,6 +16,7 @@
package android.provider;
+import android.annotation.RequiresPermission;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
@@ -32,6 +33,9 @@ import android.provider.BrowserContract.Searches;
import android.util.Log;
import android.webkit.WebIconDatabase;
+import static android.Manifest.permission.READ_HISTORY_BOOKMARKS;
+import static android.Manifest.permission.WRITE_HISTORY_BOOKMARKS;
+
public class Browser {
private static final String LOGTAG = "browser";
@@ -41,6 +45,8 @@ public class Browser {
* {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} permission and writing to it
* requires the {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} permission.
*/
+ @RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
+ @RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri BOOKMARKS_URI = Uri.parse("content://browser/bookmarks");
/**
@@ -122,6 +128,8 @@ public class Browser {
* {@link android.Manifest.permission#READ_HISTORY_BOOKMARKS} permission and writing to it
* requires the {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS} permission.
*/
+ @RequiresPermission.Read(@RequiresPermission(READ_HISTORY_BOOKMARKS))
+ @RequiresPermission.Write(@RequiresPermission(WRITE_HISTORY_BOOKMARKS))
public static final Uri SEARCHES_URI = Uri.parse("content://browser/searches");
/**
@@ -233,6 +241,7 @@ public class Browser {
*
* @param cr The ContentResolver used to access the database.
*/
+ @RequiresPermission(READ_HISTORY_BOOKMARKS)
public static final Cursor getAllBookmarks(ContentResolver cr) throws
IllegalStateException {
return cr.query(Bookmarks.CONTENT_URI,
@@ -248,6 +257,7 @@ public class Browser {
*
* @param cr The ContentResolver used to access the database.
*/
+ @RequiresPermission(READ_HISTORY_BOOKMARKS)
public static final Cursor getAllVisitedUrls(ContentResolver cr) throws
IllegalStateException {
return cr.query(Combined.CONTENT_URI,
@@ -308,6 +318,7 @@ public class Browser {
* @param real If true, this is an actual visit, and should add to the
* number of visits. If false, the user entered it manually.
*/
+ @RequiresPermission(allOf = {READ_HISTORY_BOOKMARKS, WRITE_HISTORY_BOOKMARKS})
public static final void updateVisitedHistory(ContentResolver cr,
String url, boolean real) {
long now = System.currentTimeMillis();
@@ -358,6 +369,7 @@ public class Browser {
* @param cr The ContentResolver used to access the database.
* @hide pending API council approval
*/
+ @RequiresPermission(READ_HISTORY_BOOKMARKS)
public static final String[] getVisitedHistory(ContentResolver cr) {
Cursor c = null;
String[] str = null;
@@ -393,6 +405,7 @@ public class Browser {
*
* @param cr The ContentResolver used to access the database.
*/
+ @RequiresPermission(allOf = {READ_HISTORY_BOOKMARKS, WRITE_HISTORY_BOOKMARKS})
public static final void truncateHistory(ContentResolver cr) {
// TODO make a single request to the provider to do this in a single transaction
Cursor cursor = null;
@@ -424,6 +437,7 @@ public class Browser {
* @param cr The ContentResolver used to access the database.
* @return boolean True if the history can be cleared.
*/
+ @RequiresPermission(READ_HISTORY_BOOKMARKS)
public static final boolean canClearHistory(ContentResolver cr) {
Cursor cursor = null;
boolean ret = false;
@@ -446,6 +460,7 @@ public class Browser {
* Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
* @param cr The ContentResolver used to access the database.
*/
+ @RequiresPermission(WRITE_HISTORY_BOOKMARKS)
public static final void clearHistory(ContentResolver cr) {
deleteHistoryWhere(cr, null);
}
@@ -461,6 +476,7 @@ public class Browser {
* @param whereClause String to limit the items affected.
* null means all items.
*/
+ @RequiresPermission(allOf = {READ_HISTORY_BOOKMARKS, WRITE_HISTORY_BOOKMARKS})
private static final void deleteHistoryWhere(ContentResolver cr, String whereClause) {
Cursor cursor = null;
try {
@@ -486,6 +502,7 @@ public class Browser {
* @param end Last date to remove. If -1, all dates after begin.
* Non-inclusive.
*/
+ @RequiresPermission(WRITE_HISTORY_BOOKMARKS)
public static final void deleteHistoryTimeFrame(ContentResolver cr,
long begin, long end) {
String whereClause;
@@ -511,6 +528,7 @@ public class Browser {
* @param cr The ContentResolver used to access the database.
* @param url url to remove.
*/
+ @RequiresPermission(WRITE_HISTORY_BOOKMARKS)
public static final void deleteFromHistory(ContentResolver cr,
String url) {
cr.delete(History.CONTENT_URI, History.URL + "=?", new String[] { url });
@@ -523,6 +541,7 @@ public class Browser {
* @param cr The ContentResolver used to access the database.
* @param search The string to add to the searches database.
*/
+ @RequiresPermission(allOf = {READ_HISTORY_BOOKMARKS, WRITE_HISTORY_BOOKMARKS})
public static final void addSearchUrl(ContentResolver cr, String search) {
// The content provider will take care of updating existing searches instead of duplicating
ContentValues values = new ContentValues();
@@ -536,6 +555,7 @@ public class Browser {
* Requires {@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS}
* @param cr The ContentResolver used to access the database.
*/
+ @RequiresPermission(WRITE_HISTORY_BOOKMARKS)
public static final void clearSearches(ContentResolver cr) {
// FIXME: Should this clear the urls to which these searches lead?
// (i.e. remove google.com/query= blah blah blah)
@@ -557,6 +577,7 @@ public class Browser {
* @param listener IconListener that gets the icons once they are
* retrieved.
*/
+ @RequiresPermission(READ_HISTORY_BOOKMARKS)
public static final void requestAllIcons(ContentResolver cr, String where,
WebIconDatabase.IconListener listener) {
// Do nothing: this is no longer used.
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 3340c73c32db..9782d7202b73 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -76,6 +76,18 @@ public final class WebViewFactory {
private static boolean sAddressSpaceReserved = false;
private static PackageInfo sPackageInfo;
+ // Error codes for loadWebViewNativeLibraryFromPackage
+ public static final int LIBLOAD_SUCCESS = 0;
+ public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1;
+ public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2;
+ public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3;
+ public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4;
+
+ // native relro loading error codes
+ public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5;
+ public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6;
+ public static final int LIBLOAD_FAILED_JNI_CALL = 7;
+
private static class MissingWebViewPackageException extends AndroidRuntimeException {
public MissingWebViewPackageException(String message) { super(message); }
public MissingWebViewPackageException(Exception e) { super(e); }
@@ -136,6 +148,18 @@ public final class WebViewFactory {
return sPackageInfo;
}
+ /**
+ * Load the native library for the given package name iff that package
+ * name is the same as the one providing the current webview.
+ */
+ public static int loadWebViewNativeLibraryFromPackage(String packageName) {
+ sPackageInfo = findPreferredWebViewPackage();
+ if (packageName != null && packageName.equals(sPackageInfo.packageName)) {
+ return loadNativeLibrary();
+ }
+ return LIBLOAD_WRONG_PACKAGE_NAME;
+ }
+
static WebViewFactoryProvider getProvider() {
synchronized (sProviderLock) {
// For now the main purpose of this function (and the factory abstraction) is to keep
@@ -434,32 +458,34 @@ public final class WebViewFactory {
}
}
- private static void loadNativeLibrary() {
+ private static int loadNativeLibrary() {
if (!sAddressSpaceReserved) {
Log.e(LOGTAG, "can't load with relro file; address space not reserved");
- return;
+ return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
}
try {
getUpdateService().waitForRelroCreationCompleted(VMRuntime.getRuntime().is64Bit());
} catch (RemoteException e) {
Log.e(LOGTAG, "error waiting for relro creation, proceeding without", e);
- return;
+ return LIBLOAD_FAILED_WAITING_FOR_RELRO;
}
try {
String[] args = getWebViewNativeLibraryPaths();
- boolean result = nativeLoadWithRelroFile(args[0] /* path32 */,
+ int result = nativeLoadWithRelroFile(args[0] /* path32 */,
args[1] /* path64 */,
CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
- if (!result) {
+ if (result != LIBLOAD_SUCCESS) {
Log.w(LOGTAG, "failed to load with relro file, proceeding without");
} else if (DEBUG) {
Log.v(LOGTAG, "loaded with relro file");
}
+ return result;
} catch (MissingWebViewPackageException e) {
Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
+ return LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
}
}
@@ -470,6 +496,6 @@ public final class WebViewFactory {
private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
private static native boolean nativeCreateRelroFile(String lib32, String lib64,
String relro32, String relro64);
- private static native boolean nativeLoadWithRelroFile(String lib32, String lib64,
+ private static native int nativeLoadWithRelroFile(String lib32, String lib64,
String relro32, String relro64);
}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index b049e494f933..652fff265980 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1957,6 +1957,9 @@ public class Editor {
if (mPositionListener != null) {
mPositionListener.onScrollChanged();
}
+ if (mSelectionActionMode != null) {
+ mSelectionActionMode.invalidateContentRect();
+ }
}
/**
@@ -3085,10 +3088,12 @@ public class Editor {
MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
}
- menu.add(0, TextView.ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
- setAlphabeticShortcut('a').
- setShowAsAction(
- MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ if (canSelectText() && !hasPasswordTransformationMethod()) {
+ menu.add(0, TextView.ID_SELECT_ALL, 0, com.android.internal.R.string.selectAll).
+ setAlphabeticShortcut('a').
+ setShowAsAction(
+ MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ }
updateReplaceItem(menu);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 62685a1898f7..dced05198c2c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1309,6 +1309,14 @@
<permission android:name="android.permission.MANAGE_USERS"
android:protectionLevel="signature|system" />
+ <!-- @hide Allows an application to set the profile owners and the device owner.
+ This permission is not available to third party applications.-->
+ <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature"
+ android:label="@string/permlab_manageProfileAndDeviceOwners"
+ android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+
<!-- Allows an application to get full detailed information about
recently running tasks, with full fidelity to the real state.
@hide -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6f554f08ce17..51c2062d806e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -699,6 +699,12 @@
discover information about which applications are used on the device.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_manageProfileAndDeviceOwners">Manage profile and device owners</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to set the profile/device owners.
+ [CHAR LIMIT=NONE] -->
+ <string name="permdesc_manageProfileAndDeviceOwners">Allows apps to set the profile owners and the device owner.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_reorderTasks">reorder running apps</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_reorderTasks">Allows the app to move tasks to the
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index 5fca8ec9a358..836f86875dcd 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \
thread/TaskManager.cpp \
utils/Blur.cpp \
utils/GLUtils.cpp \
+ utils/LinearAllocator.cpp \
utils/SortedListImpl.cpp \
AmbientShadow.cpp \
AnimationContext.cpp \
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index c92ab91d21bf..f535afb2d61a 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -127,7 +127,7 @@ private:
}
void tryRecycleState(DeferredDisplayState* state) {
- mAllocator.rewindIfLastAlloc(state, sizeof(DeferredDisplayState));
+ mAllocator.rewindIfLastAlloc(state);
}
/**
diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk
index 51898d2a1d22..b6f0baf4bf3e 100644
--- a/libs/hwui/tests/Android.mk
+++ b/libs/hwui/tests/Android.mk
@@ -34,16 +34,3 @@ LOCAL_SRC_FILES += \
tests/main.cpp
include $(BUILD_EXECUTABLE)
-
-include $(CLEAR_VARS)
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.common.mk
-LOCAL_MODULE := hwui_unit_tests
-LOCAL_MODULE_TAGS := tests
-
-include $(LOCAL_PATH)/Android.common.mk
-
-LOCAL_SRC_FILES += \
- tests/ClipAreaTests.cpp \
-
-include $(BUILD_NATIVE_TEST)
diff --git a/libs/hwui/unit_tests/Android.mk b/libs/hwui/unit_tests/Android.mk
new file mode 100644
index 000000000000..51601b072405
--- /dev/null
+++ b/libs/hwui/unit_tests/Android.mk
@@ -0,0 +1,34 @@
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+local_target_dir := $(TARGET_OUT_DATA)/local/tmp
+LOCAL_PATH:= $(call my-dir)/..
+
+include $(CLEAR_VARS)
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.common.mk
+LOCAL_MODULE := hwui_unit_tests
+LOCAL_MODULE_TAGS := tests
+
+include $(LOCAL_PATH)/Android.common.mk
+
+LOCAL_SRC_FILES += \
+ unit_tests/ClipAreaTests.cpp \
+ unit_tests/LinearAllocatorTests.cpp \
+ unit_tests/main.cpp
+
+
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/hwui/tests/ClipAreaTests.cpp b/libs/hwui/unit_tests/ClipAreaTests.cpp
index 166d5b6e92f6..166d5b6e92f6 100644
--- a/libs/hwui/tests/ClipAreaTests.cpp
+++ b/libs/hwui/unit_tests/ClipAreaTests.cpp
diff --git a/libs/hwui/unit_tests/LinearAllocatorTests.cpp b/libs/hwui/unit_tests/LinearAllocatorTests.cpp
new file mode 100644
index 000000000000..b3959d169e1d
--- /dev/null
+++ b/libs/hwui/unit_tests/LinearAllocatorTests.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <utils/LinearAllocator.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+struct SimplePair {
+ int one = 1;
+ int two = 2;
+};
+
+class SignalingDtor {
+public:
+ SignalingDtor() {
+ mDestroyed = nullptr;
+ }
+ SignalingDtor(bool* destroyedSignal) {
+ mDestroyed = destroyedSignal;
+ *mDestroyed = false;
+ }
+ virtual ~SignalingDtor() {
+ if (mDestroyed) {
+ *mDestroyed = true;
+ }
+ }
+ void setSignal(bool* destroyedSignal) {
+ mDestroyed = destroyedSignal;
+ }
+private:
+ bool* mDestroyed;
+};
+
+TEST(LinearAllocator, alloc) {
+ LinearAllocator la;
+ EXPECT_EQ(0u, la.usedSize());
+ la.alloc(64);
+ // There's some internal tracking as well as padding
+ // so the usedSize isn't strictly defined
+ EXPECT_LE(64u, la.usedSize());
+ EXPECT_GT(80u, la.usedSize());
+ auto pair = la.alloc<SimplePair>();
+ EXPECT_LE(64u + sizeof(SimplePair), la.usedSize());
+ EXPECT_GT(80u + sizeof(SimplePair), la.usedSize());
+ EXPECT_EQ(1, pair->one);
+ EXPECT_EQ(2, pair->two);
+}
+
+TEST(LinearAllocator, dtor) {
+ bool destroyed[10];
+ {
+ LinearAllocator la;
+ for (int i = 0; i < 5; i++) {
+ la.alloc<SignalingDtor>()->setSignal(destroyed + i);
+ la.alloc<SimplePair>();
+ }
+ la.alloc(100);
+ for (int i = 0; i < 5; i++) {
+ auto sd = new (la) SignalingDtor(destroyed + 5 + i);
+ la.autoDestroy(sd);
+ new (la) SimplePair();
+ }
+ la.alloc(100);
+ for (int i = 0; i < 10; i++) {
+ EXPECT_FALSE(destroyed[i]);
+ }
+ }
+ for (int i = 0; i < 10; i++) {
+ EXPECT_TRUE(destroyed[i]);
+ }
+}
+
+TEST(LinearAllocator, rewind) {
+ bool destroyed;
+ {
+ LinearAllocator la;
+ auto addr = la.alloc(100);
+ EXPECT_LE(100u, la.usedSize());
+ la.rewindIfLastAlloc(addr, 100);
+ EXPECT_GT(16u, la.usedSize());
+ size_t emptySize = la.usedSize();
+ auto sigdtor = la.alloc<SignalingDtor>();
+ sigdtor->setSignal(&destroyed);
+ EXPECT_FALSE(destroyed);
+ EXPECT_LE(emptySize, la.usedSize());
+ la.rewindIfLastAlloc(sigdtor);
+ EXPECT_TRUE(destroyed);
+ EXPECT_EQ(emptySize, la.usedSize());
+ destroyed = false;
+ }
+ // Checking for a double-destroy case
+ EXPECT_EQ(destroyed, false);
+}
diff --git a/libs/hwui/unit_tests/how_to_run.txt b/libs/hwui/unit_tests/how_to_run.txt
new file mode 100755
index 000000000000..a2d6a34726df
--- /dev/null
+++ b/libs/hwui/unit_tests/how_to_run.txt
@@ -0,0 +1,4 @@
+mmm -j8 $ANDROID_BUILD_TOP/frameworks/base/libs/hwui/unit_tests &&
+adb push $ANDROID_PRODUCT_OUT/data/nativetest/hwui_unit_tests/hwui_unit_tests \
+ /data/nativetest/hwui_unit_tests/hwui_unit_tests &&
+adb shell /data/nativetest/hwui_unit_tests/hwui_unit_tests
diff --git a/libs/hwui/unit_tests/main.cpp b/libs/hwui/unit_tests/main.cpp
new file mode 100644
index 000000000000..c9b96360b36b
--- /dev/null
+++ b/libs/hwui/unit_tests/main.cpp
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
new file mode 100644
index 000000000000..59b12cf66a89
--- /dev/null
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LOG_NDEBUG 1
+
+#include "utils/LinearAllocator.h"
+
+#include <stdlib.h>
+#include <utils/Log.h>
+
+
+// The ideal size of a page allocation (these need to be multiples of 8)
+#define INITIAL_PAGE_SIZE ((size_t)4096) // 4kb
+#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
+
+// The maximum amount of wasted space we can have per page
+// Allocations exceeding this will have their own dedicated page
+// If this is too low, we will malloc too much
+// Too high, and we may waste too much space
+// Must be smaller than INITIAL_PAGE_SIZE
+#define MAX_WASTE_SIZE ((size_t)1024)
+
+#if ALIGN_DOUBLE
+#define ALIGN_SZ (sizeof(double))
+#else
+#define ALIGN_SZ (sizeof(int))
+#endif
+
+#define ALIGN(x) ((x + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1))
+#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)p)))
+
+#if LOG_NDEBUG
+#define ADD_ALLOCATION(size)
+#define RM_ALLOCATION(size)
+#else
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+static size_t s_totalAllocations = 0;
+static nsecs_t s_nextLog = 0;
+static android::Mutex s_mutex;
+
+static void _logUsageLocked() {
+ nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ if (now > s_nextLog) {
+ s_nextLog = now + milliseconds_to_nanoseconds(10);
+ ALOGV("Total memory usage: %zu kb", s_totalAllocations / 1024);
+ }
+}
+
+static void _addAllocation(size_t size) {
+ android::AutoMutex lock(s_mutex);
+ s_totalAllocations += size;
+ _logUsageLocked();
+}
+
+#define ADD_ALLOCATION(size) _addAllocation(size);
+#define RM_ALLOCATION(size) _addAllocation(-size);
+#endif
+
+#define min(x,y) (((x) < (y)) ? (x) : (y))
+
+void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la) {
+ return la.alloc(size);
+}
+
+namespace android {
+namespace uirenderer {
+
+class LinearAllocator::Page {
+public:
+ Page* next() { return mNextPage; }
+ void setNext(Page* next) { mNextPage = next; }
+
+ Page()
+ : mNextPage(0)
+ {}
+
+ void* operator new(size_t /*size*/, void* buf) { return buf; }
+
+ void* start() {
+ return (void*) (((size_t)this) + sizeof(Page));
+ }
+
+ void* end(int pageSize) {
+ return (void*) (((size_t)start()) + pageSize);
+ }
+
+private:
+ Page(const Page& /*other*/) {}
+ Page* mNextPage;
+};
+
+LinearAllocator::LinearAllocator()
+ : mPageSize(INITIAL_PAGE_SIZE)
+ , mMaxAllocSize(MAX_WASTE_SIZE)
+ , mNext(0)
+ , mCurrentPage(0)
+ , mPages(0)
+ , mTotalAllocated(0)
+ , mWastedSpace(0)
+ , mPageCount(0)
+ , mDedicatedPageCount(0) {}
+
+LinearAllocator::~LinearAllocator(void) {
+ while (mDtorList) {
+ auto node = mDtorList;
+ mDtorList = node->next;
+ node->dtor(node->addr);
+ }
+ Page* p = mPages;
+ while (p) {
+ Page* next = p->next();
+ p->~Page();
+ free(p);
+ RM_ALLOCATION(mPageSize);
+ p = next;
+ }
+}
+
+void* LinearAllocator::start(Page* p) {
+ return ALIGN_PTR(((size_t*)p) + sizeof(Page));
+}
+
+void* LinearAllocator::end(Page* p) {
+ return ((char*)p) + mPageSize;
+}
+
+bool LinearAllocator::fitsInCurrentPage(size_t size) {
+ return mNext && ((char*)mNext + size) <= end(mCurrentPage);
+}
+
+void LinearAllocator::ensureNext(size_t size) {
+ if (fitsInCurrentPage(size)) return;
+
+ if (mCurrentPage && mPageSize < MAX_PAGE_SIZE) {
+ mPageSize = min(MAX_PAGE_SIZE, mPageSize * 2);
+ mPageSize = ALIGN(mPageSize);
+ }
+ mWastedSpace += mPageSize;
+ Page* p = newPage(mPageSize);
+ if (mCurrentPage) {
+ mCurrentPage->setNext(p);
+ }
+ mCurrentPage = p;
+ if (!mPages) {
+ mPages = mCurrentPage;
+ }
+ mNext = start(mCurrentPage);
+}
+
+void* LinearAllocator::alloc(size_t size) {
+ size = ALIGN(size);
+ if (size > mMaxAllocSize && !fitsInCurrentPage(size)) {
+ ALOGV("Exceeded max size %zu > %zu", size, mMaxAllocSize);
+ // Allocation is too large, create a dedicated page for the allocation
+ Page* page = newPage(size);
+ mDedicatedPageCount++;
+ page->setNext(mPages);
+ mPages = page;
+ if (!mCurrentPage)
+ mCurrentPage = mPages;
+ return start(page);
+ }
+ ensureNext(size);
+ void* ptr = mNext;
+ mNext = ((char*)mNext) + size;
+ mWastedSpace -= size;
+ return ptr;
+}
+
+void LinearAllocator::addToDestructionList(Destructor dtor, void* addr) {
+ static_assert(std::is_standard_layout<DestructorNode>::value,
+ "DestructorNode must have standard layout");
+ static_assert(std::is_trivially_destructible<DestructorNode>::value,
+ "DestructorNode must be trivially destructable");
+ auto node = new (*this) DestructorNode();
+ node->dtor = dtor;
+ node->addr = addr;
+ node->next = mDtorList;
+ mDtorList = node;
+}
+
+void LinearAllocator::runDestructorFor(void* addr) {
+ auto node = mDtorList;
+ DestructorNode* previous = nullptr;
+ while (node) {
+ if (node->addr == addr) {
+ if (previous) {
+ previous->next = node->next;
+ } else {
+ mDtorList = node->next;
+ }
+ node->dtor(node->addr);
+ rewindIfLastAlloc(node, sizeof(DestructorNode));
+ break;
+ }
+ previous = node;
+ node = node->next;
+ }
+}
+
+void LinearAllocator::rewindIfLastAlloc(void* ptr, size_t allocSize) {
+ // First run the destructor as running the destructor will
+ // also rewind for the DestructorNode allocation which will
+ // have been allocated after this void* if it has a destructor
+ runDestructorFor(ptr);
+ // Don't bother rewinding across pages
+ allocSize = ALIGN(allocSize);
+ if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage)
+ && ptr == ((char*)mNext - allocSize)) {
+ mWastedSpace += allocSize;
+ mNext = ptr;
+ }
+}
+
+LinearAllocator::Page* LinearAllocator::newPage(size_t pageSize) {
+ pageSize = ALIGN(pageSize + sizeof(LinearAllocator::Page));
+ ADD_ALLOCATION(pageSize);
+ mTotalAllocated += pageSize;
+ mPageCount++;
+ void* buf = malloc(pageSize);
+ return new (buf) Page();
+}
+
+static const char* toSize(size_t value, float& result) {
+ if (value < 2000) {
+ result = value;
+ return "B";
+ }
+ if (value < 2000000) {
+ result = value / 1024.0f;
+ return "KB";
+ }
+ result = value / 1048576.0f;
+ return "MB";
+}
+
+void LinearAllocator::dumpMemoryStats(const char* prefix) {
+ float prettySize;
+ const char* prettySuffix;
+ prettySuffix = toSize(mTotalAllocated, prettySize);
+ ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix);
+ prettySuffix = toSize(mWastedSpace, prettySize);
+ ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix,
+ (float) mWastedSpace / (float) mTotalAllocated * 100.0f);
+ ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
new file mode 100644
index 000000000000..d90dd825ea1d
--- /dev/null
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2012, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_LINEARALLOCATOR_H
+#define ANDROID_LINEARALLOCATOR_H
+
+#include <stddef.h>
+#include <type_traits>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * A memory manager that internally allocates multi-kbyte buffers for placing objects in. It avoids
+ * the overhead of malloc when many objects are allocated. It is most useful when creating many
+ * small objects with a similar lifetime, and doesn't add significant overhead for large
+ * allocations.
+ */
+class LinearAllocator {
+public:
+ LinearAllocator();
+ ~LinearAllocator();
+
+ /**
+ * Reserves and returns a region of memory of at least size 'size', aligning as needed.
+ * Typically this is used in an object's overridden new() method or as a replacement for malloc.
+ *
+ * The lifetime of the returned buffers is tied to that of the LinearAllocator. If calling
+ * delete() on an object stored in a buffer is needed, it should be overridden to use
+ * rewindIfLastAlloc()
+ */
+ void* alloc(size_t size);
+
+ /**
+ * Allocates an instance of the template type with the default constructor
+ * and adds it to the automatic destruction list.
+ */
+ template<class T>
+ T* alloc() {
+ T* ret = new (*this) T;
+ autoDestroy(ret);
+ return ret;
+ }
+
+ /**
+ * Adds the pointer to the tracking list to have its destructor called
+ * when the LinearAllocator is destroyed.
+ */
+ template<class T>
+ void autoDestroy(T* addr) {
+ if (!std::is_trivially_destructible<T>::value) {
+ auto dtor = [](void* addr) { ((T*)addr)->~T(); };
+ addToDestructionList(dtor, addr);
+ }
+ }
+
+ /**
+ * Attempt to deallocate the given buffer, with the LinearAllocator attempting to rewind its
+ * state if possible.
+ */
+ void rewindIfLastAlloc(void* ptr, size_t allocSize);
+
+ /**
+ * Same as rewindIfLastAlloc(void*, size_t)
+ */
+ template<class T>
+ void rewindIfLastAlloc(T* ptr) {
+ rewindIfLastAlloc((void*)ptr, sizeof(T));
+ }
+
+ /**
+ * Dump memory usage statistics to the log (allocated and wasted space)
+ */
+ void dumpMemoryStats(const char* prefix = "");
+
+ /**
+ * The number of bytes used for buffers allocated in the LinearAllocator (does not count space
+ * wasted)
+ */
+ size_t usedSize() const { return mTotalAllocated - mWastedSpace; }
+
+private:
+ LinearAllocator(const LinearAllocator& other);
+
+ class Page;
+ typedef void (*Destructor)(void* addr);
+ struct DestructorNode {
+ Destructor dtor;
+ void* addr;
+ DestructorNode* next = nullptr;
+ };
+
+ void addToDestructionList(Destructor, void* addr);
+ void runDestructorFor(void* addr);
+ Page* newPage(size_t pageSize);
+ bool fitsInCurrentPage(size_t size);
+ void ensureNext(size_t size);
+ void* start(Page *p);
+ void* end(Page* p);
+
+ size_t mPageSize;
+ size_t mMaxAllocSize;
+ void* mNext;
+ Page* mCurrentPage;
+ Page* mPages;
+ DestructorNode* mDtorList = nullptr;
+
+ // Memory usage tracking
+ size_t mTotalAllocated;
+ size_t mWastedSpace;
+ size_t mPageCount;
+ size_t mDedicatedPageCount;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+void* operator new(std::size_t size, android::uirenderer::LinearAllocator& la);
+
+#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/preloaded-classes b/preloaded-classes
index 86bd5c9ef9ec..95d0b4276c9b 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -828,6 +828,11 @@ android.hardware.soundtrigger.SoundTriggerModule
android.hardware.usb.UsbDevice
android.hardware.usb.UsbDeviceConnection
android.hardware.usb.UsbRequest
+# Initializing android.icu.impl.ICUBinary loads the ICU data.
+# Opening the files in the Zygote avoids StrictMode violations.
+# It also ensures the ICU data files are mapped on boot and all
+# apps will be consistent (even if files are added to /data).
+android.icu.impl.ICUBinary
android.inputmethodservice.ExtractEditText
android.location.Location
android.location.Location$1
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 9a30f0dd8371..6b56279354ba 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -86,6 +86,8 @@ import android.provider.Settings;
import android.provider.Settings.System;
import android.telecom.TelecomManager;
import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.MathUtils;
import android.util.Slog;
@@ -110,10 +112,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
-import java.util.Set;
/**
* The implementation of the volume manager service.
@@ -407,8 +407,7 @@ public class AudioService extends IAudioService.Stub {
return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
}
- private final HashMap<String, DeviceListSpec> mConnectedDevices =
- new HashMap<String, DeviceListSpec>();
+ private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
// Forced device usage for communications
private int mForcedUseForComm;
@@ -2830,16 +2829,22 @@ public class AudioService extends IAudioService.Stub {
}
}
public void onServiceDisconnected(int profile) {
+ ArraySet<String> toRemove = null;
switch (profile) {
case BluetoothProfile.A2DP:
synchronized (mConnectedDevices) {
synchronized (mA2dpAvrcpLock) {
// Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
- for(Map.Entry<String, DeviceListSpec> entry
- : mConnectedDevices.entrySet()) {
- DeviceListSpec deviceSpec = entry.getValue();
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
- makeA2dpDeviceUnavailableNow(deviceSpec.mDeviceAddress);
+ toRemove = toRemove != null ? toRemove : new ArraySet<String>();
+ toRemove.add(deviceSpec.mDeviceAddress);
+ }
+ }
+ if (toRemove != null) {
+ for (int i = 0; i < toRemove.size(); i++) {
+ makeA2dpDeviceUnavailableNow(toRemove.valueAt(i));
}
}
}
@@ -2849,11 +2854,16 @@ public class AudioService extends IAudioService.Stub {
case BluetoothProfile.A2DP_SINK:
synchronized (mConnectedDevices) {
// Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
- for(Map.Entry<String, DeviceListSpec> entry
- : mConnectedDevices.entrySet()) {
- DeviceListSpec deviceSpec = entry.getValue();
+ for(int i = 0; i < mConnectedDevices.size(); i++) {
+ DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
- makeA2dpSrcUnavailable(deviceSpec.mDeviceAddress);
+ toRemove = toRemove != null ? toRemove : new ArraySet<String>();
+ toRemove.add(deviceSpec.mDeviceAddress);
+ }
+ }
+ if (toRemove != null) {
+ for (int i = 0; i < toRemove.size(); i++) {
+ makeA2dpSrcUnavailable(toRemove.valueAt(i));
}
}
}
@@ -4147,11 +4157,8 @@ public class AudioService extends IAudioService.Stub {
// Restore device connection states
synchronized (mConnectedDevices) {
- Set set = mConnectedDevices.entrySet();
- Iterator i = set.iterator();
- while (i.hasNext()) {
- Map.Entry device = (Map.Entry)i.next();
- DeviceListSpec spec = (DeviceListSpec)device.getValue();
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ DeviceListSpec spec = mConnectedDevices.valueAt(i);
AudioSystem.setDeviceConnectionState(
spec.mDeviceType,
AudioSystem.DEVICE_STATE_AVAILABLE,
@@ -4600,8 +4607,8 @@ public class AudioService extends IAudioService.Stub {
int delay = 0;
if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
int devices = 0;
- for (String key : mConnectedDevices.keySet()) {
- int dev = mConnectedDevices.get(key).mDeviceType;
+ for (int i = 0; i < mConnectedDevices.size(); i++) {
+ int dev = mConnectedDevices.valueAt(i).mDeviceType;
if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
&& ((dev & mBecomingNoisyIntentDevices) != 0)) {
devices |= dev;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index eb9234a1029e..6fc3103257dd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3983,15 +3983,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
+ " for device owner");
}
synchronized (this) {
- if (!allowedToSetDeviceOwnerOnDevice()) {
- throw new IllegalStateException(
- "Trying to set device owner but device is already provisioned.");
- }
-
- if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
- throw new IllegalStateException(
- "Trying to set device owner but device owner is already set.");
- }
+ enforceCanSetDeviceOwner();
// Shutting down backup manager service permanently.
long ident = Binder.clearCallingIdentity();
@@ -4009,7 +4001,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Device owner is not set and does not exist, set it.
mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
} else {
- // Device owner is not set but a profile owner exists, update Device owner state.
+ // Device owner state already exists, update it.
mDeviceOwner.setDeviceOwner(packageName, ownerName);
}
mDeviceOwner.writeOwnerFile();
@@ -4225,43 +4217,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (!mHasFeature) {
return false;
}
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
-
- UserInfo info = mUserManager.getUserInfo(userHandle);
- if (info == null) {
- // User doesn't exist.
- throw new IllegalArgumentException(
- "Attempted to set profile owner for invalid userId: " + userHandle);
- }
- if (info.isGuest()) {
- throw new IllegalStateException("Cannot set a profile owner on a guest");
- }
-
if (who == null
|| !DeviceOwner.isInstalledForUser(who.getPackageName(), userHandle)) {
throw new IllegalArgumentException("Component " + who
+ " not installed for userId:" + userHandle);
}
synchronized (this) {
- // Only SYSTEM_UID can override the userSetupComplete
- if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID
- && hasUserSetupCompleted(userHandle)) {
- throw new IllegalStateException(
- "Trying to set profile owner but user is already set-up.");
- }
-
+ enforceCanSetProfileOwner(userHandle);
if (mDeviceOwner == null) {
// Device owner state does not exist, create it.
mDeviceOwner = DeviceOwner.createWithProfileOwner(who, ownerName,
userHandle);
- mDeviceOwner.writeOwnerFile();
- return true;
} else {
- // Device owner already exists, update it.
+ // Device owner state already exists, update it.
mDeviceOwner.setProfileOwner(who, ownerName, userHandle);
- mDeviceOwner.writeOwnerFile();
- return true;
}
+ mDeviceOwner.writeOwnerFile();
+ return true;
}
}
@@ -4451,18 +4423,77 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
- * Device owner can only be set on an unprovisioned device. However, if initiated via "adb",
- * we also allow it if no accounts or additional users are present on the device.
+ * The profile owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
+ * permission.
+ * The profile owner can only be set before the user setup phase has completed,
+ * except for:
+ * - SYSTEM_UID
+ * - adb if there are not accounts.
*/
- private boolean allowedToSetDeviceOwnerOnDevice() {
- if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
- return true;
+ private void enforceCanSetProfileOwner(int userHandle) {
+ UserInfo info = mUserManager.getUserInfo(userHandle);
+ if (info == null) {
+ // User doesn't exist.
+ throw new IllegalArgumentException(
+ "Attempted to set profile owner for invalid userId: " + userHandle);
+ }
+ if (info.isGuest()) {
+ throw new IllegalStateException("Cannot set a profile owner on a guest");
+ }
+ if (getProfileOwner(userHandle) != null) {
+ throw new IllegalStateException("Trying to set the profile owner, but profile owner "
+ + "is already set.");
+ }
+ int callingUid = Binder.getCallingUid();
+ if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+ if (hasUserSetupCompleted(userHandle) &&
+ AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
+ throw new IllegalStateException("Not allowed to set the profile owner because "
+ + "there are already some accounts on the profile");
+ }
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+ if (hasUserSetupCompleted(userHandle)
+ && UserHandle.getAppId(callingUid) != Process.SYSTEM_UID) {
+ throw new IllegalStateException("Cannot set the profile owner on a user which is "
+ + "already set-up");
}
+ }
- int callingId = Binder.getCallingUid();
- return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID)
- && mUserManager.getUserCount() == 1
- && AccountManager.get(mContext).getAccounts().length == 0;
+ /**
+ * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
+ * permission.
+ * The device owner can only be set before the setup phase of the primary user has completed,
+ * except for adb if no accounts or additional users are present on the device.
+ */
+ private void enforceCanSetDeviceOwner() {
+ if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
+ throw new IllegalStateException("Trying to set the device owner, but device owner "
+ + "is already set.");
+ }
+ int callingUid = Binder.getCallingUid();
+ if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+ if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+ return;
+ }
+ if (mUserManager.getUserCount() > 1) {
+ throw new IllegalStateException("Not allowed to set the device owner because there "
+ + "are already several users on the device");
+ }
+ if (AccountManager.get(mContext).getAccounts().length > 0) {
+ throw new IllegalStateException("Not allowed to set the device owner because there "
+ + "are already some accounts on the device");
+ }
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
+ if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
+ throw new IllegalStateException("Cannot set the device owner if the device is "
+ + "already set-up");
+ }
}
private void enforceCrossUserPermission(int userHandle) {