summaryrefslogtreecommitdiffstats
path: root/services/core
diff options
context:
space:
mode:
Diffstat (limited to 'services/core')
-rw-r--r--services/core/java/com/android/server/BootReceiver.java260
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java98
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java11
-rw-r--r--services/core/java/com/android/server/IntentResolver.java118
-rw-r--r--services/core/java/com/android/server/NetworkScoreService.java12
-rw-r--r--services/core/java/com/android/server/SystemService.java199
-rw-r--r--services/core/java/com/android/server/SystemServiceManager.java227
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityManagerService.java2
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java14
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerState.java26
-rw-r--r--services/core/java/com/android/server/display/LocalDisplayAdapter.java12
-rw-r--r--services/core/java/com/android/server/dreams/DreamController.java169
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java9
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecKeycode.java2
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java71
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java81
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java15
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java25
-rw-r--r--services/core/java/com/android/server/hdmi/HotplugDetectionAction.java2
-rw-r--r--services/core/java/com/android/server/lights/LightsService.java8
-rw-r--r--services/core/java/com/android/server/notification/ConditionProviders.java90
-rw-r--r--services/core/java/com/android/server/notification/CountdownConditionProvider.java5
-rw-r--r--services/core/java/com/android/server/notification/DowntimeConditionProvider.java289
-rw-r--r--services/core/java/com/android/server/notification/ManagedServices.java3
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java4
-rw-r--r--services/core/java/com/android/server/notification/ZenLog.java35
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java125
-rw-r--r--services/core/java/com/android/server/pm/Installer.java290
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java145
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java37
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java101
-rw-r--r--services/core/java/com/android/server/pm/PreferredComponent.java36
-rw-r--r--services/core/java/com/android/server/power/Notifier.java1
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java344
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java32
-rw-r--r--services/core/java/com/android/server/tv/PersistentDataStore.java22
-rw-r--r--services/core/java/com/android/server/tv/TvInputHardwareManager.java10
-rw-r--r--services/core/java/com/android/server/tv/TvInputManagerService.java6
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java24
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java6
-rw-r--r--services/core/jni/onload.cpp4
41 files changed, 1850 insertions, 1120 deletions
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
deleted file mode 100644
index 7249985..0000000
--- a/services/core/java/com/android/server/BootReceiver.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.IPackageManager;
-import android.os.Build;
-import android.os.DropBoxManager;
-import android.os.FileObserver;
-import android.os.FileUtils;
-import android.os.RecoverySystem;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemProperties;
-import android.provider.Downloads;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Performs a number of miscellaneous, non-system-critical actions
- * after the system has finished booting.
- */
-public class BootReceiver extends BroadcastReceiver {
- private static final String TAG = "BootReceiver";
-
- // Maximum size of a logged event (files get truncated if they're longer).
- // Give userdebug builds a larger max to capture extra debug, esp. for last_kmsg.
- private static final int LOG_SIZE =
- SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536;
-
- private static final File TOMBSTONE_DIR = new File("/data/tombstones");
-
- // The pre-froyo package and class of the system updater, which
- // ran in the system process. We need to remove its packages here
- // in order to clean up after a pre-froyo-to-froyo update.
- private static final String OLD_UPDATER_PACKAGE =
- "com.google.android.systemupdater";
- private static final String OLD_UPDATER_CLASS =
- "com.google.android.systemupdater.SystemUpdateReceiver";
-
- // Keep a reference to the observer so the finalizer doesn't disable it.
- private static FileObserver sTombstoneObserver = null;
-
- @Override
- public void onReceive(final Context context, Intent intent) {
- // Log boot events in the background to avoid blocking the main thread with I/O
- new Thread() {
- @Override
- public void run() {
- try {
- logBootEvents(context);
- } catch (Exception e) {
- Slog.e(TAG, "Can't log boot events", e);
- }
- try {
- boolean onlyCore = false;
- try {
- onlyCore = IPackageManager.Stub.asInterface(ServiceManager.getService(
- "package")).isOnlyCoreApps();
- } catch (RemoteException e) {
- }
- if (!onlyCore) {
- removeOldUpdatePackages(context);
- }
- } catch (Exception e) {
- Slog.e(TAG, "Can't remove old update packages", e);
- }
-
- }
- }.start();
- }
-
- private void removeOldUpdatePackages(Context context) {
- Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS);
- }
-
- private void logBootEvents(Context ctx) throws IOException {
- final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
- final SharedPreferences prefs = ctx.getSharedPreferences("log_files", Context.MODE_PRIVATE);
- final String headers = new StringBuilder(512)
- .append("Build: ").append(Build.FINGERPRINT).append("\n")
- .append("Hardware: ").append(Build.BOARD).append("\n")
- .append("Revision: ")
- .append(SystemProperties.get("ro.revision", "")).append("\n")
- .append("Bootloader: ").append(Build.BOOTLOADER).append("\n")
- .append("Radio: ").append(Build.RADIO).append("\n")
- .append("Kernel: ")
- .append(FileUtils.readTextFile(new File("/proc/version"), 1024, "...\n"))
- .append("\n").toString();
- final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
-
- String recovery = RecoverySystem.handleAftermath();
- if (recovery != null && db != null) {
- db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
- }
-
- String lastKmsgFooter = "";
- if (bootReason != null) {
- lastKmsgFooter = new StringBuilder(512)
- .append("\n")
- .append("Boot info:\n")
- .append("Last boot reason: ").append(bootReason).append("\n")
- .toString();
- }
-
- if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
- String now = Long.toString(System.currentTimeMillis());
- SystemProperties.set("ro.runtime.firstboot", now);
- if (db != null) db.addText("SYSTEM_BOOT", headers);
-
- // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
- addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
- "/proc/last_kmsg", -LOG_SIZE, "SYSTEM_LAST_KMSG");
- addFileWithFootersToDropBox(db, prefs, headers, lastKmsgFooter,
- "/sys/fs/pstore/console-ramoops", -LOG_SIZE,
- "SYSTEM_LAST_KMSG");
- addFileToDropBox(db, prefs, headers, "/cache/recovery/log",
- -LOG_SIZE, "SYSTEM_RECOVERY_LOG");
- addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_console",
- -LOG_SIZE, "APANIC_CONSOLE");
- addFileToDropBox(db, prefs, headers, "/data/dontpanic/apanic_threads",
- -LOG_SIZE, "APANIC_THREADS");
- addAuditErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_AUDIT");
- addFsckErrorsToDropBox(db, prefs, headers, -LOG_SIZE, "SYSTEM_FSCK");
- } else {
- if (db != null) db.addText("SYSTEM_RESTART", headers);
- }
-
- // Scan existing tombstones (in case any new ones appeared)
- File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
- for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
- addFileToDropBox(db, prefs, headers, tombstoneFiles[i].getPath(),
- LOG_SIZE, "SYSTEM_TOMBSTONE");
- }
-
- // Start watching for new tombstone files; will record them as they occur.
- // This gets registered with the singleton file observer thread.
- sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CLOSE_WRITE) {
- @Override
- public void onEvent(int event, String path) {
- try {
- String filename = new File(TOMBSTONE_DIR, path).getPath();
- addFileToDropBox(db, prefs, headers, filename, LOG_SIZE, "SYSTEM_TOMBSTONE");
- } catch (IOException e) {
- Slog.e(TAG, "Can't log tombstone", e);
- }
- }
- };
-
- sTombstoneObserver.startWatching();
- }
-
- private static void addFileToDropBox(
- DropBoxManager db, SharedPreferences prefs,
- String headers, String filename, int maxSize, String tag) throws IOException {
- addFileWithFootersToDropBox(db, prefs, headers, "", filename, maxSize,
- tag);
- }
-
- private static void addFileWithFootersToDropBox(
- DropBoxManager db, SharedPreferences prefs,
- String headers, String footers, String filename, int maxSize,
- String tag) throws IOException {
- if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled
-
- File file = new File(filename);
- long fileTime = file.lastModified();
- if (fileTime <= 0) return; // File does not exist
-
- if (prefs != null) {
- long lastTime = prefs.getLong(filename, 0);
- if (lastTime == fileTime) return; // Already logged this particular file
- // TODO: move all these SharedPreferences Editor commits
- // outside this function to the end of logBootEvents
- prefs.edit().putLong(filename, fileTime).apply();
- }
-
- Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
- db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") + footers);
- }
-
- private static void addAuditErrorsToDropBox(DropBoxManager db, SharedPreferences prefs,
- String headers, int maxSize, String tag) throws IOException {
- if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled
- Slog.i(TAG, "Copying audit failures to DropBox");
-
- File file = new File("/proc/last_kmsg");
- long fileTime = file.lastModified();
- if (fileTime <= 0) {
- file = new File("/sys/fs/pstore/console-ramoops");
- fileTime = file.lastModified();
- }
-
- if (fileTime <= 0) return; // File does not exist
-
- if (prefs != null) {
- long lastTime = prefs.getLong(tag, 0);
- if (lastTime == fileTime) return; // Already logged this particular file
- // TODO: move all these SharedPreferences Editor commits
- // outside this function to the end of logBootEvents
- prefs.edit().putLong(tag, fileTime).apply();
- }
-
- String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
- StringBuilder sb = new StringBuilder();
- for (String line : log.split("\n")) {
- if (line.contains("audit")) {
- sb.append(line + "\n");
- }
- }
- Slog.i(TAG, "Copied " + sb.toString().length() + " worth of audits to DropBox");
- db.addText(tag, headers + sb.toString());
- }
-
- private static void addFsckErrorsToDropBox(DropBoxManager db, SharedPreferences prefs,
- String headers, int maxSize, String tag) throws IOException {
- boolean upload_needed = false;
- if (db == null || !db.isTagEnabled(tag)) return; // Logging disabled
- Slog.i(TAG, "Checking for fsck errors");
-
- File file = new File("/dev/fscklogs/log");
- long fileTime = file.lastModified();
- if (fileTime <= 0) return; // File does not exist
-
- String log = FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n");
- StringBuilder sb = new StringBuilder();
- for (String line : log.split("\n")) {
- if (line.contains("FILE SYSTEM WAS MODIFIED")) {
- upload_needed = true;
- break;
- }
- }
-
- if (upload_needed) {
- addFileToDropBox(db, prefs, headers, "/dev/fscklogs/log", maxSize, tag);
- }
-
- // Remove the file so we don't re-upload if the runtime restarts.
- file.delete();
- }
-}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index dd5a7ea..5bef4bf 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -264,6 +264,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private INetworkManagementService mNetd;
private INetworkPolicyManager mPolicyManager;
+ private String mCurrentTcpBufferSizes;
+
private static final int ENABLED = 1;
private static final int DISABLED = 0;
@@ -1534,11 +1536,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return;
}
- if (mtu < 68 || mtu > 10000) {
+ if (LinkProperties.isValidMtu(mtu, newLp.hasGlobalIPv6Address()) == false) {
loge("Unexpected mtu value: " + mtu + ", " + iface);
return;
}
+ // Cannot set MTU without interface name
+ if (TextUtils.isEmpty(iface)) {
+ loge("Setting MTU size with null iface.");
+ return;
+ }
+
try {
if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
mNetd.setMtu(iface, mtu);
@@ -1547,30 +1555,40 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
- /**
- * Reads the network specific TCP buffer sizes from SystemProperties
- * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
- * wide use
- */
- private void updateNetworkSettings(NetworkStateTracker nt) {
- String key = nt.getTcpBufferSizesPropName();
- String bufferSizes = key == null ? null : SystemProperties.get(key);
+ private static final String DEFAULT_TCP_BUFFER_SIZES = "4096,87380,110208,4096,16384,110208";
+
+ private void updateTcpBufferSizes(NetworkAgentInfo nai) {
+ if (isDefaultNetwork(nai) == false) {
+ return;
+ }
- if (TextUtils.isEmpty(bufferSizes)) {
- if (VDBG) log(key + " not found in system properties. Using defaults");
+ String tcpBufferSizes = nai.linkProperties.getTcpBufferSizes();
+ String[] values = null;
+ if (tcpBufferSizes != null) {
+ values = tcpBufferSizes.split(",");
+ }
- // Setting to default values so we won't be stuck to previous values
- key = "net.tcp.buffersize.default";
- bufferSizes = SystemProperties.get(key);
+ if (values == null || values.length != 6) {
+ if (VDBG) log("Invalid tcpBufferSizes string: " + tcpBufferSizes +", using defaults");
+ tcpBufferSizes = DEFAULT_TCP_BUFFER_SIZES;
+ values = tcpBufferSizes.split(",");
}
- // Set values in kernel
- if (bufferSizes.length() != 0) {
- if (VDBG) {
- log("Setting TCP values: [" + bufferSizes
- + "] which comes from [" + key + "]");
- }
- setBufferSize(bufferSizes);
+ if (tcpBufferSizes.equals(mCurrentTcpBufferSizes)) return;
+
+ try {
+ if (VDBG) Slog.d(TAG, "Setting tx/rx TCP buffers to " + tcpBufferSizes);
+
+ final String prefix = "/sys/kernel/ipv4/tcp_";
+ FileUtils.stringToFile(prefix + "rmem_min", values[0]);
+ FileUtils.stringToFile(prefix + "rmem_def", values[1]);
+ FileUtils.stringToFile(prefix + "rmem_max", values[2]);
+ FileUtils.stringToFile(prefix + "wmem_min", values[3]);
+ FileUtils.stringToFile(prefix + "wmem_def", values[4]);
+ FileUtils.stringToFile(prefix + "wmem_max", values[5]);
+ mCurrentTcpBufferSizes = tcpBufferSizes;
+ } catch (IOException e) {
+ loge("Can't set TCP buffer sizes:" + e);
}
final String defaultRwndKey = "net.tcp.default_init_rwnd";
@@ -1583,33 +1601,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
- /**
- * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max]
- * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem
- *
- * @param bufferSizes in the format of "readMin, readInitial, readMax,
- * writeMin, writeInitial, writeMax"
- */
- private void setBufferSize(String bufferSizes) {
- try {
- String[] values = bufferSizes.split(",");
-
- if (values.length == 6) {
- final String prefix = "/sys/kernel/ipv4/tcp_";
- FileUtils.stringToFile(prefix + "rmem_min", values[0]);
- FileUtils.stringToFile(prefix + "rmem_def", values[1]);
- FileUtils.stringToFile(prefix + "rmem_max", values[2]);
- FileUtils.stringToFile(prefix + "wmem_min", values[3]);
- FileUtils.stringToFile(prefix + "wmem_def", values[4]);
- FileUtils.stringToFile(prefix + "wmem_max", values[5]);
- } else {
- loge("Invalid buffersize string: " + bufferSizes);
- }
- } catch (IOException e) {
- loge("Can't set tcp buffer sizes:" + e);
- }
- }
-
private void flushVmDnsCache() {
/*
* Tell the VMs to toss their DNS caches
@@ -1972,12 +1963,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
break;
}
- case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: {
- info = (NetworkInfo) msg.obj;
- int type = info.getType();
- if (mNetConfigs[type].isDefault()) updateNetworkSettings(mNetTrackers[type]);
- break;
- }
}
}
}
@@ -4146,6 +4131,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
updateInterfaces(newLp, oldLp, netId);
updateMtu(newLp, oldLp);
+ updateTcpBufferSizes(networkAgent);
// TODO - figure out what to do for clat
// for (LinkProperties lp : newLp.getStackedLinks()) {
// updateMtu(lp, null);
@@ -4371,6 +4357,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
loge("Exception setting default network :" + e);
}
handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
+ updateTcpBufferSizes(newNetwork);
}
private void handleConnectionValidated(NetworkAgentInfo newNetwork) {
@@ -4428,6 +4415,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
isNewDefault = true;
updateActiveDefaultNetwork(newNetwork);
if (newNetwork.linkProperties != null) {
+ updateTcpBufferSizes(newNetwork);
setDefaultDnsSystemProperties(
newNetwork.linkProperties.getDnsServers());
} else {
@@ -4486,8 +4474,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
1000);
}
}
- // TODO - read the tcp buffer size config string from somewhere
- // updateNetworkSettings();
}
// Notify battery stats service about this network, both the normal
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 4687e3f..e0f9b9c 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -603,10 +603,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
MSG_HARD_KEYBOARD_SWITCH_CHANGED, available ? 1 : 0, enabled ? 1 : 0));
}
- public void handleHardKeyboardStatusChange(boolean available, boolean enabled) {
+ public void handleHardKeyboardStatusChange(boolean available,
+ boolean showImeWithHardKeyboard) {
if (DEBUG) {
- Slog.w(TAG, "HardKeyboardStatusChanged: available = " + available + ", enabled = "
- + enabled);
+ Slog.w(TAG, "HardKeyboardStatusChanged: available = " + available
+ + ", showImeWithHardKeyboard= " + showImeWithHardKeyboard);
}
synchronized(mMethodMap) {
if (mSwitchingDialog != null && mSwitchingDialogTitleView != null
@@ -2810,11 +2811,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
? View.VISIBLE : View.GONE);
final Switch hardKeySwitch = (Switch)mSwitchingDialogTitleView.findViewById(
com.android.internal.R.id.hard_keyboard_switch);
- hardKeySwitch.setChecked(mWindowManagerService.isHardKeyboardEnabled());
+ hardKeySwitch.setChecked(mWindowManagerService.isShowImeWithHardKeyboardEnabled());
hardKeySwitch.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- mWindowManagerService.setHardKeyboardEnabled(isChecked);
+ mWindowManagerService.setShowImeWithHardKeyboard(isChecked);
// Ensure that the input method dialog is dismissed when changing
// the hardware keyboard state.
hideInputMethodMenu();
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 64b0487..07cc864 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -69,6 +69,124 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
}
}
+ private boolean filterEquals(IntentFilter f1, IntentFilter f2) {
+ int s1 = f1.countActions();
+ int s2 = f2.countActions();
+ if (s1 != s2) {
+ return false;
+ }
+ for (int i=0; i<s1; i++) {
+ if (!f2.hasAction(f1.getAction(i))) {
+ return false;
+ }
+ }
+ s1 = f1.countCategories();
+ s2 = f2.countCategories();
+ if (s1 != s2) {
+ return false;
+ }
+ for (int i=0; i<s1; i++) {
+ if (!f2.hasCategory(f1.getCategory(i))) {
+ return false;
+ }
+ }
+ s1 = f1.countDataTypes();
+ s2 = f2.countDataTypes();
+ if (s1 != s2) {
+ return false;
+ }
+ for (int i=0; i<s1; i++) {
+ if (!f2.hasExactDataType(f1.getDataType(i))) {
+ return false;
+ }
+ }
+ s1 = f1.countDataSchemes();
+ s2 = f2.countDataSchemes();
+ if (s1 != s2) {
+ return false;
+ }
+ for (int i=0; i<s1; i++) {
+ if (!f2.hasDataScheme(f1.getDataScheme(i))) {
+ return false;
+ }
+ }
+ s1 = f1.countDataAuthorities();
+ s2 = f2.countDataAuthorities();
+ if (s1 != s2) {
+ return false;
+ }
+ for (int i=0; i<s1; i++) {
+ if (!f2.hasDataAuthority(f1.getDataAuthority(i))) {
+ return false;
+ }
+ }
+ s1 = f1.countDataPaths();
+ s2 = f2.countDataPaths();
+ if (s1 != s2) {
+ return false;
+ }
+ for (int i=0; i<s1; i++) {
+ if (!f2.hasDataPath(f1.getDataPath(i))) {
+ return false;
+ }
+ }
+ s1 = f1.countDataSchemeSpecificParts();
+ s2 = f2.countDataSchemeSpecificParts();
+ if (s1 != s2) {
+ return false;
+ }
+ for (int i=0; i<s1; i++) {
+ if (!f2.hasDataSchemeSpecificPart(f1.getDataSchemeSpecificPart(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private ArrayList<F> collectFilters(F[] array, IntentFilter matching) {
+ ArrayList<F> res = null;
+ if (array != null) {
+ for (int i=0; i<array.length; i++) {
+ F cur = array[i];
+ if (cur == null) {
+ break;
+ }
+ if (filterEquals(cur, matching)) {
+ if (res == null) {
+ res = new ArrayList<>();
+ }
+ res.add(cur);
+ }
+ }
+ }
+ return res;
+ }
+
+ public ArrayList<F> findFilters(IntentFilter matching) {
+ if (matching.countDataSchemes() == 1) {
+ // Fast case.
+ return collectFilters(mSchemeToFilter.get(matching.getDataScheme(0)), matching);
+ } else if (matching.countDataTypes() != 0 && matching.countActions() == 1) {
+ // Another fast case.
+ return collectFilters(mTypedActionToFilter.get(matching.getAction(0)), matching);
+ } else if (matching.countDataTypes() == 0 && matching.countDataSchemes() == 0
+ && matching.countActions() == 1) {
+ // Last fast case.
+ return collectFilters(mActionToFilter.get(matching.getAction(0)), matching);
+ } else {
+ ArrayList<F> res = null;
+ for (F cur : mFilters) {
+ if (filterEquals(cur, matching)) {
+ if (res == null) {
+ res = new ArrayList<>();
+ }
+ res.add(cur);
+ }
+ }
+ return res;
+ }
+ }
+
public void removeFilter(F f) {
removeFilterInternal(f);
mFilters.remove(f);
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index ab4d4dc..395e365 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -17,9 +17,9 @@
package com.android.server;
import android.Manifest.permission;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.INetworkScoreCache;
import android.net.INetworkScoreService;
@@ -30,6 +30,7 @@ import android.net.ScoredNetwork;
import android.os.Binder;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -51,9 +52,6 @@ import java.util.Set;
public class NetworkScoreService extends INetworkScoreService.Stub {
private static final String TAG = "NetworkScoreService";
- /** SharedPreference bit set to true after the service is first initialized. */
- private static final String PREF_SCORING_PROVISIONED = "is_provisioned";
-
private final Context mContext;
private final Map<Integer, INetworkScoreCache> mScoreCaches;
@@ -65,8 +63,8 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
/** Called when the system is ready to run third-party code but before it actually does so. */
void systemReady() {
- SharedPreferences prefs = mContext.getSharedPreferences(TAG, Context.MODE_PRIVATE);
- if (!prefs.getBoolean(PREF_SCORING_PROVISIONED, false)) {
+ ContentResolver cr = mContext.getContentResolver();
+ if (Settings.Global.getInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 0) == 0) {
// On first run, we try to initialize the scorer to the one configured at build time.
// This will be a no-op if the scorer isn't actually valid.
String defaultPackage = mContext.getResources().getString(
@@ -74,7 +72,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
if (!TextUtils.isEmpty(defaultPackage)) {
NetworkScorerAppManager.setActiveScorer(mContext, defaultPackage);
}
- prefs.edit().putBoolean(PREF_SCORING_PROVISIONED, true).apply();
+ Settings.Global.putInt(cr, Settings.Global.NETWORK_SCORING_PROVISIONED, 1);
}
}
diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java
new file mode 100644
index 0000000..6e67970
--- /dev/null
+++ b/services/core/java/com/android/server/SystemService.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.os.IBinder;
+import android.os.ServiceManager;
+
+/**
+ * The base class for services running in the system process. Override and implement
+ * the lifecycle event callback methods as needed.
+ * <p>
+ * The lifecycle of a SystemService:
+ * </p><ul>
+ * <li>The constructor is called and provided with the system {@link Context}
+ * to initialize the system service.
+ * <li>{@link #onStart()} is called to get the service running. The service should
+ * publish its binder interface at this point using
+ * {@link #publishBinderService(String, IBinder)}. It may also publish additional
+ * local interfaces that other services within the system server may use to access
+ * privileged internal functions.
+ * <li>Then {@link #onBootPhase(int)} is called as many times as there are boot phases
+ * until {@link #PHASE_BOOT_COMPLETE} is sent, which is the last boot phase. Each phase
+ * is an opportunity to do special work, like acquiring optional service dependencies,
+ * waiting to see if SafeMode is enabled, or registering with a service that gets
+ * started after this one.
+ * </ul><p>
+ * NOTE: All lifecycle methods are called from the system server's main looper thread.
+ * </p>
+ *
+ * {@hide}
+ */
+public abstract class SystemService {
+ /*
+ * Boot Phases
+ */
+ public static final int PHASE_WAIT_FOR_DEFAULT_DISPLAY = 100; // maybe should be a dependency?
+
+ /**
+ * After receiving this boot phase, services can obtain lock settings data.
+ */
+ public static final int PHASE_LOCK_SETTINGS_READY = 480;
+
+ /**
+ * After receiving this boot phase, services can safely call into core system services
+ * such as the PowerManager or PackageManager.
+ */
+ public static final int PHASE_SYSTEM_SERVICES_READY = 500;
+
+ /**
+ * After receiving this boot phase, services can broadcast Intents.
+ */
+ public static final int PHASE_ACTIVITY_MANAGER_READY = 550;
+
+ /**
+ * After receiving this boot phase, services can start/bind to third party apps.
+ * Apps will be able to make Binder calls into services at this point.
+ */
+ public static final int PHASE_THIRD_PARTY_APPS_CAN_START = 600;
+
+ /**
+ * After receiving this boot phase, services can allow user interaction with the device.
+ * This phase occurs when boot has completed and the home application has started.
+ * System services may prefer to listen to this phase rather than registering a
+ * broadcast receiver for ACTION_BOOT_COMPLETED to reduce overall latency.
+ */
+ public static final int PHASE_BOOT_COMPLETED = 1000;
+
+ private final Context mContext;
+
+ /**
+ * Initializes the system service.
+ * <p>
+ * Subclasses must define a single argument constructor that accepts the context
+ * and passes it to super.
+ * </p>
+ *
+ * @param context The system server context.
+ */
+ public SystemService(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Gets the system context.
+ */
+ public final Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Returns true if the system is running in safe mode.
+ * TODO: we should define in which phase this becomes valid
+ */
+ public final boolean isSafeMode() {
+ return getManager().isSafeMode();
+ }
+
+ /**
+ * Called when the dependencies listed in the @Service class-annotation are available
+ * and after the chosen start phase.
+ * When this method returns, the service should be published.
+ */
+ public abstract void onStart();
+
+ /**
+ * Called on each phase of the boot process. Phases before the service's start phase
+ * (as defined in the @Service annotation) are never received.
+ *
+ * @param phase The current boot phase.
+ */
+ public void onBootPhase(int phase) {}
+
+ /**
+ * Called when a new user is starting, for system services to initialize any per-user
+ * state they maintain for running users.
+ * @param userHandle The identifier of the user.
+ */
+ public void onStartUser(int userHandle) {}
+
+ /**
+ * Called when switching to a different foreground user, for system services that have
+ * special behavior for whichever user is currently in the foreground. This is called
+ * before any application processes are aware of the new user.
+ * @param userHandle The identifier of the user.
+ */
+ public void onSwitchUser(int userHandle) {}
+
+ /**
+ * Called when an existing user is stopping, for system services to finalize any per-user
+ * state they maintain for running users. This is called prior to sending the SHUTDOWN
+ * broadcast to the user; it is a good place to stop making use of any resources of that
+ * user (such as binding to a service running in the user).
+ * @param userHandle The identifier of the user.
+ */
+ public void onStopUser(int userHandle) {}
+
+ /**
+ * Called when an existing user is stopping, for system services to finalize any per-user
+ * state they maintain for running users. This is called after all application process
+ * teardown of the user is complete.
+ * @param userHandle The identifier of the user.
+ */
+ public void onCleanupUser(int userHandle) {}
+
+ /**
+ * Publish the service so it is accessible to other services and apps.
+ */
+ protected final void publishBinderService(String name, IBinder service) {
+ publishBinderService(name, service, false);
+ }
+
+ /**
+ * Publish the service so it is accessible to other services and apps.
+ */
+ protected final void publishBinderService(String name, IBinder service,
+ boolean allowIsolated) {
+ ServiceManager.addService(name, service, allowIsolated);
+ }
+
+ /**
+ * Get a binder service by its name.
+ */
+ protected final IBinder getBinderService(String name) {
+ return ServiceManager.getService(name);
+ }
+
+ /**
+ * Publish the service so it is only accessible to the system process.
+ */
+ protected final <T> void publishLocalService(Class<T> type, T service) {
+ LocalServices.addService(type, service);
+ }
+
+ /**
+ * Get a local service by interface.
+ */
+ protected final <T> T getLocalService(Class<T> type) {
+ return LocalServices.getService(type);
+ }
+
+ private SystemServiceManager getManager() {
+ return LocalServices.getService(SystemServiceManager.class);
+ }
+}
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
new file mode 100644
index 0000000..fda6479
--- /dev/null
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.content.Context;
+import android.util.Slog;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+
+/**
+ * Manages creating, starting, and other lifecycle events of
+ * {@link com.android.server.SystemService system services}.
+ *
+ * {@hide}
+ */
+public class SystemServiceManager {
+ private static final String TAG = "SystemServiceManager";
+
+ private final Context mContext;
+ private boolean mSafeMode;
+
+ // Services that should receive lifecycle events.
+ private final ArrayList<SystemService> mServices = new ArrayList<SystemService>();
+
+ private int mCurrentPhase = -1;
+
+ public SystemServiceManager(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Starts a service by class name.
+ *
+ * @return The service instance.
+ */
+ @SuppressWarnings("unchecked")
+ public SystemService startService(String className) {
+ final Class<SystemService> serviceClass;
+ try {
+ serviceClass = (Class<SystemService>)Class.forName(className);
+ } catch (ClassNotFoundException ex) {
+ Slog.i(TAG, "Starting " + className);
+ throw new RuntimeException("Failed to create service " + className
+ + ": service class not found, usually indicates that the caller should "
+ + "have called PackageManager.hasSystemFeature() to check whether the "
+ + "feature is available on this device before trying to start the "
+ + "services that implement it", ex);
+ }
+ return startService(serviceClass);
+ }
+
+ /**
+ * Creates and starts a system service. The class must be a subclass of
+ * {@link com.android.server.SystemService}.
+ *
+ * @param serviceClass A Java class that implements the SystemService interface.
+ * @return The service instance, never null.
+ * @throws RuntimeException if the service fails to start.
+ */
+ @SuppressWarnings("unchecked")
+ public <T extends SystemService> T startService(Class<T> serviceClass) {
+ final String name = serviceClass.getName();
+ Slog.i(TAG, "Starting " + name);
+
+ // Create the service.
+ if (!SystemService.class.isAssignableFrom(serviceClass)) {
+ throw new RuntimeException("Failed to create " + name
+ + ": service must extend " + SystemService.class.getName());
+ }
+ final T service;
+ try {
+ Constructor<T> constructor = serviceClass.getConstructor(Context.class);
+ service = constructor.newInstance(mContext);
+ } catch (InstantiationException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service could not be instantiated", ex);
+ } catch (IllegalAccessException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service must have a public constructor with a Context argument", ex);
+ } catch (NoSuchMethodException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service must have a public constructor with a Context argument", ex);
+ } catch (InvocationTargetException ex) {
+ throw new RuntimeException("Failed to create service " + name
+ + ": service constructor threw an exception", ex);
+ }
+
+ // Register it.
+ mServices.add(service);
+
+ // Start it.
+ try {
+ service.onStart();
+ } catch (RuntimeException ex) {
+ throw new RuntimeException("Failed to start service " + name
+ + ": onStart threw an exception", ex);
+ }
+ return service;
+ }
+
+ /**
+ * Starts the specified boot phase for all system services that have been started up to
+ * this point.
+ *
+ * @param phase The boot phase to start.
+ */
+ public void startBootPhase(final int phase) {
+ if (phase <= mCurrentPhase) {
+ throw new IllegalArgumentException("Next phase must be larger than previous");
+ }
+ mCurrentPhase = phase;
+
+ Slog.i(TAG, "Starting phase " + mCurrentPhase);
+
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onBootPhase(mCurrentPhase);
+ } catch (Exception ex) {
+ throw new RuntimeException("Failed to boot service "
+ + service.getClass().getName()
+ + ": onBootPhase threw an exception during phase "
+ + mCurrentPhase, ex);
+ }
+ }
+ }
+
+ public void startUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onStartUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting start of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void switchUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onSwitchUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting switch of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void stopUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onStopUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting stop of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ public void cleanupUser(final int userHandle) {
+ final int serviceLen = mServices.size();
+ for (int i = 0; i < serviceLen; i++) {
+ final SystemService service = mServices.get(i);
+ try {
+ service.onCleanupUser(userHandle);
+ } catch (Exception ex) {
+ Slog.wtf(TAG, "Failure reporting cleanup of user " + userHandle
+ + " to service " + service.getClass().getName(), ex);
+ }
+ }
+ }
+
+ /** Sets the safe mode flag for services to query. */
+ public void setSafeMode(boolean safeMode) {
+ mSafeMode = safeMode;
+ }
+
+ /**
+ * Returns whether we are booting into safe mode.
+ * @return safe mode flag
+ */
+ public boolean isSafeMode() {
+ return mSafeMode;
+ }
+
+ /**
+ * Outputs the state of this manager to the System log.
+ */
+ public void dump() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("Current phase: ").append(mCurrentPhase).append("\n");
+ builder.append("Services:\n");
+ final int startedLen = mServices.size();
+ for (int i = 0; i < startedLen; i++) {
+ final SystemService service = mServices.get(i);
+ builder.append("\t")
+ .append(service.getClass().getSimpleName())
+ .append("\n");
+ }
+
+ Slog.e(TAG, builder.toString());
+ }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ad2704a..ecd8f11 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2031,7 +2031,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS);
- mSystemThread.installSystemApplicationInfo(info);
+ mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
synchronized (this) {
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 9a67321..46cb6c3 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -37,7 +37,7 @@ import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
-import android.text.format.DateUtils;
+import android.os.Trace;
import android.util.MathUtils;
import android.util.Slog;
import android.util.Spline;
@@ -74,6 +74,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private static boolean DEBUG = false;
private static final boolean DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT = false;
+ private static final String SCREEN_ON_BLOCKED_TRACE_NAME = "Screen on blocked";
+
// If true, uses the electron beam on animation.
// We might want to turn this off if we cannot get a guarantee that the screen
// actually turns on and starts showing new content after the call to set the
@@ -714,11 +716,10 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
private void blockScreenOn() {
if (!mScreenOnWasBlocked) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
mScreenOnWasBlocked = true;
mScreenOnBlockStartRealTime = SystemClock.elapsedRealtime();
- if (DEBUG) {
- Slog.d(TAG, "Blocked screen on.");
- }
+ Slog.i(TAG, "Blocking screen on until initial contents have been drawn.");
}
}
@@ -726,9 +727,8 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
if (mScreenOnWasBlocked) {
mScreenOnWasBlocked = false;
long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
- if (delay > 1000 || DEBUG) {
- Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
- }
+ Slog.i(TAG, "Unblocked screen on after " + delay + " ms");
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, SCREEN_ON_BLOCKED_TRACE_NAME, 0);
}
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 6522b89..a7651e4 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -23,6 +23,7 @@ import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
+import android.os.Trace;
import android.util.FloatProperty;
import android.util.IntProperty;
import android.util.Slog;
@@ -405,19 +406,38 @@ final class DisplayPowerState {
}
boolean suspending = Display.isSuspendedState(state);
if (stateChanged && !suspending) {
- mBlanker.requestDisplayState(state);
+ requestDisplayState(state);
}
if (backlightChanged) {
- mBacklight.setBrightness(backlight);
+ setBrightness(backlight);
}
if (stateChanged && suspending) {
- mBlanker.requestDisplayState(state);
+ requestDisplayState(state);
}
}
// Let the outer class know that all changes have been applied.
postScreenUpdateThreadSafe();
}
+
+ private void requestDisplayState(int state) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
+ + Display.stateToString(state) + ")");
+ try {
+ mBlanker.requestDisplayState(state);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ }
+
+ private void setBrightness(int backlight) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setBrightness(" + backlight + ")");
+ try {
+ mBacklight.setBrightness(backlight);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ }
};
}
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 4fd006d..9c91ab5 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -21,7 +21,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemProperties;
-import android.util.Pair;
+import android.os.Trace;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -224,8 +224,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
@Override
public void requestDisplayStateLocked(int state) {
if (mState != state) {
- SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(),
- getPowerModeForState(state));
+ final int mode = getPowerModeForState(state);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "requestDisplayState("
+ + Display.stateToString(state) + ", id=" + mBuiltInDisplayId + ")");
+ try {
+ SurfaceControl.setDisplayPowerMode(getDisplayTokenLocked(), mode);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
mState = state;
updateDeviceInfoLocked();
}
diff --git a/services/core/java/com/android/server/dreams/DreamController.java b/services/core/java/com/android/server/dreams/DreamController.java
index 334f0ac..768ccf2 100644
--- a/services/core/java/com/android/server/dreams/DreamController.java
+++ b/services/core/java/com/android/server/dreams/DreamController.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.IBinder.DeathRecipient;
+import android.os.Trace;
import android.os.UserHandle;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamService;
@@ -111,41 +112,46 @@ final class DreamController {
boolean isTest, boolean canDoze, int userId) {
stopDream(true /*immediate*/);
- // Close the notification shade. Don't need to send to all, but better to be explicit.
- mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "startDream");
+ try {
+ // Close the notification shade. Don't need to send to all, but better to be explicit.
+ mContext.sendBroadcastAsUser(mCloseNotificationShadeIntent, UserHandle.ALL);
- Slog.i(TAG, "Starting dream: name=" + name
- + ", isTest=" + isTest + ", canDoze=" + canDoze
- + ", userId=" + userId);
+ Slog.i(TAG, "Starting dream: name=" + name
+ + ", isTest=" + isTest + ", canDoze=" + canDoze
+ + ", userId=" + userId);
- mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
+ mCurrentDream = new DreamRecord(token, name, isTest, canDoze, userId);
- try {
- mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
- } catch (RemoteException ex) {
- Slog.e(TAG, "Unable to add window token for dream.", ex);
- stopDream(true /*immediate*/);
- return;
- }
+ try {
+ mIWindowManager.addWindowToken(token, WindowManager.LayoutParams.TYPE_DREAM);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Unable to add window token for dream.", ex);
+ stopDream(true /*immediate*/);
+ return;
+ }
- Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
- intent.setComponent(name);
- intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
- try {
- if (!mContext.bindServiceAsUser(intent, mCurrentDream,
- Context.BIND_AUTO_CREATE, new UserHandle(userId))) {
- Slog.e(TAG, "Unable to bind dream service: " + intent);
+ Intent intent = new Intent(DreamService.SERVICE_INTERFACE);
+ intent.setComponent(name);
+ intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ try {
+ if (!mContext.bindServiceAsUser(intent, mCurrentDream,
+ Context.BIND_AUTO_CREATE, new UserHandle(userId))) {
+ Slog.e(TAG, "Unable to bind dream service: " + intent);
+ stopDream(true /*immediate*/);
+ return;
+ }
+ } catch (SecurityException ex) {
+ Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
stopDream(true /*immediate*/);
return;
}
- } catch (SecurityException ex) {
- Slog.e(TAG, "Unable to bind dream service: " + intent, ex);
- stopDream(true /*immediate*/);
- return;
- }
- mCurrentDream.mBound = true;
- mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);
+ mCurrentDream.mBound = true;
+ mHandler.postDelayed(mStopUnconnectedDreamRunnable, DREAM_CONNECTION_TIMEOUT);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
public void stopDream(boolean immediate) {
@@ -153,71 +159,76 @@ final class DreamController {
return;
}
- if (!immediate) {
- if (mCurrentDream.mWakingGently) {
- return; // already waking gently
- }
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "stopDream");
+ try {
+ if (!immediate) {
+ if (mCurrentDream.mWakingGently) {
+ return; // already waking gently
+ }
- if (mCurrentDream.mService != null) {
- // Give the dream a moment to wake up and finish itself gently.
- mCurrentDream.mWakingGently = true;
- try {
- mCurrentDream.mService.wakeUp();
- mHandler.postDelayed(mStopStubbornDreamRunnable, DREAM_FINISH_TIMEOUT);
- return;
- } catch (RemoteException ex) {
- // oh well, we tried, finish immediately instead
+ if (mCurrentDream.mService != null) {
+ // Give the dream a moment to wake up and finish itself gently.
+ mCurrentDream.mWakingGently = true;
+ try {
+ mCurrentDream.mService.wakeUp();
+ mHandler.postDelayed(mStopStubbornDreamRunnable, DREAM_FINISH_TIMEOUT);
+ return;
+ } catch (RemoteException ex) {
+ // oh well, we tried, finish immediately instead
+ }
}
}
- }
- final DreamRecord oldDream = mCurrentDream;
- mCurrentDream = null;
- Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
- + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
- + ", userId=" + oldDream.mUserId);
+ final DreamRecord oldDream = mCurrentDream;
+ mCurrentDream = null;
+ Slog.i(TAG, "Stopping dream: name=" + oldDream.mName
+ + ", isTest=" + oldDream.mIsTest + ", canDoze=" + oldDream.mCanDoze
+ + ", userId=" + oldDream.mUserId);
- mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
- mHandler.removeCallbacks(mStopStubbornDreamRunnable);
+ mHandler.removeCallbacks(mStopUnconnectedDreamRunnable);
+ mHandler.removeCallbacks(mStopStubbornDreamRunnable);
- if (oldDream.mSentStartBroadcast) {
- mContext.sendBroadcastAsUser(mDreamingStoppedIntent, UserHandle.ALL);
- }
+ if (oldDream.mSentStartBroadcast) {
+ mContext.sendBroadcastAsUser(mDreamingStoppedIntent, UserHandle.ALL);
+ }
- if (oldDream.mService != null) {
- // Tell the dream that it's being stopped so that
- // it can shut down nicely before we yank its window token out from
- // under it.
- try {
- oldDream.mService.detach();
- } catch (RemoteException ex) {
- // we don't care; this thing is on the way out
+ if (oldDream.mService != null) {
+ // Tell the dream that it's being stopped so that
+ // it can shut down nicely before we yank its window token out from
+ // under it.
+ try {
+ oldDream.mService.detach();
+ } catch (RemoteException ex) {
+ // we don't care; this thing is on the way out
+ }
+
+ try {
+ oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
+ } catch (NoSuchElementException ex) {
+ // don't care
+ }
+ oldDream.mService = null;
}
- try {
- oldDream.mService.asBinder().unlinkToDeath(oldDream, 0);
- } catch (NoSuchElementException ex) {
- // don't care
+ if (oldDream.mBound) {
+ mContext.unbindService(oldDream);
}
- oldDream.mService = null;
- }
- if (oldDream.mBound) {
- mContext.unbindService(oldDream);
- }
+ try {
+ mIWindowManager.removeWindowToken(oldDream.mToken);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "Error removing window token for dream.", ex);
+ }
- try {
- mIWindowManager.removeWindowToken(oldDream.mToken);
- } catch (RemoteException ex) {
- Slog.w(TAG, "Error removing window token for dream.", ex);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onDreamStopped(oldDream.mToken);
+ }
+ });
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mListener.onDreamStopped(oldDream.mToken);
- }
- });
}
private void attach(IDreamService service) {
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index 2407253..4b812cf 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -173,6 +173,10 @@ final class Constants {
static final int SYSTEM_AUDIO_STATUS_OFF = 0;
static final int SYSTEM_AUDIO_STATUS_ON = 1;
+ // [Menu State]
+ static final int MENU_STATE_ACTIVATED = 0;
+ static final int MENU_STATE_DEACTIVATED = 1;
+
// Bit mask used to get the routing path of the top level device.
// When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0.
static final int ROUTING_PATH_TOP_MASK = 0xF000;
@@ -276,5 +280,10 @@ final class Constants {
// values which denotes the device type in HDMI Spec 1.4.
static final String PROPERTY_DEVICE_TYPE = "ro.hdmi.device_type";
+ // MHL RCPE messages
+ static final int MHL_RCPE_NO_ERROR = 0x00;
+ static final int MHL_RCPE_INEFFECTIVE_KEYCODE = 0x01;
+ static final int MHL_RCPE_RESPONDER_BUSY = 0x02;
+
private Constants() { /* cannot be instantiated */ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index c0c8424..46b2b3e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -21,7 +21,7 @@ import android.view.KeyEvent;
/**
* Helper class to translate android keycode to hdmi cec keycode and vice versa.
*/
-public class HdmiCecKeycode {
+final class HdmiCecKeycode {
public static final int UNSUPPORTED_KEYCODE = -1;
public static final int NO_PARAM = -1;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index b894fd7..4862f93 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -17,10 +17,15 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
import android.util.Slog;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
@@ -39,15 +44,21 @@ abstract class HdmiCecLocalDevice {
private static final String TAG = "HdmiCecLocalDevice";
private static final int MSG_DISABLE_DEVICE_TIMEOUT = 1;
+ private static final int MSG_USER_CONTROL_RELEASE_TIMEOUT = 2;
// Timeout in millisecond for device clean up (5s).
// Normal actions timeout is 2s but some of them would have several sequence of timeout.
private static final int DEVICE_CLEANUP_TIMEOUT = 5000;
+ // Within the timer, a received <User Control Pressed> will start "Press and Hold" behavior.
+ // When it expires, we can assume <User Control Release> is received.
+ private static final int FOLLOWER_SAFETY_TIMEOUT = 550;
protected final HdmiControlService mService;
protected final int mDeviceType;
protected int mAddress;
protected int mPreferredAddress;
protected HdmiDeviceInfo mDeviceInfo;
+ protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
+ protected int mLastKeyRepeatCount = 0;
static class ActiveSource {
int logicalAddress;
@@ -111,6 +122,9 @@ abstract class HdmiCecLocalDevice {
case MSG_DISABLE_DEVICE_TIMEOUT:
handleDisableDeviceTimeout();
break;
+ case MSG_USER_CONTROL_RELEASE_TIMEOUT:
+ handleUserControlReleased();
+ break;
}
}
};
@@ -230,10 +244,14 @@ abstract class HdmiCecLocalDevice {
return handleImageViewOn(message);
case Constants.MESSAGE_USER_CONTROL_PRESSED:
return handleUserControlPressed(message);
+ case Constants.MESSAGE_USER_CONTROL_RELEASED:
+ return handleUserControlReleased();
case Constants.MESSAGE_SET_STREAM_PATH:
return handleSetStreamPath(message);
case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
return handleGiveDevicePowerStatus(message);
+ case Constants.MESSAGE_MENU_REQUEST:
+ return handleGiveDeviceMenuStatus(message);
case Constants.MESSAGE_VENDOR_COMMAND:
return handleVendorCommand(message);
case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID:
@@ -376,6 +394,7 @@ abstract class HdmiCecLocalDevice {
@ServiceThreadOnly
protected boolean handleUserControlPressed(HdmiCecMessage message) {
assertRunOnServiceThread();
+ mHandler.removeMessages(MSG_USER_CONTROL_RELEASE_TIMEOUT);
if (mService.isPowerOnOrTransient() && isPowerOffOrToggleCommand(message)) {
mService.standby();
return true;
@@ -383,9 +402,54 @@ abstract class HdmiCecLocalDevice {
mService.wakeUp();
return true;
}
+
+ final long downTime = SystemClock.uptimeMillis();
+ final byte[] params = message.getParams();
+ final int keycode = HdmiCecKeycode.cecKeyToAndroidKey(params[0],
+ params.length > 1 ? params[1] : HdmiCecKeycode.NO_PARAM);
+ int keyRepeatCount = 0;
+ if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
+ if (keycode == mLastKeycode) {
+ keyRepeatCount = mLastKeyRepeatCount + 1;
+ } else {
+ injectKeyEvent(downTime, KeyEvent.ACTION_UP, mLastKeycode, 0);
+ }
+ }
+ mLastKeycode = keycode;
+ mLastKeyRepeatCount = keyRepeatCount;
+
+ if (keycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
+ injectKeyEvent(downTime, KeyEvent.ACTION_DOWN, keycode, keyRepeatCount);
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_USER_CONTROL_RELEASE_TIMEOUT),
+ FOLLOWER_SAFETY_TIMEOUT);
+ return true;
+ }
+ return false;
+ }
+
+ @ServiceThreadOnly
+ protected boolean handleUserControlReleased() {
+ assertRunOnServiceThread();
+ mHandler.removeMessages(MSG_USER_CONTROL_RELEASE_TIMEOUT);
+ mLastKeyRepeatCount = 0;
+ if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
+ final long upTime = SystemClock.uptimeMillis();
+ injectKeyEvent(upTime, KeyEvent.ACTION_UP, mLastKeycode, 0);
+ mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
+ return true;
+ }
return false;
}
+ static void injectKeyEvent(long time, int action, int keycode, int repeat) {
+ KeyEvent keyEvent = KeyEvent.obtain(time, time, action, keycode,
+ repeat, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
+ InputDevice.SOURCE_HDMI, null);
+ InputManager.getInstance().injectInputEvent(keyEvent,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ keyEvent.recycle();
+ }
+
static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) {
byte[] params = message.getParams();
return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
@@ -420,6 +484,13 @@ abstract class HdmiCecLocalDevice {
return true;
}
+ protected boolean handleGiveDeviceMenuStatus(HdmiCecMessage message) {
+ // Always report menu active to receive Remote Control.
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildReportMenuStatus(
+ mAddress, message.getSource(), Constants.MENU_STATE_ACTIVATED));
+ return true;
+ }
+
protected boolean handleVendorCommand(HdmiCecMessage message) {
mService.invokeVendorCommandListeners(mDeviceType, message.getSource(),
message.getParams(), false);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 47b0794..809fef4 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -100,7 +100,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
private List<HdmiDeviceInfo> mSafeExternalInputs = Collections.emptyList();
// Map-like container of all cec devices including local ones.
- // A logical address of device is used as key of container.
+ // device id is used as key of container.
// This is not thread-safe. For external purpose use mSafeDeviceInfos.
private final SparseArray<HdmiDeviceInfo> mDeviceInfos = new SparseArray<>();
@@ -167,12 +167,19 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
/**
* Performs the action 'device select', or 'one touch play' initiated by TV.
*
- * @param targetAddress logical address of the device to select
+ * @param id id of HDMI device to select
* @param callback callback object to report the result with
*/
@ServiceThreadOnly
- void deviceSelect(int targetAddress, IHdmiControlCallback callback) {
+ void deviceSelect(int id, IHdmiControlCallback callback) {
assertRunOnServiceThread();
+ HdmiDeviceInfo targetDevice = mDeviceInfos.get(id);
+ if (targetDevice == null) {
+ invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
+ return;
+ }
+ // TODO: Handle MHL device
+ int targetAddress = targetDevice.getLogicalAddress();
ActiveSource active = getActiveSource();
if (active.isValid() && targetAddress == active.logicalAddress) {
invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
@@ -187,18 +194,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
return;
}
if (!mService.isControlEnabled()) {
- HdmiDeviceInfo info = getDeviceInfo(targetAddress);
- if (info != null) {
- setActiveSource(info);
- }
+ setActiveSource(targetDevice);
invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
return;
}
- HdmiDeviceInfo targetDevice = getDeviceInfo(targetAddress);
- if (targetDevice == null) {
- invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
- return;
- }
removeAction(DeviceSelectAction.class);
addAndStartAction(new DeviceSelectAction(this, targetDevice, callback));
}
@@ -231,7 +230,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
setActiveSource(newActive);
int logicalAddress = newActive.logicalAddress;
- if (getDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) {
+ if (getCecDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) {
if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) {
setPrevPortId(getActivePortId());
}
@@ -279,7 +278,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
// Show OSD port change banner
if (notifyInputChange) {
ActiveSource activeSource = getActiveSource();
- HdmiDeviceInfo info = getDeviceInfo(activeSource.logicalAddress);
+ HdmiDeviceInfo info = getCecDeviceInfo(activeSource.logicalAddress);
if (info == null) {
info = new HdmiDeviceInfo(Constants.ADDR_INVALID, path, portId,
HdmiDeviceInfo.DEVICE_RESERVED, 0, null);
@@ -363,7 +362,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int logicalAddress = message.getSource();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
- if (getDeviceInfo(logicalAddress) == null) {
+ if (getCecDeviceInfo(logicalAddress) == null) {
handleNewDeviceAtTheTailOfActivePath(physicalAddress);
} else {
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
@@ -389,7 +388,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (portId != Constants.INVALID_PORT_ID) {
// TODO: Do this only if TV is not showing multiview like PIP/PAP.
- HdmiDeviceInfo inactiveSource = getDeviceInfo(message.getSource());
+ HdmiDeviceInfo inactiveSource = getCecDeviceInfo(message.getSource());
if (inactiveSource == null) {
return true;
}
@@ -577,7 +576,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
protected boolean handleSetOsdName(HdmiCecMessage message) {
int source = message.getSource();
- HdmiDeviceInfo deviceInfo = getDeviceInfo(source);
+ HdmiDeviceInfo deviceInfo = getCecDeviceInfo(source);
// If the device is not in device list, ignore it.
if (deviceInfo == null) {
Slog.e(TAG, "No source device info for <Set Osd Name>." + message);
@@ -952,11 +951,11 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
private HdmiDeviceInfo addDeviceInfo(HdmiDeviceInfo deviceInfo) {
assertRunOnServiceThread();
- HdmiDeviceInfo oldDeviceInfo = getDeviceInfo(deviceInfo.getLogicalAddress());
+ HdmiDeviceInfo oldDeviceInfo = getCecDeviceInfo(deviceInfo.getLogicalAddress());
if (oldDeviceInfo != null) {
- removeDeviceInfo(deviceInfo.getLogicalAddress());
+ removeDeviceInfo(deviceInfo.getId());
}
- mDeviceInfos.append(deviceInfo.getLogicalAddress(), deviceInfo);
+ mDeviceInfos.append(deviceInfo.getId(), deviceInfo);
updateSafeDeviceInfoList();
return oldDeviceInfo;
}
@@ -967,15 +966,15 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
*
* <p>Declared as package-private. accessed by {@link HdmiControlService} only.
*
- * @param logicalAddress logical address of device to be removed
+ * @param id id of device to be removed
* @return removed {@link HdmiDeviceInfo} it exists. Otherwise, returns {@code null}
*/
@ServiceThreadOnly
- private HdmiDeviceInfo removeDeviceInfo(int logicalAddress) {
+ private HdmiDeviceInfo removeDeviceInfo(int id) {
assertRunOnServiceThread();
- HdmiDeviceInfo deviceInfo = mDeviceInfos.get(logicalAddress);
+ HdmiDeviceInfo deviceInfo = mDeviceInfos.get(id);
if (deviceInfo != null) {
- mDeviceInfos.remove(logicalAddress);
+ mDeviceInfos.remove(id);
}
updateSafeDeviceInfoList();
return deviceInfo;
@@ -1035,7 +1034,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
for (int i = 0; i < mDeviceInfos.size(); ++i) {
HdmiDeviceInfo info = mDeviceInfos.valueAt(i);
- if (isLocalDeviceAddress(i)) {
+ if (isLocalDeviceAddress(info.getLogicalAddress())) {
continue;
}
if (info.isSourceType() && !hideDevicesBehindLegacySwitch(info)) {
@@ -1095,23 +1094,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
HdmiDeviceInfo getAvrDeviceInfo() {
assertRunOnServiceThread();
- return getDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
+ return getCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
}
/**
* Return a {@link HdmiDeviceInfo} corresponding to the given {@code logicalAddress}.
*
- * <p>Declared as package-private. accessed by {@link HdmiControlService} only.
- * This is not thread-safe. For thread safety, call {@link #getSafeDeviceInfo(int)}.
+ * This is not thread-safe. For thread safety, call {@link #getSafeCecDeviceInfo(int)}.
*
- * @param logicalAddress logical address to be retrieved
+ * @param address logical address of the device to be retrieved
* @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}.
* Returns null if no logical address matched
*/
@ServiceThreadOnly
- HdmiDeviceInfo getDeviceInfo(int logicalAddress) {
+ HdmiDeviceInfo getCecDeviceInfo(int logicalAddress) {
assertRunOnServiceThread();
- return mDeviceInfos.get(logicalAddress);
+ return mDeviceInfos.get(HdmiDeviceInfo.idForCecDevice(logicalAddress));
}
boolean hasSystemAudioDevice() {
@@ -1119,19 +1117,24 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
HdmiDeviceInfo getSafeAvrDeviceInfo() {
- return getSafeDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
+ return getSafeCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM);
}
/**
- * Thread safe version of {@link #getDeviceInfo(int)}.
+ * Thread safe version of {@link #getCecDeviceInfo(int)}.
*
* @param logicalAddress logical address to be retrieved
* @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}.
* Returns null if no logical address matched
*/
- HdmiDeviceInfo getSafeDeviceInfo(int logicalAddress) {
+ HdmiDeviceInfo getSafeCecDeviceInfo(int logicalAddress) {
synchronized (mLock) {
- return mSafeAllDeviceInfos.get(logicalAddress);
+ for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
+ if (info.isCecDevice() && info.getLogicalAddress() == logicalAddress) {
+ return info;
+ }
+ }
+ return null;
}
}
@@ -1160,7 +1163,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
final void removeCecDevice(int address) {
assertRunOnServiceThread();
- HdmiDeviceInfo info = removeDeviceInfo(address);
+ HdmiDeviceInfo info = removeDeviceInfo(HdmiDeviceInfo.idForCecDevice(address));
mCecMessageCache.flushMessagesFrom(address);
invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE);
@@ -1240,7 +1243,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
boolean isInDeviceList(int logicalAddress, int physicalAddress) {
assertRunOnServiceThread();
- HdmiDeviceInfo device = getDeviceInfo(logicalAddress);
+ HdmiDeviceInfo device = getCecDeviceInfo(logicalAddress);
if (device == null) {
return false;
}
@@ -1427,7 +1430,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
private boolean checkRecorder(int recorderAddress) {
- HdmiDeviceInfo device = getDeviceInfo(recorderAddress);
+ HdmiDeviceInfo device = getCecDeviceInfo(recorderAddress);
return (device != null)
&& (HdmiUtils.getTypeFromAddress(recorderAddress)
== HdmiDeviceInfo.DEVICE_RECORDER);
@@ -1528,7 +1531,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
void updateDevicePowerStatus(int logicalAddress, int newPowerStatus) {
- HdmiDeviceInfo info = getDeviceInfo(logicalAddress);
+ HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress);
if (info == null) {
Slog.w(TAG, "Can not update power status of non-existing device:" + logicalAddress);
return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 0855bfa..b53cd45 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -338,6 +338,21 @@ public class HdmiCecMessageBuilder {
}
/**
+ * Build &lt;Report Menu Status&gt; command.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @param menuStatus menu status of the device
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildReportMenuStatus(int src, int dest, int menuStatus) {
+ byte[] param = new byte[] {
+ (byte) (menuStatus)
+ };
+ return buildCommand(src, dest, Constants.MESSAGE_MENU_STATUS, param);
+ }
+
+ /**
* Build &lt;System Audio Mode Request&gt; command.
*
* @param src source address of command
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 2818ea7..14c066e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -568,7 +568,7 @@ public final class HdmiControlService extends SystemService {
if (tv == null) {
return null;
}
- return tv.getDeviceInfo(logicalAddress);
+ return tv.getCecDeviceInfo(logicalAddress);
}
/**
@@ -949,7 +949,7 @@ public final class HdmiControlService extends SystemService {
}
@Override
- public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) {
+ public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) {
enforceAccessPermission();
runOnServiceThread(new Runnable() {
@Override
@@ -964,7 +964,7 @@ public final class HdmiControlService extends SystemService {
invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE);
return;
}
- tv.deviceSelect(logicalAddress, callback);
+ tv.deviceSelect(deviceId, callback);
}
});
}
@@ -996,12 +996,21 @@ public final class HdmiControlService extends SystemService {
runOnServiceThread(new Runnable() {
@Override
public void run() {
- HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType);
- if (localDevice == null) {
- Slog.w(TAG, "Local device not available");
- return;
+ if (mMhlController != null) {
+ HdmiMhlLocalDevice device = mMhlController.getLocalDevice(mActivePortId);
+ if (device != null) {
+ device.sendKeyEvent(keyCode, isPressed);
+ return;
+ }
+ }
+ if (mCecController != null) {
+ HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType);
+ if (localDevice == null) {
+ Slog.w(TAG, "Local device not available");
+ return;
+ }
+ localDevice.sendKeyEvent(keyCode, isPressed);
}
- localDevice.sendKeyEvent(keyCode, isPressed);
}
});
}
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 51e68b6..722be71 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -207,7 +207,7 @@ final class HotplugDetectionAction extends HdmiCecFeatureAction {
}
private void mayChangeRoutingPath(int address) {
- HdmiDeviceInfo info = tv().getDeviceInfo(address);
+ HdmiDeviceInfo info = tv().getCecDeviceInfo(address);
if (info != null) {
tv().handleRemoveActiveRoutingPath(info.getPhysicalAddress());
}
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index 94cf668..9dcc529 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -23,6 +23,7 @@ import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.IHardwareService;
import android.os.Message;
+import android.os.Trace;
import android.util.Slog;
import java.io.FileInputStream;
@@ -105,7 +106,12 @@ public class LightsService extends SystemService {
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
- setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", " + color + ")");
+ try {
+ setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index a06daf6..189131c 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -51,8 +51,9 @@ public class ConditionProviders extends ManagedServices {
= new ArrayMap<IBinder, IConditionListener>();
private final ArrayList<ConditionRecord> mRecords = new ArrayList<ConditionRecord>();
private final CountdownConditionProvider mCountdown = new CountdownConditionProvider();
+ private final DowntimeConditionProvider mDowntime = new DowntimeConditionProvider();
- private Uri mExitConditionId;
+ private Condition mExitCondition;
private ComponentName mExitConditionComponent;
public ConditionProviders(Context context, Handler handler,
@@ -97,6 +98,7 @@ public class ConditionProviders extends ManagedServices {
}
}
mCountdown.dump(pw, filter);
+ mDowntime.dump(pw, filter);
}
@Override
@@ -110,6 +112,10 @@ public class ConditionProviders extends ManagedServices {
mCountdown.attachBase(mContext);
registerService(mCountdown.asInterface(), CountdownConditionProvider.COMPONENT,
UserHandle.USER_OWNER);
+ mDowntime.attachBase(mContext);
+ registerService(mDowntime.asInterface(), DowntimeConditionProvider.COMPONENT,
+ UserHandle.USER_OWNER);
+ mDowntime.setCallback(new DowntimeCallback());
}
@Override
@@ -125,7 +131,7 @@ public class ConditionProviders extends ManagedServices {
if (info.component.equals(mExitConditionComponent)) {
// ensure record exists, we'll wire it up and subscribe below
final ConditionRecord manualRecord =
- getRecordLocked(mExitConditionId, mExitConditionComponent);
+ getRecordLocked(mExitCondition.id, mExitConditionComponent);
manualRecord.isManual = true;
}
final int N = mRecords.size();
@@ -149,11 +155,11 @@ public class ConditionProviders extends ManagedServices {
if (!r.component.equals(removed.component)) continue;
if (r.isManual) {
// removing the current manual condition, exit zen
- mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "manualServiceRemoved");
}
if (r.isAutomatic) {
// removing an automatic condition, exit zen
- mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "automaticServiceRemoved");
}
mRecords.remove(i);
}
@@ -249,7 +255,8 @@ public class ConditionProviders extends ManagedServices {
} else if (DEBUG) {
Slog.d(TAG, "Exit zen: manual condition false: " + c);
}
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
+ "manualConditionExit");
unsubscribeLocked(r);
r.isManual = false;
}
@@ -263,33 +270,46 @@ public class ConditionProviders extends ManagedServices {
} else if (DEBUG) {
Slog.d(TAG, "Exit zen: automatic condition false: " + c);
}
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_OFF,
+ "automaticConditionExit");
} else if (c.state == Condition.STATE_TRUE) {
Slog.d(TAG, "Enter zen: automatic condition true: " + c);
- mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+ mZenModeHelper.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
+ "automaticConditionEnter");
}
}
}
}
}
- public void setZenModeCondition(Uri conditionId, String reason) {
- if (DEBUG) Slog.d(TAG, "setZenModeCondition " + conditionId);
+ public void setZenModeCondition(Condition condition, String reason) {
+ if (DEBUG) Slog.d(TAG, "setZenModeCondition " + condition);
synchronized(mMutex) {
ComponentName conditionComponent = null;
- if (ZenModeConfig.isValidCountdownConditionId(conditionId)) {
- // constructed by the client, make sure the record exists...
- final ConditionRecord r = getRecordLocked(conditionId,
- CountdownConditionProvider.COMPONENT);
- if (r.info == null) {
- // ... and is associated with the in-process service
- r.info = checkServiceTokenLocked(mCountdown.asInterface());
+ if (condition != null) {
+ if (ZenModeConfig.isValidCountdownConditionId(condition.id)) {
+ // constructed by the client, make sure the record exists...
+ final ConditionRecord r = getRecordLocked(condition.id,
+ CountdownConditionProvider.COMPONENT);
+ if (r.info == null) {
+ // ... and is associated with the in-process service
+ r.info = checkServiceTokenLocked(mCountdown.asInterface());
+ }
+ }
+ if (ZenModeConfig.isValidDowntimeConditionId(condition.id)) {
+ // constructed by the client, make sure the record exists...
+ final ConditionRecord r = getRecordLocked(condition.id,
+ DowntimeConditionProvider.COMPONENT);
+ if (r.info == null) {
+ // ... and is associated with the in-process service
+ r.info = checkServiceTokenLocked(mDowntime.asInterface());
+ }
}
}
final int N = mRecords.size();
for (int i = 0; i < N; i++) {
final ConditionRecord r = mRecords.get(i);
- final boolean idEqual = r.id.equals(conditionId);
+ final boolean idEqual = condition != null && r.id.equals(condition.id);
if (r.isManual && !idEqual) {
// was previous manual condition, unsubscribe
unsubscribeLocked(r);
@@ -303,10 +323,10 @@ public class ConditionProviders extends ManagedServices {
conditionComponent = r.component;
}
}
- if (!Objects.equals(mExitConditionId, conditionId)) {
- mExitConditionId = conditionId;
+ if (!Objects.equals(mExitCondition, condition)) {
+ mExitCondition = condition;
mExitConditionComponent = conditionComponent;
- ZenLog.traceExitCondition(mExitConditionId, mExitConditionComponent, reason);
+ ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, reason);
saveZenConfigLocked();
}
}
@@ -318,6 +338,7 @@ public class ConditionProviders extends ManagedServices {
RemoteException re = null;
if (provider != null) {
try {
+ Slog.d(TAG, "Subscribing to " + r.id + " with " + provider);
provider.onSubscribe(r.id);
} catch (RemoteException e) {
Slog.w(TAG, "Error subscribing to " + r, e);
@@ -436,12 +457,13 @@ public class ConditionProviders extends ManagedServices {
return;
}
synchronized (mMutex) {
- final boolean changingExit = !Objects.equals(mExitConditionId, config.exitConditionId);
- mExitConditionId = config.exitConditionId;
+ final boolean changingExit = !Objects.equals(mExitCondition, config.exitCondition);
+ mExitCondition = config.exitCondition;
mExitConditionComponent = config.exitConditionComponent;
if (changingExit) {
- ZenLog.traceExitCondition(mExitConditionId, mExitConditionComponent, "config");
+ ZenLog.traceExitCondition(mExitCondition, mExitConditionComponent, "config");
}
+ mDowntime.setConfig(config);
if (config.conditionComponents == null || config.conditionIds == null
|| config.conditionComponents.length != config.conditionIds.length) {
if (DEBUG) Slog.d(TAG, "loadZenConfig: no conditions");
@@ -488,7 +510,7 @@ public class ConditionProviders extends ManagedServices {
config.conditionIds[i] = r.id;
}
}
- config.exitConditionId = mExitConditionId;
+ config.exitCondition = mExitCondition;
config.exitConditionComponent = mExitConditionComponent;
if (DEBUG) Slog.d(TAG, "Setting zen config to: " + config);
mZenModeHelper.setConfig(config);
@@ -510,6 +532,26 @@ public class ConditionProviders extends ManagedServices {
}
}
+ private class DowntimeCallback implements DowntimeConditionProvider.Callback {
+ @Override
+ public void onDowntimeChanged(boolean inDowntime) {
+ final int mode = mZenModeHelper.getZenMode();
+ final ZenModeConfig config = mZenModeHelper.getConfig();
+ // enter downtime
+ if (inDowntime && mode == Global.ZEN_MODE_OFF && config != null) {
+ final Condition condition = mDowntime.createCondition(config.toDowntimeInfo(),
+ Condition.STATE_TRUE);
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS, "downtimeEnter");
+ setZenModeCondition(condition, "downtime");
+ }
+ // exit downtime
+ if (!inDowntime && mode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS
+ && mDowntime.isDowntimeCondition(mExitCondition)) {
+ mZenModeHelper.setZenMode(Global.ZEN_MODE_OFF, "downtimeExit");
+ }
+ }
+ }
+
private static class ConditionRecord {
public final Uri id;
public final ComponentName component;
diff --git a/services/core/java/com/android/server/notification/CountdownConditionProvider.java b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
index aaf7cfc..37aacaa 100644
--- a/services/core/java/com/android/server/notification/CountdownConditionProvider.java
+++ b/services/core/java/com/android/server/notification/CountdownConditionProvider.java
@@ -29,6 +29,7 @@ import android.service.notification.ConditionProviderService;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
import android.text.format.DateUtils;
+import android.util.Log;
import android.util.Slog;
import com.android.server.notification.NotificationManagerService.DumpFilter;
@@ -38,8 +39,8 @@ import java.util.Date;
/** Built-in zen condition provider for simple time-based conditions */
public class CountdownConditionProvider extends ConditionProviderService {
- private static final String TAG = "CountdownConditionProvider";
- private static final boolean DEBUG = false;
+ private static final String TAG = "CountdownConditions";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final ComponentName COMPONENT =
new ComponentName("android", CountdownConditionProvider.class.getName());
diff --git a/services/core/java/com/android/server/notification/DowntimeConditionProvider.java b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
new file mode 100644
index 0000000..317ebef
--- /dev/null
+++ b/services/core/java/com/android/server/notification/DowntimeConditionProvider.java
@@ -0,0 +1,289 @@
+/**
+ * Copyright (c) 2014, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.service.notification.IConditionProvider;
+import android.service.notification.ZenModeConfig;
+import android.service.notification.ZenModeConfig.DowntimeInfo;
+import android.text.format.DateFormat;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Objects;
+
+/** Built-in zen condition provider for managing downtime */
+public class DowntimeConditionProvider extends ConditionProviderService {
+ private static final String TAG = "DowntimeConditions";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ public static final ComponentName COMPONENT =
+ new ComponentName("android", DowntimeConditionProvider.class.getName());
+
+ private static final String ENTER_ACTION = TAG + ".enter";
+ private static final int ENTER_CODE = 100;
+ private static final String EXIT_ACTION = TAG + ".exit";
+ private static final int EXIT_CODE = 101;
+ private static final String EXTRA_TIME = "time";
+
+ private final Calendar mCalendar = Calendar.getInstance();
+ private final Context mContext = this;
+ private final ArraySet<Integer> mDays = new ArraySet<Integer>();
+
+ private boolean mConnected;
+ private boolean mInDowntime;
+ private ZenModeConfig mConfig;
+ private Callback mCallback;
+
+ public DowntimeConditionProvider() {
+ if (DEBUG) Slog.d(TAG, "new DowntimeConditionProvider()");
+ }
+
+ public void dump(PrintWriter pw, DumpFilter filter) {
+ pw.println(" DowntimeConditionProvider:");
+ pw.print(" mConnected="); pw.println(mConnected);
+ pw.print(" mInDowntime="); pw.println(mInDowntime);
+ }
+
+ public void attachBase(Context base) {
+ attachBaseContext(base);
+ }
+
+ public IConditionProvider asInterface() {
+ return (IConditionProvider) onBind(null);
+ }
+
+ public void setCallback(Callback callback) {
+ mCallback = callback;
+ }
+
+ @Override
+ public void onConnected() {
+ if (DEBUG) Slog.d(TAG, "onConnected");
+ mConnected = true;
+ final IntentFilter filter = new IntentFilter();
+ filter.addAction(ENTER_ACTION);
+ filter.addAction(EXIT_ACTION);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ mContext.registerReceiver(mReceiver, filter);
+ init();
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Slog.d(TAG, "onDestroy");
+ mConnected = false;
+ }
+
+ @Override
+ public void onRequestConditions(int relevance) {
+ if (DEBUG) Slog.d(TAG, "onRequestConditions relevance=" + relevance);
+ if ((relevance & Condition.FLAG_RELEVANT_NOW) != 0) {
+ if (mInDowntime && mConfig != null) {
+ notifyCondition(createCondition(mConfig.toDowntimeInfo(), Condition.STATE_TRUE));
+ }
+ }
+ }
+
+ @Override
+ public void onSubscribe(Uri conditionId) {
+ if (DEBUG) Slog.d(TAG, "onSubscribe conditionId=" + conditionId);
+ final DowntimeInfo downtime = ZenModeConfig.tryParseDowntimeConditionId(conditionId);
+ if (downtime != null && mConfig != null) {
+ final int state = mConfig.toDowntimeInfo().equals(downtime) && mInDowntime
+ ? Condition.STATE_TRUE : Condition.STATE_FALSE;
+ if (DEBUG) Slog.d(TAG, "notify condition state: " + Condition.stateToString(state));
+ notifyCondition(createCondition(downtime, state));
+ }
+ }
+
+ @Override
+ public void onUnsubscribe(Uri conditionId) {
+ if (DEBUG) Slog.d(TAG, "onUnsubscribe conditionId=" + conditionId);
+ }
+
+ public void setConfig(ZenModeConfig config) {
+ if (Objects.equals(mConfig, config)) return;
+ if (DEBUG) Slog.d(TAG, "setConfig");
+ mConfig = config;
+ if (mConnected) {
+ init();
+ }
+ }
+
+ public boolean isInDowntime() {
+ return mInDowntime;
+ }
+
+ public Condition createCondition(DowntimeInfo downtime, int state) {
+ if (downtime == null) return null;
+ final Uri id = ZenModeConfig.toDowntimeConditionId(downtime);
+ final String skeleton = DateFormat.is24HourFormat(mContext) ? "Hm" : "hma";
+ final Locale locale = Locale.getDefault();
+ final String pattern = DateFormat.getBestDateTimePattern(locale, skeleton);
+ final long time = getTime(System.currentTimeMillis(), downtime.endHour, downtime.endMinute);
+ final String formatted = new SimpleDateFormat(pattern, locale).format(new Date(time));
+ final String summary = mContext.getString(R.string.downtime_condition_summary, formatted);
+ return new Condition(id, summary, "", "", 0, state, Condition.FLAG_RELEVANT_NOW);
+ }
+
+ public boolean isDowntimeCondition(Condition condition) {
+ return condition != null && ZenModeConfig.isValidDowntimeConditionId(condition.id);
+ }
+
+ private void init() {
+ updateDays();
+ reevaluateDowntime();
+ updateAlarms();
+ }
+
+ private void updateDays() {
+ mDays.clear();
+ if (mConfig != null) {
+ final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
+ for (int i = 0; days != null && i < days.length; i++) {
+ mDays.add(days[i]);
+ }
+ }
+ }
+
+ private boolean isInDowntime(long time) {
+ if (mConfig == null || mDays.size() == 0) return false;
+ final long start = getTime(time, mConfig.sleepStartHour, mConfig.sleepStartMinute);
+ long end = getTime(time, mConfig.sleepEndHour, mConfig.sleepEndMinute);
+ if (start == end) return false;
+ if (end < start) {
+ end = addDays(end, 1);
+ }
+ return isInDowntime(-1, time, start, end) || isInDowntime(0, time, start, end);
+ }
+
+ private boolean isInDowntime(int daysOffset, long time, long start, long end) {
+ final int day = ((getDayOfWeek(time) + daysOffset - 1) % Calendar.SATURDAY) + 1;
+ start = addDays(start, daysOffset);
+ end = addDays(end, daysOffset);
+ return mDays.contains(day) && time >= start && time < end;
+ }
+
+ private void reevaluateDowntime() {
+ final boolean inDowntime = isInDowntime(System.currentTimeMillis());
+ if (DEBUG) Slog.d(TAG, "inDowntime=" + inDowntime);
+ if (inDowntime == mInDowntime) return;
+ Slog.i(TAG, (inDowntime ? "Entering" : "Exiting" ) + " downtime");
+ mInDowntime = inDowntime;
+ ZenLog.traceDowntime(mInDowntime, getDayOfWeek(System.currentTimeMillis()), mDays);
+ fireDowntimeChanged();
+ }
+
+ private void fireDowntimeChanged() {
+ if (mCallback != null) {
+ mCallback.onDowntimeChanged(mInDowntime);
+ }
+ }
+
+ private void updateAlarms() {
+ if (mConfig == null) return;
+ updateAlarm(ENTER_ACTION, ENTER_CODE, mConfig.sleepStartHour, mConfig.sleepStartMinute);
+ updateAlarm(EXIT_ACTION, EXIT_CODE, mConfig.sleepEndHour, mConfig.sleepEndMinute);
+ }
+
+ private int getDayOfWeek(long time) {
+ mCalendar.setTimeInMillis(time);
+ return mCalendar.get(Calendar.DAY_OF_WEEK);
+ }
+
+ private long getTime(long millis, int hour, int min) {
+ mCalendar.setTimeInMillis(millis);
+ mCalendar.set(Calendar.HOUR_OF_DAY, hour);
+ mCalendar.set(Calendar.MINUTE, min);
+ mCalendar.set(Calendar.SECOND, 0);
+ mCalendar.set(Calendar.MILLISECOND, 0);
+ return mCalendar.getTimeInMillis();
+ }
+
+ private long addDays(long time, int days) {
+ mCalendar.setTimeInMillis(time);
+ mCalendar.add(Calendar.DATE, days);
+ return mCalendar.getTimeInMillis();
+ }
+
+ private void updateAlarm(String action, int requestCode, int hr, int min) {
+ final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ final long now = System.currentTimeMillis();
+ mCalendar.setTimeInMillis(now);
+ mCalendar.set(Calendar.HOUR_OF_DAY, hr);
+ mCalendar.set(Calendar.MINUTE, min);
+ mCalendar.set(Calendar.SECOND, 0);
+ mCalendar.set(Calendar.MILLISECOND, 0);
+ long time = mCalendar.getTimeInMillis();
+ if (time <= now) {
+ time = addDays(time, 1);
+ }
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
+ new Intent(action).putExtra(EXTRA_TIME, time), PendingIntent.FLAG_UPDATE_CURRENT);
+ alarms.cancel(pendingIntent);
+ if (mConfig.sleepMode != null) {
+ if (DEBUG) Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
+ action, ts(time), time - now, ts(now)));
+ alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
+ }
+ }
+
+ private static String ts(long time) {
+ return new Date(time) + " (" + time + ")";
+ }
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ final long now = System.currentTimeMillis();
+ if (ENTER_ACTION.equals(action) || EXIT_ACTION.equals(action)) {
+ final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
+ if (DEBUG) Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
+ action, ts(schTime), ts(now), now - schTime));
+ } else {
+ if (DEBUG) Slog.d(TAG, action + " fired at " + now);
+ }
+ reevaluateDowntime();
+ updateAlarms();
+ }
+ };
+
+ public interface Callback {
+ void onDowntimeChanged(boolean inDowntime);
+ }
+}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 36be21f..f647037 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -41,6 +41,7 @@ import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArraySet;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -64,7 +65,7 @@ import java.util.Set;
*/
abstract public class ManagedServices {
protected final String TAG = getClass().getSimpleName();
- protected static final boolean DEBUG = true;
+ protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String ENABLED_SERVICES_SEPARATOR = ":";
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d6afe68..f2ac963 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1351,11 +1351,11 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public void setZenModeCondition(Uri conditionId) {
+ public void setZenModeCondition(Condition condition) {
enforceSystemOrSystemUI("INotificationManager.setZenModeCondition");
final long identity = Binder.clearCallingIdentity();
try {
- mConditionProviders.setZenModeCondition(conditionId, "binderCall");
+ mConditionProviders.setZenModeCondition(condition, "binderCall");
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java
index b22ed2d..525f5f8 100644
--- a/services/core/java/com/android/server/notification/ZenLog.java
+++ b/services/core/java/com/android/server/notification/ZenLog.java
@@ -22,8 +22,10 @@ import android.net.Uri;
import android.os.Build;
import android.os.RemoteException;
import android.provider.Settings.Global;
+import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
import android.service.notification.ZenModeConfig;
+import android.util.ArraySet;
import android.util.Slog;
import java.io.PrintWriter;
@@ -52,13 +54,14 @@ public class ZenLog {
private static final int TYPE_ALLOW_DISABLE = 2;
private static final int TYPE_SET_RINGER_MODE = 3;
private static final int TYPE_DOWNTIME = 4;
- private static final int TYPE_ZEN_MODE = 5;
- private static final int TYPE_EXIT_CONDITION = 6;
- private static final int TYPE_SUBSCRIBE = 7;
- private static final int TYPE_UNSUBSCRIBE = 8;
- private static final int TYPE_CONFIG = 9;
- private static final int TYPE_FOLLOW_RINGER_MODE = 10;
- private static final int TYPE_NOT_INTERCEPTED = 11;
+ private static final int TYPE_SET_ZEN_MODE = 5;
+ private static final int TYPE_UPDATE_ZEN_MODE = 6;
+ private static final int TYPE_EXIT_CONDITION = 7;
+ private static final int TYPE_SUBSCRIBE = 8;
+ private static final int TYPE_UNSUBSCRIBE = 9;
+ private static final int TYPE_CONFIG = 10;
+ private static final int TYPE_FOLLOW_RINGER_MODE = 11;
+ private static final int TYPE_NOT_INTERCEPTED = 12;
private static int sNext;
private static int sSize;
@@ -82,17 +85,20 @@ public class ZenLog {
append(TYPE_SET_RINGER_MODE, ringerModeToString(ringerMode));
}
- public static void traceDowntime(boolean enter, int day, int[] days) {
- append(TYPE_DOWNTIME, enter + ",day=" + day + ",days=" + (days != null ? Arrays.asList(days)
- : null));
+ public static void traceDowntime(boolean inDowntime, int day, ArraySet<Integer> days) {
+ append(TYPE_DOWNTIME, inDowntime + ",day=" + day + ",days=" + days);
+ }
+
+ public static void traceSetZenMode(int mode, String reason) {
+ append(TYPE_SET_ZEN_MODE, zenModeToString(mode) + "," + reason);
}
public static void traceUpdateZenMode(int fromMode, int toMode) {
- append(TYPE_ZEN_MODE, zenModeToString(fromMode) + " -> " + zenModeToString(toMode));
+ append(TYPE_UPDATE_ZEN_MODE, zenModeToString(fromMode) + " -> " + zenModeToString(toMode));
}
- public static void traceExitCondition(Uri id, ComponentName component, String reason) {
- append(TYPE_EXIT_CONDITION, id + "," + componentToString(component) + "," + reason);
+ public static void traceExitCondition(Condition c, ComponentName component, String reason) {
+ append(TYPE_EXIT_CONDITION, c + "," + componentToString(component) + "," + reason);
}
public static void traceSubscribe(Uri uri, IConditionProvider provider, RemoteException e) {
@@ -122,7 +128,8 @@ public class ZenLog {
case TYPE_ALLOW_DISABLE: return "allow_disable";
case TYPE_SET_RINGER_MODE: return "set_ringer_mode";
case TYPE_DOWNTIME: return "downtime";
- case TYPE_ZEN_MODE: return "zen_mode";
+ case TYPE_SET_ZEN_MODE: return "set_zen_mode";
+ case TYPE_UPDATE_ZEN_MODE: return "update_zen_mode";
case TYPE_EXIT_CONDITION: return "exit_condition";
case TYPE_SUBSCRIBE: return "subscribe";
case TYPE_UNSUBSCRIBE: return "unsubscribe";
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 9282283..758f334 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -20,10 +20,8 @@ import static android.media.AudioAttributes.USAGE_ALARM;
import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
import static android.media.AudioAttributes.USAGE_UNKNOWN;
-import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.Notification;
-import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -44,6 +42,7 @@ import android.provider.Settings.Secure;
import android.service.notification.NotificationListenerService;
import android.service.notification.ZenModeConfig;
import android.telecomm.TelecommManager;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.R;
@@ -57,8 +56,6 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Date;
import java.util.Objects;
/**
@@ -66,12 +63,7 @@ import java.util.Objects;
*/
public class ZenModeHelper {
private static final String TAG = "ZenModeHelper";
-
- private static final String ACTION_ENTER_ZEN = "enter_zen";
- private static final int REQUEST_CODE_ENTER = 100;
- private static final String ACTION_EXIT_ZEN = "exit_zen";
- private static final int REQUEST_CODE_EXIT = 101;
- private static final String EXTRA_TIME = "time";
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
private final Handler mHandler;
@@ -96,10 +88,8 @@ public class ZenModeHelper {
mSettingsObserver.observe();
final IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_ENTER_ZEN);
- filter.addAction(ACTION_EXIT_ZEN);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
- mContext.registerReceiver(new ZenBroadcastReceiver(), filter);
+ mContext.registerReceiver(mReceiver, filter);
}
public static ZenModeConfig readDefaultConfig(Resources resources) {
@@ -156,7 +146,7 @@ public class ZenModeHelper {
public void requestFromListener(int hints) {
final int newZen = zenFromListenerHint(hints, -1);
if (newZen != -1) {
- setZenMode(newZen);
+ setZenMode(newZen, "listener");
}
}
@@ -179,24 +169,19 @@ public class ZenModeHelper {
return false;
}
}
- // audience has veto power over all following rules
- if (!audienceMatches(record)) {
- ZenLog.traceIntercepted(record, "!audienceMatches");
- return true;
- }
if (isCall(record)) {
if (!mConfig.allowCalls) {
ZenLog.traceIntercepted(record, "!allowCalls");
return true;
}
- return false;
+ return shouldInterceptAudience(record);
}
if (isMessage(record)) {
if (!mConfig.allowMessages) {
ZenLog.traceIntercepted(record, "!allowMessages");
return true;
}
- return false;
+ return shouldInterceptAudience(record);
}
ZenLog.traceIntercepted(record, "!allowed");
return true;
@@ -204,11 +189,20 @@ public class ZenModeHelper {
return false;
}
+ private boolean shouldInterceptAudience(NotificationRecord record) {
+ if (!audienceMatches(record)) {
+ ZenLog.traceIntercepted(record, "!audienceMatches");
+ return true;
+ }
+ return false;
+ }
+
public int getZenMode() {
return mZenMode;
}
- public void setZenMode(int zenModeValue) {
+ public void setZenMode(int zenModeValue, String reason) {
+ ZenLog.traceSetZenMode(zenModeValue, reason);
Global.putInt(mContext.getContentResolver(), Global.ZEN_MODE, zenModeValue);
}
@@ -216,9 +210,6 @@ public class ZenModeHelper {
final int mode = Global.getInt(mContext.getContentResolver(),
Global.ZEN_MODE, Global.ZEN_MODE_OFF);
if (mode != mZenMode) {
- Slog.d(TAG, String.format("updateZenMode: %s -> %s",
- Global.zenModeToString(mZenMode),
- Global.zenModeToString(mode)));
ZenLog.traceUpdateZenMode(mZenMode, mode);
}
mZenMode = mode;
@@ -255,12 +246,12 @@ public class ZenModeHelper {
if (mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS) {
if (ringerMode != AudioManager.RINGER_MODE_SILENT) {
mPreviousRingerMode = ringerMode;
- Slog.d(TAG, "Silencing ringer");
+ if (DEBUG) Slog.d(TAG, "Silencing ringer");
forcedRingerMode = AudioManager.RINGER_MODE_SILENT;
}
} else {
if (ringerMode == AudioManager.RINGER_MODE_SILENT) {
- Slog.d(TAG, "Unsilencing ringer");
+ if (DEBUG) Slog.d(TAG, "Unsilencing ringer");
forcedRingerMode = mPreviousRingerMode != -1 ? mPreviousRingerMode
: AudioManager.RINGER_MODE_NORMAL;
mPreviousRingerMode = -1;
@@ -318,7 +309,6 @@ public class ZenModeHelper {
dispatchOnConfigChanged();
final String val = Integer.toString(mConfig.hashCode());
Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
- updateAlarms();
updateZenMode();
return true;
}
@@ -339,7 +329,7 @@ public class ZenModeHelper {
}
if (newZen != -1) {
ZenLog.traceFollowRingerMode(ringerMode, mZenMode, newZen);
- setZenMode(newZen);
+ setZenMode(newZen, "ringerMode");
}
}
}
@@ -377,7 +367,7 @@ public class ZenModeHelper {
final TelecommManager telecomm =
(TelecommManager) mContext.getSystemService(Context.TELECOMM_SERVICE);
mDefaultPhoneApp = telecomm != null ? telecomm.getDefaultPhoneApp() : null;
- Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
+ if (DEBUG) Slog.d(TAG, "Default phone app: " + mDefaultPhoneApp);
}
return pkg != null && mDefaultPhoneApp != null
&& pkg.equals(mDefaultPhoneApp.getPackageName());
@@ -409,40 +399,6 @@ public class ZenModeHelper {
}
}
- private void updateAlarms() {
- updateAlarm(ACTION_ENTER_ZEN, REQUEST_CODE_ENTER,
- mConfig.sleepStartHour, mConfig.sleepStartMinute);
- updateAlarm(ACTION_EXIT_ZEN, REQUEST_CODE_EXIT,
- mConfig.sleepEndHour, mConfig.sleepEndMinute);
- }
-
- private void updateAlarm(String action, int requestCode, int hr, int min) {
- final AlarmManager alarms = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
- final long now = System.currentTimeMillis();
- final Calendar c = Calendar.getInstance();
- c.setTimeInMillis(now);
- c.set(Calendar.HOUR_OF_DAY, hr);
- c.set(Calendar.MINUTE, min);
- c.set(Calendar.SECOND, 0);
- c.set(Calendar.MILLISECOND, 0);
- if (c.getTimeInMillis() <= now) {
- c.add(Calendar.DATE, 1);
- }
- final long time = c.getTimeInMillis();
- final PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, requestCode,
- new Intent(action).putExtra(EXTRA_TIME, time), PendingIntent.FLAG_UPDATE_CURRENT);
- alarms.cancel(pendingIntent);
- if (mConfig.sleepMode != null) {
- Slog.d(TAG, String.format("Scheduling %s for %s, %s in the future, now=%s",
- action, ts(time), time - now, ts(now)));
- alarms.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
- }
- }
-
- private static String ts(long time) {
- return new Date(time) + " (" + time + ")";
- }
-
private final Runnable mRingerModeChanged = new Runnable() {
@Override
public void run() {
@@ -475,47 +431,12 @@ public class ZenModeHelper {
}
}
- private class ZenBroadcastReceiver extends BroadcastReceiver {
- private final Calendar mCalendar = Calendar.getInstance();
-
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (ACTION_ENTER_ZEN.equals(intent.getAction())) {
- setZenMode(intent, Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
- } else if (ACTION_EXIT_ZEN.equals(intent.getAction())) {
- setZenMode(intent, Global.ZEN_MODE_OFF);
- } else if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(intent.getAction())) {
- mHandler.post(mRingerModeChanged);
- }
- }
-
- private void setZenMode(Intent intent, int zenModeValue) {
- final long schTime = intent.getLongExtra(EXTRA_TIME, 0);
- final long now = System.currentTimeMillis();
- Slog.d(TAG, String.format("%s scheduled for %s, fired at %s, delta=%s",
- intent.getAction(), ts(schTime), ts(now), now - schTime));
-
- final int[] days = ZenModeConfig.tryParseDays(mConfig.sleepMode);
- boolean enter = false;
- final int day = getDayOfWeek(schTime);
- if (days != null) {
- for (int i = 0; i < days.length; i++) {
- if (days[i] == day) {
- enter = true;
- ZenModeHelper.this.setZenMode(zenModeValue);
- break;
- }
- }
- }
- ZenLog.traceDowntime(enter, day, days);
- updateAlarms();
+ mHandler.post(mRingerModeChanged);
}
-
- private int getDayOfWeek(long time) {
- mCalendar.setTimeInMillis(time);
- return mCalendar.get(Calendar.DAY_OF_WEEK);
- }
- }
+ };
public static class Callback {
void onConfigChanged() {}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index b261ef5..d1e03ec 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -16,33 +16,23 @@
package com.android.server.pm;
-import com.android.server.SystemService;
-
import android.content.Context;
import android.content.pm.PackageStats;
-import android.net.LocalSocket;
-import android.net.LocalSocketAddress;
+import android.os.Build;
import android.util.Slog;
+import dalvik.system.VMRuntime;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.List;
+import com.android.internal.os.InstallerConnection;
+import com.android.server.SystemService;
public final class Installer extends SystemService {
private static final String TAG = "Installer";
- private static final boolean LOCAL_DEBUG = false;
-
- InputStream mIn;
- OutputStream mOut;
- LocalSocket mSocket;
-
- byte buf[] = new byte[1024];
- int buflen = 0;
+ private final InstallerConnection mInstaller;
public Installer(Context context) {
super(context);
+ mInstaller = new InstallerConnection();
}
@Override
@@ -51,154 +41,6 @@ public final class Installer extends SystemService {
ping();
}
- private boolean connect() {
- if (mSocket != null) {
- return true;
- }
- Slog.i(TAG, "connecting...");
- try {
- mSocket = new LocalSocket();
-
- LocalSocketAddress address = new LocalSocketAddress("installd",
- LocalSocketAddress.Namespace.RESERVED);
-
- mSocket.connect(address);
-
- mIn = mSocket.getInputStream();
- mOut = mSocket.getOutputStream();
- } catch (IOException ex) {
- disconnect();
- return false;
- }
- return true;
- }
-
- private void disconnect() {
- Slog.i(TAG, "disconnecting...");
- try {
- if (mSocket != null)
- mSocket.close();
- } catch (IOException ex) {
- }
- try {
- if (mIn != null)
- mIn.close();
- } catch (IOException ex) {
- }
- try {
- if (mOut != null)
- mOut.close();
- } catch (IOException ex) {
- }
- mSocket = null;
- mIn = null;
- mOut = null;
- }
-
- private boolean readBytes(byte buffer[], int len) {
- int off = 0, count;
- if (len < 0)
- return false;
- while (off != len) {
- try {
- count = mIn.read(buffer, off, len - off);
- if (count <= 0) {
- Slog.e(TAG, "read error " + count);
- break;
- }
- off += count;
- } catch (IOException ex) {
- Slog.e(TAG, "read exception");
- break;
- }
- }
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "read " + len + " bytes");
- }
- if (off == len)
- return true;
- disconnect();
- return false;
- }
-
- private boolean readReply() {
- int len;
- buflen = 0;
- if (!readBytes(buf, 2))
- return false;
- len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
- if ((len < 1) || (len > 1024)) {
- Slog.e(TAG, "invalid reply length (" + len + ")");
- disconnect();
- return false;
- }
- if (!readBytes(buf, len))
- return false;
- buflen = len;
- return true;
- }
-
- private boolean writeCommand(String _cmd) {
- byte[] cmd = _cmd.getBytes();
- int len = cmd.length;
- if ((len < 1) || (len > 1024))
- return false;
- buf[0] = (byte) (len & 0xff);
- buf[1] = (byte) ((len >> 8) & 0xff);
- try {
- mOut.write(buf, 0, 2);
- mOut.write(cmd, 0, len);
- } catch (IOException ex) {
- Slog.e(TAG, "write error");
- disconnect();
- return false;
- }
- return true;
- }
-
- private synchronized String transaction(String cmd) {
- if (!connect()) {
- Slog.e(TAG, "connection failed");
- return "-1";
- }
-
- if (!writeCommand(cmd)) {
- /*
- * If installd died and restarted in the background (unlikely but
- * possible) we'll fail on the next write (this one). Try to
- * reconnect and write the command one more time before giving up.
- */
- Slog.e(TAG, "write command failed? reconnect!");
- if (!connect() || !writeCommand(cmd)) {
- return "-1";
- }
- }
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "send: '" + cmd + "'");
- }
- if (readReply()) {
- String s = new String(buf, 0, buflen);
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "recv: '" + s + "'");
- }
- return s;
- } else {
- if (LOCAL_DEBUG) {
- Slog.i(TAG, "fail");
- }
- return "-1";
- }
- }
-
- private int execute(String cmd) {
- String res = transaction(cmd);
- try {
- return Integer.parseInt(res);
- } catch (NumberFormatException ex) {
- return -1;
- }
- }
-
public int install(String name, int uid, int gid, String seinfo) {
StringBuilder builder = new StringBuilder("install");
builder.append(' ');
@@ -209,11 +51,16 @@ public final class Installer extends SystemService {
builder.append(gid);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
StringBuilder builder = new StringBuilder("patchoat");
builder.append(' ');
builder.append(apkPath);
@@ -224,37 +71,34 @@ public final class Installer extends SystemService {
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
- StringBuilder builder = new StringBuilder("patchoat");
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
- builder.append(uid);
- builder.append(isPublic ? " 1" : " 0");
- builder.append(" *"); // No pkgName arg present
- builder.append(' ');
- builder.append(instructionSet);
- return execute(builder.toString());
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
+ return mInstaller.patchoat(apkPath, uid, isPublic, instructionSet);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
- StringBuilder builder = new StringBuilder("dexopt");
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
- builder.append(uid);
- builder.append(isPublic ? " 1" : " 0");
- builder.append(" *"); // No pkgName arg present
- builder.append(' ');
- builder.append(instructionSet);
- return execute(builder.toString());
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
+ return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
builder.append(apkPath);
@@ -265,7 +109,7 @@ public final class Installer extends SystemService {
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int idmap(String targetApkPath, String overlayApkPath, int uid) {
@@ -276,10 +120,15 @@ public final class Installer extends SystemService {
builder.append(overlayApkPath);
builder.append(' ');
builder.append(uid);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int movedex(String srcPath, String dstPath, String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
StringBuilder builder = new StringBuilder("movedex");
builder.append(' ');
builder.append(srcPath);
@@ -287,16 +136,21 @@ public final class Installer extends SystemService {
builder.append(dstPath);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int rmdex(String codePath, String instructionSet) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+
StringBuilder builder = new StringBuilder("rmdex");
builder.append(' ');
builder.append(codePath);
builder.append(' ');
builder.append(instructionSet);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int remove(String name, int userId) {
@@ -305,7 +159,7 @@ public final class Installer extends SystemService {
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int rename(String oldname, String newname) {
@@ -314,7 +168,7 @@ public final class Installer extends SystemService {
builder.append(oldname);
builder.append(' ');
builder.append(newname);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int fixUid(String name, int uid, int gid) {
@@ -325,7 +179,7 @@ public final class Installer extends SystemService {
builder.append(uid);
builder.append(' ');
builder.append(gid);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int deleteCacheFiles(String name, int userId) {
@@ -334,7 +188,7 @@ public final class Installer extends SystemService {
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int deleteCodeCacheFiles(String name, int userId) {
@@ -343,7 +197,7 @@ public final class Installer extends SystemService {
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int createUserData(String name, int uid, int userId, String seinfo) {
@@ -356,21 +210,21 @@ public final class Installer extends SystemService {
builder.append(userId);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int createUserConfig(int userId) {
StringBuilder builder = new StringBuilder("mkuserconfig");
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int removeUserDataDirs(int userId) {
StringBuilder builder = new StringBuilder("rmuser");
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int clearUserData(String name, int userId) {
@@ -379,11 +233,11 @@ public final class Installer extends SystemService {
builder.append(name);
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public boolean ping() {
- if (execute("ping") < 0) {
+ if (mInstaller.execute("ping") < 0) {
return false;
} else {
return true;
@@ -391,18 +245,25 @@ public final class Installer extends SystemService {
}
public int pruneDexCache(String cacheSubDir) {
- return execute("prunedexcache " + cacheSubDir);
+ return mInstaller.execute("prunedexcache " + cacheSubDir);
}
public int freeCache(long freeStorageSize) {
StringBuilder builder = new StringBuilder("freecache");
builder.append(' ');
builder.append(String.valueOf(freeStorageSize));
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
+ for (String instructionSet : instructionSets) {
+ if (!isValidInstructionSet(instructionSet)) {
+ Slog.e(TAG, "Invalid instruction set: " + instructionSet);
+ return -1;
+ }
+ }
+
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
builder.append(pkgName);
@@ -423,7 +284,7 @@ public final class Installer extends SystemService {
// just the primary.
builder.append(instructionSets[0]);
- String s = transaction(builder.toString());
+ String s = mInstaller.transact(builder.toString());
String res[] = s.split(" ");
if ((res == null) || (res.length != 5)) {
@@ -441,7 +302,7 @@ public final class Installer extends SystemService {
}
public int moveFiles() {
- return execute("movefiles");
+ return mInstaller.execute("movefiles");
}
/**
@@ -467,7 +328,7 @@ public final class Installer extends SystemService {
builder.append(' ');
builder.append(userId);
- return execute(builder.toString());
+ return mInstaller.execute(builder.toString());
}
public boolean restoreconData(String pkgName, String seinfo, int uid) {
@@ -478,6 +339,23 @@ public final class Installer extends SystemService {
builder.append(seinfo != null ? seinfo : "!");
builder.append(' ');
builder.append(uid);
- return (execute(builder.toString()) == 0);
+ return (mInstaller.execute(builder.toString()) == 0);
+ }
+
+ /**
+ * Returns true iff. {@code instructionSet} is a valid instruction set.
+ */
+ private static boolean isValidInstructionSet(String instructionSet) {
+ if (instructionSet == null) {
+ return false;
+ }
+
+ for (String abi : Build.SUPPORTED_ABIS) {
+ if (instructionSet.equals(VMRuntime.getInstructionSet(abi))) {
+ return true;
+ }
+ }
+
+ return false;
}
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index c7e3fb7..dca8ad4 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -36,19 +36,23 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG;
import android.app.ActivityManager;
import android.app.AppOpsManager;
+import android.app.PackageDeleteObserver;
+import android.app.PackageInstallObserver;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.IPackageDeleteObserver2;
+import android.content.IntentSender;
+import android.content.IntentSender.SendIntentException;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageInstallerCallback;
import android.content.pm.IPackageInstallerSession;
-import android.content.pm.InstallSessionInfo;
-import android.content.pm.InstallSessionParams;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
@@ -63,6 +67,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.system.ErrnoException;
import android.system.Os;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.AtomicFile;
@@ -279,8 +284,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
final File sessionStageDir = new File(readStringAttribute(in, ATTR_SESSION_STAGE_DIR));
final boolean sealed = readBooleanAttribute(in, ATTR_SEALED);
- final InstallSessionParams params = new InstallSessionParams(
- InstallSessionParams.MODE_INVALID);
+ final SessionParams params = new SessionParams(
+ SessionParams.MODE_INVALID);
params.mode = readIntAttribute(in, ATTR_MODE);
params.installFlags = readIntAttribute(in, ATTR_INSTALL_FLAGS);
params.installLocation = readIntAttribute(in, ATTR_INSTALL_LOCATION);
@@ -292,9 +297,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
params.referrerUri = readUriAttribute(in, ATTR_REFERRER_URI);
params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
- return new PackageInstallerSession(mInternalCallback, mPm, mInstallThread.getLooper(),
- sessionId, userId, installerPackageName, params, createdMillis, sessionStageDir,
- sealed);
+ return new PackageInstallerSession(mInternalCallback, mContext, mPm,
+ mInstallThread.getLooper(), sessionId, userId, installerPackageName, params,
+ createdMillis, sessionStageDir, sealed);
}
private void writeSessionsLocked() {
@@ -326,7 +331,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
private void writeSessionLocked(XmlSerializer out, PackageInstallerSession session)
throws IOException {
- final InstallSessionParams params = session.params;
+ final SessionParams params = session.params;
final Snapshot snapshot = session.snapshot();
out.startTag(null, TAG_SESSION);
@@ -366,7 +371,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public int createSession(InstallSessionParams params, String installerPackageName, int userId) {
+ public int createSession(SessionParams params, String installerPackageName, int userId) {
final int callingUid = Binder.getCallingUid();
mPm.enforceCrossUserPermission(callingUid, userId, true, "createSession");
@@ -389,8 +394,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
switch (params.mode) {
- case InstallSessionParams.MODE_FULL_INSTALL:
- case InstallSessionParams.MODE_INHERIT_EXISTING:
+ case SessionParams.MODE_FULL_INSTALL:
+ case SessionParams.MODE_INHERIT_EXISTING:
break;
default:
throw new IllegalArgumentException("Params must have valid mode set");
@@ -437,7 +442,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
final long createdMillis = System.currentTimeMillis();
final File sessionStageDir = prepareSessionStageDir(sessionId);
- session = new PackageInstallerSession(mInternalCallback, mPm,
+ session = new PackageInstallerSession(mInternalCallback, mContext, mPm,
mInstallThread.getLooper(), sessionId, userId, installerPackageName, params,
createdMillis, sessionStageDir, false);
mSessions.put(sessionId, session);
@@ -501,7 +506,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public InstallSessionInfo getSessionInfo(int sessionId) {
+ public SessionInfo getSessionInfo(int sessionId) {
synchronized (mSessions) {
final PackageInstallerSession session = mSessions.get(sessionId);
if (!isCallingUidOwner(session)) {
@@ -512,11 +517,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public List<InstallSessionInfo> getAllSessions(int userId) {
+ public List<SessionInfo> getAllSessions(int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getAllSessions");
enforceCallerCanReadSessions();
- final List<InstallSessionInfo> result = new ArrayList<>();
+ final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
@@ -529,11 +534,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public List<InstallSessionInfo> getMySessions(String installerPackageName, int userId) {
+ public List<SessionInfo> getMySessions(String installerPackageName, int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "getMySessions");
mAppOps.checkPackage(Binder.getCallingUid(), installerPackageName);
- final List<InstallSessionInfo> result = new ArrayList<>();
+ final List<SessionInfo> result = new ArrayList<>();
synchronized (mSessions) {
for (int i = 0; i < mSessions.size(); i++) {
final PackageInstallerSession session = mSessions.valueAt(i);
@@ -547,37 +552,26 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
@Override
- public void uninstall(String packageName, int flags, IPackageDeleteObserver2 observer,
- int userId) {
+ public void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) {
mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstall");
+ final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
+ statusReceiver);
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
== PackageManager.PERMISSION_GRANTED) {
// Sweet, call straight through!
- mPm.deletePackage(packageName, observer, userId, flags);
+ mPm.deletePackage(packageName, adapter.getBinder(), userId, flags);
} else {
// Take a short detour to confirm with user
final Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.fromParts("package", packageName, null));
- intent.putExtra(PackageInstaller.EXTRA_CALLBACK, observer.asBinder());
- try {
- observer.onUserActionRequired(intent);
- } catch (RemoteException ignored) {
- }
+ intent.putExtra(PackageInstaller.EXTRA_CALLBACK, adapter.getBinder().asBinder());
+ adapter.onUserActionRequired(intent);
}
}
@Override
- public void uninstallSplit(String basePackageName, String overlayName, int flags,
- IPackageDeleteObserver2 observer, int userId) {
- mPm.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, "uninstallSplit");
-
- // TODO: flesh out once PM has split support
- throw new UnsupportedOperationException();
- }
-
- @Override
public void setPermissionsResult(int sessionId, boolean accepted) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, TAG);
@@ -636,6 +630,87 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
}
}
+ static class PackageDeleteObserverAdapter extends PackageDeleteObserver {
+ private final Context mContext;
+ private final IntentSender mTarget;
+
+ public PackageDeleteObserverAdapter(Context context, IntentSender target) {
+ mContext = context;
+ mTarget = target;
+ }
+
+ @Override
+ public void onUserActionRequired(Intent intent) {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_USER_ACTION_REQUIRED);
+ fillIn.putExtra(Intent.EXTRA_INTENT, intent);
+ try {
+ mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+
+ @Override
+ public void onPackageDeleted(String basePackageName, int returnCode, String msg) {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageManager.deleteStatusToPublicStatus(returnCode));
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
+ PackageManager.deleteStatusToString(returnCode, msg));
+ fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
+ try {
+ mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+ }
+
+ static class PackageInstallObserverAdapter extends PackageInstallObserver {
+ private final Context mContext;
+ private final IntentSender mTarget;
+
+ public PackageInstallObserverAdapter(Context context, IntentSender target) {
+ mContext = context;
+ mTarget = target;
+ }
+
+ @Override
+ public void onUserActionRequired(Intent intent) {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_USER_ACTION_REQUIRED);
+ fillIn.putExtra(Intent.EXTRA_INTENT, intent);
+ try {
+ mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+
+ @Override
+ public void onPackageInstalled(String basePackageName, int returnCode, String msg,
+ Bundle extras) {
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
+ PackageManager.installStatusToPublicStatus(returnCode));
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
+ PackageManager.installStatusToString(returnCode, msg));
+ fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode);
+ if (extras != null) {
+ final String existing = extras.getString(
+ PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE);
+ if (!TextUtils.isEmpty(existing)) {
+ fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAMES, new String[] {
+ existing });
+ }
+ }
+ try {
+ mTarget.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (SendIntentException ignored) {
+ }
+ }
+ }
+
private static class Callbacks extends Handler {
private static final int MSG_SESSION_CREATED = 1;
private static final int MSG_SESSION_OPENED = 2;
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a3184f0..5ef24f2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -25,13 +25,15 @@ import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_WRONLY;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageInstallObserver2;
import android.content.pm.IPackageInstallerSession;
-import android.content.pm.InstallSessionInfo;
-import android.content.pm.InstallSessionParams;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ApkLite;
@@ -59,6 +61,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
+import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter;
import libcore.io.Libcore;
@@ -81,13 +84,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// TODO: treat INHERIT_EXISTING as installExistingPackage()
private final PackageInstallerService.InternalCallback mCallback;
+ private final Context mContext;
private final PackageManagerService mPm;
private final Handler mHandler;
final int sessionId;
final int userId;
final String installerPackageName;
- final InstallSessionParams params;
+ final SessionParams params;
final long createdMillis;
final File sessionStageDir;
@@ -159,10 +163,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
};
public PackageInstallerSession(PackageInstallerService.InternalCallback callback,
- PackageManagerService pm, Looper looper, int sessionId, int userId,
- String installerPackageName, InstallSessionParams params, long createdMillis,
+ Context context, PackageManagerService pm, Looper looper, int sessionId, int userId,
+ String installerPackageName, SessionParams params, long createdMillis,
File sessionStageDir, boolean sealed) {
mCallback = callback;
+ mContext = context;
mPm = pm;
mHandler = new Handler(looper, mHandlerCallback);
@@ -188,8 +193,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
computeProgressLocked();
}
- public InstallSessionInfo generateInfo() {
- final InstallSessionInfo info = new InstallSessionInfo();
+ public SessionInfo generateInfo() {
+ final SessionInfo info = new SessionInfo();
info.sessionId = sessionId;
info.installerPackageName = installerPackageName;
@@ -246,8 +251,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@Override
- public String[] list() {
- assertNotSealed("list");
+ public String[] getNames() {
+ assertNotSealed("getNames");
return sessionStageDir.list();
}
@@ -337,9 +342,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
@Override
- public void commit(IPackageInstallObserver2 observer) {
- Preconditions.checkNotNull(observer);
- mHandler.obtainMessage(MSG_COMMIT, observer).sendToTarget();
+ public void commit(IntentSender statusReceiver) {
+ Preconditions.checkNotNull(statusReceiver);
+
+ final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(mContext,
+ statusReceiver);
+ mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
}
private void commitLocked() throws PackageManagerException {
@@ -385,7 +393,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Inherit any packages and native libraries from existing install that
// haven't been overridden.
- if (params.mode == InstallSessionParams.MODE_INHERIT_EXISTING) {
+ if (params.mode == SessionParams.MODE_INHERIT_EXISTING) {
spliceExistingFilesIntoStage();
}
@@ -396,7 +404,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
- final IPackageInstallObserver2 remoteObserver = mRemoteObserver;
final IPackageInstallObserver2 localObserver = new IPackageInstallObserver2.Stub() {
@Override
public void onUserActionRequired(Intent intent) {
@@ -488,7 +495,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// currently relying on PMS to do this.
// TODO: teach about compatible upgrade keysets.
- if (params.mode == InstallSessionParams.MODE_FULL_INSTALL) {
+ if (params.mode == SessionParams.MODE_FULL_INSTALL) {
// Full installs must include a base package
if (!seenSplits.contains(null)) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 89bd1d4..c1f7e85 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -107,12 +107,12 @@ import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
-import android.content.pm.InstallSessionParams;
import android.content.pm.InstrumentationInfo;
import android.content.pm.ManifestDigest;
import android.content.pm.PackageCleanItem;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
+import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.LegacyPackageDeleteObserver;
import android.content.pm.PackageParser.ActivityIntentInfo;
@@ -1394,16 +1394,27 @@ public class PackageManagerService extends IPackageManager.Stub {
* list of process files because dexopt will have been run
* if necessary during zygote startup.
*/
- String bootClassPath = System.getProperty("java.boot.class.path");
+ final String bootClassPath = System.getenv("BOOTCLASSPATH");
+ final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
+
if (bootClassPath != null) {
- String[] paths = splitString(bootClassPath, ':');
- for (int i=0; i<paths.length; i++) {
- alreadyDexOpted.add(paths[i]);
+ String[] bootClassPathElements = splitString(bootClassPath, ':');
+ for (String element : bootClassPathElements) {
+ alreadyDexOpted.add(element);
}
} else {
Slog.w(TAG, "No BOOTCLASSPATH found!");
}
+ if (systemServerClassPath != null) {
+ String[] systemServerClassPathElements = splitString(systemServerClassPath, ':');
+ for (String element : systemServerClassPathElements) {
+ alreadyDexOpted.add(element);
+ }
+ } else {
+ Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
+ }
+
boolean didDexOptLibraryOrTool = false;
final List<String> allInstructionSets = getAllInstructionSets();
@@ -2920,7 +2931,8 @@ public class PackageManagerService extends IPackageManager.Stub {
findPreferredActivity(intent, resolvedType,
flags, query, 0, false, true, false, userId);
// Add the new activity as the last chosen for this filter
- addPreferredActivityInternal(filter, match, null, activity, false, userId);
+ addPreferredActivityInternal(filter, match, null, activity, false, userId,
+ "Setting last chosen");
}
@Override
@@ -7835,7 +7847,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
void installStage(String packageName, File stageDir, IPackageInstallObserver2 observer,
- InstallSessionParams params, String installerPackageName, int installerUid,
+ PackageInstaller.SessionParams params, String installerPackageName, int installerUid,
UserHandle user) {
final VerificationParams verifParams = new VerificationParams(null, params.originatingUri,
params.referrerUri, installerUid, null);
@@ -11462,11 +11474,13 @@ public class PackageManagerService extends IPackageManager.Stub {
@Override
public void addPreferredActivity(IntentFilter filter, int match,
ComponentName[] set, ComponentName activity, int userId) {
- addPreferredActivityInternal(filter, match, set, activity, true, userId);
+ addPreferredActivityInternal(filter, match, set, activity, true, userId,
+ "Adding preferred");
}
private void addPreferredActivityInternal(IntentFilter filter, int match,
- ComponentName[] set, ComponentName activity, boolean always, int userId) {
+ ComponentName[] set, ComponentName activity, boolean always, int userId,
+ String opname) {
// writer
int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, true, "add preferred activity");
@@ -11488,10 +11502,11 @@ public class PackageManagerService extends IPackageManager.Stub {
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
}
- Slog.i(TAG, "Adding preferred activity " + activity + " for user " + userId + " :");
+ PreferredIntentResolver pir = mSettings.editPreferredActivitiesLPw(userId);
+ Slog.i(TAG, opname + " activity " + activity.flattenToShortString() + " for user "
+ + userId + ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
- mSettings.editPreferredActivitiesLPw(userId).addFilter(
- new PreferredActivity(filter, match, set, activity, always));
+ pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
mSettings.writePackageRestrictionsLPr(userId);
}
}
@@ -11514,7 +11529,6 @@ public class PackageManagerService extends IPackageManager.Stub {
final int callingUid = Binder.getCallingUid();
enforceCrossUserPermission(callingUid, userId, true, "replace preferred activity");
- final int callingUserId = UserHandle.getUserId(callingUid);
synchronized (mPackages) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -11529,30 +11543,61 @@ public class PackageManagerService extends IPackageManager.Stub {
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
}
- PreferredIntentResolver pir = mSettings.mPreferredActivities.get(callingUserId);
+ PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
if (pir != null) {
- Intent intent = new Intent(filter.getAction(0)).addCategory(filter.getCategory(0));
- if (filter.countDataSchemes() == 1) {
- Uri.Builder builder = new Uri.Builder();
- builder.scheme(filter.getDataScheme(0));
- intent.setData(builder.build());
- }
- List<PreferredActivity> matches = pir.queryIntent(
- intent, null, true, callingUserId);
+ // Get all of the existing entries that exactly match this filter.
+ ArrayList<PreferredActivity> existing = pir.findFilters(filter);
+ if (existing != null && existing.size() == 1) {
+ PreferredActivity cur = existing.get(0);
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Checking replace of preferred:");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ if (!cur.mPref.mAlways) {
+ Slog.i(TAG, " -- CUR; not mAlways!");
+ } else {
+ Slog.i(TAG, " -- CUR: mMatch=" + cur.mPref.mMatch);
+ Slog.i(TAG, " -- CUR: mSet="
+ + Arrays.toString(cur.mPref.mSetComponents));
+ Slog.i(TAG, " -- CUR: mComponent=" + cur.mPref.mShortComponent);
+ Slog.i(TAG, " -- NEW: mMatch="
+ + (match&IntentFilter.MATCH_CATEGORY_MASK));
+ Slog.i(TAG, " -- CUR: mSet=" + Arrays.toString(set));
+ Slog.i(TAG, " -- CUR: mComponent=" + activity.flattenToShortString());
+ }
+ }
+ if (cur.mPref.mAlways && cur.mPref.mComponent.equals(activity)
+ && cur.mPref.mMatch == (match&IntentFilter.MATCH_CATEGORY_MASK)
+ && cur.mPref.sameSet(set)) {
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Replacing with same preferred activity "
+ + cur.mPref.mShortComponent + " for user "
+ + userId + ":");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ } else {
+ Slog.i(TAG, "Replacing with same preferred activity "
+ + cur.mPref.mShortComponent + " for user "
+ + userId);
+ }
+ return;
+ }
+ }
+
if (DEBUG_PREFERRED) {
- Slog.i(TAG, matches.size() + " preferred matches for " + intent);
+ Slog.i(TAG, existing.size() + " existing preferred matches for:");
+ filter.dump(new LogPrinter(Log.INFO, TAG), " ");
}
- for (int i = 0; i < matches.size(); i++) {
- PreferredActivity pa = matches.get(i);
+ for (int i = 0; i < existing.size(); i++) {
+ PreferredActivity pa = existing.get(i);
if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Removing preferred activity "
+ Slog.i(TAG, "Removing existing preferred activity "
+ pa.mPref.mComponent + ":");
- filter.dump(new LogPrinter(Log.INFO, TAG), " ");
+ pa.dump(new LogPrinter(Log.INFO, TAG), " ");
}
pir.removeFilter(pa);
}
}
- addPreferredActivityInternal(filter, match, set, activity, true, callingUserId);
+ addPreferredActivityInternal(filter, match, set, activity, true, userId,
+ "Replacing preferred");
}
}
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index f437372..69c1909 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -44,10 +44,10 @@ public class PreferredComponent {
// Whether this is to be the one that's always chosen. If false, it's the most recently chosen.
public boolean mAlways;
- private final String[] mSetPackages;
- private final String[] mSetClasses;
- private final String[] mSetComponents;
- private final String mShortComponent;
+ final String[] mSetPackages;
+ final String[] mSetClasses;
+ final String[] mSetComponents;
+ final String mShortComponent;
private String mParseError;
private final Callbacks mCallbacks;
@@ -193,7 +193,12 @@ public class PreferredComponent {
}
public boolean sameSet(List<ResolveInfo> query, int priority) {
- if (mSetPackages == null) return false;
+ if (mSetPackages == null) {
+ return query == null;
+ }
+ if (query == null) {
+ return false;
+ }
final int NQ = query.size();
final int NS = mSetPackages.length;
int numMatch = 0;
@@ -215,6 +220,27 @@ public class PreferredComponent {
return numMatch == NS;
}
+ public boolean sameSet(ComponentName[] comps) {
+ if (mSetPackages == null) return false;
+ final int NQ = comps.length;
+ final int NS = mSetPackages.length;
+ int numMatch = 0;
+ for (int i=0; i<NQ; i++) {
+ ComponentName cn = comps[i];
+ boolean good = false;
+ for (int j=0; j<NS; j++) {
+ if (mSetPackages[j].equals(cn.getPackageName())
+ && mSetClasses[j].equals(cn.getClassName())) {
+ numMatch++;
+ good = true;
+ break;
+ }
+ }
+ if (!good) return false;
+ }
+ return numMatch == NS;
+ }
+
public void dump(PrintWriter out, String prefix, Object ident) {
out.print(prefix); out.print(
Integer.toHexString(System.identityHashCode(ident)));
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 2b4a24a..46497242 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -406,7 +406,6 @@ final class Notifier {
private void sendNextBroadcast() {
final int powerState;
- final int goToSleepReason;
synchronized (mLock) {
if (mBroadcastedPowerState == POWER_STATE_UNKNOWN) {
// Broadcasted power state is unknown. Send wake up.
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index f0fd911..9734bd4 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -56,10 +56,9 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.SystemService;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.WorkSource;
-import android.os.Parcel;
-import android.os.ServiceManager;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.util.EventLog;
@@ -709,7 +708,6 @@ public final class PowerManagerService extends com.android.server.SystemService
if (mLowPowerModeEnabled != lowPowerModeEnabled) {
mLowPowerModeEnabled = lowPowerModeEnabled;
powerHintInternal(POWER_HINT_LOW_POWER_MODE, lowPowerModeEnabled ? 1 : 0);
- setSurfaceFlingerLowPowerMode(lowPowerModeEnabled ? 1 : 0);
mLowPowerModeEnabled = lowPowerModeEnabled;
BackgroundThread.getHandler().post(new Runnable() {
@Override
@@ -820,17 +818,12 @@ public final class PowerManagerService extends com.android.server.SystemService
+ " [" + wakeLock.mTag + "], flags=0x" + Integer.toHexString(flags));
}
- mWakeLocks.remove(index);
- notifyWakeLockReleasedLocked(wakeLock);
- wakeLock.mLock.unlinkToDeath(wakeLock, 0);
-
if ((flags & PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE) != 0) {
mRequestWaitForNegativeProximity = true;
}
- applyWakeLockFlagsOnReleaseLocked(wakeLock);
- mDirty |= DIRTY_WAKE_LOCKS;
- updatePowerStateLocked();
+ wakeLock.mLock.unlinkToDeath(wakeLock, 0);
+ removeWakeLockLocked(wakeLock, index);
}
}
@@ -846,15 +839,19 @@ public final class PowerManagerService extends com.android.server.SystemService
return;
}
- mWakeLocks.remove(index);
- notifyWakeLockReleasedLocked(wakeLock);
-
- applyWakeLockFlagsOnReleaseLocked(wakeLock);
- mDirty |= DIRTY_WAKE_LOCKS;
- updatePowerStateLocked();
+ removeWakeLockLocked(wakeLock, index);
}
}
+ private void removeWakeLockLocked(WakeLock wakeLock, int index) {
+ mWakeLocks.remove(index);
+ notifyWakeLockReleasedLocked(wakeLock);
+
+ applyWakeLockFlagsOnReleaseLocked(wakeLock);
+ mDirty |= DIRTY_WAKE_LOCKS;
+ updatePowerStateLocked();
+ }
+
private void applyWakeLockFlagsOnReleaseLocked(WakeLock wakeLock) {
if ((wakeLock.mFlags & PowerManager.ON_AFTER_RELEASE) != 0
&& isScreenLock(wakeLock)) {
@@ -977,21 +974,26 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- mNotifier.onUserActivity(event, uid);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
+ try {
+ mNotifier.onUserActivity(event, uid);
- if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
- if (eventTime > mLastUserActivityTimeNoChangeLights
- && eventTime > mLastUserActivityTime) {
- mLastUserActivityTimeNoChangeLights = eventTime;
- mDirty |= DIRTY_USER_ACTIVITY;
- return true;
- }
- } else {
- if (eventTime > mLastUserActivityTime) {
- mLastUserActivityTime = eventTime;
- mDirty |= DIRTY_USER_ACTIVITY;
- return true;
+ if ((flags & PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) != 0) {
+ if (eventTime > mLastUserActivityTimeNoChangeLights
+ && eventTime > mLastUserActivityTime) {
+ mLastUserActivityTimeNoChangeLights = eventTime;
+ mDirty |= DIRTY_USER_ACTIVITY;
+ return true;
+ }
+ } else {
+ if (eventTime > mLastUserActivityTime) {
+ mLastUserActivityTime = eventTime;
+ mDirty |= DIRTY_USER_ACTIVITY;
+ return true;
+ }
}
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return false;
}
@@ -1014,25 +1016,30 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- switch (mWakefulness) {
- case WAKEFULNESS_ASLEEP:
- Slog.i(TAG, "Waking up from sleep (uid " + uid +")...");
- break;
- case WAKEFULNESS_DREAMING:
- Slog.i(TAG, "Waking up from dream (uid " + uid +")...");
- break;
- case WAKEFULNESS_DOZING:
- Slog.i(TAG, "Waking up from dozing (uid " + uid +")...");
- break;
- }
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
+ try {
+ switch (mWakefulness) {
+ case WAKEFULNESS_ASLEEP:
+ Slog.i(TAG, "Waking up from sleep (uid " + uid +")...");
+ break;
+ case WAKEFULNESS_DREAMING:
+ Slog.i(TAG, "Waking up from dream (uid " + uid +")...");
+ break;
+ case WAKEFULNESS_DOZING:
+ Slog.i(TAG, "Waking up from dozing (uid " + uid +")...");
+ break;
+ }
- mLastWakeTime = eventTime;
- mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_AWAKE;
- setInteractiveStateLocked(true, 0);
+ mLastWakeTime = eventTime;
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_AWAKE;
+ setInteractiveStateLocked(true, 0);
- userActivityNoUpdateLocked(
- eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ userActivityNoUpdateLocked(
+ eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
return true;
}
@@ -1060,53 +1067,58 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- switch (reason) {
- case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
- Slog.i(TAG, "Going to sleep due to device administration policy "
- + "(uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
- Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
- Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
- Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
- break;
- case PowerManager.GO_TO_SLEEP_REASON_HDMI:
- Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
- break;
- default:
- Slog.i(TAG, "Going to sleep by application request (uid " + uid +")...");
- reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
- break;
- }
-
- mLastSleepTime = eventTime;
- mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_DOZING;
- mSandmanSummoned = true;
- setInteractiveStateLocked(false, reason);
-
- // Report the number of wake locks that will be cleared by going to sleep.
- int numWakeLocksCleared = 0;
- final int numWakeLocks = mWakeLocks.size();
- for (int i = 0; i < numWakeLocks; i++) {
- final WakeLock wakeLock = mWakeLocks.get(i);
- switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
- case PowerManager.FULL_WAKE_LOCK:
- case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
- case PowerManager.SCREEN_DIM_WAKE_LOCK:
- numWakeLocksCleared += 1;
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "goToSleep");
+ try {
+ switch (reason) {
+ case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
+ Slog.i(TAG, "Going to sleep due to device administration policy "
+ + "(uid " + uid +")...");
+ break;
+ case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
+ Slog.i(TAG, "Going to sleep due to screen timeout (uid " + uid +")...");
+ break;
+ case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
+ Slog.i(TAG, "Going to sleep due to lid switch (uid " + uid +")...");
+ break;
+ case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
+ Slog.i(TAG, "Going to sleep due to power button (uid " + uid +")...");
+ break;
+ case PowerManager.GO_TO_SLEEP_REASON_HDMI:
+ Slog.i(TAG, "Going to sleep due to HDMI standby (uid " + uid +")...");
+ break;
+ default:
+ Slog.i(TAG, "Going to sleep by application request (uid " + uid +")...");
+ reason = PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
break;
}
- }
- EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
- // Skip dozing if requested.
- if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
- reallyGoToSleepNoUpdateLocked(eventTime, uid);
+ mLastSleepTime = eventTime;
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_DOZING;
+ mSandmanSummoned = true;
+ setInteractiveStateLocked(false, reason);
+
+ // Report the number of wake locks that will be cleared by going to sleep.
+ int numWakeLocksCleared = 0;
+ final int numWakeLocks = mWakeLocks.size();
+ for (int i = 0; i < numWakeLocks; i++) {
+ final WakeLock wakeLock = mWakeLocks.get(i);
+ switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
+ case PowerManager.FULL_WAKE_LOCK:
+ case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
+ case PowerManager.SCREEN_DIM_WAKE_LOCK:
+ numWakeLocksCleared += 1;
+ break;
+ }
+ }
+ EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
+
+ // Skip dozing if requested.
+ if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
+ reallyGoToSleepNoUpdateLocked(eventTime, uid);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
@@ -1129,12 +1141,17 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- Slog.i(TAG, "Nap time (uid " + uid +")...");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
+ try {
+ Slog.i(TAG, "Nap time (uid " + uid +")...");
- mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_DREAMING;
- mSandmanSummoned = true;
- setInteractiveStateLocked(true, 0);
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_DREAMING;
+ mSandmanSummoned = true;
+ setInteractiveStateLocked(true, 0);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
return true;
}
@@ -1150,11 +1167,16 @@ public final class PowerManagerService extends com.android.server.SystemService
return false;
}
- Slog.i(TAG, "Sleeping (uid " + uid +")...");
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "reallyGoToSleep");
+ try {
+ Slog.i(TAG, "Sleeping (uid " + uid +")...");
- mDirty |= DIRTY_WAKEFULNESS;
- mWakefulness = WAKEFULNESS_ASLEEP;
- setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ mDirty |= DIRTY_WAKEFULNESS;
+ mWakefulness = WAKEFULNESS_ASLEEP;
+ setInteractiveStateLocked(false, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
return true;
}
@@ -1191,40 +1213,45 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
}
- // Phase 0: Basic state updates.
- updateIsPoweredLocked(mDirty);
- updateStayOnLocked(mDirty);
-
- // Phase 1: Update wakefulness.
- // Loop because the wake lock and user activity computations are influenced
- // by changes in wakefulness.
- final long now = SystemClock.uptimeMillis();
- int dirtyPhase2 = 0;
- for (;;) {
- int dirtyPhase1 = mDirty;
- dirtyPhase2 |= dirtyPhase1;
- mDirty = 0;
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
+ try {
+ // Phase 0: Basic state updates.
+ updateIsPoweredLocked(mDirty);
+ updateStayOnLocked(mDirty);
- updateWakeLockSummaryLocked(dirtyPhase1);
- updateUserActivitySummaryLocked(now, dirtyPhase1);
- if (!updateWakefulnessLocked(dirtyPhase1)) {
- break;
+ // Phase 1: Update wakefulness.
+ // Loop because the wake lock and user activity computations are influenced
+ // by changes in wakefulness.
+ final long now = SystemClock.uptimeMillis();
+ int dirtyPhase2 = 0;
+ for (;;) {
+ int dirtyPhase1 = mDirty;
+ dirtyPhase2 |= dirtyPhase1;
+ mDirty = 0;
+
+ updateWakeLockSummaryLocked(dirtyPhase1);
+ updateUserActivitySummaryLocked(now, dirtyPhase1);
+ if (!updateWakefulnessLocked(dirtyPhase1)) {
+ break;
+ }
}
- }
- // Phase 2: Update dreams and display power state.
- updateDreamLocked(dirtyPhase2);
- updateDisplayPowerStateLocked(dirtyPhase2);
+ // Phase 2: Update dreams and display power state.
+ updateDreamLocked(dirtyPhase2);
+ updateDisplayPowerStateLocked(dirtyPhase2);
- // Phase 3: Send notifications, if needed.
- if (mDisplayReady) {
- finishInteractiveStateChangeLocked();
- }
+ // Phase 3: Send notifications, if needed.
+ if (mDisplayReady) {
+ finishInteractiveStateChangeLocked();
+ }
- // Phase 4: Update suspend blocker.
- // Because we might release the last suspend blocker here, we need to make sure
- // we finished everything else first!
- updateSuspendBlockerLocked();
+ // Phase 4: Update suspend blocker.
+ // Because we might release the last suspend blocker here, we need to make sure
+ // we finished everything else first!
+ updateSuspendBlockerLocked();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
/**
@@ -1995,7 +2022,12 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable);
}
mHalAutoSuspendModeEnabled = enable;
- nativeSetAutoSuspend(enable);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalAutoSuspend(" + enable + ")");
+ try {
+ nativeSetAutoSuspend(enable);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
}
@@ -2005,7 +2037,12 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.d(TAG, "Setting HAL interactive mode to " + enable);
}
mHalInteractiveModeEnabled = enable;
- nativeSetInteractive(enable);
+ Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalInteractive(" + enable + ")");
+ try {
+ nativeSetInteractive(enable);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
}
}
@@ -2200,21 +2237,6 @@ public final class PowerManagerService extends com.android.server.SystemService
nativeSendPowerHint(hintId, data);
}
- private static void setSurfaceFlingerLowPowerMode(int enabled) {
- try {
- final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
- if (flinger != null) {
- final Parcel data = Parcel.obtain();
- data.writeInterfaceToken("android.ui.ISurfaceComposer");
- data.writeInt(enabled);
- flinger.transact(1016, data, null, 0);
- data.recycle();
- }
- } catch (RemoteException ex) {
- Slog.e(TAG, "Failed to reduce refresh rate", ex);
- }
- }
-
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
@@ -2607,20 +2629,23 @@ public final class PowerManagerService extends com.android.server.SystemService
private final class SuspendBlockerImpl implements SuspendBlocker {
private final String mName;
+ private final String mTraceName;
private int mReferenceCount;
public SuspendBlockerImpl(String name) {
mName = name;
+ mTraceName = "SuspendBlocker (" + name + ")";
}
@Override
protected void finalize() throws Throwable {
try {
if (mReferenceCount != 0) {
- Log.wtf(TAG, "Suspend blocker \"" + mName
+ Slog.wtf(TAG, "Suspend blocker \"" + mName
+ "\" was finalized without being released!");
mReferenceCount = 0;
nativeReleaseSuspendBlocker(mName);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
}
} finally {
super.finalize();
@@ -2635,6 +2660,7 @@ public final class PowerManagerService extends com.android.server.SystemService
if (DEBUG_SPEW) {
Slog.d(TAG, "Acquiring suspend blocker \"" + mName + "\".");
}
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
nativeAcquireSuspendBlocker(mName);
}
}
@@ -2649,8 +2675,9 @@ public final class PowerManagerService extends com.android.server.SystemService
Slog.d(TAG, "Releasing suspend blocker \"" + mName + "\".");
}
nativeReleaseSuspendBlocker(mName);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
} else if (mReferenceCount < 0) {
- Log.wtf(TAG, "Suspend blocker \"" + mName
+ Slog.wtf(TAG, "Suspend blocker \"" + mName
+ "\" was released without being acquired!", new Throwable());
mReferenceCount = 0;
}
@@ -2666,6 +2693,8 @@ public final class PowerManagerService extends com.android.server.SystemService
}
private final class ScreenOnBlockerImpl implements ScreenOnBlocker {
+ private static final String TRACE_NAME = "ScreenOnBlocker";
+
private int mNestCount;
public boolean isHeld() {
@@ -2678,9 +2707,12 @@ public final class PowerManagerService extends com.android.server.SystemService
public void acquire() {
synchronized (this) {
mNestCount += 1;
- if (DEBUG) {
+ if (DEBUG || true) {
Slog.d(TAG, "Screen on blocked: mNestCount=" + mNestCount);
}
+ if (mNestCount == 1) {
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, TRACE_NAME, 0);
+ }
}
}
@@ -2688,16 +2720,16 @@ public final class PowerManagerService extends com.android.server.SystemService
public void release() {
synchronized (this) {
mNestCount -= 1;
- if (mNestCount < 0) {
- Log.wtf(TAG, "Screen on blocker was released without being acquired!",
- new Throwable());
- mNestCount = 0;
- }
if (mNestCount == 0) {
+ if (DEBUG || true) {
+ Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
+ }
mHandler.sendEmptyMessage(MSG_SCREEN_ON_BLOCKER_RELEASED);
- }
- if (DEBUG) {
- Slog.d(TAG, "Screen on unblocked: mNestCount=" + mNestCount);
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_NAME, 0);
+ } else if (mNestCount < 0) {
+ Slog.wtf(TAG, "Screen on blocker was released without being acquired!",
+ new Throwable());
+ mNestCount = 0;
}
}
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 21905f0..297dacf 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -48,9 +48,7 @@ import java.util.Map;
* A note on locking: We rely on the fact that calls onto mBar are oneway or
* if they are local, that they just enqueue messages to not deadlock.
*/
-public class StatusBarManagerService extends IStatusBarService.Stub
- implements WindowManagerService.OnHardKeyboardStatusChangeListener
-{
+public class StatusBarManagerService extends IStatusBarService.Stub {
private static final String TAG = "StatusBarManagerService";
private static final boolean SPEW = false;
@@ -95,7 +93,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub
public StatusBarManagerService(Context context, WindowManagerService windowManager) {
mContext = context;
mWindowManager = windowManager;
- mWindowManager.setOnHardKeyboardStatusChangeListener(this);
final Resources res = context.getResources();
mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons));
@@ -394,29 +391,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub
}
@Override
- public void setHardKeyboardEnabled(final boolean enabled) {
- mHandler.post(new Runnable() {
- public void run() {
- mWindowManager.setHardKeyboardEnabled(enabled);
- }
- });
- }
-
- @Override
- public void onHardKeyboardStatusChange(final boolean available, final boolean enabled) {
- mHandler.post(new Runnable() {
- public void run() {
- if (mBar != null) {
- try {
- mBar.setHardKeyboardStatus(available, enabled);
- } catch (RemoteException ex) {
- }
- }
- }
- });
- }
-
- @Override
public void toggleRecentApps() {
if (mBar != null) {
try {
@@ -510,11 +484,9 @@ public class StatusBarManagerService extends IStatusBarService.Stub
switches[2] = mMenuVisible ? 1 : 0;
switches[3] = mImeWindowVis;
switches[4] = mImeBackDisposition;
- switches[7] = mShowImeSwitcher ? 1 : 0;
+ switches[5] = mShowImeSwitcher ? 1 : 0;
binders.add(mImeToken);
}
- switches[5] = mWindowManager.isHardKeyboardAvailable() ? 1 : 0;
- switches[6] = mWindowManager.isHardKeyboardEnabled() ? 1 : 0;
}
/**
diff --git a/services/core/java/com/android/server/tv/PersistentDataStore.java b/services/core/java/com/android/server/tv/PersistentDataStore.java
index 05a2bde..fcfaaea 100644
--- a/services/core/java/com/android/server/tv/PersistentDataStore.java
+++ b/services/core/java/com/android/server/tv/PersistentDataStore.java
@@ -45,6 +45,7 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
/**
@@ -69,7 +70,8 @@ final class PersistentDataStore {
// The atomic file used to safely read or write the file.
private final AtomicFile mAtomicFile;
- private final List<TvContentRating> mBlockedRatings = new ArrayList<TvContentRating>();
+ private final List<TvContentRating> mBlockedRatings =
+ Collections.synchronizedList(new ArrayList<TvContentRating>());
private boolean mBlockedRatingsChanged;
@@ -107,9 +109,11 @@ final class PersistentDataStore {
public boolean isRatingBlocked(TvContentRating rating) {
loadIfNeeded();
- for (TvContentRating blcokedRating : mBlockedRatings) {
- if (rating.contains(blcokedRating)) {
- return true;
+ synchronized (mBlockedRatings) {
+ for (TvContentRating blcokedRating : mBlockedRatings) {
+ if (rating.contains(blcokedRating)) {
+ return true;
+ }
}
}
return false;
@@ -271,10 +275,12 @@ final class PersistentDataStore {
serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startTag(null, TAG_TV_INPUT_MANAGER_STATE);
serializer.startTag(null, TAG_BLOCKED_RATINGS);
- for (TvContentRating rating : mBlockedRatings) {
- serializer.startTag(null, TAG_RATING);
- serializer.attribute(null, ATTR_STRING, rating.flattenToString());
- serializer.endTag(null, TAG_RATING);
+ synchronized (mBlockedRatings) {
+ for (TvContentRating rating : mBlockedRatings) {
+ serializer.startTag(null, TAG_RATING);
+ serializer.attribute(null, ATTR_STRING, rating.flattenToString());
+ serializer.endTag(null, TAG_RATING);
+ }
}
serializer.endTag(null, TAG_BLOCKED_RATINGS);
serializer.startTag(null, TAG_PARENTAL_CONTROLS);
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 78ea6c9..ae9ae13 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -285,7 +285,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return -1;
}
- public void addHdmiTvInput(int logicalAddress, TvInputInfo info) {
+ public void addHdmiTvInput(int id, TvInputInfo info) {
if (info.getType() != TvInputInfo.TYPE_HDMI) {
throw new IllegalArgumentException("info (" + info + ") has non-HDMI type.");
}
@@ -295,13 +295,13 @@ class TvInputHardwareManager implements TvInputHal.Callback {
if (parentIndex < 0) {
throw new IllegalArgumentException("info (" + info + ") has invalid parentId.");
}
- String oldInputId = mHdmiInputIdMap.get(logicalAddress);
+ String oldInputId = mHdmiInputIdMap.get(id);
if (oldInputId != null) {
Slog.w(TAG, "Trying to override previous registration: old = "
- + mInputMap.get(oldInputId) + ":" + logicalAddress + ", new = "
- + info + ":" + logicalAddress);
+ + mInputMap.get(oldInputId) + ":" + id + ", new = "
+ + info + ":" + id);
}
- mHdmiInputIdMap.put(logicalAddress, info.getId());
+ mHdmiInputIdMap.put(id, info.getId());
mInputMap.put(info.getId(), info);
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 3b5e79d..88ce860 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -1223,7 +1223,7 @@ public final class TvInputManagerService extends SystemService {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
channelUri, params);
- if (TvContract.isChannelUriForPassthroughTvInput(channelUri)) {
+ if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
// Do not log the watch history for passthrough inputs.
return;
}
@@ -1962,11 +1962,11 @@ public final class TvInputManagerService extends SystemService {
}
@Override
- public void addHdmiTvInput(int logicalAddress, TvInputInfo inputInfo) {
+ public void addHdmiTvInput(int id, TvInputInfo inputInfo) {
ensureHardwarePermission();
ensureValidInput(inputInfo);
synchronized (mLock) {
- mTvInputHardwareManager.addHdmiTvInput(logicalAddress, inputInfo);
+ mTvInputHardwareManager.addHdmiTvInput(id, inputInfo);
addTvInputLocked(inputInfo);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2295656..112972f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -537,7 +537,7 @@ public class WindowManagerService extends IWindowManager.Stub
final ArrayList<WindowState> mInputMethodDialogs = new ArrayList<WindowState>();
boolean mHardKeyboardAvailable;
- boolean mHardKeyboardEnabled;
+ boolean mShowImeWithHardKeyboard;
OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
final ArrayList<WindowToken> mWallpaperTokens = new ArrayList<WindowToken>();
@@ -7015,11 +7015,11 @@ public class WindowManagerService extends IWindowManager.Stub
boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
if (hardKeyboardAvailable != mHardKeyboardAvailable) {
mHardKeyboardAvailable = hardKeyboardAvailable;
- mHardKeyboardEnabled = hardKeyboardAvailable;
+ mShowImeWithHardKeyboard = !hardKeyboardAvailable;
mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
}
- if (!mHardKeyboardEnabled) {
+ if (mShowImeWithHardKeyboard) {
config.keyboard = Configuration.KEYBOARD_NOKEYS;
}
@@ -7039,16 +7039,16 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- public boolean isHardKeyboardEnabled() {
+ public boolean isShowImeWithHardKeyboardEnabled() {
synchronized (mWindowMap) {
- return mHardKeyboardEnabled;
+ return mShowImeWithHardKeyboard;
}
}
- public void setHardKeyboardEnabled(boolean enabled) {
+ public void setShowImeWithHardKeyboard(boolean enabled) {
synchronized (mWindowMap) {
- if (mHardKeyboardEnabled != enabled) {
- mHardKeyboardEnabled = enabled;
+ if (mShowImeWithHardKeyboard != enabled) {
+ mShowImeWithHardKeyboard = enabled;
mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
}
}
@@ -7062,15 +7062,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
void notifyHardKeyboardStatusChange() {
- final boolean available, enabled;
+ final boolean available, showImeWithHardKeyboard;
final OnHardKeyboardStatusChangeListener listener;
synchronized (mWindowMap) {
listener = mHardKeyboardStatusChangeListener;
available = mHardKeyboardAvailable;
- enabled = mHardKeyboardEnabled;
+ showImeWithHardKeyboard = mShowImeWithHardKeyboard;
}
if (listener != null) {
- listener.onHardKeyboardStatusChange(available, enabled);
+ listener.onHardKeyboardStatusChange(available, showImeWithHardKeyboard);
}
}
@@ -11053,7 +11053,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
public interface OnHardKeyboardStatusChangeListener {
- public void onHardKeyboardStatusChange(boolean available, boolean enabled);
+ public void onHardKeyboardStatusChange(boolean available, boolean showIme);
}
void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 61c50d6..7bf090a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1211,6 +1211,12 @@ class WindowStateAnimator {
|| w.mDecorFrame.isEmpty()) {
// The universe background isn't cropped, nor windows without policy decor.
w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height());
+ } else if (w.mAttrs.type == LayoutParams.TYPE_WALLPAPER && mAnimator.mAnimating) {
+ // If we're animating, the wallpaper crop should only be updated at the end of the
+ // animation.
+ mTmpClipRect.set(w.mSystemDecorRect);
+ applyDecorRect(w.mDecorFrame);
+ w.mSystemDecorRect.union(mTmpClipRect);
} else {
// Crop to the system decor specified by policy.
applyDecorRect(w.mDecorFrame);
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index ce2ca9b..39b70a8 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -41,6 +41,8 @@ int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
int register_android_server_hdmi_HdmiMhlController(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
int register_android_server_PersistentDataBlockService(JNIEnv* env);
+int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
+int register_android_server_Watchdog(JNIEnv* env);
};
using namespace android;
@@ -77,6 +79,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
register_android_server_hdmi_HdmiMhlController(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
+ register_android_server_fingerprint_FingerprintService(env);
+ register_android_server_Watchdog(env);
return JNI_VERSION_1_4;
}