summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java36
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java20
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags6
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java6
-rw-r--r--services/core/java/com/android/server/IntentResolver.java4
-rw-r--r--services/core/java/com/android/server/LocationManagerService.java7
-rw-r--r--services/core/java/com/android/server/MmsServiceBroker.java8
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java19
-rw-r--r--services/core/java/com/android/server/SystemConfig.java14
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java108
-rw-r--r--services/core/java/com/android/server/TextServicesManagerService.java98
-rw-r--r--services/core/java/com/android/server/Watchdog.java22
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityManagerService.java535
-rw-r--r--services/core/java/com/android/server/am/ActivityStackSupervisor.java6
-rw-r--r--services/core/java/com/android/server/am/LockTaskNotify.java14
-rw-r--r--services/core/java/com/android/server/am/TaskPersister.java12
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java2
-rw-r--r--services/core/java/com/android/server/am/UserSwitchingDialog.java37
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java296
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java3
-rw-r--r--services/core/java/com/android/server/connectivity/PacManager.java9
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java6
-rw-r--r--services/core/java/com/android/server/display/OverlayDisplayAdapter.java1
-rw-r--r--services/core/java/com/android/server/display/VirtualDisplayAdapter.java1
-rw-r--r--services/core/java/com/android/server/display/WifiDisplayAdapter.java1
-rw-r--r--services/core/java/com/android/server/hdmi/ActiveSourceHandler.java5
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java7
-rw-r--r--services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java3
-rw-r--r--services/core/java/com/android/server/hdmi/DeviceSelectAction.java6
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java3
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecKeycode.java156
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java27
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java13
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java69
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java143
-rw-r--r--services/core/java/com/android/server/hdmi/NewDeviceAction.java8
-rw-r--r--services/core/java/com/android/server/hdmi/OneTouchPlayAction.java3
-rw-r--r--services/core/java/com/android/server/hdmi/OneTouchRecordAction.java8
-rw-r--r--services/core/java/com/android/server/hdmi/SendKeyAction.java57
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioAction.java3
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java13
-rw-r--r--services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java2
-rw-r--r--services/core/java/com/android/server/hdmi/TimerRecordingAction.java7
-rw-r--r--services/core/java/com/android/server/hdmi/VolumeControlAction.java15
-rw-r--r--services/core/java/com/android/server/job/JobSchedulerService.java12
-rw-r--r--services/core/java/com/android/server/location/GpsLocationProvider.java20
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java2
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java54
-rw-r--r--services/core/java/com/android/server/notification/NotificationDelegate.java1
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java66
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java4
-rw-r--r--services/core/java/com/android/server/pm/GrantedPermissions.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageKeySetData.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java285
-rw-r--r--services/core/java/com/android/server/pm/PackageSettingBase.java26
-rw-r--r--services/core/java/com/android/server/pm/Settings.java54
-rw-r--r--services/core/java/com/android/server/pm/SharedUserSetting.java4
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java20
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java52
-rw-r--r--services/core/java/com/android/server/tv/TvInputHal.java6
-rw-r--r--services/core/java/com/android/server/tv/TvInputHardwareManager.java50
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java17
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java5
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java25
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java70
-rw-r--r--services/core/java/com/android/server/wm/WindowState.java35
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java14
-rw-r--r--services/core/java/com/android/server/wm/WindowToken.java12
-rw-r--r--services/core/jni/com_android_server_tv_TvInputHal.cpp12
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java1
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/print/java/com/android/server/print/RemotePrintSpooler.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java19
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsDatabase.java69
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java49
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsXml.java19
-rw-r--r--services/usage/java/com/android/server/usage/UserUsageStatsService.java124
78 files changed, 1944 insertions, 1025 deletions
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index bfbf0ac..2781890 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1040,7 +1040,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private void addServiceLocked(Service service, UserState userState) {
try {
- service.linkToOwnDeathLocked();
+ service.onAdded();
userState.mBoundServices.add(service);
userState.mComponentNameToServiceMap.put(service.mComponentName, service);
} catch (RemoteException re) {
@@ -1056,7 +1056,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
private void removeServiceLocked(Service service, UserState userState) {
userState.mBoundServices.remove(service);
userState.mComponentNameToServiceMap.remove(service.mComponentName);
- service.unlinkToOwnDeathLocked();
+ service.onRemoved();
}
/**
@@ -1931,6 +1931,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
final ResolveInfo mResolveInfo;
+ final IBinder mOverlayWindowToken = new Binder();
+
// the events pending events to be dispatched to this service
final SparseArray<AccessibilityEvent> mPendingEvents =
new SparseArray<>();
@@ -2112,7 +2114,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
userState.mBindingServices.remove(mComponentName);
mWasConnectedAndDied = false;
try {
- mServiceInterface.setConnection(this, mId);
+ mServiceInterface.init(this, mId, mOverlayWindowToken);
onUserStateChangedLocked(userState);
} catch (RemoteException re) {
Slog.w(LOG_TAG, "Error while setting connection for service: "
@@ -2602,6 +2604,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
/* do nothing - #binderDied takes care */
}
+ public void onAdded() throws RemoteException {
+ linkToOwnDeathLocked();
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mWindowManagerService.addWindowToken(mOverlayWindowToken,
+ WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ public void onRemoved() {
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mWindowManagerService.removeWindowToken(mOverlayWindowToken, true);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ unlinkToOwnDeathLocked();
+ }
+
public void linkToOwnDeathLocked() throws RemoteException {
mService.linkToDeath(this, 0);
}
@@ -2614,7 +2637,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
try {
// Clear the proxy in the other process so this
// IAccessibilityServiceConnection can be garbage collected.
- mServiceInterface.setConnection(null, mId);
+ mServiceInterface.init(null, mId, null);
} catch (RemoteException re) {
/* ignore */
}
@@ -3156,7 +3179,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
case WindowManager.LayoutParams.TYPE_STATUS_BAR:
case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL:
case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL:
- case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY:
case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
@@ -3165,6 +3187,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
return AccessibilityWindowInfo.TYPE_SYSTEM;
}
+ case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: {
+ return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY;
+ }
+
default: {
return -1;
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6a6dcaf..bf67461 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -238,8 +238,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private boolean mLockdownEnabled;
private LockdownVpnTracker mLockdownTracker;
- private Nat464Xlat mClat;
-
/** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
private Object mRulesLock = new Object();
/** Currently active network rules by UID. */
@@ -715,12 +713,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
intentFilter.addAction(Intent.ACTION_USER_STOPPING);
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
- mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler);
try {
mNetd.registerObserver(mTethering);
mNetd.registerObserver(mDataActivityObserver);
- mNetd.registerObserver(mClat);
} catch (RemoteException e) {
loge("Error registering observer :" + e);
}
@@ -3549,7 +3545,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
// we do anything else, make sure its LinkProperties are accurate.
- mClat.fixupLinkProperties(networkAgent, oldLp);
+ if (networkAgent.clatd != null) {
+ networkAgent.clatd.fixupLinkProperties(oldLp);
+ }
updateInterfaces(newLp, oldLp, netId);
updateMtu(newLp, oldLp);
@@ -3568,15 +3566,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
- private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo na) {
- final boolean wasRunningClat = mClat.isRunningClat(na);
- final boolean shouldRunClat = Nat464Xlat.requiresClat(na);
+ private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo nai) {
+ final boolean wasRunningClat = nai.clatd != null && nai.clatd.isStarted();
+ final boolean shouldRunClat = Nat464Xlat.requiresClat(nai);
if (!wasRunningClat && shouldRunClat) {
- // Start clatd. If it's already been started but is not running yet, this is a no-op.
- mClat.startClat(na);
+ nai.clatd = new Nat464Xlat(mContext, mNetd, mTrackerHandler, nai);
+ nai.clatd.start();
} else if (wasRunningClat && !shouldRunClat) {
- mClat.stopClat();
+ nai.clatd.stop();
}
}
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 64d8f6f..8417ccc 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -52,7 +52,7 @@ option java_package com.android.server
# NotificationManagerService.java
# ---------------------------
# when a NotificationManager.notify is called
-2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3)
+2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3),(update|1)
# when someone tries to cancel a notification, the notification manager sometimes
# calls this with flags too
2751 notification_cancel (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3)
@@ -69,6 +69,10 @@ option java_package com.android.server
27511 notification_expansion (key|3),(user_action|1),(expanded|1)
# when a notification has been clicked
27520 notification_clicked (key|3)
+# when a notification action button has been clicked
+27521 notification_action_clicked (key|3),(action_index|1)
+# when a notification has been canceled
+27530 notification_canceled (key|3),(reason|1)
# ---------------------------
# Watchdog.java
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 1623eac..edea274 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -774,7 +774,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (defIm == null && mMethodList.size() > 0) {
defIm = InputMethodUtils.getMostApplicableDefaultIME(
mSettings.getEnabledInputMethodListLocked());
- Slog.i(TAG, "No default found, using " + defIm.getId());
+ if (defIm != null) {
+ Slog.i(TAG, "Default found, using " + defIm.getId());
+ } else {
+ Slog.i(TAG, "No default found");
+ }
}
if (defIm != null) {
setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index 07cc864..387eabc 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -21,7 +21,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -30,6 +29,7 @@ import java.util.Set;
import android.net.Uri;
import android.util.FastImmutableArraySet;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Slog;
@@ -736,7 +736,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
/**
* All filters that have been registered.
*/
- private final HashSet<F> mFilters = new HashSet<F>();
+ private final ArraySet<F> mFilters = new ArraySet<F>();
/**
* All of the MIME types that have been registered, such as "image/jpeg",
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 28a6917..d9c96e4 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1796,9 +1796,6 @@ public class LocationManagerService extends ILocationManager.Stub {
@Override
public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) {
- if (mGpsStatusProvider == null) {
- return false;
- }
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
LocationManager.GPS_PROVIDER);
@@ -1813,6 +1810,10 @@ public class LocationManagerService extends ILocationManager.Stub {
Binder.restoreCallingIdentity(ident);
}
+ if (mGpsStatusProvider == null) {
+ return false;
+ }
+
try {
mGpsStatusProvider.addGpsStatusListener(listener);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 926235f..9596b57 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -219,7 +219,7 @@ public class MmsServiceBroker extends SystemService {
// Service API calls implementation, proxied to the real MmsService in "com.android.mms.service"
private final class BinderService extends IMms.Stub {
@Override
- public void sendMessage(long subId, String callingPkg, Uri contentUri,
+ public void sendMessage(int subId, String callingPkg, Uri contentUri,
String locationUrl, Bundle configOverrides, PendingIntent sentIntent)
throws RemoteException {
mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
@@ -232,7 +232,7 @@ public class MmsServiceBroker extends SystemService {
}
@Override
- public void downloadMessage(long subId, String callingPkg, String locationUrl,
+ public void downloadMessage(int subId, String callingPkg, String locationUrl,
Uri contentUri, Bundle configOverrides,
PendingIntent downloadedIntent) throws RemoteException {
mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS,
@@ -259,7 +259,7 @@ public class MmsServiceBroker extends SystemService {
}
@Override
- public Bundle getCarrierConfigValues(long subId) throws RemoteException {
+ public Bundle getCarrierConfigValues(int subId) throws RemoteException {
return getServiceGuarded().getCarrierConfigValues(subId);
}
@@ -360,7 +360,7 @@ public class MmsServiceBroker extends SystemService {
}
@Override
- public void sendStoredMessage(long subId, String callingPkg, Uri messageUri,
+ public void sendStoredMessage(int subId, String callingPkg, Uri messageUri,
Bundle configOverrides, PendingIntent sentIntent) throws RemoteException {
mContext.enforceCallingPermission(Manifest.permission.SEND_SMS,
"Send stored MMS message");
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 020c951..0f033d7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -940,6 +940,17 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
@Override
+ public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
+ mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ try {
+ mConnector.execute(
+ "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
+ }
+ }
+
+ @Override
public void addRoute(int netId, RouteInfo route) {
modifyRoute("add", "" + netId, route);
}
@@ -1854,23 +1865,23 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
@Override
- public void stopClatd() throws IllegalStateException {
+ public void stopClatd(String interfaceName) throws IllegalStateException {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("clatd", "stop");
+ mConnector.execute("clatd", "stop", interfaceName);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
@Override
- public boolean isClatdStarted() {
+ public boolean isClatdStarted(String interfaceName) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
final NativeDaemonEvent event;
try {
- event = mConnector.execute("clatd", "status");
+ event = mConnector.execute("clatd", "status", interfaceName);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index cf2a49f..f4fb519 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -32,8 +32,6 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
-import java.util.HashMap;
-import java.util.HashSet;
import static com.android.internal.util.ArrayUtils.appendInt;
@@ -50,7 +48,7 @@ public class SystemConfig {
// These are the built-in uid -> permission mappings that were read from the
// system configuration files.
- final SparseArray<HashSet<String>> mSystemPermissions = new SparseArray<>();
+ final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>();
// These are the built-in shared libraries that were read from the
// system configuration files. Keys are the library names; strings are the
@@ -59,7 +57,7 @@ public class SystemConfig {
// These are the features this devices supports that were read from the
// system configuration files.
- final HashMap<String, FeatureInfo> mAvailableFeatures = new HashMap<>();
+ final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
public static final class PermissionEntry {
public final String name;
@@ -94,7 +92,7 @@ public class SystemConfig {
return mGlobalGids;
}
- public SparseArray<HashSet<String>> getSystemPermissions() {
+ public SparseArray<ArraySet<String>> getSystemPermissions() {
return mSystemPermissions;
}
@@ -102,7 +100,7 @@ public class SystemConfig {
return mSharedLibraries;
}
- public HashMap<String, FeatureInfo> getAvailableFeatures() {
+ public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
return mAvailableFeatures;
}
@@ -252,9 +250,9 @@ public class SystemConfig {
continue;
}
perm = perm.intern();
- HashSet<String> perms = mSystemPermissions.get(uid);
+ ArraySet<String> perms = mSystemPermissions.get(uid);
if (perms == null) {
- perms = new HashSet<String>();
+ perms = new ArraySet<String>();
mSystemPermissions.put(uid, perms);
}
perms.add(perm);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index b3337bb..fcc5339 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -72,7 +72,7 @@ import com.android.server.am.BatteryStatsService;
* and 15973975 by saving the phoneId of the registrant and then using the
* phoneId when deciding to to make a callback. This is necessary because
* a subId changes from to a dummy value when a SIM is removed and thus won't
- * compare properly. Because SubscriptionManager.getPhoneId(long subId) handles
+ * compare properly. Because SubscriptionManager.getPhoneId(int subId) handles
* the dummy value conversion we properly do the callbacks.
*
* Eventually we may want to remove the notion of dummy value but for now this
@@ -95,7 +95,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
int events;
- long subId;
+ int subId;
int phoneId;
@@ -154,7 +154,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private VoLteServiceState mVoLteServiceState = new VoLteServiceState();
- private long mDefaultSubId = SubscriptionManager.INVALID_SUB_ID;
+ private int mDefaultSubId = SubscriptionManager.INVALID_SUB_ID;
private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_ID;
@@ -201,7 +201,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
case MSG_UPDATE_DEFAULT_SUB: {
int newDefaultPhoneId = msg.arg1;
- long newDefaultSubId = (Long)(msg.obj);
+ int newDefaultSubId = (Integer)(msg.obj);
if (VDBG) {
log("MSG_UPDATE_DEFAULT_SUB:current mDefaultSubId=" + mDefaultSubId
+ " current mDefaultPhoneId=" + mDefaultPhoneId + " newDefaultSubId= "
@@ -212,11 +212,12 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
//defaultSubId comes before new defaultSubId update) we need to recall all
//possible missed notify callback
synchronized (mRecords) {
- for (Record r : mRecords) {
- if(r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
- checkPossibleMissNotify(r, newDefaultPhoneId);
- }
- }
+ for (Record r : mRecords) {
+ if(r.subId == SubscriptionManager.DEFAULT_SUB_ID) {
+ checkPossibleMissNotify(r, newDefaultPhoneId);
+ }
+ }
+ handleRemoveListLocked();
}
mDefaultSubId = newDefaultSubId;
mDefaultPhoneId = newDefaultPhoneId;
@@ -235,7 +236,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
if (DBG) log("onReceive: userHandle=" + userHandle);
mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, userHandle, 0));
} else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
- Long newDefaultSubIdObj = new Long(intent.getLongExtra(
+ Integer newDefaultSubIdObj = new Integer(intent.getIntExtra(
PhoneConstants.SUBSCRIPTION_KEY, SubscriptionManager.getDefaultSubId()));
int newDefaultPhoneId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
SubscriptionManager.getPhoneId(mDefaultSubId));
@@ -331,13 +332,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
@Override
- public void listenForSubscriber(long subId, String pkgForDebug, IPhoneStateListener callback,
+ public void listenForSubscriber(int subId, String pkgForDebug, IPhoneStateListener callback,
int events, boolean notifyNow) {
listen(pkgForDebug, callback, events, notifyNow, subId);
}
private void listen(String pkgForDebug, IPhoneStateListener callback, int events,
- boolean notifyNow, long subId) {
+ boolean notifyNow, int subId) {
int callerUid = UserHandle.getCallingUserId();
int myUid = UserHandle.myUserId();
if (VDBG) {
@@ -345,10 +346,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
+ " notifyNow=" + notifyNow + " subId=" + subId + " myUid=" + myUid
+ " callerUid=" + callerUid);
}
- if (events != 0) {
+
+ if (events != PhoneStateListener.LISTEN_NONE) {
/* Checks permission and throws Security exception */
checkListenerPermission(events);
-
synchronized (mRecords) {
// register
Record r = null;
@@ -363,26 +364,26 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
r = new Record();
r.binder = b;
- r.callback = callback;
- r.pkgForDebug = pkgForDebug;
- r.callerUid = callerUid;
- // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
- // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
- if (!SubscriptionManager.isValidSubId(subId)) {
- r.subId = SubscriptionManager.DEFAULT_SUB_ID;
- } else {//APP specify subID
- r.subId = subId;
- }
- r.phoneId = SubscriptionManager.getPhoneId(r.subId);
-
mRecords.add(r);
if (DBG) log("listen: add new record");
}
+ r.callback = callback;
+ r.pkgForDebug = pkgForDebug;
+ r.callerUid = callerUid;
+ // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
+ // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
+ if (!SubscriptionManager.isValidSubId(subId)) {
+ r.subId = SubscriptionManager.DEFAULT_SUB_ID;
+ } else {//APP specify subID
+ r.subId = subId;
+ }
+ r.phoneId = SubscriptionManager.getPhoneId(r.subId);
+
int phoneId = r.phoneId;
r.events = events;
if (DBG) {
- log("listen: r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
+ log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId);
}
if (VDBG) toStringLogSSC("listen");
if (notifyNow && validatePhoneId(phoneId)) {
@@ -502,6 +503,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
} else {
+ if(DBG) log("listen: Unregister");
remove(callback.asBinder());
}
}
@@ -543,7 +545,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
broadcastCallStateChanged(state, incomingNumber, SubscriptionManager.DEFAULT_SUB_ID);
}
- public void notifyCallStateForSubscriber(long subId, int state, String incomingNumber) {
+ public void notifyCallStateForSubscriber(int subId, int state, String incomingNumber) {
if (!checkNotifyPermission("notifyCallState()")) {
return;
}
@@ -573,7 +575,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
broadcastCallStateChanged(state, incomingNumber, subId);
}
- public void notifyServiceStateForPhoneId(int phoneId, long subId, ServiceState state) {
+ public void notifyServiceStateForPhoneId(int phoneId, int subId, ServiceState state) {
if (!checkNotifyPermission("notifyServiceState()")){
return;
}
@@ -619,7 +621,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
notifySignalStrengthForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, signalStrength);
}
- public void notifySignalStrengthForSubscriber(long subId, SignalStrength signalStrength) {
+ public void notifySignalStrengthForSubscriber(int subId, SignalStrength signalStrength) {
if (!checkNotifyPermission("notifySignalStrength()")) {
return;
}
@@ -679,7 +681,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
notifyCellInfoForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cellInfo);
}
- public void notifyCellInfoForSubscriber(long subId, List<CellInfo> cellInfo) {
+ public void notifyCellInfoForSubscriber(int subId, List<CellInfo> cellInfo) {
if (!checkNotifyPermission("notifyCellInfo()")) {
return;
}
@@ -736,7 +738,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
@Override
- public void notifyMessageWaitingChangedForPhoneId(int phoneId, long subId, boolean mwi) {
+ public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) {
if (!checkNotifyPermission("notifyMessageWaitingChanged()")) {
return;
}
@@ -766,7 +768,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
notifyCallForwardingChangedForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cfi);
}
- public void notifyCallForwardingChangedForSubscriber(long subId, boolean cfi) {
+ public void notifyCallForwardingChangedForSubscriber(int subId, boolean cfi) {
if (!checkNotifyPermission("notifyCallForwardingChanged()")) {
return;
}
@@ -797,7 +799,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
notifyDataActivityForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, state);
}
- public void notifyDataActivityForSubscriber(long subId, int state) {
+ public void notifyDataActivityForSubscriber(int subId, int state) {
if (!checkNotifyPermission("notifyDataActivity()" )) {
return;
}
@@ -825,7 +827,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
networkCapabilities, networkType, roaming);
}
- public void notifyDataConnectionForSubscriber(long subId, int state,
+ public void notifyDataConnectionForSubscriber(int subId, int state,
boolean isDataConnectivityPossible, String reason, String apn, String apnType,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int networkType, boolean roaming) {
@@ -914,7 +916,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
reason, apnType);
}
- public void notifyDataConnectionFailedForSubscriber(long subId,
+ public void notifyDataConnectionFailedForSubscriber(int subId,
String reason, String apnType) {
if (!checkNotifyPermission("notifyDataConnectionFailed()")) {
return;
@@ -947,7 +949,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cellLocation);
}
- public void notifyCellLocationForSubscriber(long subId, Bundle cellLocation) {
+ public void notifyCellLocationForSubscriber(int subId, Bundle cellLocation) {
log("notifyCellLocationForSubscriber: subId=" + subId
+ " cellLocation=" + cellLocation);
if (!checkNotifyPermission("notifyCellLocation()")) {
@@ -1094,7 +1096,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- public void notifyOemHookRawEventForSubscriber(long subId, byte[] rawData) {
+ public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) {
if (!checkNotifyPermission("notifyOemHookRawEventForSubscriber")) {
return;
}
@@ -1160,7 +1162,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
// the legacy intent broadcasting
//
- private void broadcastServiceStateChanged(ServiceState state, long subId) {
+ private void broadcastServiceStateChanged(ServiceState state, int subId) {
long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.notePhoneState(state.getState());
@@ -1179,7 +1181,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) {
+ private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int subId) {
long ident = Binder.clearCallingIdentity();
try {
mBatteryStats.notePhoneSignalStrength(signalStrength);
@@ -1198,7 +1200,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
- private void broadcastCallStateChanged(int state, String incomingNumber, long subId) {
+ private void broadcastCallStateChanged(int state, String incomingNumber, int subId) {
long ident = Binder.clearCallingIdentity();
try {
if (state == TelephonyManager.CALL_STATE_IDLE) {
@@ -1226,7 +1228,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private void broadcastDataConnectionStateChanged(int state,
boolean isDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
- NetworkCapabilities networkCapabilities, boolean roaming, long subId) {
+ NetworkCapabilities networkCapabilities, boolean roaming, int subId) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
@@ -1258,7 +1260,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
private void broadcastDataConnectionFailed(String reason, String apnType,
- long subId) {
+ int subId) {
Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason);
intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType);
@@ -1374,11 +1376,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private static class LogSSC {
private Time mTime;
private String mS;
- private long mSubId;
+ private int mSubId;
private int mPhoneId;
private ServiceState mState;
- public void set(Time t, String s, long subId, int phoneId, ServiceState state) {
+ public void set(Time t, String s, int subId, int phoneId, ServiceState state) {
mTime = t; mS = s; mSubId = subId; mPhoneId = phoneId; mState = state;
}
@@ -1391,7 +1393,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
private LogSSC logSSC [] = new LogSSC[10];
private int next = 0;
- private void logServiceStateChanged(String s, long subId, int phoneId, ServiceState state) {
+ private void logServiceStateChanged(String s, int subId, int phoneId, ServiceState state) {
if (logSSC == null || logSSC.length == 0) {
return;
}
@@ -1427,7 +1429,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
- boolean subIdMatch(long rSubId, long subId) {
+ boolean subIdMatch(int rSubId, int subId) {
if(rSubId == SubscriptionManager.DEFAULT_SUB_ID) {
return (subId == mDefaultSubId);
} else {
@@ -1445,7 +1447,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.callback.onServiceStateChanged(
new ServiceState(mServiceState[phoneId]));
} catch (RemoteException ex) {
- remove(r.binder);
+ mRemoveList.add(r.binder);
}
}
@@ -1472,7 +1474,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
: gsmSignalStrength));
} catch (RemoteException ex) {
- remove(r.binder);
+ mRemoveList.add(r.binder);
}
}
@@ -1484,7 +1486,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
r.callback.onCellInfoChanged(mCellInfo.get(phoneId));
} catch (RemoteException ex) {
- remove(r.binder);
+ mRemoveList.add(r.binder);
}
}
@@ -1497,7 +1499,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.callback.onMessageWaitingIndicatorChanged(
mMessageWaiting[phoneId]);
} catch (RemoteException ex) {
- remove(r.binder);
+ mRemoveList.add(r.binder);
}
}
@@ -1510,7 +1512,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.callback.onCallForwardingIndicatorChanged(
mCallForwarding[phoneId]);
} catch (RemoteException ex) {
- remove(r.binder);
+ mRemoveList.add(r.binder);
}
}
@@ -1535,7 +1537,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub {
r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId],
mDataConnectionNetworkType[phoneId]);
} catch (RemoteException ex) {
- remove(r.binder);
+ mRemoveList.add(r.binder);
}
}
}
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index d4c436f..5add88e 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -16,6 +16,7 @@
package com.android.server;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.textservice.ISpellCheckerService;
import com.android.internal.textservice.ISpellCheckerSession;
@@ -28,14 +29,18 @@ import org.xmlpull.v1.XmlPullParserException;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
import android.app.IUserSwitchObserver;
+import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -43,6 +48,7 @@ import android.os.IRemoteCallback;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.textservice.SpellCheckerService;
import android.text.TextUtils;
@@ -84,6 +90,12 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
public TextServicesManagerService(Context context) {
mSystemReady = false;
mContext = context;
+
+ final IntentFilter broadcastFilter = new IntentFilter();
+ broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
+ broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mContext.registerReceiver(new TextServicesBroadcastReceiver(), broadcastFilter);
+
int userId = UserHandle.USER_OWNER;
try {
ActivityManagerNative.getDefault().registerUserSwitchObserver(
@@ -119,6 +131,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
private void switchUserLocked(int userId) {
mSettings.setCurrentUserId(userId);
+ updateCurrentProfileIds();
unbindServiceLocked();
buildSpellCheckerMapLocked(mContext, mSpellCheckerList, mSpellCheckerMap, mSettings);
SpellCheckerInfo sci = getCurrentSpellChecker(null);
@@ -133,6 +146,16 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
+ void updateCurrentProfileIds() {
+ List<UserInfo> profiles =
+ UserManager.get(mContext).getProfiles(mSettings.getCurrentUserId());
+ int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
+ for (int i = 0; i < currentProfileIds.length; i++) {
+ currentProfileIds[i] = profiles.get(i).id;
+ }
+ mSettings.setCurrentProfileIds(currentProfileIds);
+ }
+
private class TextServicesMonitor extends PackageMonitor {
private boolean isChangingPackagesOfCurrentUser() {
final int userId = getChangingUserId();
@@ -171,6 +194,19 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
}
}
+ class TextServicesBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_USER_ADDED.equals(action)
+ || Intent.ACTION_USER_REMOVED.equals(action)) {
+ updateCurrentProfileIds();
+ return;
+ }
+ Slog.w(TAG, "Unexpected intent " + intent);
+ }
+ }
+
private static void buildSpellCheckerMapLocked(Context context,
ArrayList<SpellCheckerInfo> list, HashMap<String, SpellCheckerInfo> map,
TextServicesSettings settings) {
@@ -223,7 +259,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
Slog.d(TAG, "--- calledFromForegroundUserOrSystemProcess ? "
+ "calling uid = " + uid + " system uid = " + Process.SYSTEM_UID
+ " calling userId = " + userId + ", foreground user id = "
- + mSettings.getCurrentUserId());
+ + mSettings.getCurrentUserId() + ", calling pid = " + Binder.getCallingPid());
try {
final String[] packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
for (int i = 0; i < packageNames.length; ++i) {
@@ -237,10 +273,40 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
if (uid == Process.SYSTEM_UID || userId == mSettings.getCurrentUserId()) {
return true;
- } else {
- Slog.w(TAG, "--- IPC called from background users. Ignore. \n" + getStackTrace());
- return false;
}
+
+ // Permits current profile to use TSFM as long as the current text service is the system's
+ // one. This is a tentative solution and should be replaced with fully functional multiuser
+ // support.
+ // TODO: Implement multiuser support in TSMS.
+ final boolean isCurrentProfile = mSettings.isCurrentProfile(userId);
+ if (DBG) {
+ Slog.d(TAG, "--- userId = "+ userId + " isCurrentProfile = " + isCurrentProfile);
+ }
+ if (mSettings.isCurrentProfile(userId)) {
+ final SpellCheckerInfo spellCheckerInfo = getCurrentSpellCheckerWithoutVerification();
+ if (spellCheckerInfo != null) {
+ final ServiceInfo serviceInfo = spellCheckerInfo.getServiceInfo();
+ final boolean isSystemSpellChecker =
+ (serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ if (DBG) {
+ Slog.d(TAG, "--- current spell checker = "+ spellCheckerInfo.getPackageName()
+ + " isSystem = " + isSystemSpellChecker);
+ }
+ if (isSystemSpellChecker) {
+ return true;
+ }
+ }
+ }
+
+ // Unlike InputMethodManagerService#calledFromValidUser, INTERACT_ACROSS_USERS_FULL isn't
+ // taken into account here. Anyway this method is supposed to be removed once multiuser
+ // support is implemented.
+ if (DBG) {
+ Slog.d(TAG, "--- IPC from userId:" + userId + " is being ignored. \n"
+ + getStackTrace());
+ }
+ return false;
}
private boolean bindCurrentSpellCheckerService(
@@ -292,6 +358,10 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
if (!calledFromValidUser()) {
return null;
}
+ return getCurrentSpellCheckerWithoutVerification();
+ }
+
+ private SpellCheckerInfo getCurrentSpellCheckerWithoutVerification() {
synchronized (mSpellCheckerMap) {
final String curSpellCheckerId = mSettings.getSelectedSpellChecker();
if (DBG) {
@@ -914,6 +984,10 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
private static class TextServicesSettings {
private final ContentResolver mResolver;
private int mCurrentUserId;
+ @GuardedBy("mLock")
+ private int[] mCurrentProfileIds = new int[0];
+ private Object mLock = new Object();
+
public TextServicesSettings(ContentResolver resolver, int userId) {
mResolver = resolver;
mCurrentUserId = userId;
@@ -928,6 +1002,22 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
mCurrentUserId = userId;
}
+ public void setCurrentProfileIds(int[] currentProfileIds) {
+ synchronized (mLock) {
+ mCurrentProfileIds = currentProfileIds;
+ }
+ }
+
+ public boolean isCurrentProfile(int userId) {
+ synchronized (mLock) {
+ if (userId == mCurrentUserId) return true;
+ for (int i = 0; i < mCurrentProfileIds.length; i++) {
+ if (userId == mCurrentProfileIds[i]) return true;
+ }
+ return false;
+ }
+ }
+
public int getCurrentUserId() {
return mCurrentUserId;
}
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 89e3f49..8e46c4d 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -415,15 +415,9 @@ public class Watchdog extends Thread {
dumpKernelStackTraces();
}
- // Trigger the kernel to dump all blocked threads to the kernel log
- try {
- FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger");
- sysrq_trigger.write("w");
- sysrq_trigger.close();
- } catch (IOException e) {
- Slog.e(TAG, "Failed to write to /proc/sysrq-trigger");
- Slog.e(TAG, e.getMessage());
- }
+ // Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
+ doSysRq('w');
+ doSysRq('l');
// Try to add the error to the dropbox, but assuming that the ActivityManager
// itself may be deadlocked. (which has happened, causing this statement to
@@ -488,6 +482,16 @@ public class Watchdog extends Thread {
}
}
+ private void doSysRq(char c) {
+ try {
+ FileWriter sysrq_trigger = new FileWriter("/proc/sysrq-trigger");
+ sysrq_trigger.write(c);
+ sysrq_trigger.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to write to /proc/sysrq-trigger", e);
+ }
+ }
+
private File dumpKernelStackTraces() {
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
if (tracesPath == null || tracesPath.length() == 0) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8dfb321..9179cc4 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1606,192 +1606,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final ArrayList<ProcessMemInfo> memInfos = (ArrayList<ProcessMemInfo>)msg.obj;
Thread thread = new Thread() {
@Override public void run() {
- final SparseArray<ProcessMemInfo> infoMap
- = new SparseArray<ProcessMemInfo>(memInfos.size());
- for (int i=0, N=memInfos.size(); i<N; i++) {
- ProcessMemInfo mi = memInfos.get(i);
- infoMap.put(mi.pid, mi);
- }
- updateCpuStatsNow();
- synchronized (mProcessCpuTracker) {
- final int N = mProcessCpuTracker.countStats();
- for (int i=0; i<N; i++) {
- ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
- if (st.vsize > 0) {
- long pss = Debug.getPss(st.pid, null);
- if (pss > 0) {
- if (infoMap.indexOfKey(st.pid) < 0) {
- ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
- ProcessList.NATIVE_ADJ, -1, "native", null);
- mi.pss = pss;
- memInfos.add(mi);
- }
- }
- }
- }
- }
-
- long totalPss = 0;
- for (int i=0, N=memInfos.size(); i<N; i++) {
- ProcessMemInfo mi = memInfos.get(i);
- if (mi.pss == 0) {
- mi.pss = Debug.getPss(mi.pid, null);
- }
- totalPss += mi.pss;
- }
- Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
- @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
- if (lhs.oomAdj != rhs.oomAdj) {
- return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
- }
- if (lhs.pss != rhs.pss) {
- return lhs.pss < rhs.pss ? 1 : -1;
- }
- return 0;
- }
- });
-
- StringBuilder tag = new StringBuilder(128);
- StringBuilder stack = new StringBuilder(128);
- tag.append("Low on memory -- ");
- appendMemBucket(tag, totalPss, "total", false);
- appendMemBucket(stack, totalPss, "total", true);
-
- StringBuilder logBuilder = new StringBuilder(1024);
- logBuilder.append("Low on memory:\n");
-
- boolean firstLine = true;
- int lastOomAdj = Integer.MIN_VALUE;
- for (int i=0, N=memInfos.size(); i<N; i++) {
- ProcessMemInfo mi = memInfos.get(i);
-
- if (mi.oomAdj != ProcessList.NATIVE_ADJ
- && (mi.oomAdj < ProcessList.SERVICE_ADJ
- || mi.oomAdj == ProcessList.HOME_APP_ADJ
- || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
- if (lastOomAdj != mi.oomAdj) {
- lastOomAdj = mi.oomAdj;
- if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
- tag.append(" / ");
- }
- if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
- if (firstLine) {
- stack.append(":");
- firstLine = false;
- }
- stack.append("\n\t at ");
- } else {
- stack.append("$");
- }
- } else {
- tag.append(" ");
- stack.append("$");
- }
- if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
- appendMemBucket(tag, mi.pss, mi.name, false);
- }
- appendMemBucket(stack, mi.pss, mi.name, true);
- if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
- && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
- stack.append("(");
- for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
- if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
- stack.append(DUMP_MEM_OOM_LABEL[k]);
- stack.append(":");
- stack.append(DUMP_MEM_OOM_ADJ[k]);
- }
- }
- stack.append(")");
- }
- }
-
- logBuilder.append(" ");
- logBuilder.append(ProcessList.makeOomAdjString(mi.oomAdj));
- logBuilder.append(' ');
- logBuilder.append(ProcessList.makeProcStateString(mi.procState));
- logBuilder.append(' ');
- ProcessList.appendRamKb(logBuilder, mi.pss);
- logBuilder.append(" kB: ");
- logBuilder.append(mi.name);
- logBuilder.append(" (");
- logBuilder.append(mi.pid);
- logBuilder.append(") ");
- logBuilder.append(mi.adjType);
- logBuilder.append('\n');
- if (mi.adjReason != null) {
- logBuilder.append(" ");
- logBuilder.append(mi.adjReason);
- logBuilder.append('\n');
- }
- }
-
- logBuilder.append(" ");
- ProcessList.appendRamKb(logBuilder, totalPss);
- logBuilder.append(" kB: TOTAL\n");
-
- long[] infos = new long[Debug.MEMINFO_COUNT];
- Debug.getMemInfo(infos);
- logBuilder.append(" MemInfo: ");
- logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
- logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
- logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
- logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
- logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
- if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
- logBuilder.append(" ZRAM: ");
- logBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
- logBuilder.append(" kB RAM, ");
- logBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
- logBuilder.append(" kB swap total, ");
- logBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
- logBuilder.append(" kB swap free\n");
- }
- Slog.i(TAG, logBuilder.toString());
-
- StringBuilder dropBuilder = new StringBuilder(1024);
- /*
- StringWriter oomSw = new StringWriter();
- PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
- StringWriter catSw = new StringWriter();
- PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
- String[] emptyArgs = new String[] { };
- dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw);
- oomPw.flush();
- String oomString = oomSw.toString();
- */
- dropBuilder.append(stack);
- dropBuilder.append('\n');
- dropBuilder.append('\n');
- dropBuilder.append(logBuilder);
- dropBuilder.append('\n');
- /*
- dropBuilder.append(oomString);
- dropBuilder.append('\n');
- */
- StringWriter catSw = new StringWriter();
- synchronized (ActivityManagerService.this) {
- PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
- String[] emptyArgs = new String[] { };
- catPw.println();
- dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
- catPw.println();
- mServices.dumpServicesLocked(null, catPw, emptyArgs, 0,
- false, false, null);
- catPw.println();
- dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
- catPw.flush();
- }
- dropBuilder.append(catSw.toString());
- addErrorToDropBox("lowmem", null, "system_server", null,
- null, tag.toString(), dropBuilder.toString(), null, null);
- //Slog.i(TAG, "Sent to dropbox:");
- //Slog.i(TAG, dropBuilder.toString());
- synchronized (ActivityManagerService.this) {
- long now = SystemClock.uptimeMillis();
- if (mLastMemUsageReportTime < now) {
- mLastMemUsageReportTime = now;
- }
- }
+ reportMemUsage(memInfos);
}
};
thread.start();
@@ -1952,9 +1767,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ (SystemClock.uptimeMillis()-start) + "ms");
mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(),
- memInfo.getBuffersSizeKb()+memInfo.getShmemSizeKb()
- +memInfo.getSlabSizeKb(),
- nativeTotalPss);
+ memInfo.getKernelUsedSizeKb(), nativeTotalPss);
}
}
@@ -8849,7 +8662,8 @@ public final class ActivityManagerService extends ActivityManagerNative
task = mStackSupervisor.anyTaskForIdLocked(task.taskId);
if (task != null) {
if (!isSystemInitiated
- && ((mFocusedActivity == null) || (task != mFocusedActivity.task))) {
+ && ((mStackSupervisor.getFocusedStack() == null)
+ || (task != mStackSupervisor.getFocusedStack().topTask()))) {
throw new IllegalArgumentException("Invalid task, not in foreground");
}
mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated);
@@ -13923,6 +13737,35 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ private static final int KSM_SHARED = 0;
+ private static final int KSM_SHARING = 1;
+ private static final int KSM_UNSHARED = 2;
+ private static final int KSM_VOLATILE = 3;
+
+ private final long[] getKsmInfo() {
+ long[] longOut = new long[4];
+ final int[] SINGLE_LONG_FORMAT = new int[] {
+ Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
+ };
+ long[] longTmp = new long[1];
+ Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
+ SINGLE_LONG_FORMAT, null, longTmp, null);
+ longOut[KSM_SHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+ longTmp[0] = 0;
+ Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
+ SINGLE_LONG_FORMAT, null, longTmp, null);
+ longOut[KSM_SHARING] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+ longTmp[0] = 0;
+ Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
+ SINGLE_LONG_FORMAT, null, longTmp, null);
+ longOut[KSM_UNSHARED] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+ longTmp[0] = 0;
+ Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
+ SINGLE_LONG_FORMAT, null, longTmp, null);
+ longOut[KSM_VOLATILE] = longTmp[0] * ProcessList.PAGE_SIZE / 1024;
+ return longOut;
+ }
+
final void dumpApplicationMemoryUsage(FileDescriptor fd,
PrintWriter pw, String prefix, String[] args, boolean brief, PrintWriter categoryPw) {
boolean dumpDetails = false;
@@ -14240,8 +14083,7 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(),
memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(),
- memInfo.getBuffersSizeKb()+memInfo.getShmemSizeKb()+memInfo.getSlabSizeKb(),
- nativeProcTotalPss);
+ memInfo.getKernelUsedSizeKb(), nativeProcTotalPss);
}
}
if (!brief) {
@@ -14269,7 +14111,7 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(" Free RAM: "); pw.print(cachedPss + memInfo.getCachedSizeKb()
+ memInfo.getFreeSizeKb()); pw.print(" kB (");
pw.print(cachedPss); pw.print(" cached pss + ");
- pw.print(memInfo.getCachedSizeKb()); pw.print(" cached + ");
+ pw.print(memInfo.getCachedSizeKb()); pw.print(" cached kernel + ");
pw.print(memInfo.getFreeSizeKb()); pw.println(" free)");
} else {
pw.print("ram,"); pw.print(memInfo.getTotalSizeKb()); pw.print(",");
@@ -14280,16 +14122,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (!isCompact) {
pw.print(" Used RAM: "); pw.print(totalPss - cachedPss
- + memInfo.getBuffersSizeKb() + memInfo.getShmemSizeKb()
- + memInfo.getSlabSizeKb()); pw.print(" kB (");
+ + memInfo.getKernelUsedSizeKb()); pw.print(" kB (");
pw.print(totalPss - cachedPss); pw.print(" used pss + ");
- pw.print(memInfo.getBuffersSizeKb()); pw.print(" buffers + ");
- pw.print(memInfo.getShmemSizeKb()); pw.print(" shmem + ");
- pw.print(memInfo.getSlabSizeKb()); pw.println(" slab)");
+ pw.print(memInfo.getKernelUsedSizeKb()); pw.print(" kernel)\n");
pw.print(" Lost RAM: "); pw.print(memInfo.getTotalSizeKb()
- totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- - memInfo.getBuffersSizeKb() - memInfo.getShmemSizeKb()
- - memInfo.getSlabSizeKb()); pw.println(" kB");
+ - memInfo.getKernelUsedSizeKb()); pw.println(" kB");
}
if (!brief) {
if (memInfo.getZramTotalSizeKb() != 0) {
@@ -14307,32 +14145,16 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.println(memInfo.getSwapFreeSizeKb());
}
}
- final int[] SINGLE_LONG_FORMAT = new int[] {
- Process.PROC_SPACE_TERM|Process.PROC_OUT_LONG
- };
- long[] longOut = new long[1];
- Process.readProcFile("/sys/kernel/mm/ksm/pages_shared",
- SINGLE_LONG_FORMAT, null, longOut, null);
- long shared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
- longOut[0] = 0;
- Process.readProcFile("/sys/kernel/mm/ksm/pages_sharing",
- SINGLE_LONG_FORMAT, null, longOut, null);
- long sharing = longOut[0] * ProcessList.PAGE_SIZE / 1024;
- longOut[0] = 0;
- Process.readProcFile("/sys/kernel/mm/ksm/pages_unshared",
- SINGLE_LONG_FORMAT, null, longOut, null);
- long unshared = longOut[0] * ProcessList.PAGE_SIZE / 1024;
- longOut[0] = 0;
- Process.readProcFile("/sys/kernel/mm/ksm/pages_volatile",
- SINGLE_LONG_FORMAT, null, longOut, null);
- long voltile = longOut[0] * ProcessList.PAGE_SIZE / 1024;
+ final long[] ksm = getKsmInfo();
if (!isCompact) {
- if (sharing != 0 || shared != 0 || unshared != 0 || voltile != 0) {
- pw.print(" KSM: "); pw.print(sharing);
+ if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
+ || ksm[KSM_VOLATILE] != 0) {
+ pw.print(" KSM: "); pw.print(ksm[KSM_SHARING]);
pw.print(" kB saved from shared ");
- pw.print(shared); pw.println(" kB");
- pw.print(" "); pw.print(unshared); pw.print(" kB unshared; ");
- pw.print(voltile); pw.println(" kB volatile");
+ pw.print(ksm[KSM_SHARED]); pw.println(" kB");
+ pw.print(" "); pw.print(ksm[KSM_UNSHARED]);
+ pw.print(" kB unshared; ");
+ pw.print(ksm[KSM_VOLATILE]); pw.println(" kB volatile");
}
pw.print(" Tuning: ");
pw.print(ActivityManager.staticGetMemoryClass());
@@ -14352,9 +14174,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
pw.println();
} else {
- pw.print("ksm,"); pw.print(sharing); pw.print(",");
- pw.print(shared); pw.print(","); pw.print(unshared); pw.print(",");
- pw.println(voltile);
+ pw.print("ksm,"); pw.print(ksm[KSM_SHARING]); pw.print(",");
+ pw.print(ksm[KSM_SHARED]); pw.print(","); pw.print(ksm[KSM_UNSHARED]);
+ pw.print(","); pw.println(ksm[KSM_VOLATILE]);
pw.print("tuning,");
pw.print(ActivityManager.staticGetMemoryClass());
pw.print(',');
@@ -14373,6 +14195,265 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
+ String name) {
+ sb.append(" ");
+ sb.append(ProcessList.makeOomAdjString(oomAdj));
+ sb.append(' ');
+ sb.append(ProcessList.makeProcStateString(procState));
+ sb.append(' ');
+ ProcessList.appendRamKb(sb, pss);
+ sb.append(" kB: ");
+ sb.append(name);
+ }
+
+ private void appendMemInfo(StringBuilder sb, ProcessMemInfo mi) {
+ appendBasicMemEntry(sb, mi.oomAdj, mi.procState, mi.pss, mi.name);
+ sb.append(" (");
+ sb.append(mi.pid);
+ sb.append(") ");
+ sb.append(mi.adjType);
+ sb.append('\n');
+ if (mi.adjReason != null) {
+ sb.append(" ");
+ sb.append(mi.adjReason);
+ sb.append('\n');
+ }
+ }
+
+ void reportMemUsage(ArrayList<ProcessMemInfo> memInfos) {
+ final SparseArray<ProcessMemInfo> infoMap = new SparseArray<>(memInfos.size());
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ infoMap.put(mi.pid, mi);
+ }
+ updateCpuStatsNow();
+ synchronized (mProcessCpuTracker) {
+ final int N = mProcessCpuTracker.countStats();
+ for (int i=0; i<N; i++) {
+ ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
+ if (st.vsize > 0) {
+ long pss = Debug.getPss(st.pid, null);
+ if (pss > 0) {
+ if (infoMap.indexOfKey(st.pid) < 0) {
+ ProcessMemInfo mi = new ProcessMemInfo(st.name, st.pid,
+ ProcessList.NATIVE_ADJ, -1, "native", null);
+ mi.pss = pss;
+ memInfos.add(mi);
+ }
+ }
+ }
+ }
+ }
+
+ long totalPss = 0;
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+ if (mi.pss == 0) {
+ mi.pss = Debug.getPss(mi.pid, null);
+ }
+ totalPss += mi.pss;
+ }
+ Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
+ @Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
+ if (lhs.oomAdj != rhs.oomAdj) {
+ return lhs.oomAdj < rhs.oomAdj ? -1 : 1;
+ }
+ if (lhs.pss != rhs.pss) {
+ return lhs.pss < rhs.pss ? 1 : -1;
+ }
+ return 0;
+ }
+ });
+
+ StringBuilder tag = new StringBuilder(128);
+ StringBuilder stack = new StringBuilder(128);
+ tag.append("Low on memory -- ");
+ appendMemBucket(tag, totalPss, "total", false);
+ appendMemBucket(stack, totalPss, "total", true);
+
+ StringBuilder fullNativeBuilder = new StringBuilder(1024);
+ StringBuilder shortNativeBuilder = new StringBuilder(1024);
+ StringBuilder fullJavaBuilder = new StringBuilder(1024);
+
+ boolean firstLine = true;
+ int lastOomAdj = Integer.MIN_VALUE;
+ long extraNativeRam = 0;
+ long cachedPss = 0;
+ for (int i=0, N=memInfos.size(); i<N; i++) {
+ ProcessMemInfo mi = memInfos.get(i);
+
+ if (mi.oomAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+ cachedPss += mi.pss;
+ }
+
+ if (mi.oomAdj != ProcessList.NATIVE_ADJ
+ && (mi.oomAdj < ProcessList.SERVICE_ADJ
+ || mi.oomAdj == ProcessList.HOME_APP_ADJ
+ || mi.oomAdj == ProcessList.PREVIOUS_APP_ADJ)) {
+ if (lastOomAdj != mi.oomAdj) {
+ lastOomAdj = mi.oomAdj;
+ if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ tag.append(" / ");
+ }
+ if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ) {
+ if (firstLine) {
+ stack.append(":");
+ firstLine = false;
+ }
+ stack.append("\n\t at ");
+ } else {
+ stack.append("$");
+ }
+ } else {
+ tag.append(" ");
+ stack.append("$");
+ }
+ if (mi.oomAdj <= ProcessList.FOREGROUND_APP_ADJ) {
+ appendMemBucket(tag, mi.pss, mi.name, false);
+ }
+ appendMemBucket(stack, mi.pss, mi.name, true);
+ if (mi.oomAdj >= ProcessList.FOREGROUND_APP_ADJ
+ && ((i+1) >= N || memInfos.get(i+1).oomAdj != lastOomAdj)) {
+ stack.append("(");
+ for (int k=0; k<DUMP_MEM_OOM_ADJ.length; k++) {
+ if (DUMP_MEM_OOM_ADJ[k] == mi.oomAdj) {
+ stack.append(DUMP_MEM_OOM_LABEL[k]);
+ stack.append(":");
+ stack.append(DUMP_MEM_OOM_ADJ[k]);
+ }
+ }
+ stack.append(")");
+ }
+ }
+
+ appendMemInfo(fullNativeBuilder, mi);
+ if (mi.oomAdj == ProcessList.NATIVE_ADJ) {
+ // The short form only has native processes that are >= 1MB.
+ if (mi.pss >= 1000) {
+ appendMemInfo(shortNativeBuilder, mi);
+ } else {
+ extraNativeRam += mi.pss;
+ }
+ } else {
+ // Short form has all other details, but if we have collected RAM
+ // from smaller native processes let's dump a summary of that.
+ if (extraNativeRam > 0) {
+ appendBasicMemEntry(shortNativeBuilder, ProcessList.NATIVE_ADJ,
+ -1, extraNativeRam, "(Other native)");
+ shortNativeBuilder.append('\n');
+ extraNativeRam = 0;
+ }
+ appendMemInfo(fullJavaBuilder, mi);
+ }
+ }
+
+ fullJavaBuilder.append(" ");
+ ProcessList.appendRamKb(fullJavaBuilder, totalPss);
+ fullJavaBuilder.append(" kB: TOTAL\n");
+
+ MemInfoReader memInfo = new MemInfoReader();
+ memInfo.readMemInfo();
+ final long[] infos = memInfo.getRawInfo();
+
+ StringBuilder memInfoBuilder = new StringBuilder(1024);
+ Debug.getMemInfo(infos);
+ memInfoBuilder.append(" MemInfo: ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_VM_ALLOC_USED]).append(" kB vm alloc, ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n");
+ memInfoBuilder.append(" ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n");
+ if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) {
+ memInfoBuilder.append(" ZRAM: ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_ZRAM_TOTAL]);
+ memInfoBuilder.append(" kB RAM, ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_SWAP_TOTAL]);
+ memInfoBuilder.append(" kB swap total, ");
+ memInfoBuilder.append(infos[Debug.MEMINFO_SWAP_FREE]);
+ memInfoBuilder.append(" kB swap free\n");
+ }
+ final long[] ksm = getKsmInfo();
+ if (ksm[KSM_SHARING] != 0 || ksm[KSM_SHARED] != 0 || ksm[KSM_UNSHARED] != 0
+ || ksm[KSM_VOLATILE] != 0) {
+ memInfoBuilder.append(" KSM: "); memInfoBuilder.append(ksm[KSM_SHARING]);
+ memInfoBuilder.append(" kB saved from shared ");
+ memInfoBuilder.append(ksm[KSM_SHARED]); memInfoBuilder.append(" kB\n");
+ memInfoBuilder.append(" "); memInfoBuilder.append(ksm[KSM_UNSHARED]);
+ memInfoBuilder.append(" kB unshared; ");
+ memInfoBuilder.append(ksm[KSM_VOLATILE]); memInfoBuilder.append(" kB volatile\n");
+ }
+ memInfoBuilder.append(" Free RAM: ");
+ memInfoBuilder.append(cachedPss + memInfo.getCachedSizeKb()
+ + memInfo.getFreeSizeKb());
+ memInfoBuilder.append(" kB\n");
+ memInfoBuilder.append(" Used RAM: ");
+ memInfoBuilder.append(totalPss - cachedPss + memInfo.getKernelUsedSizeKb());
+ memInfoBuilder.append(" kB\n");
+ memInfoBuilder.append(" Lost RAM: ");
+ memInfoBuilder.append(memInfo.getTotalSizeKb()
+ - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
+ - memInfo.getKernelUsedSizeKb());
+ memInfoBuilder.append(" kB\n");
+ Slog.i(TAG, "Low on memory:");
+ Slog.i(TAG, shortNativeBuilder.toString());
+ Slog.i(TAG, fullJavaBuilder.toString());
+ Slog.i(TAG, memInfoBuilder.toString());
+
+ StringBuilder dropBuilder = new StringBuilder(1024);
+ /*
+ StringWriter oomSw = new StringWriter();
+ PrintWriter oomPw = new FastPrintWriter(oomSw, false, 256);
+ StringWriter catSw = new StringWriter();
+ PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+ String[] emptyArgs = new String[] { };
+ dumpApplicationMemoryUsage(null, oomPw, " ", emptyArgs, true, catPw);
+ oomPw.flush();
+ String oomString = oomSw.toString();
+ */
+ dropBuilder.append("Low on memory:");
+ dropBuilder.append(stack);
+ dropBuilder.append('\n');
+ dropBuilder.append(fullNativeBuilder);
+ dropBuilder.append(fullJavaBuilder);
+ dropBuilder.append('\n');
+ dropBuilder.append(memInfoBuilder);
+ dropBuilder.append('\n');
+ /*
+ dropBuilder.append(oomString);
+ dropBuilder.append('\n');
+ */
+ StringWriter catSw = new StringWriter();
+ synchronized (ActivityManagerService.this) {
+ PrintWriter catPw = new FastPrintWriter(catSw, false, 256);
+ String[] emptyArgs = new String[] { };
+ catPw.println();
+ dumpProcessesLocked(null, catPw, emptyArgs, 0, false, null);
+ catPw.println();
+ mServices.dumpServicesLocked(null, catPw, emptyArgs, 0,
+ false, false, null);
+ catPw.println();
+ dumpActivitiesLocked(null, catPw, emptyArgs, 0, false, false, null);
+ catPw.flush();
+ }
+ dropBuilder.append(catSw.toString());
+ addErrorToDropBox("lowmem", null, "system_server", null,
+ null, tag.toString(), dropBuilder.toString(), null, null);
+ //Slog.i(TAG, "Sent to dropbox:");
+ //Slog.i(TAG, dropBuilder.toString());
+ synchronized (ActivityManagerService.this) {
+ long now = SystemClock.uptimeMillis();
+ if (mLastMemUsageReportTime < now) {
+ mLastMemUsageReportTime = now;
+ }
+ }
+ }
+
/**
* Searches array of arguments for the specified string
* @param args array of argument strings
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 03dd3c0..eaff6be 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -120,7 +120,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
static final boolean DEBUG_RELEASE = DEBUG || false;
static final boolean DEBUG_SAVED_STATE = DEBUG || false;
static final boolean DEBUG_SCREENSHOTS = DEBUG || false;
- static final boolean DEBUG_STATES = DEBUG || false;
+ static final boolean DEBUG_STATES = DEBUG || true;
static final boolean DEBUG_VISIBLE_BEHIND = DEBUG || false;
public static final int HOME_STACK_ID = 0;
@@ -444,10 +444,6 @@ public final class ActivityStackSupervisor implements DisplayListener {
return mService.startHomeActivityLocked(mCurrentUser);
}
- void keyguardWaitingForActivityDrawn() {
- mWindowManager.keyguardWaitingForActivityDrawn();
- }
-
TaskRecord anyTaskForIdLocked(int id) {
int numDisplays = mActivityDisplays.size();
for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java
index 5768ddb..b3777ed 100644
--- a/services/core/java/com/android/server/am/LockTaskNotify.java
+++ b/services/core/java/com/android/server/am/LockTaskNotify.java
@@ -19,6 +19,7 @@ package com.android.server.am;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.view.WindowManager;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
@@ -56,8 +57,7 @@ public class LockTaskNotify {
if (mLastToast != null) {
mLastToast.cancel();
}
- mLastToast = Toast.makeText(mContext, text, Toast.LENGTH_LONG);
- mLastToast.show();
+ mLastToast = makeAllUserToastAndShow(text);
}
public void show(boolean starting) {
@@ -65,7 +65,15 @@ public class LockTaskNotify {
if (starting) {
showString = R.string.lock_to_app_start;
}
- Toast.makeText(mContext, mContext.getString(showString), Toast.LENGTH_LONG).show();
+ makeAllUserToastAndShow(mContext.getString(showString));
+ }
+
+ private Toast makeAllUserToastAndShow(String text) {
+ Toast toast = Toast.makeText(mContext, text, Toast.LENGTH_LONG);
+ toast.getWindowParams().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+ toast.show();
+ return toast;
}
private final class H extends Handler {
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index afc781f..b331c84 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -166,7 +166,7 @@ public class TaskPersister {
break;
}
}
- if (queueNdx < 0) {
+ if (queueNdx < 0 && task.isPersistable) {
mWriteQueue.add(new TaskWriteQueueItem(task));
}
} else {
@@ -473,13 +473,15 @@ public class TaskPersister {
if (DEBUG) Slog.d(TAG, "mRecents=" + tasks);
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = tasks.get(taskNdx);
- if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" +
- task.isPersistable);
- if (task.isPersistable && !task.stack.isHomeStack()) {
+ if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task +
+ " persistable=" + task.isPersistable);
+ if ((task.isPersistable || task.inRecents)
+ && !task.stack.isHomeStack()) {
if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
persistentTaskIds.add(task.taskId);
} else {
- if (DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + task);
+ if (DEBUG) Slog.d(TAG,
+ "omitting from persistentTaskIds task=" + task);
}
}
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4dfd23b..ee93233 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -144,7 +144,7 @@ final class TaskRecord {
boolean mReuseTask = false;
private Bitmap mLastThumbnail; // Last thumbnail captured for this item.
- private final File mLastThumbnailFile; // File containing last thubmnail.
+ private final File mLastThumbnailFile; // File containing last thumbnail.
private final String mFilename;
CharSequence lastDescription; // Last description captured for this item.
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index dfc8df5..36263ec 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -17,17 +17,11 @@
package com.android.server.am;
import android.app.AlertDialog;
-import android.app.Service;
-import android.content.ActivityNotFoundException;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
import android.content.res.Resources;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Slog;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.TextView;
@@ -39,11 +33,10 @@ import com.android.internal.R;
* in the background rather than just freeze the screen and not know if the user-switch affordance
* was being handled.
*/
-final class UserSwitchingDialog extends AlertDialog {
+final class UserSwitchingDialog extends AlertDialog
+ implements ViewTreeObserver.OnWindowShownListener {
private static final String TAG = "ActivityManagerUserSwitchingDialog";
- private static final int MSG_START_USER = 1;
-
private final ActivityManagerService mService;
private final int mUserId;
@@ -74,19 +67,21 @@ final class UserSwitchingDialog extends AlertDialog {
@Override
public void show() {
+ // Slog.v(TAG, "show called");
super.show();
- // TODO: Instead of just an arbitrary delay, wait for a signal that the window was fully
- // displayed by the window manager
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_USER), 250);
+ final View decorView = getWindow().getDecorView();
+ if (decorView != null) {
+ decorView.getViewTreeObserver().addOnWindowShownListener(this);
+ }
}
- private final Handler mHandler = new Handler() {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_START_USER:
- mService.startUserInForeground(mUserId, UserSwitchingDialog.this);
- break;
- }
+ @Override
+ public void onWindowShown() {
+ // Slog.v(TAG, "onWindowShown called");
+ mService.startUserInForeground(mUserId, this);
+ final View decorView = getWindow().getDecorView();
+ if (decorView != null) {
+ decorView.getViewTreeObserver().removeOnWindowShownListener(this);
}
- };
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index c382be0..576556b 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
import java.net.Inet4Address;
@@ -43,45 +44,41 @@ import com.android.server.net.BaseNetworkObserver;
* Class to manage a 464xlat CLAT daemon.
*/
public class Nat464Xlat extends BaseNetworkObserver {
- private Context mContext;
- private INetworkManagementService mNMService;
- private IConnectivityManager mConnService;
- // Whether we started clatd and expect it to be running.
- private boolean mIsStarted;
- // Whether the clatd interface exists (i.e., clatd is running).
- private boolean mIsRunning;
- // The LinkProperties of the clat interface.
- private LinkProperties mLP;
- // Current LinkProperties of the network. Includes mLP as a stacked link when clat is active.
- private LinkProperties mBaseLP;
+ private static final String TAG = "Nat464Xlat";
+
+ // This must match the interface prefix in clatd.c.
+ private static final String CLAT_PREFIX = "v4-";
+
+ private final INetworkManagementService mNMService;
+
// ConnectivityService Handler for LinkProperties updates.
- private Handler mHandler;
- // Marker to connote which network we're augmenting.
- private Messenger mNetworkMessenger;
+ private final Handler mHandler;
- // This must match the interface name in clatd.conf.
- private static final String CLAT_INTERFACE_NAME = "clat4";
+ // The network we're running on, and its type.
+ private final NetworkAgentInfo mNetwork;
- private static final String TAG = "Nat464Xlat";
+ // Internal state variables.
+ //
+ // The possible states are:
+ // - Idle: start() not called. Everything is null.
+ // - Starting: start() called. Interfaces are non-null. isStarted() returns true.
+ // mIsRunning is false.
+ // - Running: start() called, and interfaceAdded() told us that mIface is up. Clat IP address
+ // is non-null. mIsRunning is true.
+ //
+ // Once mIface is non-null and isStarted() is true, methods called by ConnectivityService on
+ // its handler thread must not modify any internal state variables; they are only updated by the
+ // interface observers, called on the notification threads.
+ private String mBaseIface;
+ private String mIface;
+ private boolean mIsRunning;
- public Nat464Xlat(Context context, INetworkManagementService nmService,
- IConnectivityManager connService, Handler handler) {
- mContext = context;
+ public Nat464Xlat(
+ Context context, INetworkManagementService nmService,
+ Handler handler, NetworkAgentInfo nai) {
mNMService = nmService;
- mConnService = connService;
mHandler = handler;
-
- mIsStarted = false;
- mIsRunning = false;
- mLP = new LinkProperties();
-
- // If this is a runtime restart, it's possible that clatd is already
- // running, but we don't know about it. If so, stop it.
- try {
- if (mNMService.isClatdStarted()) {
- mNMService.stopClatd();
- }
- } catch(RemoteException e) {} // Well, we tried.
+ mNetwork = nai;
}
/**
@@ -94,137 +91,196 @@ public class Nat464Xlat extends BaseNetworkObserver {
final boolean connected = nai.networkInfo.isConnected();
final boolean hasIPv4Address =
(nai.linkProperties != null) ? nai.linkProperties.hasIPv4Address() : false;
- Slog.d(TAG, "requiresClat: netType=" + netType +
- ", connected=" + connected +
- ", hasIPv4Address=" + hasIPv4Address);
- // Only support clat on mobile for now.
- return netType == TYPE_MOBILE && connected && !hasIPv4Address;
+ // Only support clat on mobile and wifi for now, because these are the only IPv6-only
+ // networks we can connect to.
+ return connected && !hasIPv4Address && (netType == TYPE_MOBILE || netType == TYPE_WIFI);
}
- public boolean isRunningClat(NetworkAgentInfo network) {
- return mNetworkMessenger == network.messenger;
+ /**
+ * Determines whether clatd is started. Always true, except a) if start has not yet been called,
+ * or b) if our interface was removed.
+ */
+ public boolean isStarted() {
+ return mIface != null;
+ }
+
+ /**
+ * Clears internal state. Must not be called by ConnectivityService.
+ */
+ private void clear() {
+ mIface = null;
+ mBaseIface = null;
+ mIsRunning = false;
}
/**
- * Starts the clat daemon.
- * @param lp The link properties of the interface to start clatd on.
+ * Starts the clat daemon. Called by ConnectivityService on the handler thread.
*/
- public void startClat(NetworkAgentInfo network) {
- if (mNetworkMessenger != null && mNetworkMessenger != network.messenger) {
- Slog.e(TAG, "startClat: too many networks requesting clat");
+ public void start() {
+ if (isStarted()) {
+ Slog.e(TAG, "startClat: already started");
return;
}
- mNetworkMessenger = network.messenger;
- LinkProperties lp = network.linkProperties;
- mBaseLP = new LinkProperties(lp);
- if (mIsStarted) {
- Slog.e(TAG, "startClat: already started");
+
+ if (mNetwork.linkProperties == null) {
+ Slog.e(TAG, "startClat: Can't start clat with null LinkProperties");
return;
}
- String iface = lp.getInterfaceName();
- Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp);
+
try {
- mNMService.startClatd(iface);
+ mNMService.registerObserver(this);
} catch(RemoteException e) {
- Slog.e(TAG, "Error starting clat daemon: " + e);
+ Slog.e(TAG, "startClat: Can't register interface observer for clat on " + mNetwork);
+ return;
+ }
+
+ mBaseIface = mNetwork.linkProperties.getInterfaceName();
+ if (mBaseIface == null) {
+ Slog.e(TAG, "startClat: Can't start clat on null interface");
+ return;
+ }
+ mIface = CLAT_PREFIX + mBaseIface;
+ // From now on, isStarted() will return true.
+
+ Slog.i(TAG, "Starting clatd on " + mBaseIface);
+ try {
+ mNMService.startClatd(mBaseIface);
+ } catch(RemoteException|IllegalStateException e) {
+ Slog.e(TAG, "Error starting clatd: " + e);
}
- mIsStarted = true;
}
/**
- * Stops the clat daemon.
+ * Stops the clat daemon. Called by ConnectivityService on the handler thread.
*/
- public void stopClat() {
- if (mIsStarted) {
+ public void stop() {
+ if (isStarted()) {
Slog.i(TAG, "Stopping clatd");
try {
- mNMService.stopClatd();
- } catch(RemoteException e) {
- Slog.e(TAG, "Error stopping clat daemon: " + e);
+ mNMService.stopClatd(mBaseIface);
+ } catch(RemoteException|IllegalStateException e) {
+ Slog.e(TAG, "Error stopping clatd: " + e);
}
- mIsStarted = false;
- mIsRunning = false;
- mNetworkMessenger = null;
- mBaseLP = null;
- mLP.clear();
+ // When clatd stops and its interface is deleted, interfaceRemoved() will notify
+ // ConnectivityService and call clear().
} else {
- Slog.e(TAG, "stopClat: already stopped");
+ Slog.e(TAG, "clatd: already stopped");
}
}
- private void updateConnectivityService() {
- Message msg = mHandler.obtainMessage(
- NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, mBaseLP);
- msg.replyTo = mNetworkMessenger;
+ private void updateConnectivityService(LinkProperties lp) {
+ Message msg = mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, lp);
+ msg.replyTo = mNetwork.messenger;
Slog.i(TAG, "sending message to ConnectivityService: " + msg);
msg.sendToTarget();
}
- // Copies the stacked clat link in oldLp, if any, to the LinkProperties in nai.
- public void fixupLinkProperties(NetworkAgentInfo nai, LinkProperties oldLp) {
- if (isRunningClat(nai) &&
- nai.linkProperties != null &&
- !nai.linkProperties.getAllInterfaceNames().contains(CLAT_INTERFACE_NAME)) {
- Slog.d(TAG, "clatd running, updating NAI for " + nai.linkProperties.getInterfaceName());
+ /**
+ * Copies the stacked clat link in oldLp, if any, to the LinkProperties in mNetwork.
+ * This is necessary because the LinkProperties in mNetwork come from the transport layer, which
+ * has no idea that 464xlat is running on top of it.
+ */
+ public void fixupLinkProperties(LinkProperties oldLp) {
+ if (mNetwork.clatd != null &&
+ mIsRunning &&
+ mNetwork.linkProperties != null &&
+ !mNetwork.linkProperties.getAllInterfaceNames().contains(mIface)) {
+ Slog.d(TAG, "clatd running, updating NAI for " + mIface);
for (LinkProperties stacked: oldLp.getStackedLinks()) {
- if (CLAT_INTERFACE_NAME.equals(stacked.getInterfaceName())) {
- nai.linkProperties.addStackedLink(stacked);
+ if (mIface.equals(stacked.getInterfaceName())) {
+ mNetwork.linkProperties.addStackedLink(stacked);
break;
}
}
}
}
+ private LinkProperties makeLinkProperties(LinkAddress clatAddress) {
+ LinkProperties stacked = new LinkProperties();
+ stacked.setInterfaceName(mIface);
+
+ // Although the clat interface is a point-to-point tunnel, we don't
+ // point the route directly at the interface because some apps don't
+ // understand routes without gateways (see, e.g., http://b/9597256
+ // http://b/9597516). Instead, set the next hop of the route to the
+ // clat IPv4 address itself (for those apps, it doesn't matter what
+ // the IP of the gateway is, only that there is one).
+ RouteInfo ipv4Default = new RouteInfo(
+ new LinkAddress(Inet4Address.ANY, 0),
+ clatAddress.getAddress(), mIface);
+ stacked.addRoute(ipv4Default);
+ stacked.addLinkAddress(clatAddress);
+ return stacked;
+ }
+
+ private LinkAddress getLinkAddress(String iface) {
+ try {
+ InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
+ return config.getLinkAddress();
+ } catch(RemoteException|IllegalStateException e) {
+ Slog.e(TAG, "Error getting link properties: " + e);
+ return null;
+ }
+ }
+
+ private void maybeSetIpv6NdOffload(String iface, boolean on) {
+ if (mNetwork.networkInfo.getType() != TYPE_WIFI) {
+ return;
+ }
+ try {
+ Slog.d(TAG, (on ? "En" : "Dis") + "abling ND offload on " + iface);
+ mNMService.setInterfaceIpv6NdOffload(iface, on);
+ } catch(RemoteException|IllegalStateException e) {
+ Slog.w(TAG, "Changing IPv6 ND offload on " + iface + "failed: " + e);
+ }
+ }
+
@Override
public void interfaceAdded(String iface) {
- if (iface.equals(CLAT_INTERFACE_NAME)) {
- Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
- " added, mIsRunning = " + mIsRunning + " -> true");
- mIsRunning = true;
-
- // Create the LinkProperties for the clat interface by fetching the
- // IPv4 address for the interface and adding an IPv4 default route,
- // then stack the LinkProperties on top of the link it's running on.
- try {
- InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
- LinkAddress clatAddress = config.getLinkAddress();
- mLP.clear();
- mLP.setInterfaceName(iface);
-
- // Although the clat interface is a point-to-point tunnel, we don't
- // point the route directly at the interface because some apps don't
- // understand routes without gateways (see, e.g., http://b/9597256
- // http://b/9597516). Instead, set the next hop of the route to the
- // clat IPv4 address itself (for those apps, it doesn't matter what
- // the IP of the gateway is, only that there is one).
- RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0),
- clatAddress.getAddress(), iface);
- mLP.addRoute(ipv4Default);
- mLP.addLinkAddress(clatAddress);
- mBaseLP.addStackedLink(mLP);
- Slog.i(TAG, "Adding stacked link. tracker LP: " + mBaseLP);
- updateConnectivityService();
- } catch(RemoteException e) {
- Slog.e(TAG, "Error getting link properties: " + e);
+ // Called by the InterfaceObserver on its own thread, so can race with stop().
+ if (isStarted() && mIface.equals(iface)) {
+ Slog.i(TAG, "interface " + iface + " added, mIsRunning " + mIsRunning + "->true");
+
+ if (!mIsRunning) {
+ LinkAddress clatAddress = getLinkAddress(iface);
+ if (clatAddress == null) {
+ return;
+ }
+ mIsRunning = true;
+ maybeSetIpv6NdOffload(mBaseIface, false);
+ LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
+ lp.addStackedLink(makeLinkProperties(clatAddress));
+ Slog.i(TAG, "Adding stacked link " + mIface + " on top of " + mBaseIface);
+ updateConnectivityService(lp);
}
}
}
@Override
public void interfaceRemoved(String iface) {
- if (iface == CLAT_INTERFACE_NAME) {
+ if (isStarted() && mIface.equals(iface)) {
+ Slog.i(TAG, "interface " + iface + " removed, mIsRunning " + mIsRunning + "->false");
+
if (mIsRunning) {
- NetworkUtils.resetConnections(
- CLAT_INTERFACE_NAME,
- NetworkUtils.RESET_IPV4_ADDRESSES);
- mBaseLP.removeStackedLink(mLP);
- updateConnectivityService();
+ // The interface going away likely means clatd has crashed. Ask netd to stop it,
+ // because otherwise when we try to start it again on the same base interface netd
+ // will complain that it's already started.
+ //
+ // Note that this method can be called by the interface observer at the same time
+ // that ConnectivityService calls stop(). In this case, the second call to
+ // stopClatd() will just throw IllegalStateException, which we'll ignore.
+ try {
+ mNMService.unregisterObserver(this);
+ mNMService.stopClatd(mBaseIface);
+ } catch (RemoteException|IllegalStateException e) {
+ // Well, we tried.
+ }
+ maybeSetIpv6NdOffload(mBaseIface, true);
+ LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
+ lp.removeStackedLink(mIface);
+ clear();
+ updateConnectivityService(lp);
}
- Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME +
- " removed, mIsRunning = " + mIsRunning + " -> false");
- mIsRunning = false;
- mLP.clear();
- Slog.i(TAG, "mLP = " + mLP);
}
}
-};
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 15ffc0d..4cf2a4a 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -63,6 +63,9 @@ public class NetworkAgentInfo {
public final Messenger messenger;
public final AsyncChannel asyncChannel;
+ // Used by ConnectivityService to keep track of 464xlat.
+ public Nat464Xlat clatd;
+
public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
NetworkMisc misc) {
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 07fe7ba..7d1da01 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -265,14 +265,9 @@ public class PacManager {
}
Intent intent = new Intent();
intent.setClassName(PAC_PACKAGE, PAC_SERVICE);
- // Already bound no need to bind again.
if ((mProxyConnection != null) && (mConnection != null)) {
- if (mLastPort != -1) {
- sendPacBroadcast(new ProxyInfo(mPacUrl, mLastPort));
- } else {
- Log.e(TAG, "Received invalid port from Local Proxy,"
- + " PAC will not be operational");
- }
+ // Already bound no need to bind again, just download the new file.
+ IoThread.getHandler().post(mPacDownloader);
return;
}
mConnection = new ServiceConnection() {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 3f6b71a..83756aa 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -215,7 +215,7 @@ public class Vpn {
*/
public synchronized boolean prepare(String oldPackage, String newPackage) {
// Return false if the package does not match.
- if (oldPackage != null && !oldPackage.equals(mPackage)) {
+ if (oldPackage != null && getAppUid(oldPackage, mUserHandle) != mOwnerUID) {
// The package doesn't match. If this VPN was not previously authorized, return false
// to force user authorization. Otherwise, revoke the VPN anyway.
if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) {
@@ -234,8 +234,8 @@ public class Vpn {
}
// Return true if we do not need to revoke.
- if (newPackage == null ||
- (newPackage.equals(mPackage) && !newPackage.equals(VpnConfig.LEGACY_VPN))) {
+ if (newPackage == null || (!newPackage.equals(VpnConfig.LEGACY_VPN) &&
+ getAppUid(newPackage, mUserHandle) == mOwnerUID)) {
return true;
}
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 3b23b6a..f514531 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -248,6 +248,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter {
mInfo.width = mWidth;
mInfo.height = mHeight;
mInfo.refreshRate = mRefreshRate;
+ mInfo.supportedRefreshRates = new float[] { mRefreshRate };
mInfo.densityDpi = mDensityDpi;
mInfo.xDpi = mDensityDpi;
mInfo.yDpi = mDensityDpi;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index c2b4478..0232bad 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -257,6 +257,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter {
mInfo.width = mWidth;
mInfo.height = mHeight;
mInfo.refreshRate = 60;
+ mInfo.supportedRefreshRates = new float[] { 60.0f };
mInfo.densityDpi = mDensityDpi;
mInfo.xDpi = mDensityDpi;
mInfo.yDpi = mDensityDpi;
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index a17d731..6b010d9 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -625,6 +625,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
mInfo.width = mWidth;
mInfo.height = mHeight;
mInfo.refreshRate = mRefreshRate;
+ mInfo.supportedRefreshRates = new float[] { mRefreshRate };
mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame
mInfo.flags = mFlags;
mInfo.type = Display.TYPE_WIFI;
diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
index cb92112..9593a9c 100644
--- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
+++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java
@@ -57,8 +57,9 @@ final class ActiveSourceHandler {
* Handles the incoming active source command.
*
* @param newActive new active source information
+ * @param deviceType device type of the new active source
*/
- void process(ActiveSource newActive) {
+ void process(ActiveSource newActive, int deviceType) {
// Seq #17
HdmiCecLocalDeviceTv tv = mSource;
ActiveSource activeSource = tv.getActiveSource();
@@ -68,7 +69,7 @@ final class ActiveSourceHandler {
}
HdmiDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress);
if (device == null) {
- tv.startNewDeviceAction(newActive);
+ tv.startNewDeviceAction(newActive, deviceType);
}
if (!tv.isProhibitMode()) {
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index b0a3a66..bb12eae 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -205,13 +205,6 @@ final class Constants {
static final int UNKNOWN_VOLUME = -1;
- // IRT(Initiator Repetition Time) in millisecond as recommended in the standard.
- // Outgoing UCP commands, when in 'Press and Hold' mode, should be this much apart
- // from the adjacent one so as not to place unnecessarily heavy load on the CEC line.
- // TODO: This value might need tweaking per product basis. Consider putting it
- // in config.xml to allow customization.
- static final int IRT_MS = 300;
-
static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback";
static final String PROPERTY_PREFERRED_ADDRESS_TV = "persist.sys.hdmi.addr.tv";
diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
index d965caa..3dd1522 100644
--- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java
@@ -70,7 +70,8 @@ final class DevicePowerStatusAction extends HdmiCecFeatureAction {
@Override
boolean processCommand(HdmiCecMessage cmd) {
- if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS) {
+ if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS
+ || mTargetAddress != cmd.getSource()) {
return false;
}
if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
index d155e84..5a1d896 100644
--- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java
@@ -95,7 +95,7 @@ final class DeviceSelectAction extends HdmiCecFeatureAction {
sendCommand(mGivePowerStatus, new SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == Constants.SEND_RESULT_NAK) {
+ if (error != Constants.SEND_RESULT_SUCCESS) {
invokeCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
finish();
return;
@@ -168,6 +168,10 @@ final class DeviceSelectAction extends HdmiCecFeatureAction {
}
private void sendSetStreamPath() {
+ // Turn the active source invalidated, which remains so till <Active Source> comes from
+ // the selected device.
+ tv().getActiveSource().invalidate();
+ tv().setActivePath(mTarget.getPhysicalAddress());
sendCommand(HdmiCecMessageBuilder.buildSetStreamPath(
getSourceAddress(), mTarget.getPhysicalAddress()));
invokeCallback(HdmiControlManager.RESULT_SUCCESS);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index fc53c50..d26be57 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -85,8 +85,7 @@ abstract class HdmiCecFeatureAction {
* Process the command. Called whenever a new command arrives.
*
* @param cmd command to process
- * @return true if the command was consumed in the process; Otherwise false, which
- * indicates that the command shall be handled by other actions.
+ * @return true if the command was consumed in the process; Otherwise false.
*/
abstract boolean processCommand(HdmiCecMessage cmd);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
index 61c9424..2eca42b 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java
@@ -18,6 +18,10 @@ package com.android.server.hdmi;
import android.view.KeyEvent;
+import libcore.util.EmptyArray;
+
+import java.util.Arrays;
+
/**
* Helper class to translate android keycode to hdmi cec keycode and vice versa.
*/
@@ -156,46 +160,60 @@ final class HdmiCecKeycode {
/**
* A mapping between Android and CEC keycode.
+ * <p>
+ * Normal implementation of this looks like
*
- * <p>Normal implementation of this looks like
* <pre>
- * new KeycodeEntry(KeyEvent.KEYCODE_DPAD_CENTER, CEC_KEYCODE_SELECT);
+ * new KeycodeEntry(KeyEvent.KEYCODE_DPAD_CENTER, CEC_KEYCODE_SELECT);
* </pre>
- * <p>However, some keys in CEC requires additional parameter.
- * In order to use parameterized cec key, add unique android keycode (existing or custom)
- * corresponding to a pair of cec keycode and and its param.
+ * <p>
+ * However, some keys in CEC requires additional parameter. In order to use parameterized cec
+ * key, add unique android keycode (existing or custom) corresponding to a pair of cec keycode
+ * and and its param.
+ *
* <pre>
- * new KeycodeEntry(CUSTOME_ANDORID_KEY_1, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
- * UI_BROADCAST_TOGGLE_ALL);
- * new KeycodeEntry(CUSTOME_ANDORID_KEY_2, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
- * UI_BROADCAST_ANALOGUE);
+ * new KeycodeEntry(CUSTOME_ANDORID_KEY_1, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
+ * UI_BROADCAST_TOGGLE_ALL);
+ * new KeycodeEntry(CUSTOME_ANDORID_KEY_2, CEC_KEYCODE_SELECT_BROADCAST_TYPE,
+ * UI_BROADCAST_ANALOGUE);
* </pre>
*/
private static class KeycodeEntry {
private final int mAndroidKeycode;
- private final int mCecKeycode;
private final boolean mIsRepeatable;
+ private final byte[] mCecKeycodeAndParams;
- private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable) {
+ private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable,
+ byte[] cecParams) {
mAndroidKeycode = androidKeycode;
- mCecKeycode = cecKeycode;
mIsRepeatable = isRepeatable;
+ mCecKeycodeAndParams = new byte[cecParams.length + 1];
+ System.arraycopy(cecParams, 0, mCecKeycodeAndParams, 1, cecParams.length);
+ mCecKeycodeAndParams[0] = (byte) (cecKeycode & 0xFF);
+ }
+
+ private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable) {
+ this(androidKeycode, cecKeycode, isRepeatable, EmptyArray.BYTE);
+ }
+
+ private KeycodeEntry(int androidKeycode, int cecKeycode, byte[] cecParams) {
+ this(androidKeycode, cecKeycode, true, cecParams);
}
private KeycodeEntry(int androidKeycode, int cecKeycode) {
- this(androidKeycode, cecKeycode, true);
+ this(androidKeycode, cecKeycode, true, EmptyArray.BYTE);
}
- private int toCecKeycodeIfMatched(int androidKeycode) {
+ private byte[] toCecKeycodeAndParamIfMatched(int androidKeycode) {
if (mAndroidKeycode == androidKeycode) {
- return mCecKeycode;
+ return mCecKeycodeAndParams;
} else {
- return UNSUPPORTED_KEYCODE;
+ return null;
}
}
- private int toAndroidKeycodeIfMatched(int cecKeycode) {
- if (cecKeycode == mCecKeycode) {
+ private int toAndroidKeycodeIfMatched(byte[] cecKeycodeAndParams) {
+ if (Arrays.equals(mCecKeycodeAndParams, cecKeycodeAndParams)) {
return mAndroidKeycode;
} else {
return UNSUPPORTED_KEYCODE;
@@ -211,6 +229,11 @@ final class HdmiCecKeycode {
}
}
+ private static byte[] intToSingleByteArray(int value) {
+ return new byte[] {
+ (byte) (value & 0xFF) };
+ }
+
// Keycode entry container for all mappings.
// Note that order of entry is the same as above cec keycode definition.
private static final KeycodeEntry[] KEYCODE_ENTRIES = new KeycodeEntry[] {
@@ -227,19 +250,25 @@ final class HdmiCecKeycode {
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_UP),
// No Android keycode defined for CEC_KEYCODE_LEFT_DOWN
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_DOWN),
- new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU, false),
- new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU, false),
- new KeycodeEntry(KeyEvent.KEYCODE_MENU, CEC_KEYCODE_CONTENTS_MENU, false),
+ new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU),
+ new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_CONTENTS_MENU, CEC_KEYCODE_CONTENTS_MENU, false),
// No Android keycode defined for CEC_KEYCODE_FAVORITE_MENU
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_FAVORITE_MENU),
+ // Note that both BACK and ESCAPE are mapped to EXIT of CEC keycode.
+ // This would be problematic when translates CEC keycode to Android keycode.
+ // In current implementation, we pick BACK as mapping of EXIT key.
+ // If you'd like to map CEC EXIT to Android EXIT key, change order of
+ // the following two definition.
new KeycodeEntry(KeyEvent.KEYCODE_BACK, CEC_KEYCODE_EXIT),
+ new KeycodeEntry(KeyEvent.KEYCODE_ESCAPE, CEC_KEYCODE_EXIT),
// RESERVED
new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_TOP_MENU, CEC_KEYCODE_MEDIA_TOP_MENU),
- // No Android keycode defined for CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_MEDIA_CONTEXT_MENU,
+ CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU),
// RESERVED
// No Android keycode defined for CEC_KEYCODE_NUMBER_ENTRY_MODE
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_NUMBER_ENTRY_MODE),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_NUMBER_ENTRY, CEC_KEYCODE_NUMBER_ENTRY_MODE),
new KeycodeEntry(KeyEvent.KEYCODE_11, CEC_KEYCODE_NUMBER_11),
new KeycodeEntry(KeyEvent.KEYCODE_12, CEC_KEYCODE_NUMBER_12),
new KeycodeEntry(KeyEvent.KEYCODE_0, CEC_KEYCODE_NUMBER_0_OR_NUMBER_10),
@@ -276,7 +305,12 @@ final class HdmiCecKeycode {
new KeycodeEntry(KeyEvent.KEYCODE_VOLUME_MUTE, CEC_KEYCODE_MUTE, false),
new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PLAY, CEC_KEYCODE_PLAY),
new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_STOP, CEC_KEYCODE_STOP),
+ // Note that we map both MEDIA_PAUSE and MEDIA_PLAY_PAUSE to CEC PAUSE key.
+ // When it translates CEC PAUSE key, it picks Android MEDIA_PAUSE key as a mapping of
+ // it. If you'd like to choose MEDIA_PLAY_PAUSE, please change order of the following
+ // two lines.
new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PAUSE, CEC_KEYCODE_PAUSE),
+ new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, CEC_KEYCODE_PAUSE),
new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_RECORD, CEC_KEYCODE_RECORD),
new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_REWIND, CEC_KEYCODE_REWIND),
new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, CEC_KEYCODE_FAST_FORWARD),
@@ -291,48 +325,61 @@ final class HdmiCecKeycode {
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RESERVED),
// No Android keycode defined for CEC_KEYCODE_ANGLE
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_ANGLE),
- // No Android keycode defined for CEC_KEYCODE_SUB_PICTURE
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SUB_PICTURE),
+ new KeycodeEntry(KeyEvent.KEYCODE_CAPTIONS, CEC_KEYCODE_SUB_PICTURE),
// No Android keycode defined for CEC_KEYCODE_VIDEO_ON_DEMAND
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_VIDEO_ON_DEMAND),
new KeycodeEntry(KeyEvent.KEYCODE_GUIDE, CEC_KEYCODE_ELECTRONIC_PROGRAM_GUIDE),
- // No Android keycode defined for CEC_KEYCODE_TIMER_PROGRAMMING
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TIMER_PROGRAMMING),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_TIMER_PROGRAMMING, CEC_KEYCODE_TIMER_PROGRAMMING),
// No Android keycode defined for CEC_KEYCODE_INITIAL_CONFIGURATION
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_INITIAL_CONFIGURATION),
// No Android keycode defined for CEC_KEYCODE_SELECT_BROADCAST_TYPE
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_BROADCAST_TYPE),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_TERRESTRIAL_ANALOG,
+ CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+ intToSingleByteArray(UI_BROADCAST_ANALOGUE)),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_TERRESTRIAL_DIGITAL,
+ CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+ intToSingleByteArray(UI_BROADCAST_DIGITAL_TERRESTRIAL)),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_SATELLITE_BS,
+ CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+ intToSingleByteArray(UI_BROADCAST_DIGITAL_SATELLITE)),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_SATELLITE_CS,
+ CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+ intToSingleByteArray(UI_BROADCAST_DIGITAL_COMMNICATIONS_SATELLITE)),
+ new KeycodeEntry(KeyEvent.KEYCODE_TV_NETWORK,
+ CEC_KEYCODE_SELECT_BROADCAST_TYPE, true,
+ intToSingleByteArray(UI_BROADCAST_TOGGLE_ANALOGUE_DIGITAL)),
// No Android keycode defined for CEC_KEYCODE_SELECT_SOUND_PRESENTATION
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_SOUND_PRESENTATION),
// RESERVED
// The following deterministic key definitions do not need key mapping
// since they are supposed to be generated programmatically only.
// No Android keycode defined for CEC_KEYCODE_PLAY_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PLAY_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PLAY_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_PAUSE_PLAY_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_PLAY_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_PLAY_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_RECORD_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RECORD_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RECORD_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_PAUSE_RECORD_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_RECORD_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_RECORD_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_STOP_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_STOP_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_STOP_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_MUTE_FUNCTION
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_MUTE_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_RESTORE_VOLUME_FUNCTION
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RESTORE_VOLUME_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_TUNE_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TUNE_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TUNE_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_SELECT_MEDIA_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_MEDIA_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_MEDIA_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_POWER_TOGGLE_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_TOGGLE_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_TOGGLE_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_POWER_OFF_FUNCTION
- new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_OFF_FUNCTION),
+ new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_OFF_FUNCTION, false),
// No Android keycode defined for CEC_KEYCODE_POWER_ON_FUNCTION
new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_ON_FUNCTION, false),
// RESERVED
@@ -347,31 +394,31 @@ final class HdmiCecKeycode {
};
/**
- * Translate Android keycode to Hdmi Cec keycode.
+ * Translate Android keycode to Hdmi Cec keycode and params.
*
* @param keycode Android keycode. For details, refer {@link KeyEvent}
- * @return single byte CEC keycode if matched.
+ * @return byte array of CEC keycode and params if matched. Otherwise, return null.
*/
- static int androidKeyToCecKey(int keycode) {
+ static byte[] androidKeyToCecKey(int keycode) {
for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) {
- int cecKeycode = KEYCODE_ENTRIES[i].toCecKeycodeIfMatched(keycode);
- if (cecKeycode != UNSUPPORTED_KEYCODE) {
- return cecKeycode;
+ byte[] cecKeycodeAndParams = KEYCODE_ENTRIES[i].toCecKeycodeAndParamIfMatched(keycode);
+ if (cecKeycodeAndParams != null) {
+ return cecKeycodeAndParams;
}
}
- return UNSUPPORTED_KEYCODE;
+ return null;
}
/**
- * Translate Hdmi CEC keycode to Android keycode.
+ * Translate Hdmi CEC keycode with params to Android keycode.
*
- * @param keycode CEC keycode
- * @return cec keycode corresponding to the given android keycode.
- * If finds no matched keycode, return {@link #UNSUPPORTED_KEYCODE}
+ * @param cecKeycodeAndParams CEC keycode and params
+ * @return cec keycode corresponding to the given android keycode. If finds no matched keycode,
+ * return {@link #UNSUPPORTED_KEYCODE}
*/
- static int cecKeyToAndroidKey(int keycode) {
+ static int cecKeycodeAndParamsToAndroidKey(byte[] cecKeycodeAndParams) {
for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) {
- int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(keycode);
+ int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(cecKeycodeAndParams);
if (androidKey != UNSUPPORTED_KEYCODE) {
return androidKey;
}
@@ -399,7 +446,6 @@ final class HdmiCecKeycode {
* Returns {@code true} if given Android keycode is supported, otherwise {@code false}.
*/
static boolean isSupportedKeycode(int androidKeycode) {
- return HdmiCecKeycode.androidKeyToCecKey(androidKeycode)
- != HdmiCecKeycode.UNSUPPORTED_KEYCODE;
- }
+ return HdmiCecKeycode.androidKeyToCecKey(androidKeycode) != null;
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 8f9af61..4f8b9fb 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -34,7 +34,6 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
/**
@@ -125,7 +124,7 @@ abstract class HdmiCecLocalDevice {
// A collection of FeatureAction.
// Note that access to this collection should happen in service thread.
- private final LinkedList<HdmiCecFeatureAction> mActions = new LinkedList<>();
+ private final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>();
private final Handler mHandler = new Handler () {
@Override
@@ -290,12 +289,14 @@ abstract class HdmiCecLocalDevice {
@ServiceThreadOnly
private boolean dispatchMessageToAction(HdmiCecMessage message) {
assertRunOnServiceThread();
- for (HdmiCecFeatureAction action : mActions) {
- if (action.processCommand(message)) {
- return true;
- }
+ boolean processed = false;
+ // Use copied action list in that processCommand may remove itself.
+ for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) {
+ // Iterates all actions to check whether incoming message is consumed.
+ boolean result = action.processCommand(message);
+ processed = processed || result;
}
- return false;
+ return processed;
}
@ServiceThreadOnly
@@ -425,9 +426,7 @@ abstract class HdmiCecLocalDevice {
final long downTime = SystemClock.uptimeMillis();
final byte[] params = message.getParams();
- // Note that we don't support parameterized keycode now.
- // TODO: translate parameterized keycode as well.
- final int keycode = HdmiCecKeycode.cecKeyToAndroidKey(params[0]);
+ final int keycode = HdmiCecKeycode.cecKeycodeAndParamsToAndroidKey(params);
int keyRepeatCount = 0;
if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
if (keycode == mLastKeycode) {
@@ -517,8 +516,8 @@ abstract class HdmiCecLocalDevice {
}
protected boolean handleVendorCommand(HdmiCecMessage message) {
- if (!mService.invokeVendorCommandListeners(mDeviceType, message.getSource(),
- message.getParams(), false)) {
+ if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(),
+ message.getDestination(), message.getParams(), false)) {
// Vendor command listener may not have been registered yet. Respond with
// <Feature Abort> [NOT_IN_CORRECT_MODE] so that the sender can try again later.
mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
@@ -530,8 +529,8 @@ abstract class HdmiCecLocalDevice {
byte[] params = message.getParams();
int vendorId = HdmiUtils.threeBytesToInt(params);
if (vendorId == mService.getVendorId()) {
- if (!mService.invokeVendorCommandListeners(mDeviceType, message.getSource(), params,
- true)) {
+ if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(),
+ message.getDestination(), params, true)) {
mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE);
}
} else if (message.getDestination() != Constants.ADDR_BROADCAST &&
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 780d54b..85a1a15 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -50,6 +50,8 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
assertRunOnServiceThread();
mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
mAddress, mService.getPhysicalAddress(), mDeviceType));
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
+ mAddress, mService.getVendorId()));
startQueuedActions();
}
@@ -156,7 +158,7 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
maySetActiveSource(physicalAddress);
- maySendActiveSource();
+ maySendActiveSource(message.getSource());
wakeUpIfActiveSource();
return true; // Broadcast message.
}
@@ -196,10 +198,13 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
}
}
- private void maySendActiveSource() {
+ private void maySendActiveSource(int dest) {
if (mIsActiveSource) {
mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(
mAddress, mService.getPhysicalAddress()));
+ // Always reports menu-status active to receive RCP.
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildReportMenuStatus(
+ mAddress, dest, Constants.MENU_STATE_ACTIVATED));
}
}
@@ -207,7 +212,7 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
@ServiceThreadOnly
protected boolean handleRequestActiveSource(HdmiCecMessage message) {
assertRunOnServiceThread();
- maySendActiveSource();
+ maySendActiveSource(message.getSource());
return true; // Broadcast message.
}
@@ -230,4 +235,4 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice {
super.dump(pw);
pw.println("mIsActiveSource: " + mIsActiveSource);
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 0fb4b48..6bae761 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -110,6 +110,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
// If true, TV wakes itself up when receiving <Text/Image View On>.
private boolean mAutoWakeup;
+ // List of the logical address of local CEC devices. Unmodifiable, thread-safe.
+ private List<Integer> mLocalDeviceAddresses;
+
private final HdmiCecStandbyModeHandler mStandbyHandler;
// If true, do not do routing control/send active source for internal source.
@@ -141,10 +144,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
mSkipRoutingControl = (reason == HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE);
launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC &&
reason != HdmiControlService.INITIATED_BY_BOOT_UP);
+ mLocalDeviceAddresses = initLocalDeviceAddresses();
launchDeviceDiscovery();
startQueuedActions();
}
+
+ @ServiceThreadOnly
+ private List<Integer> initLocalDeviceAddresses() {
+ assertRunOnServiceThread();
+ List<Integer> addresses = new ArrayList<>();
+ for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+ addresses.add(device.getDeviceInfo().getLogicalAddress());
+ }
+ return Collections.unmodifiableList(addresses);
+ }
+
@Override
@ServiceThreadOnly
protected int getPreferredAddress() {
@@ -351,13 +366,26 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (!action.isEmpty()) {
action.get(0).processKeyEvent(keyCode, isPressed);
} else {
- if (isPressed && getActiveSource().isValid()) {
- int logicalAddress = getActiveSource().logicalAddress;
- addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
- } else {
- Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed);
+ if (isPressed) {
+ int logicalAddress = findKeyReceiverAddress();
+ if (logicalAddress != Constants.ADDR_INVALID) {
+ addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));
+ return;
+ }
}
+ Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed);
+ }
+ }
+
+ private int findKeyReceiverAddress() {
+ if (getActiveSource().isValid()) {
+ return getActiveSource().logicalAddress;
+ }
+ HdmiDeviceInfo info = getDeviceInfoByPath(getActivePath());
+ if (info != null) {
+ return info.getLogicalAddress();
}
+ return Constants.ADDR_INVALID;
}
private static void invokeCallback(IHdmiControlCallback callback, int result) {
@@ -377,11 +405,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
assertRunOnServiceThread();
int logicalAddress = message.getSource();
int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
- if (getCecDeviceInfo(logicalAddress) == null) {
+ HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress);
+ if (info == null) {
handleNewDeviceAtTheTailOfActivePath(physicalAddress);
} else {
ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress);
- ActiveSourceHandler.create(this, null).process(activeSource);
+ ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType());
}
return true;
}
@@ -471,7 +500,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
if (!isInDeviceList(address, path)) {
handleNewDeviceAtTheTailOfActivePath(path);
}
- startNewDeviceAction(ActiveSource.of(address, path));
+ startNewDeviceAction(ActiveSource.of(address, path), type);
return true;
}
@@ -507,7 +536,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
return false;
}
- void startNewDeviceAction(ActiveSource activeSource) {
+ void startNewDeviceAction(ActiveSource activeSource, int deviceType) {
for (NewDeviceAction action : getActions(NewDeviceAction.class)) {
// If there is new device action which has the same logical address and path
// ignore new request.
@@ -523,7 +552,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
- activeSource.physicalAddress));
+ activeSource.physicalAddress, deviceType));
}
private void handleNewDeviceAtTheTailOfActivePath(int path) {
@@ -1182,15 +1211,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
}
- @ServiceThreadOnly
private boolean isLocalDeviceAddress(int address) {
- assertRunOnServiceThread();
- for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
- if (device.isAddressOf(address)) {
- return true;
- }
- }
- return false;
+ return mLocalDeviceAddresses.contains(address);
}
@ServiceThreadOnly
@@ -1240,6 +1262,17 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
}
+ List<HdmiDeviceInfo> getSafeCecDevicesLocked() {
+ ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>();
+ for (HdmiDeviceInfo info : mSafeAllDeviceInfos) {
+ if (isLocalDeviceAddress(info.getLogicalAddress())) {
+ continue;
+ }
+ infoList.add(info);
+ }
+ return infoList;
+ }
+
/**
* Called when a device is newly added or a new device is detected or
* existing device is updated.
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 60d1520..aeb21db 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -90,6 +90,8 @@ import java.util.Locale;
*/
public final class HdmiControlService extends SystemService {
private static final String TAG = "HdmiControlService";
+ private final Locale HONG_KONG = new Locale("zh", "HK");
+ private final Locale MACAU = new Locale("zh", "MO");
static final String PERMISSION = "android.permission.HDMI_CEC";
@@ -146,13 +148,25 @@ public final class HdmiControlService extends SystemService {
}
break;
case Intent.ACTION_CONFIGURATION_CHANGED:
- String language = Locale.getDefault().getISO3Language();
+ String language = getMenuLanguage();
if (!mLanguage.equals(language)) {
onLanguageChanged(language);
}
break;
}
}
+
+ private String getMenuLanguage() {
+ Locale locale = Locale.getDefault();
+ if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) {
+ // Android always returns "zho" for all Chinese variants.
+ // Use "bibliographic" code defined in CEC639-2 for traditional
+ // Chinese used in Taiwan/Hong Kong/Macau.
+ return "chi";
+ } else {
+ return locale.getISO3Language();
+ }
+ }
}
// A thread to handle synchronous IO of CEC and MHL control service.
@@ -303,6 +317,7 @@ public final class HdmiControlService extends SystemService {
}
} else {
Slog.i(TAG, "Device does not support HDMI-CEC.");
+ return;
}
mMhlController = HdmiMhlControllerStub.create(this);
@@ -315,20 +330,23 @@ public final class HdmiControlService extends SystemService {
mMessageValidator = new HdmiCecMessageValidator(this);
publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
- // Register broadcast receiver for power state change.
if (mCecController != null) {
+ // Register broadcast receiver for power state change.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter);
+
+ // Register ContentObserver to monitor the settings change.
+ registerContentObserver();
}
}
/**
* Called when the initialization of local devices is complete.
*/
- private void onInitializeCecComplete() {
+ private void onInitializeCecComplete(int initiatedBy) {
if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) {
mPowerStatus = HdmiControlManager.POWER_STATUS_ON;
}
@@ -336,7 +354,22 @@ public final class HdmiControlService extends SystemService {
if (isTvDevice()) {
mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup()));
- registerContentObserver();
+ }
+ int reason = -1;
+ switch (initiatedBy) {
+ case INITIATED_BY_BOOT_UP:
+ reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START;
+ break;
+ case INITIATED_BY_ENABLE_CEC:
+ reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING;
+ break;
+ case INITIATED_BY_SCREEN_ON:
+ case INITIATED_BY_WAKE_UP_MESSAGE:
+ reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
+ break;
+ }
+ if (reason != -1) {
+ invokeVendorCommandListenersOnControlStateChanged(true, reason);
}
}
@@ -401,10 +434,6 @@ public final class HdmiControlService extends SystemService {
Global.putInt(cr, key, toInt(value));
}
- private void unregisterSettingsObserver() {
- getContext().getContentResolver().unregisterContentObserver(mSettingsObserver);
- }
-
private void initializeCec(int initiatedBy) {
mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
initializeLocalDevices(initiatedBy);
@@ -459,7 +488,7 @@ public final class HdmiControlService extends SystemService {
if (initiatedBy != INITIATED_BY_HOTPLUG) {
// In case of the hotplug we don't call onInitializeCecComplete()
// since we reallocate the logical address only.
- onInitializeCecComplete();
+ onInitializeCecComplete(initiatedBy);
}
notifyAddressAllocated(allocatedDevices, initiatedBy);
}
@@ -729,20 +758,18 @@ public final class HdmiControlService extends SystemService {
void onHotplug(int portId, boolean connected) {
assertRunOnServiceThread();
- ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
- for (int type : mLocalDevices) {
- if (type == HdmiDeviceInfo.DEVICE_TV) {
- // Skip the reallocation of the logical address on TV.
- continue;
- }
- HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
- if (localDevice == null) {
- localDevice = HdmiCecLocalDevice.create(this, type);
- localDevice.init();
+ if (connected && !isTvDevice()) {
+ ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
+ for (int type : mLocalDevices) {
+ HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type);
+ if (localDevice == null) {
+ localDevice = HdmiCecLocalDevice.create(this, type);
+ localDevice.init();
+ }
+ localDevices.add(localDevice);
}
- localDevices.add(localDevice);
+ allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG);
}
- allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG);
for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
device.onHotplug(portId, connected);
@@ -827,6 +854,7 @@ public final class HdmiControlService extends SystemService {
@ServiceThreadOnly
void handleMhlHotplugEvent(int portId, boolean connected) {
assertRunOnServiceThread();
+ // Hotplug event is used to add/remove MHL devices as TV input.
if (connected) {
HdmiMhlLocalDeviceStub newDevice = new HdmiMhlLocalDeviceStub(this, portId);
HdmiMhlLocalDeviceStub oldDevice = mMhlController.addLocalDevice(newDevice);
@@ -834,17 +862,14 @@ public final class HdmiControlService extends SystemService {
oldDevice.onDeviceRemoved();
Slog.i(TAG, "Old device of port " + portId + " is removed");
}
+ invokeDeviceEventListeners(newDevice.getInfo(), DEVICE_EVENT_ADD_DEVICE);
+ updateSafeMhlInput();
} else {
HdmiMhlLocalDeviceStub device = mMhlController.removeLocalDevice(portId);
if (device != null) {
device.onDeviceRemoved();
- // There is no explicit event for device removal.
- // Hence we remove the device on hotplug event.
- HdmiDeviceInfo deviceInfo = device.getInfo();
- if (deviceInfo != null) {
- invokeDeviceEventListeners(deviceInfo, DEVICE_EVENT_REMOVE_DEVICE);
- updateSafeMhlInput();
- }
+ invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE);
+ updateSafeMhlInput();
} else {
Slog.w(TAG, "No device to remove:[portId=" + portId);
}
@@ -880,11 +905,8 @@ public final class HdmiControlService extends SystemService {
assertRunOnServiceThread();
HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId);
- // Hotplug event should already have been called before device status change event.
if (device != null) {
device.setDeviceStatusChange(adopterId, deviceId);
- invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_ADD_DEVICE);
- updateSafeMhlInput();
} else {
Slog.w(TAG, "No mhl device exists for device status event[portId:"
+ portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]");
@@ -1025,6 +1047,7 @@ public final class HdmiControlService extends SystemService {
@Override
public HdmiDeviceInfo getActiveSource() {
+ enforceAccessPermission();
HdmiCecLocalDeviceTv tv = tv();
if (tv == null) {
Slog.w(TAG, "Local tv device not available");
@@ -1238,6 +1261,19 @@ public final class HdmiControlService extends SystemService {
}
}
+ // Returns all the CEC devices on the bus including system audio, switch,
+ // even those of reserved type.
+ @Override
+ public List<HdmiDeviceInfo> getDeviceList() {
+ enforceAccessPermission();
+ HdmiCecLocalDeviceTv tv = tv();
+ synchronized (mLock) {
+ return (tv == null)
+ ? Collections.<HdmiDeviceInfo>emptyList()
+ : tv.getSafeCecDevicesLocked();
+ }
+ }
+
@Override
public void setSystemAudioVolume(final int oldIndex, final int newIndex,
final int maxIndex) {
@@ -1344,11 +1380,13 @@ public final class HdmiControlService extends SystemService {
@Override
public void setHdmiRecordListener(IHdmiRecordListener listener) {
+ enforceAccessPermission();
HdmiControlService.this.setHdmiRecordListener(listener);
}
@Override
public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) {
+ enforceAccessPermission();
runOnServiceThread(new Runnable() {
@Override
public void run() {
@@ -1363,6 +1401,7 @@ public final class HdmiControlService extends SystemService {
@Override
public void stopOneTouchRecord(final int recorderAddress) {
+ enforceAccessPermission();
runOnServiceThread(new Runnable() {
@Override
public void run() {
@@ -1378,6 +1417,7 @@ public final class HdmiControlService extends SystemService {
@Override
public void startTimerRecording(final int recorderAddress, final int sourceType,
final byte[] recordSource) {
+ enforceAccessPermission();
runOnServiceThread(new Runnable() {
@Override
public void run() {
@@ -1393,6 +1433,7 @@ public final class HdmiControlService extends SystemService {
@Override
public void clearTimerRecording(final int recorderAddress, final int sourceType,
final byte[] recordSource) {
+ enforceAccessPermission();
runOnServiceThread(new Runnable() {
@Override
public void run() {
@@ -1696,7 +1737,7 @@ public final class HdmiControlService extends SystemService {
}
boolean isTvDevice() {
- return tv() != null;
+ return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV);
}
private HdmiCecLocalDevicePlayback playback() {
@@ -1782,6 +1823,8 @@ public final class HdmiControlService extends SystemService {
private void onStandby() {
assertRunOnServiceThread();
mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY;
+ invokeVendorCommandListenersOnControlStateChanged(false,
+ HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
disableDevices(new PendingActionClearedCallback() {
@@ -1820,9 +1863,6 @@ public final class HdmiControlService extends SystemService {
for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) {
device.disableDevice(mStandbyMessageReceived, callback);
}
- if (isTvDevice()) {
- unregisterSettingsObserver();
- }
}
mMhlController.clearAllLocalDevices();
@@ -1867,8 +1907,8 @@ public final class HdmiControlService extends SystemService {
}
}
- boolean invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params,
- boolean hasVendorId) {
+ boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress,
+ byte[] params, boolean hasVendorId) {
synchronized (mLock) {
if (mVendorCommandListenerRecords.isEmpty()) {
return false;
@@ -1878,7 +1918,7 @@ public final class HdmiControlService extends SystemService {
continue;
}
try {
- record.mListener.onReceived(srcAddress, params, hasVendorId);
+ record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to notify vendor command reception", e);
}
@@ -1887,6 +1927,22 @@ public final class HdmiControlService extends SystemService {
}
}
+ boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) {
+ synchronized (mLock) {
+ if (mVendorCommandListenerRecords.isEmpty()) {
+ return false;
+ }
+ for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) {
+ try {
+ record.mListener.onControlStateChanged(enabled, reason);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e);
+ }
+ }
+ return true;
+ }
+ }
+
private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) {
HdmiMhlVendorCommandListenerRecord record =
new HdmiMhlVendorCommandListenerRecord(listener);
@@ -1936,6 +1992,11 @@ public final class HdmiControlService extends SystemService {
void setControlEnabled(boolean enabled) {
assertRunOnServiceThread();
+ if (!enabled) {
+ // Call the vendor handler before the service is disabled.
+ invokeVendorCommandListenersOnControlStateChanged(false,
+ HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING);
+ }
int value = toInt(enabled);
mCecController.setOption(OPTION_CEC_ENABLE, value);
mMhlController.setOption(OPTION_MHL_ENABLE, value);
@@ -2008,9 +2069,7 @@ public final class HdmiControlService extends SystemService {
// may not be the MHL-enabled one. In this case the device info to be passed to
// input change listener should be the one describing the corresponding HDMI port.
HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId);
- HdmiDeviceInfo info = (device != null && device.getInfo() != null)
- ? device.getInfo()
- : mPortDeviceMap.get(portId);
+ HdmiDeviceInfo info = (device != null) ? device.getInfo() : mPortDeviceMap.get(portId);
invokeInputChangeListener(info);
}
@@ -2042,7 +2101,7 @@ public final class HdmiControlService extends SystemService {
assertRunOnServiceThread();
Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE);
intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId);
- intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRAM_PARAM1, extra);
+ intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRA_PARAM1, extra);
getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
HdmiControlService.PERMISSION);
}
diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
index 2074085..998889b 100644
--- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java
+++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java
@@ -47,6 +47,7 @@ final class NewDeviceAction extends HdmiCecFeatureAction {
private final int mDeviceLogicalAddress;
private final int mDevicePhysicalAddress;
+ private final int mDeviceType;
private int mVendorId;
private String mDisplayName;
@@ -57,12 +58,14 @@ final class NewDeviceAction extends HdmiCecFeatureAction {
* @param source {@link HdmiCecLocalDevice} instance
* @param deviceLogicalAddress logical address of the device in interest
* @param devicePhysicalAddress physical address of the device in interest
+ * @param deviceType type of the device
*/
NewDeviceAction(HdmiCecLocalDevice source, int deviceLogicalAddress,
- int devicePhysicalAddress) {
+ int devicePhysicalAddress, int deviceType) {
super(source);
mDeviceLogicalAddress = deviceLogicalAddress;
mDevicePhysicalAddress = devicePhysicalAddress;
+ mDeviceType = deviceType;
mVendorId = Constants.UNKNOWN_VENDOR_ID;
}
@@ -155,8 +158,7 @@ final class NewDeviceAction extends HdmiCecFeatureAction {
HdmiDeviceInfo deviceInfo = new HdmiDeviceInfo(
mDeviceLogicalAddress, mDevicePhysicalAddress,
tv().getPortId(mDevicePhysicalAddress),
- HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress),
- mVendorId, mDisplayName);
+ mDeviceType, mVendorId, mDisplayName);
tv().addCecDevice(deviceInfo);
if (HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress)
diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
index 7db991a..e764a1c 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java
@@ -92,7 +92,8 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction {
@Override
boolean processCommand(HdmiCecMessage cmd) {
- if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS) {
+ if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS
+ || mTargetAddress != cmd.getSource()) {
return false;
}
if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) {
diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
index 39c0d7f..906944b 100644
--- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
+++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java
@@ -68,23 +68,21 @@ public class OneTouchRecordAction extends HdmiCecFeatureAction {
finish();
return;
}
-
- mState = STATE_WAITING_FOR_RECORD_STATUS;
- addTimer(mState, RECORD_STATUS_TIMEOUT_MS);
}
});
+ mState = STATE_WAITING_FOR_RECORD_STATUS;
+ addTimer(mState, RECORD_STATUS_TIMEOUT_MS);
}
@Override
boolean processCommand(HdmiCecMessage cmd) {
- if (mState != STATE_WAITING_FOR_RECORD_STATUS) {
+ if (mState != STATE_WAITING_FOR_RECORD_STATUS || mRecorderAddress != cmd.getSource()) {
return false;
}
switch (cmd.getOpcode()) {
case Constants.MESSAGE_RECORD_STATUS:
return handleRecordStatus(cmd);
-
}
return false;
}
diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java
index ed978e0..eef5010 100644
--- a/services/core/java/com/android/server/hdmi/SendKeyAction.java
+++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java
@@ -15,7 +15,7 @@
*/
package com.android.server.hdmi;
-import static com.android.server.hdmi.Constants.IRT_MS;
+import static com.android.server.hdmi.HdmiConfig.IRT_MS;
import android.util.Slog;
import android.view.KeyEvent;
@@ -35,6 +35,11 @@ import android.view.KeyEvent;
final class SendKeyAction extends HdmiCecFeatureAction {
private static final String TAG = "SendKeyAction";
+ // Amount of time this action waits for a new release key input event. When timed out,
+ // the action sends out UCR and finishes its lifecycle. Used to deal with missing key release
+ // event, which can lead the device on the receiving end to generating unintended key repeats.
+ private static final int AWAIT_RELEASE_KEY_MS = 1000;
+
// State in which the action is at work. The state is set in {@link #start()} and
// persists throughout the process till it is set back to {@code STATE_NONE} at the end.
private static final int STATE_PROCESSING_KEYCODE = 1;
@@ -45,6 +50,10 @@ final class SendKeyAction extends HdmiCecFeatureAction {
// The key code of the last key press event the action is passed via processKeyEvent.
private int mLastKeycode;
+ // The time stamp when the last CEC key command was sent. Used to determine the press-and-hold
+ // operation.
+ private long mLastSendKeyTime;
+
/**
* Constructor.
*
@@ -61,6 +70,7 @@ final class SendKeyAction extends HdmiCecFeatureAction {
@Override
public boolean start() {
sendKeyDown(mLastKeycode);
+ mLastSendKeyTime = getCurrentTime();
// finish action for non-repeatable key.
if (!HdmiCecKeycode.isRepeatableKey(mLastKeycode)) {
sendKeyUp();
@@ -68,10 +78,14 @@ final class SendKeyAction extends HdmiCecFeatureAction {
return true;
}
mState = STATE_PROCESSING_KEYCODE;
- addTimer(mState, IRT_MS);
+ addTimer(mState, AWAIT_RELEASE_KEY_MS);
return true;
}
+ private long getCurrentTime() {
+ return System.currentTimeMillis();
+ }
+
/**
* Called when a key event should be handled for the action.
*
@@ -83,24 +97,32 @@ final class SendKeyAction extends HdmiCecFeatureAction {
Slog.w(TAG, "Not in a valid state");
return;
}
- // A new key press event that comes in with a key code different from the last
- // one sets becomes a new key code to be used for press-and-hold operation.
- // Removes any pending timer and starts a new timer for itself.
- // Key release event indicates that the action shall be finished. Send UCR
- // command and terminate the action. Other release events are ignored.
if (isPressed) {
+ // A new key press event that comes in with a key code different from the last
+ // one becomes a new key code to be used for press-and-hold operation.
if (keycode != mLastKeycode) {
sendKeyDown(keycode);
+ mLastSendKeyTime = getCurrentTime();
if (!HdmiCecKeycode.isRepeatableKey(keycode)) {
sendKeyUp();
finish();
return;
}
- mActionTimer.clearTimerMessage();
- addTimer(mState, IRT_MS);
- mLastKeycode = keycode;
+ } else {
+ // Press-and-hold key transmission takes place if Android key inputs are
+ // repeatedly coming in and more than IRT_MS has passed since the last
+ // press-and-hold key transmission.
+ if (getCurrentTime() - mLastSendKeyTime >= IRT_MS) {
+ sendKeyDown(keycode);
+ mLastSendKeyTime = getCurrentTime();
+ }
}
+ mActionTimer.clearTimerMessage();
+ addTimer(mState, AWAIT_RELEASE_KEY_MS);
+ mLastKeycode = keycode;
} else {
+ // Key release event indicates that the action shall be finished. Send UCR
+ // command and terminate the action. Other release events are ignored.
if (keycode == mLastKeycode) {
sendKeyUp();
finish();
@@ -109,12 +131,12 @@ final class SendKeyAction extends HdmiCecFeatureAction {
}
private void sendKeyDown(int keycode) {
- int cecKeycode = HdmiCecKeycode.androidKeyToCecKey(keycode);
- if (cecKeycode == HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
+ byte[] cecKeycodeAndParams = HdmiCecKeycode.androidKeyToCecKey(keycode);
+ if (cecKeycodeAndParams == null) {
return;
}
sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),
- mTargetAddress, new byte[] { (byte) (cecKeycode & 0xFF) }));
+ mTargetAddress, cecKeycodeAndParams));
}
private void sendKeyUp() {
@@ -130,15 +152,12 @@ final class SendKeyAction extends HdmiCecFeatureAction {
@Override
public void handleTimerEvent(int state) {
- // Timer event occurs every IRT_MS milliseconds to perform key-repeat (or press-and-hold)
- // operation. If the last received key code is as same as the one with which the action
- // is started, plus there was no key release event in last IRT_MS timeframe, send a UCP
- // command and start another timer to schedule the next press-and-hold command.
+ // Timeout on waiting for the release key event. Send UCR and quit the action.
if (mState != STATE_PROCESSING_KEYCODE) {
Slog.w(TAG, "Not in a valid state");
return;
}
- sendKeyDown(mLastKeycode);
- addTimer(mState, IRT_MS);
+ sendKeyUp();
+ finish();
}
}
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index 0871194..6023354 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -125,6 +125,9 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction {
@Override
final boolean processCommand(HdmiCecMessage cmd) {
+ if (cmd.getSource() != mAvrLogicalAddress) {
+ return false;
+ }
switch (mState) {
case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE:
if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
index 3653aac..50f8475 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java
@@ -58,17 +58,16 @@ final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction {
@Override
boolean processCommand(HdmiCecMessage cmd) {
- if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS) {
+ if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS
+ || mAvrAddress != cmd.getSource()) {
return false;
}
- switch (cmd.getOpcode()) {
- case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
- handleSystemAudioModeStatusMessage();
- return true;
- default:
- return false;
+ if (cmd.getOpcode() == Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS) {
+ handleSystemAudioModeStatusMessage();
+ return true;
}
+ return false;
}
private void handleSystemAudioModeStatusMessage() {
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
index bfcda50..dba3591 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java
@@ -79,7 +79,7 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction {
@Override
boolean processCommand(HdmiCecMessage cmd) {
- if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS) {
+ if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS || mAvrAddress != cmd.getSource()) {
return false;
}
diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
index 8fc0182..5fcbc91 100644
--- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
+++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java
@@ -96,11 +96,8 @@ public class TimerRecordingAction extends HdmiCecFeatureAction {
@Override
boolean processCommand(HdmiCecMessage cmd) {
- if (mState != STATE_WAITING_FOR_TIMER_STATUS) {
- return false;
- }
-
- if (cmd.getSource() != mRecorderAddress) {
+ if (mState != STATE_WAITING_FOR_TIMER_STATUS
+ || cmd.getSource() != mRecorderAddress) {
return false;
}
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
index 4338fc7..cd38b1f 100644
--- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -16,10 +16,10 @@
package com.android.server.hdmi;
-import static com.android.server.hdmi.Constants.IRT_MS;
import static com.android.server.hdmi.Constants.MESSAGE_FEATURE_ABORT;
import static com.android.server.hdmi.Constants.MESSAGE_REPORT_AUDIO_STATUS;
import static com.android.server.hdmi.Constants.MESSAGE_USER_CONTROL_PRESSED;
+import static com.android.server.hdmi.HdmiConfig.IRT_MS;
import android.media.AudioManager;
@@ -45,6 +45,7 @@ final class VolumeControlAction extends HdmiCecFeatureAction {
private boolean mIsVolumeUp;
private long mLastKeyUpdateTime;
private int mLastAvrVolume;
+ private boolean mLastAvrMute;
private boolean mSentKeyPressed;
/**
@@ -74,6 +75,7 @@ final class VolumeControlAction extends HdmiCecFeatureAction {
mAvrAddress = avrAddress;
mIsVolumeUp = isVolumeUp;
mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+ mLastAvrMute = false;
mSentKeyPressed = false;
updateLastKeyUpdateTime();
@@ -108,6 +110,8 @@ final class VolumeControlAction extends HdmiCecFeatureAction {
HdmiLogger.debug("Volume Key Status Changed[old:%b new:%b]", mIsVolumeUp, isVolumeUp);
sendVolumeKeyReleased();
mIsVolumeUp = isVolumeUp;
+ sendVolumeKeyPressed();
+ resetTimer();
}
updateLastKeyUpdateTime();
}
@@ -129,9 +133,8 @@ final class VolumeControlAction extends HdmiCecFeatureAction {
return handleReportAudioStatus(cmd);
case MESSAGE_FEATURE_ABORT:
return handleFeatureAbort(cmd);
- default:
- return false;
}
+ return false;
}
private boolean handleReportAudioStatus(HdmiCecMessage cmd) {
@@ -139,9 +142,12 @@ final class VolumeControlAction extends HdmiCecFeatureAction {
boolean mute = (params[0] & 0x80) == 0x80;
int volume = params[0] & 0x7F;
mLastAvrVolume = volume;
+ mLastAvrMute = mute;
if (shouldUpdateAudioVolume(mute)) {
HdmiLogger.debug("Force volume change[mute:%b, volume=%d]", mute, volume);
tv().setAudioStatus(mute, volume);
+ mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+ mLastAvrMute = false;
}
return true;
}
@@ -182,8 +188,9 @@ final class VolumeControlAction extends HdmiCecFeatureAction {
sendVolumeKeyReleased();
}
if (mLastAvrVolume != UNKNOWN_AVR_VOLUME) {
- tv().setAudioStatus(false, mLastAvrVolume);
+ tv().setAudioStatus(mLastAvrMute, mLastAvrVolume);
mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+ mLastAvrMute = false;
}
}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c6d2db2..83d6986 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -137,11 +137,15 @@ public class JobSchedulerService extends com.android.server.SystemService
public void onReceive(Context context, Intent intent) {
Slog.d(TAG, "Receieved: " + intent.getAction());
if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
- int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
- if (DEBUG) {
- Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+ // If this is an outright uninstall rather than the first half of an
+ // app update sequence, cancel the jobs associated with the app.
+ if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ if (DEBUG) {
+ Slog.d(TAG, "Removing jobs for uid: " + uidRemoved);
+ }
+ cancelJobsForUid(uidRemoved);
}
- cancelJobsForUid(uidRemoved);
} else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
if (DEBUG) {
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 0198e46..c2cb4b1 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -473,14 +473,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
checkSmsSuplInit(intent);
} else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
checkWapSuplInit(intent);
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- int networkState;
- if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
- networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
- } else {
- networkState = LocationProvider.AVAILABLE;
- }
-
+ } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE)) {
// retrieve NetworkInfo result for this UID
NetworkInfo info =
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
@@ -488,6 +481,15 @@ public class GpsLocationProvider implements LocationProviderInterface {
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
info = connManager.getNetworkInfo(info.getType());
+ int networkState;
+ if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false) ||
+ !info.isConnected()) {
+ networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
+ } else {
+ networkState = LocationProvider.AVAILABLE;
+ }
+
+
updateNetworkState(networkState, info);
} else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
|| Intent.ACTION_SCREEN_OFF.equals(action)
@@ -715,7 +717,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
intentFilter = new IntentFilter();
intentFilter.addAction(ALARM_WAKEUP);
intentFilter.addAction(ALARM_TIMEOUT);
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE);
intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 531d20a..e9b3f8b 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -326,7 +326,7 @@ public final class MediaProjectionManagerService extends SystemService
final long token = Binder.clearCallingIdentity();
try {
- dump(pw);
+ MediaProjectionManagerService.this.dump(pw);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index b5aa4d8..150ad34 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -45,7 +45,6 @@ import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES;
import static android.provider.Settings.Global.NETSTATS_DEV_ROTATE_AGE;
import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES;
import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL;
-import static android.provider.Settings.Global.NETSTATS_REPORT_XT_OVER_DEV;
import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED;
import static android.provider.Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE;
import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION;
@@ -184,7 +183,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public long getPollInterval();
public long getTimeCacheMaxAge();
public boolean getSampleEnabled();
- public boolean getReportXtOverDev();
public static class Config {
public final long bucketDuration;
@@ -229,8 +227,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private NetworkStatsRecorder mUidRecorder;
private NetworkStatsRecorder mUidTagRecorder;
- /** Cached {@link #mDevRecorder} stats. */
- private NetworkStatsCollection mDevStatsCached;
/** Cached {@link #mXtRecorder} stats. */
private NetworkStatsCollection mXtStatsCached;
@@ -305,7 +301,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// read historical network stats from disk, since policy service
// might need them right away.
- mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked();
mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked();
// bootstrap initial stats to prevent double-counting later
@@ -386,7 +381,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mUidRecorder = null;
mUidTagRecorder = null;
- mDevStatsCached = null;
mXtStatsCached = null;
mSystemReady = false;
@@ -523,48 +517,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
/**
- * Return network summary, splicing between {@link #mDevStatsCached}
- * and {@link #mXtStatsCached} when appropriate.
+ * Return network summary, splicing between DEV and XT stats when
+ * appropriate.
*/
private NetworkStats internalGetSummaryForNetwork(
NetworkTemplate template, long start, long end) {
- if (!mSettings.getReportXtOverDev()) {
- // shortcut when XT reporting disabled
- return mDevStatsCached.getSummary(template, start, end);
- }
-
- // splice stats between DEV and XT, switching over from DEV to XT at
- // first atomic bucket.
- final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis();
- final NetworkStats dev = mDevStatsCached.getSummary(
- template, Math.min(start, firstAtomicBucket), Math.min(end, firstAtomicBucket));
- final NetworkStats xt = mXtStatsCached.getSummary(
- template, Math.max(start, firstAtomicBucket), Math.max(end, firstAtomicBucket));
-
- xt.combineAllValues(dev);
- return xt;
+ // We've been using pure XT stats long enough that we no longer need to
+ // splice DEV and XT together.
+ return mXtStatsCached.getSummary(template, start, end);
}
/**
- * Return network history, splicing between {@link #mDevStatsCached}
- * and {@link #mXtStatsCached} when appropriate.
+ * Return network history, splicing between DEV and XT stats when
+ * appropriate.
*/
private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) {
- if (!mSettings.getReportXtOverDev()) {
- // shortcut when XT reporting disabled
- return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
- }
-
- // splice stats between DEV and XT, switching over from DEV to XT at
- // first atomic bucket.
- final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis();
- final NetworkStatsHistory dev = mDevStatsCached.getHistory(
- template, UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, firstAtomicBucket);
- final NetworkStatsHistory xt = mXtStatsCached.getHistory(
- template, UID_ALL, SET_ALL, TAG_NONE, fields, firstAtomicBucket, Long.MAX_VALUE);
-
- xt.recordEntireHistory(dev);
- return xt;
+ // We've been using pure XT stats long enough that we no longer need to
+ // splice DEV and XT together.
+ return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields);
}
@Override
@@ -1329,10 +1299,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return getGlobalBoolean(NETSTATS_SAMPLE_ENABLED, true);
}
@Override
- public boolean getReportXtOverDev() {
- return getGlobalBoolean(NETSTATS_REPORT_XT_OVER_DEV, true);
- }
- @Override
public Config getDevConfig() {
return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS),
getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS),
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index 97f0a1e..24fc455 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -20,6 +20,7 @@ public interface NotificationDelegate {
void onSetDisabled(int status);
void onClearAll(int callingUid, int callingPid, int userId);
void onNotificationClick(int callingUid, int callingPid, String key);
+ void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex);
void onNotificationClear(int callingUid, int callingPid,
String pkg, String tag, int id, int userId);
void onNotificationError(int callingUid, int callingPid,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 22f060f..42a8551 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -41,6 +41,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -541,6 +542,20 @@ public class NotificationManagerService extends SystemService {
}
@Override
+ public void onNotificationActionClick(int callingUid, int callingPid, String key,
+ int actionIndex) {
+ synchronized (mNotificationList) {
+ EventLogTags.writeNotificationActionClicked(key, actionIndex);
+ NotificationRecord r = mNotificationsByKey.get(key);
+ if (r == null) {
+ Log.w(TAG, "No notification with key: " + key);
+ return;
+ }
+ // TODO: Log action click via UsageStats.
+ }
+ }
+
+ @Override
public void onNotificationClear(int callingUid, int callingPid,
String pkg, String tag, int id, int userId) {
cancelNotification(callingUid, callingPid, pkg, tag, id, 0,
@@ -643,7 +658,7 @@ public class NotificationManagerService extends SystemService {
}
};
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
@@ -659,6 +674,8 @@ public class NotificationManagerService extends SystemService {
|| (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
|| (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
|| action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
+ int changeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_ALL);
String pkgList[] = null;
boolean queryReplace = queryRemove &&
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
@@ -679,8 +696,10 @@ public class NotificationManagerService extends SystemService {
if (packageChanged) {
// We cancel notifications for packages which have just been disabled
try {
- final int enabled = getContext().getPackageManager()
- .getApplicationEnabledSetting(pkgName);
+ final IPackageManager pm = AppGlobals.getPackageManager();
+ final int enabled = pm.getApplicationEnabledSetting(pkgName,
+ changeUserId != UserHandle.USER_ALL ? changeUserId :
+ UserHandle.USER_OWNER);
if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|| enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
cancelNotifications = false;
@@ -691,6 +710,8 @@ public class NotificationManagerService extends SystemService {
if (DBG) {
Slog.i(TAG, "Exception trying to look up app enabled setting", e);
}
+ } catch (RemoteException e) {
+ // Failed to talk to PackageManagerService Should never happen!
}
}
pkgList = new String[]{pkgName};
@@ -700,13 +721,22 @@ public class NotificationManagerService extends SystemService {
for (String pkgName : pkgList) {
if (cancelNotifications) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkgName, 0, 0, !queryRestart,
- UserHandle.USER_ALL, REASON_PACKAGE_CHANGED, null);
+ changeUserId, REASON_PACKAGE_CHANGED, null);
}
}
}
mListeners.onPackagesChanged(queryReplace, pkgList);
mConditionProviders.onPackagesChanged(queryReplace, pkgList);
- } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
+ }
+ }
+ };
+
+ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+
+ if (action.equals(Intent.ACTION_SCREEN_ON)) {
// Keep track of screen on/off state, but do not turn off the notification light
// until user passes through the lock screen or views the notification.
mScreenOn = true;
@@ -889,6 +919,7 @@ public class NotificationManagerService extends SystemService {
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
getContext().registerReceiver(mIntentReceiver, filter);
+
IntentFilter pkgFilter = new IntentFilter();
pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
@@ -896,9 +927,12 @@ public class NotificationManagerService extends SystemService {
pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
pkgFilter.addDataScheme("package");
- getContext().registerReceiver(mIntentReceiver, pkgFilter);
+ getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
+ null);
+
IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- getContext().registerReceiver(mIntentReceiver, sdFilter);
+ getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, sdFilter, null,
+ null);
mSettingsObserver = new SettingsObserver(mHandler);
@@ -1698,14 +1732,6 @@ public class NotificationManagerService extends SystemService {
}
}
- // This conditional is a dirty hack to limit the logging done on
- // behalf of the download manager without affecting other apps.
- if (!pkg.equals("com.android.providers.downloads")
- || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
- EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
- pkg, id, tag, userId, notification.toString());
- }
-
if (pkg == null || notification == null) {
throw new IllegalArgumentException("null not allowed: pkg=" + pkg
+ " id=" + id + " notification=" + notification);
@@ -1755,6 +1781,14 @@ public class NotificationManagerService extends SystemService {
}
mRankingHelper.extractSignals(r);
+ // This conditional is a dirty hack to limit the logging done on
+ // behalf of the download manager without affecting other apps.
+ if (!pkg.equals("com.android.providers.downloads")
+ || Log.isLoggable("DownloadManager", Log.VERBOSE)) {
+ EventLogTags.writeNotificationEnqueue(callingUid, callingPid,
+ pkg, id, tag, userId, notification.toString(),
+ (old != null) ? 1 : 0);
+ }
// 3. Apply local rules
// blocked apps
@@ -2358,6 +2392,8 @@ public class NotificationManagerService extends SystemService {
// Save it for users of getHistoricalNotifications()
mArchive.record(r.sbn);
+
+ EventLogTags.writeNotificationCanceled(r.getKey(), reason);
}
/**
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index a7eebf8..cb9a45e 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -23,9 +23,9 @@ import android.app.job.JobService;
import android.content.ComponentName;
import android.content.Context;
import android.os.ServiceManager;
+import android.util.ArraySet;
import android.util.Log;
-import java.util.HashSet;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -59,7 +59,7 @@ public class BackgroundDexOptService extends JobService {
if (pm.isStorageLow()) {
return false;
}
- final HashSet<String> pkgs = pm.getPackagesThatNeedDexOpt();
+ final ArraySet<String> pkgs = pm.getPackagesThatNeedDexOpt();
if (pkgs == null) {
return false;
}
diff --git a/services/core/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java
index 14258a4..8f0f935 100644
--- a/services/core/java/com/android/server/pm/GrantedPermissions.java
+++ b/services/core/java/com/android/server/pm/GrantedPermissions.java
@@ -17,13 +17,12 @@
package com.android.server.pm;
import android.content.pm.ApplicationInfo;
-
-import java.util.HashSet;
+import android.util.ArraySet;
class GrantedPermissions {
int pkgFlags;
- HashSet<String> grantedPermissions = new HashSet<String>();
+ ArraySet<String> grantedPermissions = new ArraySet<String>();
int[] gids;
@@ -34,7 +33,7 @@ class GrantedPermissions {
@SuppressWarnings("unchecked")
GrantedPermissions(GrantedPermissions base) {
pkgFlags = base.pkgFlags;
- grantedPermissions = (HashSet<String>) base.grantedPermissions.clone();
+ grantedPermissions = new ArraySet<>(base.grantedPermissions);
if (base.gids != null) {
gids = base.gids.clone();
diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
index 9f9bafd..8f12c03 100644
--- a/services/core/java/com/android/server/pm/PackageKeySetData.java
+++ b/services/core/java/com/android/server/pm/PackageKeySetData.java
@@ -16,10 +16,9 @@
package com.android.server.pm;
-import com.android.internal.util.ArrayUtils;
+import android.util.ArrayMap;
-import java.util.HashMap;
-import java.util.Map;
+import com.android.internal.util.ArrayUtils;
public class PackageKeySetData {
@@ -34,7 +33,7 @@ public class PackageKeySetData {
private long[] mDefinedKeySets;
- private final Map<String, Long> mKeySetAliases = new HashMap<String, Long>();
+ private final ArrayMap<String, Long> mKeySetAliases = new ArrayMap<String, Long>();
PackageKeySetData() {
mProperSigningKeySet = KEYSET_UNASSIGNED;
@@ -132,7 +131,7 @@ public class PackageKeySetData {
return mDefinedKeySets;
}
- protected Map<String, Long> getAliases() {
+ protected ArrayMap<String, Long> getAliases() {
return mKeySetAliases;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b79e157..f9a85df 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -84,6 +84,8 @@ import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.admin.IDevicePolicyManager;
import android.app.backup.IBackupManager;
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -199,8 +201,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -329,9 +329,11 @@ public class PackageManagerService extends IPackageManager.Stub {
final boolean mFactoryTest;
final boolean mOnlyCore;
final boolean mLazyDexOpt;
+ final long mDexOptLRUThresholdInMills;
final DisplayMetrics mMetrics;
final int mDefParseFlags;
final String[] mSeparateProcesses;
+ final boolean mIsUpgrade;
// This is where all application persistent data goes.
final File mAppDataDir;
@@ -371,20 +373,20 @@ public class PackageManagerService extends IPackageManager.Stub {
// Keys are String (package name), values are Package. This also serves
// as the lock for the global state. Methods that must be called with
// this lock held have the prefix "LP".
- final HashMap<String, PackageParser.Package> mPackages =
- new HashMap<String, PackageParser.Package>();
+ final ArrayMap<String, PackageParser.Package> mPackages =
+ new ArrayMap<String, PackageParser.Package>();
// Tracks available target package names -> overlay package paths.
- final HashMap<String, HashMap<String, PackageParser.Package>> mOverlays =
- new HashMap<String, HashMap<String, PackageParser.Package>>();
+ final ArrayMap<String, ArrayMap<String, PackageParser.Package>> mOverlays =
+ new ArrayMap<String, ArrayMap<String, PackageParser.Package>>();
final Settings mSettings;
boolean mRestoredSettings;
// System configuration read by SystemConfig.
final int[] mGlobalGids;
- final SparseArray<HashSet<String>> mSystemPermissions;
- final HashMap<String, FeatureInfo> mAvailableFeatures;
+ final SparseArray<ArraySet<String>> mSystemPermissions;
+ final ArrayMap<String, FeatureInfo> mAvailableFeatures;
// If mac_permissions.xml was found for seinfo labeling.
boolean mFoundPolicyFile;
@@ -403,8 +405,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// Currently known shared libraries.
- final HashMap<String, SharedLibraryEntry> mSharedLibraries =
- new HashMap<String, SharedLibraryEntry>();
+ final ArrayMap<String, SharedLibraryEntry> mSharedLibraries =
+ new ArrayMap<String, SharedLibraryEntry>();
// All available activities, for your resolving pleasure.
final ActivityIntentResolver mActivities =
@@ -422,23 +424,23 @@ public class PackageManagerService extends IPackageManager.Stub {
// Mapping from provider base names (first directory in content URI codePath)
// to the provider information.
- final HashMap<String, PackageParser.Provider> mProvidersByAuthority =
- new HashMap<String, PackageParser.Provider>();
+ final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority =
+ new ArrayMap<String, PackageParser.Provider>();
// Mapping from instrumentation class names to info about them.
- final HashMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
- new HashMap<ComponentName, PackageParser.Instrumentation>();
+ final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation =
+ new ArrayMap<ComponentName, PackageParser.Instrumentation>();
// Mapping from permission names to info about them.
- final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups =
- new HashMap<String, PackageParser.PermissionGroup>();
+ final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups =
+ new ArrayMap<String, PackageParser.PermissionGroup>();
// Packages whose data we have transfered into another package, thus
// should no longer exist.
- final HashSet<String> mTransferedPackages = new HashSet<String>();
+ final ArraySet<String> mTransferedPackages = new ArraySet<String>();
// Broadcast actions that are only available to the system.
- final HashSet<String> mProtectedBroadcasts = new HashSet<String>();
+ final ArraySet<String> mProtectedBroadcasts = new ArraySet<String>();
/** List of packages waiting for verification. */
final SparseArray<PackageVerificationState> mPendingVerification
@@ -449,7 +451,7 @@ public class PackageManagerService extends IPackageManager.Stub {
final PackageInstallerService mInstallerService;
- HashSet<PackageParser.Package> mDeferredDexOpt = null;
+ ArraySet<PackageParser.Package> mDeferredDexOpt = null;
// Cache of users who need badging.
SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
@@ -473,24 +475,24 @@ public class PackageManagerService extends IPackageManager.Stub {
// Set of pending broadcasts for aggregating enable/disable of components.
static class PendingPackageBroadcasts {
// for each user id, a map of <package name -> components within that package>
- final SparseArray<HashMap<String, ArrayList<String>>> mUidMap;
+ final SparseArray<ArrayMap<String, ArrayList<String>>> mUidMap;
public PendingPackageBroadcasts() {
- mUidMap = new SparseArray<HashMap<String, ArrayList<String>>>(2);
+ mUidMap = new SparseArray<ArrayMap<String, ArrayList<String>>>(2);
}
public ArrayList<String> get(int userId, String packageName) {
- HashMap<String, ArrayList<String>> packages = getOrAllocate(userId);
+ ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId);
return packages.get(packageName);
}
public void put(int userId, String packageName, ArrayList<String> components) {
- HashMap<String, ArrayList<String>> packages = getOrAllocate(userId);
+ ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId);
packages.put(packageName, components);
}
public void remove(int userId, String packageName) {
- HashMap<String, ArrayList<String>> packages = mUidMap.get(userId);
+ ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId);
if (packages != null) {
packages.remove(packageName);
}
@@ -508,7 +510,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return mUidMap.keyAt(n);
}
- public HashMap<String, ArrayList<String>> packagesForUserId(int userId) {
+ public ArrayMap<String, ArrayList<String>> packagesForUserId(int userId) {
return mUidMap.get(userId);
}
@@ -525,10 +527,10 @@ public class PackageManagerService extends IPackageManager.Stub {
mUidMap.clear();
}
- private HashMap<String, ArrayList<String>> getOrAllocate(int userId) {
- HashMap<String, ArrayList<String>> map = mUidMap.get(userId);
+ private ArrayMap<String, ArrayList<String>> getOrAllocate(int userId) {
+ ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId);
if (map == null) {
- map = new HashMap<String, ArrayList<String>>();
+ map = new ArrayMap<String, ArrayList<String>>();
mUidMap.put(userId, map);
}
return map;
@@ -565,7 +567,7 @@ public class PackageManagerService extends IPackageManager.Stub {
static UserManagerService sUserManager;
// Stores a list of users whose package restrictions file needs to be updated
- private HashSet<Integer> mDirtyUsers = new HashSet<Integer>();
+ private ArraySet<Integer> mDirtyUsers = new ArraySet<Integer>();
final private DefaultContainerConnection mDefContainerConn =
new DefaultContainerConnection();
@@ -1294,6 +1296,15 @@ public class PackageManagerService extends IPackageManager.Stub {
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);
+ // TODO: add a property to control this?
+ long dexOptLRUThresholdInMinutes;
+ if (mLazyDexOpt) {
+ dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
+ } else {
+ dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
+ }
+ mDexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
+
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
if ("*".equals(separateProcesses)) {
@@ -1384,7 +1395,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// scanning install directories.
final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;
- final HashSet<String> alreadyDexOpted = new HashSet<String>();
+ final ArraySet<String> alreadyDexOpted = new ArraySet<String>();
/**
* Add everything in the in the boot class path to the
@@ -1750,7 +1761,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// If this is first boot after an OTA, and a normal boot, then
// we need to clear code cache directories.
- if (!Build.FINGERPRINT.equals(mSettings.mFingerprint) && !onlyCore) {
+ mIsUpgrade = !Build.FINGERPRINT.equals(mSettings.mFingerprint);
+ if (mIsUpgrade && !onlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (String pkgName : mSettings.mPackages.keySet()) {
deleteCodeCacheDirsLI(pkgName);
@@ -1790,6 +1802,11 @@ public class PackageManagerService extends IPackageManager.Stub {
return mOnlyCore;
}
+ @Override
+ public boolean isUpgrade() {
+ return mIsUpgrade;
+ }
+
private String getRequiredVerifierLPr() {
final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
@@ -2369,7 +2386,7 @@ public class PackageManagerService extends IPackageManager.Stub {
return PackageManager.PERMISSION_GRANTED;
}
} else {
- HashSet<String> perms = mSystemPermissions.get(uid);
+ ArraySet<String> perms = mSystemPermissions.get(uid);
if (perms != null && perms.contains(permName)) {
return PackageManager.PERMISSION_GRANTED;
}
@@ -2790,11 +2807,11 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageManager.SIGNATURE_NO_MATCH;
}
- HashSet<Signature> set1 = new HashSet<Signature>();
+ ArraySet<Signature> set1 = new ArraySet<Signature>();
for (Signature sig : s1) {
set1.add(sig);
}
- HashSet<Signature> set2 = new HashSet<Signature>();
+ ArraySet<Signature> set2 = new ArraySet<Signature>();
for (Signature sig : s2) {
set2.add(sig);
}
@@ -2829,11 +2846,11 @@ public class PackageManagerService extends IPackageManager.Stub {
return PackageManager.SIGNATURE_NO_MATCH;
}
- HashSet<Signature> existingSet = new HashSet<Signature>();
+ ArraySet<Signature> existingSet = new ArraySet<Signature>();
for (Signature sig : existingSigs.mSignatures) {
existingSet.add(sig);
}
- HashSet<Signature> scannedCompatSet = new HashSet<Signature>();
+ ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
for (Signature sig : scannedPkg.mSignatures) {
try {
Signature[] chainSignatures = sig.getChainSignatures();
@@ -3249,7 +3266,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (DEBUG_PREFERRED) {
Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
}
- mSettings.writePackageRestrictionsLPr(userId);
+ scheduleWritePackageRestrictionsLocked(userId);
}
}
}
@@ -4023,7 +4040,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void createIdmapsForPackageLI(PackageParser.Package pkg) {
- HashMap<String, PackageParser.Package> overlays = mOverlays.get(pkg.packageName);
+ ArrayMap<String, PackageParser.Package> overlays = mOverlays.get(pkg.packageName);
if (overlays == null) {
Slog.w(TAG, "Unable to create idmap for " + pkg.packageName + ": no overlay packages");
return;
@@ -4044,7 +4061,7 @@ public class PackageManagerService extends IPackageManager.Stub {
opkg.baseCodePath + ": overlay not trusted");
return false;
}
- HashMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
+ ArrayMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName);
if (overlaySet == null) {
Slog.e(TAG, "was about to create idmap for " + pkg.baseCodePath + " and " +
opkg.baseCodePath + " but target package has no known overlays");
@@ -4465,7 +4482,7 @@ public class PackageManagerService extends IPackageManager.Stub {
public void performBootDexOpt() {
enforceSystemOrRoot("Only the system can request dexopt be performed");
- final HashSet<PackageParser.Package> pkgs;
+ final ArraySet<PackageParser.Package> pkgs;
synchronized (mPackages) {
pkgs = mDeferredDexOpt;
mDeferredDexOpt = null;
@@ -4488,7 +4505,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
// Give priority to system apps that listen for pre boot complete.
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
- HashSet<String> pkgNames = getPackageNamesForIntent(intent);
+ ArraySet<String> pkgNames = getPackageNamesForIntent(intent);
for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
PackageParser.Package pkg = it.next();
if (pkgNames.contains(pkg.packageName)) {
@@ -4562,28 +4579,19 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- private void filterRecentlyUsedApps(HashSet<PackageParser.Package> pkgs) {
+ private void filterRecentlyUsedApps(ArraySet<PackageParser.Package> pkgs) {
// Filter out packages that aren't recently used.
//
// The exception is first boot of a non-eng device (aka !mLazyDexOpt), which
// should do a full dexopt.
if (mLazyDexOpt || (!isFirstBoot() && mPackageUsage.isHistoricalPackageUsageAvailable())) {
- // TODO: add a property to control this?
- long dexOptLRUThresholdInMinutes;
- if (mLazyDexOpt) {
- dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds.
- } else {
- dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users.
- }
- long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000;
-
int total = pkgs.size();
int skipped = 0;
long now = System.currentTimeMillis();
for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
PackageParser.Package pkg = i.next();
long then = pkg.mLastPackageUsageTimeInMills;
- if (then + dexOptLRUThresholdInMills < now) {
+ if (then + mDexOptLRUThresholdInMills < now) {
if (DEBUG_DEXOPT) {
Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
((then == 0) ? "never" : new Date(then)));
@@ -4598,14 +4606,14 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- private HashSet<String> getPackageNamesForIntent(Intent intent) {
+ private ArraySet<String> getPackageNamesForIntent(Intent intent) {
List<ResolveInfo> ris = null;
try {
ris = AppGlobals.getPackageManager().queryIntentReceivers(
intent, null, 0, UserHandle.USER_OWNER);
} catch (RemoteException e) {
}
- HashSet<String> pkgNames = new HashSet<String>();
+ ArraySet<String> pkgNames = new ArraySet<String>();
if (ris != null) {
for (ResolveInfo ri : ris) {
pkgNames.add(ri.activityInfo.packageName);
@@ -4683,8 +4691,8 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- public HashSet<String> getPackagesThatNeedDexOpt() {
- HashSet<String> pkgs = null;
+ public ArraySet<String> getPackagesThatNeedDexOpt() {
+ ArraySet<String> pkgs = null;
synchronized (mPackages) {
for (PackageParser.Package p : mPackages.values()) {
if (DEBUG_DEXOPT) {
@@ -4694,7 +4702,7 @@ public class PackageManagerService extends IPackageManager.Stub {
continue;
}
if (pkgs == null) {
- pkgs = new HashSet<String>();
+ pkgs = new ArraySet<String>();
}
pkgs.add(p.packageName);
}
@@ -4707,7 +4715,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
- boolean forceDex, boolean defer, HashSet<String> done) {
+ boolean forceDex, boolean defer, ArraySet<String> done) {
for (int i=0; i<libs.size(); i++) {
PackageParser.Package libPkg;
String libName;
@@ -4732,7 +4740,7 @@ public class PackageManagerService extends IPackageManager.Stub {
static final int DEX_OPT_FAILED = -1;
private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
- boolean forceDex, boolean defer, HashSet<String> done) {
+ boolean forceDex, boolean defer, ArraySet<String> done) {
final String[] instructionSets = targetInstructionSets != null ?
targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
@@ -4810,7 +4818,7 @@ public class PackageManagerService extends IPackageManager.Stub {
// our list of deferred dexopts.
if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
if (mDeferredDexOpt == null) {
- mDeferredDexOpt = new HashSet<PackageParser.Package>();
+ mDeferredDexOpt = new ArraySet<PackageParser.Package>();
}
mDeferredDexOpt.add(pkg);
return DEX_OPT_DEFERRED;
@@ -4907,7 +4915,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private static String[] getDexCodeInstructionSets(String[] instructionSets) {
- HashSet<String> dexCodeInstructionSets = new HashSet<String>(instructionSets.length);
+ ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length);
for (String instructionSet : instructionSets) {
dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
}
@@ -4950,9 +4958,9 @@ public class PackageManagerService extends IPackageManager.Stub {
private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets,
boolean forceDex, boolean defer, boolean inclDependencies) {
- HashSet<String> done;
+ ArraySet<String> done;
if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
- done = new HashSet<String>();
+ done = new ArraySet<String>();
done.add(pkg.packageName);
} else {
done = null;
@@ -6137,7 +6145,7 @@ public class PackageManagerService extends IPackageManager.Stub {
r = null;
for (i=0; i<N; i++) {
PackageParser.Permission p = pkg.permissions.get(i);
- HashMap<String, BasePermission> permissionMap =
+ ArrayMap<String, BasePermission> permissionMap =
p.tree ? mSettings.mPermissionTrees
: mSettings.mPermissions;
p.group = mPermissionGroups.get(p.info.group);
@@ -6265,9 +6273,9 @@ public class PackageManagerService extends IPackageManager.Stub {
if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) {
if (!mOverlays.containsKey(pkg.mOverlayTarget)) {
mOverlays.put(pkg.mOverlayTarget,
- new HashMap<String, PackageParser.Package>());
+ new ArrayMap<String, PackageParser.Package>());
}
- HashMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget);
+ ArrayMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget);
map.put(pkg.packageName, pkg);
PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget);
if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) {
@@ -6928,13 +6936,13 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps;
- HashSet<String> origPermissions = gp.grantedPermissions;
+ ArraySet<String> origPermissions = gp.grantedPermissions;
boolean changedPermission = false;
if (replace) {
ps.permissionsFixed = false;
if (gp == ps) {
- origPermissions = new HashSet<String>(gp.grantedPermissions);
+ origPermissions = new ArraySet<String>(gp.grantedPermissions);
gp.grantedPermissions.clear();
gp.gids = mGlobalGids;
}
@@ -7081,7 +7089,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
private boolean grantSignaturePermission(String perm, PackageParser.Package pkg,
- BasePermission bp, HashSet<String> origPermissions) {
+ BasePermission bp, ArraySet<String> origPermissions) {
boolean allowed;
allowed = (compareSignatures(
bp.packageSetting.signatures.mSignatures, pkg.mSignatures)
@@ -7339,8 +7347,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// }
// Keys are String (activity class name), values are Activity.
- private final HashMap<ComponentName, PackageParser.Activity> mActivities
- = new HashMap<ComponentName, PackageParser.Activity>();
+ private final ArrayMap<ComponentName, PackageParser.Activity> mActivities
+ = new ArrayMap<ComponentName, PackageParser.Activity>();
private int mFlags;
}
@@ -7538,8 +7546,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// }
// Keys are String (activity class name), values are Activity.
- private final HashMap<ComponentName, PackageParser.Service> mServices
- = new HashMap<ComponentName, PackageParser.Service>();
+ private final ArrayMap<ComponentName, PackageParser.Service> mServices
+ = new ArrayMap<ComponentName, PackageParser.Service>();
private int mFlags;
};
@@ -7732,8 +7740,8 @@ public class PackageManagerService extends IPackageManager.Stub {
out.println(Integer.toHexString(System.identityHashCode(filter)));
}
- private final HashMap<ComponentName, PackageParser.Provider> mProviders
- = new HashMap<ComponentName, PackageParser.Provider>();
+ private final ArrayMap<ComponentName, PackageParser.Provider> mProviders
+ = new ArrayMap<ComponentName, PackageParser.Provider>();
private int mFlags;
};
@@ -10402,6 +10410,60 @@ public class PackageManagerService extends IPackageManager.Stub {
String oldCodePath = null;
boolean systemApp = false;
synchronized (mPackages) {
+ // Check if installing already existing package
+ if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
+ String oldName = mSettings.mRenamedPackages.get(pkgName);
+ if (pkg.mOriginalPackages != null
+ && pkg.mOriginalPackages.contains(oldName)
+ && mPackages.containsKey(oldName)) {
+ // This package is derived from an original package,
+ // and this device has been updating from that original
+ // name. We must continue using the original name, so
+ // rename the new package here.
+ pkg.setPackageName(oldName);
+ pkgName = pkg.packageName;
+ replace = true;
+ if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
+ + oldName + " pkgName=" + pkgName);
+ } else if (mPackages.containsKey(pkgName)) {
+ // This package, under its official name, already exists
+ // on the device; we should replace it.
+ replace = true;
+ if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
+ }
+ }
+
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps != null) {
+ if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
+
+ // Quick sanity check that we're signed correctly if updating;
+ // we'll check this again later when scanning, but we want to
+ // bail early here before tripping over redefined permissions.
+ if (!ps.keySetData.isUsingUpgradeKeySets() || ps.sharedUser != null) {
+ try {
+ verifySignaturesLP(ps, pkg);
+ } catch (PackageManagerException e) {
+ res.setError(e.error, e.getMessage());
+ return;
+ }
+ } else {
+ if (!checkUpgradeKeySetLP(ps, pkg)) {
+ res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ + pkg.packageName + " upgrade keys do not match the "
+ + "previously installed version");
+ return;
+ }
+ }
+
+ oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
+ if (ps.pkg != null && ps.pkg.applicationInfo != null) {
+ systemApp = (ps.pkg.applicationInfo.flags &
+ ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+ res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
+ }
+
// Check whether the newly-scanned package wants to define an already-defined perm
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
@@ -10442,38 +10504,6 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- // Check if installing already existing package
- if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
- String oldName = mSettings.mRenamedPackages.get(pkgName);
- if (pkg.mOriginalPackages != null
- && pkg.mOriginalPackages.contains(oldName)
- && mPackages.containsKey(oldName)) {
- // This package is derived from an original package,
- // and this device has been updating from that original
- // name. We must continue using the original name, so
- // rename the new package here.
- pkg.setPackageName(oldName);
- pkgName = pkg.packageName;
- replace = true;
- if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName="
- + oldName + " pkgName=" + pkgName);
- } else if (mPackages.containsKey(pkgName)) {
- // This package, under its official name, already exists
- // on the device; we should replace it.
- replace = true;
- if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName);
- }
- }
- PackageSetting ps = mSettings.mPackages.get(pkgName);
- if (ps != null) {
- if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps);
- oldCodePath = mSettings.mPackages.get(pkgName).codePathString;
- if (ps.pkg != null && ps.pkg.applicationInfo != null) {
- systemApp = (ps.pkg.applicationInfo.flags &
- ApplicationInfo.FLAG_SYSTEM) != 0;
- }
- res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
- }
}
if (systemApp && onSd) {
@@ -11536,7 +11566,7 @@ public class PackageManagerService extends IPackageManager.Stub {
+ userId + ":");
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
pir.addFilter(new PreferredActivity(filter, match, set, activity, always));
- mSettings.writePackageRestrictionsLPr(userId);
+ scheduleWritePackageRestrictionsLocked(userId);
}
}
@@ -11652,8 +11682,7 @@ public class PackageManagerService extends IPackageManager.Stub {
int user = UserHandle.getCallingUserId();
if (clearPackagePreferredActivitiesLPw(packageName, user)) {
- mSettings.writePackageRestrictionsLPr(user);
- scheduleWriteSettingsLocked();
+ scheduleWritePackageRestrictionsLocked(user);
}
}
}
@@ -11703,8 +11732,7 @@ public class PackageManagerService extends IPackageManager.Stub {
int user = UserHandle.getCallingUserId();
clearPackagePreferredActivitiesLPw(null, user);
mSettings.readDefaultPreferredAppsLPw(this, user);
- mSettings.writePackageRestrictionsLPr(user);
- scheduleWriteSettingsLocked();
+ scheduleWritePackageRestrictionsLocked(user);
}
}
@@ -11756,7 +11784,7 @@ public class PackageManagerService extends IPackageManager.Stub {
filter.dump(new LogPrinter(Log.INFO, TAG), " ");
mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter(
new PersistentPreferredActivity(filter, activity));
- mSettings.writePackageRestrictionsLPr(userId);
+ scheduleWritePackageRestrictionsLocked(userId);
}
}
@@ -11798,7 +11826,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if (changed) {
- mSettings.writePackageRestrictionsLPr(userId);
+ scheduleWritePackageRestrictionsLocked(userId);
}
}
}
@@ -11819,7 +11847,7 @@ public class PackageManagerService extends IPackageManager.Stub {
CrossProfileIntentFilter filter = new CrossProfileIntentFilter(intentFilter,
ownerPackage, UserHandle.getUserId(callingUid), targetUserId, flags);
mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(filter);
- mSettings.writePackageRestrictionsLPr(sourceUserId);
+ scheduleWritePackageRestrictionsLocked(sourceUserId);
}
}
@@ -11835,15 +11863,15 @@ public class PackageManagerService extends IPackageManager.Stub {
synchronized (mPackages) {
CrossProfileIntentResolver resolver =
mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
- HashSet<CrossProfileIntentFilter> set =
- new HashSet<CrossProfileIntentFilter>(resolver.filterSet());
+ ArraySet<CrossProfileIntentFilter> set =
+ new ArraySet<CrossProfileIntentFilter>(resolver.filterSet());
for (CrossProfileIntentFilter filter : set) {
if (filter.getOwnerPackage().equals(ownerPackage)
&& filter.getOwnerUserId() == callingUserId) {
resolver.removeFilter(filter);
}
}
- mSettings.writePackageRestrictionsLPr(sourceUserId);
+ scheduleWritePackageRestrictionsLocked(sourceUserId);
}
}
@@ -13381,4 +13409,25 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
}
+
+ public void getUsageStatsIfNoPackageUsageInfo() {
+ if (!mPackageUsage.isHistoricalPackageUsageAvailable()) {
+ UsageStatsManager usm = (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);
+ if (usm == null) {
+ throw new IllegalStateException("UsageStatsManager must be initialized");
+ }
+ long now = System.currentTimeMillis();
+ Map<String, UsageStats> stats = usm.queryAndAggregateUsageStats(now - mDexOptLRUThresholdInMills, now);
+ for (Map.Entry<String, UsageStats> entry : stats.entrySet()) {
+ String packageName = entry.getKey();
+ PackageParser.Package pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ continue;
+ }
+ UsageStats usage = entry.getValue();
+ pkg.mLastPackageUsageTimeInMills = usage.getLastTimeUsed();
+ mPackageUsage.mIsHistoricalPackageUsageAvailable = true;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index bf13fd9..1dcadb4 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -21,10 +21,10 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import android.content.pm.PackageUserState;
+import android.util.ArraySet;
import android.util.SparseArray;
import java.io.File;
-import java.util.HashSet;
/**
* Settings base class for pending and resolved classes.
@@ -321,8 +321,8 @@ class PackageSettingBase extends GrantedPermissions {
void setUserState(int userId, int enabled, boolean installed, boolean stopped,
boolean notLaunched, boolean hidden,
- String lastDisableAppCaller, HashSet<String> enabledComponents,
- HashSet<String> disabledComponents, boolean blockUninstall) {
+ String lastDisableAppCaller, ArraySet<String> enabledComponents,
+ ArraySet<String> disabledComponents, boolean blockUninstall) {
PackageUserState state = modifyUserState(userId);
state.enabled = enabled;
state.installed = installed;
@@ -335,39 +335,39 @@ class PackageSettingBase extends GrantedPermissions {
state.blockUninstall = blockUninstall;
}
- HashSet<String> getEnabledComponents(int userId) {
+ ArraySet<String> getEnabledComponents(int userId) {
return readUserState(userId).enabledComponents;
}
- HashSet<String> getDisabledComponents(int userId) {
+ ArraySet<String> getDisabledComponents(int userId) {
return readUserState(userId).disabledComponents;
}
- void setEnabledComponents(HashSet<String> components, int userId) {
+ void setEnabledComponents(ArraySet<String> components, int userId) {
modifyUserState(userId).enabledComponents = components;
}
- void setDisabledComponents(HashSet<String> components, int userId) {
+ void setDisabledComponents(ArraySet<String> components, int userId) {
modifyUserState(userId).disabledComponents = components;
}
- void setEnabledComponentsCopy(HashSet<String> components, int userId) {
+ void setEnabledComponentsCopy(ArraySet<String> components, int userId) {
modifyUserState(userId).enabledComponents = components != null
- ? new HashSet<String>(components) : null;
+ ? new ArraySet<String>(components) : null;
}
- void setDisabledComponentsCopy(HashSet<String> components, int userId) {
+ void setDisabledComponentsCopy(ArraySet<String> components, int userId) {
modifyUserState(userId).disabledComponents = components != null
- ? new HashSet<String>(components) : null;
+ ? new ArraySet<String>(components) : null;
}
PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
PackageUserState state = modifyUserState(userId);
if (disabled && state.disabledComponents == null) {
- state.disabledComponents = new HashSet<String>(1);
+ state.disabledComponents = new ArraySet<String>(1);
}
if (enabled && state.enabledComponents == null) {
- state.enabledComponents = new HashSet<String>(1);
+ state.enabledComponents = new ArraySet<String>(1);
}
return state;
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 7de56c8..200eb5f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -63,6 +63,8 @@ import android.content.pm.Signature;
import android.content.pm.UserInfo;
import android.content.pm.PackageUserState;
import android.content.pm.VerifierDeviceIdentity;
+import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
@@ -78,8 +80,6 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -159,11 +159,11 @@ final class Settings {
private final File mStoppedPackagesFilename;
private final File mBackupStoppedPackagesFilename;
- final HashMap<String, PackageSetting> mPackages =
- new HashMap<String, PackageSetting>();
+ final ArrayMap<String, PackageSetting> mPackages =
+ new ArrayMap<String, PackageSetting>();
// List of replaced system applications
- private final HashMap<String, PackageSetting> mDisabledSysPackages =
- new HashMap<String, PackageSetting>();
+ private final ArrayMap<String, PackageSetting> mDisabledSysPackages =
+ new ArrayMap<String, PackageSetting>();
private static int mFirstAvailableUid = 0;
@@ -206,8 +206,8 @@ final class Settings {
final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers =
new SparseArray<CrossProfileIntentResolver>();
- final HashMap<String, SharedUserSetting> mSharedUsers =
- new HashMap<String, SharedUserSetting>();
+ final ArrayMap<String, SharedUserSetting> mSharedUsers =
+ new ArrayMap<String, SharedUserSetting>();
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
private final SparseArray<Object> mOtherUserIds =
new SparseArray<Object>();
@@ -217,12 +217,12 @@ final class Settings {
new ArrayList<Signature>();
// Mapping from permission names to info about them.
- final HashMap<String, BasePermission> mPermissions =
- new HashMap<String, BasePermission>();
+ final ArrayMap<String, BasePermission> mPermissions =
+ new ArrayMap<String, BasePermission>();
// Mapping from permission tree names to info about them.
- final HashMap<String, BasePermission> mPermissionTrees =
- new HashMap<String, BasePermission>();
+ final ArrayMap<String, BasePermission> mPermissionTrees =
+ new ArrayMap<String, BasePermission>();
// Packages that have been uninstalled and still need their external
// storage data deleted.
@@ -232,7 +232,7 @@ final class Settings {
// Keys are the new names of the packages, values are the original
// names. The packages appear everwhere else under their original
// names.
- final HashMap<String, String> mRenamedPackages = new HashMap<String, String>();
+ final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
final StringBuilder mReadMessages = new StringBuilder();
@@ -437,7 +437,7 @@ final class Settings {
void transferPermissionsLPw(String origPkg, String newPkg) {
// Transfer ownership of permissions to the new package.
for (int i=0; i<2; i++) {
- HashMap<String, BasePermission> permissions =
+ ArrayMap<String, BasePermission> permissions =
i == 0 ? mPermissionTrees : mPermissions;
for (BasePermission bp : permissions.values()) {
if (origPkg.equals(bp.sourcePackage)) {
@@ -582,7 +582,7 @@ final class Settings {
}
p.appId = dis.appId;
// Clone permissions
- p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
+ p.grantedPermissions = new ArraySet<String>(dis.grantedPermissions);
// Clone component info
List<UserInfo> users = getAllUsers();
if (users != null) {
@@ -1138,8 +1138,8 @@ final class Settings {
final boolean blockUninstall = blockUninstallStr == null
? false : Boolean.parseBoolean(blockUninstallStr);
- HashSet<String> enabledComponents = null;
- HashSet<String> disabledComponents = null;
+ ArraySet<String> enabledComponents = null;
+ ArraySet<String> disabledComponents = null;
int packageDepth = parser.getDepth();
while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
@@ -1189,9 +1189,9 @@ final class Settings {
}
}
- private HashSet<String> readComponentsLPr(XmlPullParser parser)
+ private ArraySet<String> readComponentsLPr(XmlPullParser parser)
throws IOException, XmlPullParserException {
- HashSet<String> components = null;
+ ArraySet<String> components = null;
int type;
int outerDepth = parser.getDepth();
String tagName;
@@ -1207,7 +1207,7 @@ final class Settings {
String componentName = parser.getAttributeValue(null, ATTR_NAME);
if (componentName != null) {
if (components == null) {
- components = new HashSet<String>();
+ components = new ArraySet<String>();
}
components.add(componentName);
}
@@ -1921,7 +1921,7 @@ final class Settings {
}
ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() {
- final HashSet<String> kList = new HashSet<String>(mPackages.keySet());
+ final ArraySet<String> kList = new ArraySet<String>(mPackages.keySet());
final Iterator<String> its = kList.iterator();
final ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>();
while (its.hasNext()) {
@@ -2511,7 +2511,7 @@ final class Settings {
return defValue;
}
- private void readPermissionsLPw(HashMap<String, BasePermission> out, XmlPullParser parser)
+ private void readPermissionsLPw(ArrayMap<String, BasePermission> out, XmlPullParser parser)
throws IOException, XmlPullParserException {
int outerDepth = parser.getDepth();
int type;
@@ -3016,7 +3016,7 @@ final class Settings {
}
}
- private void readGrantedPermissionsLPw(XmlPullParser parser, HashSet<String> outPerms)
+ private void readGrantedPermissionsLPw(XmlPullParser parser, ArraySet<String> outPerms)
throws IOException, XmlPullParserException {
int outerDepth = parser.getDepth();
int type;
@@ -3090,8 +3090,8 @@ final class Settings {
int sourceUserId = mCrossProfileIntentResolvers.keyAt(i);
CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(sourceUserId);
boolean needsWriting = false;
- HashSet<CrossProfileIntentFilter> cpifs =
- new HashSet<CrossProfileIntentFilter>(cpir.filterSet());
+ ArraySet<CrossProfileIntentFilter> cpifs =
+ new ArraySet<CrossProfileIntentFilter>(cpir.filterSet());
for (CrossProfileIntentFilter cpif : cpifs) {
if (cpif.getTargetUserId() == userId) {
needsWriting = true;
@@ -3147,7 +3147,7 @@ final class Settings {
return ps;
}
- private String compToString(HashSet<String> cmp) {
+ private String compToString(ArraySet<String> cmp) {
return cmp != null ? Arrays.toString(cmp.toArray()) : "[]";
}
@@ -3477,7 +3477,7 @@ final class Settings {
pw.print(prefix); pw.print(" lastDisabledCaller: ");
pw.println(lastDisabledAppCaller);
}
- HashSet<String> cmp = ps.getDisabledComponents(user.id);
+ ArraySet<String> cmp = ps.getDisabledComponents(user.id);
if (cmp != null && cmp.size() > 0) {
pw.print(prefix); pw.println(" disabledComponents:");
for (String s : cmp) {
diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java
index ca1eeea..2b406f7 100644
--- a/services/core/java/com/android/server/pm/SharedUserSetting.java
+++ b/services/core/java/com/android/server/pm/SharedUserSetting.java
@@ -16,7 +16,7 @@
package com.android.server.pm;
-import java.util.HashSet;
+import android.util.ArraySet;
/**
* Settings data for a particular shared user ID we know about.
@@ -29,7 +29,7 @@ final class SharedUserSetting extends GrantedPermissions {
// flags that are associated with this uid, regardless of any package flags
int uidFlags;
- final HashSet<PackageSetting> packages = new HashSet<PackageSetting>();
+ final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>();
final PackageSignatures signatures = new PackageSignatures();
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index f85e2d9..15e0bf0 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.util.Slog;
+import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
@@ -295,9 +296,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
}
- /**
+ /**
* Hide or show the on-screen Menu key. Only call this from the window manager, typically in
- * response to a window with FLAG_NEEDS_MENU_KEY set.
+ * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set
+ * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}.
*/
@Override
public void topAppWindowChanged(final boolean menuVisible) {
@@ -523,6 +525,20 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
}
@Override
+ public void onNotificationActionClick(String key, int actionIndex) {
+ enforceStatusBarService();
+ final int callingUid = Binder.getCallingUid();
+ final int callingPid = Binder.getCallingPid();
+ long identity = Binder.clearCallingIdentity();
+ try {
+ mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key,
+ actionIndex);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ @Override
public void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message, int userId) {
enforceStatusBarService();
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index f9b1704..65cb35b 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -16,6 +16,7 @@
package com.android.server.trust;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.SystemService;
@@ -24,6 +25,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.Manifest;
+import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
import android.app.trust.ITrustListener;
@@ -41,6 +43,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.os.Binder;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.IBinder;
@@ -100,8 +103,10 @@ public class TrustManagerService extends SystemService {
/* package */ final TrustArchive mArchive = new TrustArchive();
private final Context mContext;
private final LockPatternUtils mLockPatternUtils;
+ private final UserManager mUserManager;
- private UserManager mUserManager;
+ @GuardedBy("mUserIsTrusted")
+ private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray();
public TrustManagerService(Context context) {
super(context);
@@ -117,11 +122,15 @@ public class TrustManagerService extends SystemService {
@Override
public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
+ if (isSafeMode()) {
+ // No trust agents in safe mode.
+ return;
+ }
+ if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
mReceiver.register(mContext);
refreshAgentList(UserHandle.USER_ALL);
- } else if (phase == SystemService.PHASE_BOOT_COMPLETED && !isSafeMode()) {
+ } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_OWNER);
}
}
@@ -160,11 +169,19 @@ public class TrustManagerService extends SystemService {
public void updateTrust(int userId, boolean initiatedByUser) {
dispatchOnTrustManagedChanged(aggregateIsTrustManaged(userId), userId);
- dispatchOnTrustChanged(aggregateIsTrusted(userId), userId, initiatedByUser);
+ boolean trusted = aggregateIsTrusted(userId);
+ synchronized (mUserIsTrusted) {
+ mUserIsTrusted.put(userId, trusted);
+ }
+ dispatchOnTrustChanged(trusted, userId, initiatedByUser);
}
void refreshAgentList(int userId) {
if (DEBUG) Slog.d(TAG, "refreshAgentList()");
+ if (isSafeMode()) {
+ // Don't ever bind to trust agents in safe mode.
+ return;
+ }
if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_OWNER) {
Log.e(TAG, "refreshAgentList(userId=" + userId + "): Invalid user handle,"
+ " must be USER_ALL or a specific user.", new Throwable("here"));
@@ -547,6 +564,16 @@ public class TrustManagerService extends SystemService {
mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
}
+ @Override
+ public boolean isTrusted(int userId) throws RemoteException {
+ userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
+ false /* allowAll */, true /* requireFull */, "isTrusted", null);
+ userId = resolveProfileParent(userId);
+ synchronized (mUserIsTrusted) {
+ return mUserIsTrusted.get(userId);
+ }
+ }
+
private void enforceReportPermission() {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
@@ -561,6 +588,10 @@ public class TrustManagerService extends SystemService {
protected void dump(FileDescriptor fd, final PrintWriter fout, String[] args) {
mContext.enforceCallingPermission(Manifest.permission.DUMP,
"dumping TrustManagerService");
+ if (isSafeMode()) {
+ fout.println("disabled because the system is in safe mode.");
+ return;
+ }
final UserInfo currentUser;
final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
try {
@@ -623,6 +654,19 @@ public class TrustManagerService extends SystemService {
}
};
+ private int resolveProfileParent(int userId) {
+ long identity = Binder.clearCallingIdentity();
+ try {
+ UserInfo parent = mUserManager.getProfileParent(userId);
+ if (parent != null) {
+ return parent.getUserHandle().getIdentifier();
+ }
+ return userId;
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java
index 558ffb5..c12dd63 100644
--- a/services/core/java/com/android/server/tv/TvInputHal.java
+++ b/services/core/java/com/android/server/tv/TvInputHal.java
@@ -55,7 +55,7 @@ final class TvInputHal implements Handler.Callback {
private native long nativeOpen();
- private static native int nativeAddStream(long ptr, int deviceId, int streamId,
+ private static native int nativeAddOrUpdateStream(long ptr, int deviceId, int streamId,
Surface surface);
private static native int nativeRemoveStream(long ptr, int deviceId, int streamId);
private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId,
@@ -80,7 +80,7 @@ final class TvInputHal implements Handler.Callback {
}
}
- public int addStream(int deviceId, Surface surface, TvStreamConfig streamConfig) {
+ public int addOrUpdateStream(int deviceId, Surface surface, TvStreamConfig streamConfig) {
synchronized (mLock) {
if (mPtr == 0) {
return ERROR_NO_INIT;
@@ -89,7 +89,7 @@ final class TvInputHal implements Handler.Callback {
if (generation != streamConfig.getGeneration()) {
return ERROR_STALE_CONFIG;
}
- if (nativeAddStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
+ if (nativeAddOrUpdateStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) {
return SUCCESS;
} else {
return ERROR_UNKNOWN;
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 77ab33b..85659cf 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -122,6 +122,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
} catch (RemoteException e) {
Slog.w(TAG, "Error registering listeners to HdmiControlService:", e);
}
+ } else {
+ Slog.w(TAG, "HdmiControlService is not available");
}
}
}
@@ -186,6 +188,11 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return;
}
connection.updateConfigsLocked(configs);
+ String inputId = mHardwareInputIdMap.get(deviceId);
+ if (inputId != null) {
+ mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+ convertConnectedToState(configs.length > 0), 0, inputId).sendToTarget();
+ }
try {
connection.getCallbackLocked().onStreamConfigChanged(configs);
} catch (RemoteException e) {
@@ -255,6 +262,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
mHardwareInputIdMap.put(deviceId, info.getId());
mInputMap.put(info.getId(), info);
+ // Process pending state changes
+
+ // For logical HDMI devices, they have information from HDMI CEC signals.
for (int i = 0; i < mHdmiStateMap.size(); ++i) {
TvInputHardwareInfo hardwareInfo =
findHardwareInfoForHdmiPortLocked(mHdmiStateMap.keyAt(i));
@@ -266,8 +276,17 @@ class TvInputHardwareManager implements TvInputHal.Callback {
mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
convertConnectedToState(mHdmiStateMap.valueAt(i)), 0,
inputId).sendToTarget();
+ return;
}
}
+ // For the rest of the devices, we can tell by the number of available streams.
+ Connection connection = mConnections.get(deviceId);
+ if (connection != null) {
+ mHandler.obtainMessage(ListenerHandler.STATE_CHANGED,
+ convertConnectedToState(connection.getConfigsLocked().length > 0), 0,
+ info.getId()).sendToTarget();
+ return;
+ }
}
}
@@ -666,14 +685,14 @@ class TvInputHardwareManager implements TvInputHal.Callback {
result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig);
mActiveConfig = null;
} else {
- if (config != mActiveConfig && mActiveConfig != null) {
+ if (!config.equals(mActiveConfig)) {
result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig);
if (result != TvInputHal.SUCCESS) {
mActiveConfig = null;
return false;
}
}
- result = mHal.addStream(mInfo.getDeviceId(), surface, config);
+ result = mHal.addOrUpdateStream(mInfo.getDeviceId(), surface, config);
if (result == TvInputHal.SUCCESS) {
mActiveConfig = config;
}
@@ -743,7 +762,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
&& sinkConfig.channelMask() != mDesiredChannelMask)
|| (mDesiredFormat != AudioFormat.ENCODING_DEFAULT
&& sinkConfig.format() != mDesiredFormat)) {
- sinkConfig = mAudioSource.buildConfig(mDesiredSamplingRate, mDesiredChannelMask,
+ sinkConfig = mAudioSink.buildConfig(mDesiredSamplingRate, mDesiredChannelMask,
mDesiredFormat, null);
shouldRecreateAudioPatch = true;
}
@@ -799,7 +818,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return false;
}
- int result = mHal.addStream(mInfo.getDeviceId(), surface, config);
+ int result = mHal.addOrUpdateStream(mInfo.getDeviceId(), surface, config);
return result == TvInputHal.SUCCESS;
}
}
@@ -914,11 +933,18 @@ class TvInputHardwareManager implements TvInputHal.Callback {
break;
}
case HDMI_DEVICE_UPDATED: {
- SomeArgs args = (SomeArgs) msg.obj;
- String inputId = (String) args.arg1;
- HdmiDeviceInfo info = (HdmiDeviceInfo) args.arg2;
- args.recycle();
- mListener.onHdmiDeviceUpdated(inputId, info);
+ HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj;
+ String inputId = null;
+ synchronized (mLock) {
+ inputId = mHdmiInputIdMap.get(info.getId());
+ }
+ if (inputId != null) {
+ mListener.onHdmiDeviceUpdated(inputId, info);
+ } else {
+ Slog.w(TAG, "Could not resolve input ID matching the device info; "
+ + "ignoring.");
+ }
+ break;
}
default: {
Slog.w(TAG, "Unhandled message: " + msg);
@@ -986,11 +1012,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
mHdmiDeviceList.add(deviceInfo);
messageType = ListenerHandler.HDMI_DEVICE_UPDATED;
- String inputId = mHdmiInputIdMap.get(deviceInfo.getId());
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = inputId;
- args.arg2 = deviceInfo;
- obj = args;
+ obj = deviceInfo;
break;
}
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index fa1c0ff..f947b6a 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -346,8 +346,7 @@ final class AccessibilityController {
case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
- case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
- case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
+ case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: {
Rect magnifiedRegionBounds = mTempRect2;
mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked(
magnifiedRegionBounds);
@@ -993,8 +992,7 @@ final class AccessibilityController {
final int flags = windowState.mAttrs.flags;
- // If the window is not touchable, do not report it but take into account
- // the space it takes since the content behind it cannot be touched.
+ // If the window is not touchable - ignore.
if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) {
continue;
}
@@ -1015,9 +1013,14 @@ final class AccessibilityController {
}
}
- // Account for the space this window takes.
- unaccountedSpace.op(boundsInScreen, unaccountedSpace,
- Region.Op.REVERSE_DIFFERENCE);
+ // Account for the space this window takes if the window
+ // is not an accessibility overlay which does not change
+ // the reported windows.
+ if (windowState.mAttrs.type == WindowManager.LayoutParams
+ .TYPE_ACCESSIBILITY_OVERLAY) {
+ unaccountedSpace.op(boundsInScreen, unaccountedSpace,
+ Region.Op.REVERSE_DIFFERENCE);
+ }
// We figured out what is touchable for the entire screen - done.
if (unaccountedSpace.isEmpty()) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 30589b1..b0feca8 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -376,10 +376,9 @@ class DisplayContent {
stack.dump(prefix + " ", pw);
}
pw.println();
- pw.println(" Application tokens in bottom up Z order:");
+ pw.println(" Application tokens in top down Z order:");
int ndx = 0;
- final int numStacks = mStacks.size();
- for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 69d3191..61ea1e8 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -20,6 +20,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static com.android.server.wm.WindowManagerService.DEBUG_KEYGUARD;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
@@ -29,7 +30,6 @@ import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPA
import android.content.Context;
import android.os.Debug;
import android.os.SystemClock;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -233,12 +233,17 @@ public class WindowAnimator {
final WindowStateAnimator winAnimator = win.mWinAnimator;
if ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
if (!winAnimator.mAnimating) {
+ if (DEBUG_KEYGUARD) Slog.d(TAG,
+ "updateWindowsLocked: creating delay animation");
+
// Create a new animation to delay until keyguard is gone on its own.
winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
winAnimator.mAnimationIsEntrance = false;
}
} else {
+ if (DEBUG_KEYGUARD) Slog.d(TAG,
+ "updateWindowsLocked: StatusBar is no longer keyguard");
mKeyguardGoingAway = false;
winAnimator.clearAnimation();
}
@@ -282,7 +287,7 @@ public class WindowAnimator {
if (mPolicy.isForceHiding(win.mAttrs)) {
if (!wasAnimating && nowAnimating) {
- if (WindowManagerService.DEBUG_ANIM ||
+ if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_ANIM ||
WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
"Animation started that could impact force hide: " + win);
mBulkUpdateParams |= SET_FORCE_HIDING_CHANGED;
@@ -310,7 +315,7 @@ public class WindowAnimator {
mForceHiding = win.isDrawnLw() ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
}
}
- if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+ if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
"Force hide " + forceHidingToString()
+ " hasSurface=" + win.mHasSurface
+ " policyVis=" + win.mPolicyVisibility
@@ -327,12 +332,12 @@ public class WindowAnimator {
&& (!winAnimator.isAnimating() || hideWhenLocked))
|| ((mForceHiding == KEYGUARD_SHOWN) && hideWhenLocked)) {
changed = win.hideLw(false, false);
- if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
- "Now policy hidden: " + win);
+ if ((DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY)
+ && changed) Slog.v(TAG, "Now policy hidden: " + win);
} else {
changed = win.showLw(false, false);
- if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
- "Now policy shown: " + win);
+ if ((DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY)
+ && changed) Slog.v(TAG, "Now policy shown: " + win);
if (changed) {
if ((mBulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0
&& win.isVisibleNow() /*w.isReadyForDisplay()*/) {
@@ -404,6 +409,11 @@ public class WindowAnimator {
if (!mKeyguardGoingAwayDisableWindowAnimations) {
a = mPolicy.createForceHideEnterAnimation(wallpaperInUnForceHiding,
mKeyguardGoingAwayToNotificationShade);
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: created anim=" + a
+ + " for win=" + unForceHiding.get(i));
+ } else {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: skipping anim for win="
+ + unForceHiding.get(i));
}
if (a != null) {
final WindowStateAnimator winAnimator = unForceHiding.get(i);
@@ -422,6 +432,7 @@ public class WindowAnimator {
// Wallpaper is going away in un-force-hide motion, animate it as well.
if (!wallpaperInUnForceHiding && wallpaper != null
&& !mKeyguardGoingAwayDisableWindowAnimations) {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "updateWindowsLocked: wallpaper animating away");
Animation a = mPolicy.createForceHideWallpaperExitAnimation(
mKeyguardGoingAwayToNotificationShade);
if (a != null) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2354369..a48d39f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -166,6 +166,7 @@ public class WindowManagerService extends IWindowManager.Stub
static final boolean DEBUG_FOCUS = false;
static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
static final boolean DEBUG_ANIM = false;
+ static final boolean DEBUG_KEYGUARD = false;
static final boolean DEBUG_LAYOUT = false;
static final boolean DEBUG_RESIZE = false;
static final boolean DEBUG_LAYERS = false;
@@ -2337,6 +2338,11 @@ public class WindowManagerService extends IWindowManager.Stub
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ if (type == TYPE_ACCESSIBILITY_OVERLAY) {
+ Slog.w(TAG, "Attempted to add Accessibility overlay window with unknown token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+ }
token = new WindowToken(this, attrs.token, -1, false);
addToken = true;
} else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
@@ -2380,6 +2386,12 @@ public class WindowManagerService extends IWindowManager.Stub
+ attrs.token + ". Aborting.");
return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
}
+ } else if (type == TYPE_ACCESSIBILITY_OVERLAY) {
+ if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) {
+ Slog.w(TAG, "Attempted to add Accessibility overlay window with bad token "
+ + attrs.token + ". Aborting.");
+ return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
+ }
} else if (token.appWindowToken != null) {
Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
// It is not valid to use an app token with other system types; we will
@@ -2476,7 +2488,9 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
- win.mWinAnimator.mEnterAnimationPending = true;
+ final WindowStateAnimator winAnimator = win.mWinAnimator;
+ winAnimator.mEnterAnimationPending = true;
+ winAnimator.mEnteringAnimation = true;
if (displayContent.isDefaultDisplay) {
mPolicy.getContentInsetHintLw(attrs, outContentInsets);
@@ -2515,9 +2529,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
mInputMonitor.updateInputWindowsLw(false /*force*/);
- if (localLOGV) Slog.v(
- TAG, "New client " + client.asBinder()
- + ": window=" + win);
+ if (true || localLOGV) Slog.v(TAG, "addWindow: New client " + client.asBinder()
+ + ": window=" + win + " Callers=" + Debug.getCallers(5));
if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
reportNewConfig = true;
@@ -2681,7 +2694,8 @@ public class WindowManagerService extends IWindowManager.Stub
mPolicy.removeWindowLw(win);
win.removeLocked();
- if (DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win);
+ if (true || DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win +
+ " Callers=" + Debug.getCallers(5));
mWindowMap.remove(win.mClient.asBinder());
if (win.mAppOp != AppOpsManager.OP_NONE) {
mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage());
@@ -2986,8 +3000,8 @@ public class WindowManagerService extends IWindowManager.Stub
return 0;
}
WindowStateAnimator winAnimator = win.mWinAnimator;
- if (win.mRequestedWidth != requestedWidth
- || win.mRequestedHeight != requestedHeight) {
+ if (viewVisibility != View.GONE && (win.mRequestedWidth != requestedWidth
+ || win.mRequestedHeight != requestedHeight)) {
win.mLayoutNeeded = true;
win.mRequestedWidth = requestedWidth;
win.mRequestedHeight = requestedHeight;
@@ -3088,6 +3102,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (oldVisibility == View.GONE) {
winAnimator.mEnterAnimationPending = true;
}
+ winAnimator.mEnteringAnimation = true;
if (toBeDisplayed) {
if (win.isDrawnLw() && okToDisplay()) {
winAnimator.applyEnterAnimationLocked();
@@ -3156,6 +3171,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
} else {
winAnimator.mEnterAnimationPending = false;
+ winAnimator.mEnteringAnimation = false;
if (winAnimator.mSurfaceControl != null) {
if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
+ ": mExiting=" + win.mExiting);
@@ -5348,6 +5364,8 @@ public class WindowManagerService extends IWindowManager.Stub
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires DISABLE_KEYGUARD permission");
}
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "keyguardGoingAway: disableWinAnim="
+ + disableWindowAnimations + " kgToNotifShade=" + keyguardGoingToNotificationShade);
synchronized (mWindowMap) {
mAnimator.mKeyguardGoingAway = true;
mAnimator.mKeyguardGoingAwayToNotificationShade = keyguardGoingToNotificationShade;
@@ -5357,12 +5375,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
public void keyguardWaitingForActivityDrawn() {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "keyguardWaitingForActivityDrawn");
synchronized (mWindowMap) {
mKeyguardWaitingForActivityDrawn = true;
}
}
public void notifyActivityDrawnForKeyguard() {
+ if (DEBUG_KEYGUARD) Slog.d(TAG, "notifyActivityDrawnForKeyguard: waiting="
+ + mKeyguardWaitingForActivityDrawn);
synchronized (mWindowMap) {
if (mKeyguardWaitingForActivityDrawn) {
mPolicy.notifyActivityDrawnForKeyguardLw();
@@ -6038,6 +6059,10 @@ public class WindowManagerService extends IWindowManager.Stub
while (true) {
if (retryCount++ > 0) {
+ // Reset max/min layers on retries so we don't accidentally take a screenshot of a
+ // layer based on the previous try.
+ maxLayer = 0;
+ minLayer = Integer.MAX_VALUE;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
@@ -6060,7 +6085,17 @@ public class WindowManagerService extends IWindowManager.Stub
continue;
}
} else if (ws.mIsWallpaper) {
- // Fall through.
+ if (appWin == null) {
+ // We have not ran across the target window yet, so it is probably
+ // behind the wallpaper. This can happen when the keyguard is up and
+ // all windows are moved behind the wallpaper. We don't want to
+ // include the wallpaper layer in the screenshot as it will coverup
+ // the layer of the target window.
+ continue;
+ }
+ // Fall through. The target window is in front of the wallpaper. For this
+ // case we want to include the wallpaper layer in the screenshot because
+ // the target window might have some transparent areas.
} else if (appToken != null) {
if (ws.mAppToken == null || ws.mAppToken.token != appToken) {
// This app window is of no interest if it is not associated with the
@@ -9378,7 +9413,6 @@ public class WindowManagerService extends IWindowManager.Stub
final int type = attrs.type;
if (canBeSeen
&& (type == TYPE_SYSTEM_DIALOG
- || type == TYPE_RECENTS_OVERLAY
|| type == TYPE_SYSTEM_ERROR
|| (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) {
mInnerFields.mSyswin = true;
@@ -11628,5 +11662,23 @@ public class WindowManagerService extends IWindowManager.Stub
checkDrawnWindowsLocked();
}
}
+
+ @Override
+ public void addWindowToken(IBinder token, int type) {
+ WindowManagerService.this.addWindowToken(token, type);
+ }
+
+ @Override
+ public void removeWindowToken(IBinder token, boolean removeWindows) {
+ synchronized(mWindowMap) {
+ if (removeWindows) {
+ WindowToken wtoken = mTokenMap.remove(token);
+ if (wtoken != null) {
+ wtoken.removeAllWindows();
+ }
+ }
+ WindowManagerService.this.removeWindowToken(token);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b4a7f04..f9efc80 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -29,6 +29,7 @@ import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import android.app.AppOpsManager;
@@ -227,13 +228,33 @@ final class WindowState implements WindowManagerPolicy.WindowState {
final Rect mCompatFrame = new Rect();
final Rect mContainingFrame = new Rect();
+
+ final Rect mParentFrame = new Rect();
+
+ // The entire screen area of the device.
final Rect mDisplayFrame = new Rect();
+
+ // The region of the display frame that the display type supports displaying content on. This
+ // is mostly a special case for TV where some displays don’t have the entire display usable.
+ // {@link WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to allow
+ // window display contents to extend into the overscan region.
final Rect mOverscanFrame = new Rect();
+
+ // The display frame minus the stable insets. This value is always constant regardless of if
+ // the status bar or navigation bar is visible.
+ final Rect mStableFrame = new Rect();
+
+ // The area not occupied by the status and navigation bars. So, if both status and navigation
+ // bars are visible, the decor frame is equal to the stable frame.
+ final Rect mDecorFrame = new Rect();
+
+ // Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame
+ // minus the area occupied by the IME if the IME is present.
final Rect mContentFrame = new Rect();
- final Rect mParentFrame = new Rect();
+
+ // Legacy stuff. Generally equal to the content frame expect when the IME for older apps
+ // displays hint text.
final Rect mVisibleFrame = new Rect();
- final Rect mDecorFrame = new Rect();
- final Rect mStableFrame = new Rect();
boolean mContentChanged;
@@ -704,9 +725,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
WindowState ws = this;
WindowList windows = getWindowList();
while (true) {
- if ((ws.mAttrs.privateFlags
- & WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY) != 0) {
- return (ws.mAttrs.flags & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0;
+ if (ws.mAttrs.needsMenuKey != WindowManager.LayoutParams.NEEDS_MENU_UNSET) {
+ return ws.mAttrs.needsMenuKey == WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE;
}
// If we reached the bottom of the range of windows we are considering,
// assume no menu is needed.
@@ -883,7 +903,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
*/
boolean isVisibleNow() {
return mHasSurface && mPolicyVisibility && !mAttachedHidden
- && !mRootToken.hidden && !mExiting && !mDestroying;
+ && (!mRootToken.hidden || mAttrs.type == TYPE_APPLICATION_STARTING)
+ && !mExiting && !mDestroying;
}
/**
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 0c727f3..fc3f2c2 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -40,6 +40,7 @@ import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.os.Debug;
+import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
import android.view.Display;
@@ -141,6 +142,11 @@ class WindowStateAnimator {
// an enter animation.
boolean mEnterAnimationPending;
+ /** Used to indicate that this window is undergoing an enter animation. Used for system
+ * windows to make the callback to View.dispatchOnWindowShownCallback(). Set when the
+ * window is first added or shown, cleared when the callback has been made. */
+ boolean mEnteringAnimation;
+
boolean keyguardGoingAwayAnimation;
/** This is set when there is no Surface */
@@ -428,6 +434,14 @@ class WindowStateAnimator {
mWin.mChildWindows.get(i).mWinAnimator.finishExit();
}
+ if (mEnteringAnimation && mWin.mAppToken == null) {
+ try {
+ mEnteringAnimation = false;
+ mWin.mClient.dispatchWindowShown();
+ } catch (RemoteException e) {
+ }
+ }
+
if (!mWin.mExiting) {
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index 2267123..1a672e6 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import android.os.IBinder;
+import android.util.Slog;
import java.io.PrintWriter;
@@ -29,7 +30,7 @@ import java.io.PrintWriter;
class WindowToken {
// The window manager!
final WindowManagerService service;
-
+
// The actual token.
final IBinder token;
@@ -77,6 +78,15 @@ class WindowToken {
explicit = _explicit;
}
+ void removeAllWindows() {
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ WindowState win = windows.get(winNdx);
+ if (WindowManagerService.DEBUG_WINDOW_MOVEMENT) Slog.w(WindowManagerService.TAG,
+ "removeAllWindows: removing win=" + win);
+ win.mService.removeWindowLocked(win.mSession, win);
+ }
+ }
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("windows="); pw.println(windows);
pw.print(prefix); pw.print("windowType="); pw.print(windowType);
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index d5abe0c..5cb0543 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -235,7 +235,7 @@ public:
static JTvInputHal* createInstance(JNIEnv* env, jobject thiz);
- int addStream(int deviceId, int streamId, const sp<Surface>& surface);
+ int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface);
int removeStream(int deviceId, int streamId);
const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
@@ -312,7 +312,7 @@ JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz) {
return new JTvInputHal(env, thiz, device);
}
-int JTvInputHal::addStream(int deviceId, int streamId, const sp<Surface>& surface) {
+int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface) {
KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
if (connections.indexOfKey(streamId) < 0) {
connections.add(streamId, Connection());
@@ -555,14 +555,14 @@ static jlong nativeOpen(JNIEnv* env, jobject thiz) {
return (jlong)JTvInputHal::createInstance(env, thiz);
}
-static int nativeAddStream(JNIEnv* env, jclass clazz,
+static int nativeAddOrUpdateStream(JNIEnv* env, jclass clazz,
jlong ptr, jint deviceId, jint streamId, jobject jsurface) {
JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
if (!jsurface) {
return BAD_VALUE;
}
sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
- return tvInputHal->addStream(deviceId, streamId, surface);
+ return tvInputHal->addOrUpdateStream(deviceId, streamId, surface);
}
static int nativeRemoveStream(JNIEnv* env, jclass clazz,
@@ -612,8 +612,8 @@ static JNINativeMethod gTvInputHalMethods[] = {
/* name, signature, funcPtr */
{ "nativeOpen", "()J",
(void*) nativeOpen },
- { "nativeAddStream", "(JIILandroid/view/Surface;)I",
- (void*) nativeAddStream },
+ { "nativeAddOrUpdateStream", "(JIILandroid/view/Surface;)I",
+ (void*) nativeAddOrUpdateStream },
{ "nativeRemoveStream", "(JII)I",
(void*) nativeRemoveStream },
{ "nativeGetStreamConfigs", "(JII)[Landroid/media/tv/TvStreamConfig;",
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9ee44b9..308fcd8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4788,6 +4788,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
}
}
+ sendChangedNotification(userHandle);
}
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 6009ffd..d7f6130 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -374,6 +374,8 @@ public final class SystemServer {
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
+ // Update after UsageStatsService is available, needed before performBootDexOpt.
+ mPackageManagerService.getUsageStatsIfNoPackageUsageInfo();
// Tracks whether the updatable WebView is in a ready state and watches for update installs.
mSystemServiceManager.startService(WebViewUpdateService.class);
diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java
index 9496cae..7ab3840 100644
--- a/services/print/java/com/android/server/print/RemotePrintSpooler.java
+++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java
@@ -21,6 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -55,7 +56,8 @@ final class RemotePrintSpooler {
private static final boolean DEBUG = false;
- private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000;
+ private static final long BIND_SPOOLER_SERVICE_TIMEOUT =
+ ("eng".equals(Build.TYPE)) ? 120000 : 10000;
private final Object mLock = new Object();
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index c3d4ed9..c115339 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -932,7 +932,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes();
expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes();
- expect(mSettings.getReportXtOverDev()).andReturn(true).anyTimes();
final Config config = new Config(bucketDuration, deleteAge, deleteAge);
expect(mSettings.getDevConfig()).andReturn(config).anyTimes();
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index a70ebf4..b631331 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -21,22 +21,15 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
-import com.android.internal.content.PackageHelper;
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+import android.util.Log;
+
import com.android.internal.os.AtomicFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.util.HashSet;
-
-import android.os.Debug;
-import android.os.Environment;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.storage.IMountService;
-import android.test.AndroidTestCase;
-import android.util.Log;
public class PackageManagerSettingsTests extends AndroidTestCase {
@@ -182,11 +175,11 @@ public class PackageManagerSettingsTests extends AndroidTestCase {
assertEquals(COMPONENT_ENABLED_STATE_ENABLED, ps.getEnabled(1));
// Enable/Disable a component
- HashSet<String> components = new HashSet<String>();
+ ArraySet<String> components = new ArraySet<String>();
String component1 = PACKAGE_NAME_1 + "/.Component1";
components.add(component1);
ps.setDisabledComponents(components, 0);
- HashSet<String> componentsDisabled = ps.getDisabledComponents(0);
+ ArraySet<String> componentsDisabled = ps.getDisabledComponents(0);
assertEquals(1, componentsDisabled.size());
assertEquals(component1, componentsDisabled.toArray()[0]);
boolean hasEnabled =
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index cfa4436..11da380 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -39,6 +39,7 @@ class UsageStatsDatabase {
private static final String TAG = "UsageStatsDatabase";
private static final boolean DEBUG = UsageStatsService.DEBUG;
+ private static final String BAK_SUFFIX = ".bak";
private final Object mLock = new Object();
private final File[] mIntervalDirs;
@@ -95,11 +96,71 @@ class UsageStatsDatabase {
}
}
+ public interface CheckinAction {
+ boolean checkin(IntervalStats stats);
+ }
+
+ /**
+ * Calls {@link CheckinAction#checkin(IntervalStats)} on the given {@link CheckinAction}
+ * for all {@link IntervalStats} that haven't been checked-in.
+ * If any of the calls to {@link CheckinAction#checkin(IntervalStats)} returns false or throws
+ * an exception, the check-in will be aborted.
+ *
+ * @param checkinAction The callback to run when checking-in {@link IntervalStats}.
+ * @return true if the check-in succeeded.
+ */
+ public boolean checkinDailyFiles(CheckinAction checkinAction) {
+ synchronized (mLock) {
+ final TimeSparseArray<AtomicFile> files =
+ mSortedStatFiles[UsageStatsManager.INTERVAL_DAILY];
+ final int fileCount = files.size();
+ int start = 0;
+ while (start < fileCount - 1) {
+ if (!files.valueAt(start).getBaseFile().getName().endsWith("-c")) {
+ break;
+ }
+ }
+
+ if (start == fileCount - 1) {
+ return true;
+ }
+
+ try {
+ IntervalStats stats = new IntervalStats();
+ for (int i = start; i < fileCount - 1; i++) {
+ UsageStatsXml.read(files.valueAt(i), stats);
+ if (!checkinAction.checkin(stats)) {
+ return false;
+ }
+ }
+ } catch (IOException e) {
+ Slog.e(TAG, "Failed to check-in", e);
+ return false;
+ }
+
+ // We have successfully checked-in the stats, so rename the files so that they
+ // are marked as checked-in.
+ for (int i = start; i < fileCount - 1; i++) {
+ final AtomicFile file = files.valueAt(i);
+ final File checkedInFile = new File(file.getBaseFile().getParent(),
+ file.getBaseFile().getName() + "-c");
+ if (!file.getBaseFile().renameTo(checkedInFile)) {
+ // We must return success, as we've already marked some files as checked-in.
+ // It's better to repeat ourselves than to lose data.
+ Slog.e(TAG, "Failed to mark file " + file.getBaseFile().getPath()
+ + " as checked-in");
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+
private void indexFilesLocked() {
final FilenameFilter backupFileFilter = new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
- return !name.endsWith(".bak");
+ return !name.endsWith(BAK_SUFFIX);
}
};
@@ -383,10 +444,10 @@ class UsageStatsDatabase {
if (files != null) {
for (File f : files) {
String path = f.getPath();
- if (path.endsWith(".bak")) {
- f = new File(path.substring(0, path.length() - 4));
+ if (path.endsWith(BAK_SUFFIX)) {
+ f = new File(path.substring(0, path.length() - BAK_SUFFIX.length()));
}
- long beginTime = Long.parseLong(f.getName());
+ long beginTime = UsageStatsXml.parseBeginTime(f);
if (beginTime < expiryTime) {
new AtomicFile(f).delete();
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 2ed9745..485b2a2 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -33,11 +33,11 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.UserInfo;
import android.content.res.Configuration;
import android.os.Binder;
-import android.os.Debug;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -47,9 +47,12 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.SystemService;
import java.io.File;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;
@@ -176,7 +179,7 @@ public class UsageStatsService extends SystemService implements
long currentTimeMillis) {
UserUsageStatsService service = mUserState.get(userId);
if (service == null) {
- service = new UserUsageStatsService(userId,
+ service = new UserUsageStatsService(getContext(), userId,
new File(mUsageStatsDir, Integer.toString(userId)), this);
service.init(currentTimeMillis);
mUserState.put(userId, service);
@@ -319,6 +322,30 @@ public class UsageStatsService extends SystemService implements
mHandler.removeMessages(MSG_FLUSH_TO_DISK);
}
+ /**
+ * Called by the Binder stub.
+ */
+ void dump(String[] args, PrintWriter pw) {
+ synchronized (mLock) {
+ IndentingPrintWriter idpw = new IndentingPrintWriter(pw, " ");
+ ArraySet<String> argSet = new ArraySet<>();
+ argSet.addAll(Arrays.asList(args));
+
+ final int userCount = mUserState.size();
+ for (int i = 0; i < userCount; i++) {
+ idpw.printPair("user", mUserState.keyAt(i));
+ idpw.println();
+ idpw.increaseIndent();
+ if (argSet.contains("--checkin")) {
+ mUserState.valueAt(i).checkin(idpw);
+ } else {
+ mUserState.valueAt(i).dump(idpw);
+ }
+ idpw.decreaseIndent();
+ }
+ }
+ }
+
class H extends Handler {
public H(Looper looper) {
super(looper);
@@ -349,8 +376,12 @@ public class UsageStatsService extends SystemService implements
private class BinderService extends IUsageStatsManager.Stub {
private boolean hasPermission(String callingPackage) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == Process.SYSTEM_UID) {
+ return true;
+ }
final int mode = mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS,
- Binder.getCallingUid(), callingPackage);
+ callingUid, callingPackage);
if (mode == AppOpsManager.MODE_DEFAULT) {
// The default behavior here is to check if PackageManager has given the app
// permission.
@@ -417,6 +448,18 @@ public class UsageStatsService extends SystemService implements
Binder.restoreCallingIdentity(token);
}
}
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump UsageStats from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " without permission " + android.Manifest.permission.DUMP);
+ return;
+ }
+ UsageStatsService.this.dump(args, pw);
+ }
}
/**
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXml.java b/services/usage/java/com/android/server/usage/UsageStatsXml.java
index 9ce6d63..26148ce 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXml.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXml.java
@@ -24,21 +24,26 @@ import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.*;
public class UsageStatsXml {
private static final String TAG = "UsageStatsXml";
private static final int CURRENT_VERSION = 1;
private static final String USAGESTATS_TAG = "usagestats";
private static final String VERSION_ATTR = "version";
+ private static final String CHECKED_IN_SUFFIX = "-c";
public static long parseBeginTime(AtomicFile file) {
- return Long.parseLong(file.getBaseFile().getName());
+ return parseBeginTime(file.getBaseFile());
+ }
+
+ public static long parseBeginTime(File file) {
+ final String name = file.getName();
+ if (name.endsWith(CHECKED_IN_SUFFIX)) {
+ return Long.parseLong(
+ name.substring(0, name.length() - CHECKED_IN_SUFFIX.length()));
+ }
+ return Long.parseLong(name);
}
public static void read(AtomicFile file, IntervalStats statsOut) throws IOException {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 4916ec2..6596781 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -23,9 +23,13 @@ import android.app.usage.UsageStats;
import android.app.usage.UsageStatsManager;
import android.content.res.Configuration;
import android.os.SystemClock;
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.usage.UsageStatsDatabase.StatCombiner;
import java.io.File;
@@ -43,7 +47,13 @@ class UserUsageStatsService {
private static final String TAG = "UsageStatsService";
private static final boolean DEBUG = UsageStatsService.DEBUG;
private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ private static final int sDateFormatFlags =
+ DateUtils.FORMAT_SHOW_DATE
+ | DateUtils.FORMAT_SHOW_TIME
+ | DateUtils.FORMAT_SHOW_YEAR
+ | DateUtils.FORMAT_NUMERIC_DATE;
+ private final Context mContext;
private final UsageStatsDatabase mDatabase;
private final IntervalStats[] mCurrentStats;
private boolean mStatsChanged = false;
@@ -55,7 +65,8 @@ class UserUsageStatsService {
void onStatsUpdated();
}
- UserUsageStatsService(int userId, File usageStatsDir, StatsUpdatedListener listener) {
+ UserUsageStatsService(Context context, int userId, File usageStatsDir, StatsUpdatedListener listener) {
+ mContext = context;
mDailyExpiryDate = new UnixCalendar(0);
mDatabase = new UsageStatsDatabase(usageStatsDir);
mCurrentStats = new IntervalStats[UsageStatsManager.INTERVAL_COUNT];
@@ -433,6 +444,117 @@ class UserUsageStatsService {
tempCal.getTimeInMillis() + ")");
}
+ //
+ // -- DUMP related methods --
+ //
+
+ void checkin(final IndentingPrintWriter pw) {
+ mDatabase.checkinDailyFiles(new UsageStatsDatabase.CheckinAction() {
+ @Override
+ public boolean checkin(IntervalStats stats) {
+ printIntervalStats(pw, stats, false);
+ return true;
+ }
+ });
+ }
+
+ void dump(IndentingPrintWriter pw) {
+ // This is not a check-in, only dump in-memory stats.
+ for (int interval = 0; interval < mCurrentStats.length; interval++) {
+ pw.print("In-memory ");
+ pw.print(intervalToString(interval));
+ pw.println(" stats");
+ printIntervalStats(pw, mCurrentStats[interval], true);
+ }
+ }
+
+ private String formatDateTime(long dateTime, boolean pretty) {
+ if (pretty) {
+ return "\"" + DateUtils.formatDateTime(mContext, dateTime, sDateFormatFlags) + "\"";
+ }
+ return Long.toString(dateTime);
+ }
+
+ private String formatElapsedTime(long elapsedTime, boolean pretty) {
+ if (pretty) {
+ return "\"" + DateUtils.formatElapsedTime(elapsedTime / 1000) + "\"";
+ }
+ return Long.toString(elapsedTime);
+ }
+
+ void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats, boolean prettyDates) {
+ if (prettyDates) {
+ pw.printPair("timeRange", "\"" + DateUtils.formatDateRange(mContext,
+ stats.beginTime, stats.endTime, sDateFormatFlags) + "\"");
+ } else {
+ pw.printPair("beginTime", stats.beginTime);
+ pw.printPair("endTime", stats.endTime);
+ }
+ pw.println();
+ pw.increaseIndent();
+ pw.println("packages");
+ pw.increaseIndent();
+ final ArrayMap<String, UsageStats> pkgStats = stats.packageStats;
+ final int pkgCount = pkgStats.size();
+ for (int i = 0; i < pkgCount; i++) {
+ final UsageStats usageStats = pkgStats.valueAt(i);
+ pw.printPair("package", usageStats.mPackageName);
+ pw.printPair("totalTime", formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
+ pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates));
+ pw.println();
+ }
+ pw.decreaseIndent();
+
+ pw.println("configurations");
+ pw.increaseIndent();
+ final ArrayMap<Configuration, ConfigurationStats> configStats =
+ stats.configurations;
+ final int configCount = configStats.size();
+ for (int i = 0; i < configCount; i++) {
+ final ConfigurationStats config = configStats.valueAt(i);
+ pw.printPair("config", Configuration.resourceQualifierString(config.mConfiguration));
+ pw.printPair("totalTime", formatElapsedTime(config.mTotalTimeActive, prettyDates));
+ pw.printPair("lastTime", formatDateTime(config.mLastTimeActive, prettyDates));
+ pw.printPair("count", config.mActivationCount);
+ pw.println();
+ }
+ pw.decreaseIndent();
+
+ pw.println("events");
+ pw.increaseIndent();
+ final TimeSparseArray<UsageEvents.Event> events = stats.events;
+ final int eventCount = events != null ? events.size() : 0;
+ for (int i = 0; i < eventCount; i++) {
+ final UsageEvents.Event event = events.valueAt(i);
+ pw.printPair("time", formatDateTime(event.mTimeStamp, prettyDates));
+ pw.printPair("type", eventToString(event.mEventType));
+ pw.printPair("package", event.mPackage);
+ if (event.mClass != null) {
+ pw.printPair("class", event.mClass);
+ }
+ if (event.mConfiguration != null) {
+ pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration));
+ }
+ pw.println();
+ }
+ pw.decreaseIndent();
+ pw.decreaseIndent();
+ }
+
+ private static String intervalToString(int interval) {
+ switch (interval) {
+ case UsageStatsManager.INTERVAL_DAILY:
+ return "daily";
+ case UsageStatsManager.INTERVAL_WEEKLY:
+ return "weekly";
+ case UsageStatsManager.INTERVAL_MONTHLY:
+ return "monthly";
+ case UsageStatsManager.INTERVAL_YEARLY:
+ return "yearly";
+ default:
+ return "?";
+ }
+ }
private static String eventToString(int eventType) {
switch (eventType) {