Merge "Only init ARC when system audio mode is on"
diff --git a/Android.bp b/Android.bp
index 490de6e..ee3b396 100644
--- a/Android.bp
+++ b/Android.bp
@@ -279,6 +279,7 @@
"core/java/android/os/storage/IStorageShutdownObserver.aidl",
"core/java/android/os/storage/IObbActionListener.aidl",
"core/java/android/permission/IPermissionController.aidl",
+ "core/java/android/permission/IPermissionManager.aidl",
":keystore_aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
"core/java/android/service/appprediction/IPredictionService.aidl",
diff --git a/api/current.txt b/api/current.txt
index 2cfdd87..25801ca 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -38638,6 +38638,7 @@
field public static final String ACTION_CAPTIONING_SETTINGS = "android.settings.CAPTIONING_SETTINGS";
field public static final String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
field public static final String ACTION_CHANNEL_NOTIFICATION_SETTINGS = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
+ field public static final String ACTION_CONDITION_PROVIDER_SETTINGS = "android.settings.ACTION_CONDITION_PROVIDER_SETTINGS";
field public static final String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
field public static final String ACTION_DATA_USAGE_SETTINGS = "android.settings.DATA_USAGE_SETTINGS";
field public static final String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5ab694f..d741b61 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -113,6 +113,7 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.permission.IPermissionManager;
import android.provider.BlockedNumberContract;
import android.provider.CalendarContract;
import android.provider.CallLog;
@@ -287,6 +288,7 @@
@UnsupportedAppUsage
static volatile IPackageManager sPackageManager;
+ private static volatile IPermissionManager sPermissionManager;
@UnsupportedAppUsage
final ApplicationThread mAppThread = new ApplicationThread();
@@ -2136,16 +2138,23 @@
@UnsupportedAppUsage
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
- //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
- IBinder b = ServiceManager.getService("package");
- //Slog.v("PackageManager", "default service binder = " + b);
+ final IBinder b = ServiceManager.getService("package");
sPackageManager = IPackageManager.Stub.asInterface(b);
- //Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
+ /** Returns the permission manager */
+ public static IPermissionManager getPermissionManager() {
+ if (sPermissionManager != null) {
+ return sPermissionManager;
+ }
+ final IBinder b = ServiceManager.getService("permissionmgr");
+ sPermissionManager = IPermissionManager.Stub.asInterface(b);
+ return sPermissionManager;
+ }
+
private Configuration mMainThreadConfig = new Configuration();
Configuration applyConfigCompatMainThread(int displayDensity, Configuration config,
@@ -6317,7 +6326,8 @@
final InstrumentationInfo ii;
if (data.instrumentationName != null) {
try {
- ii = new ApplicationPackageManager(null, getPackageManager())
+ ii = new ApplicationPackageManager(
+ null, getPackageManager(), getPermissionManager())
.getInstrumentationInfo(data.instrumentationName, 0);
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
diff --git a/core/java/android/app/AppGlobals.java b/core/java/android/app/AppGlobals.java
index 1f737b6..8312327 100644
--- a/core/java/android/app/AppGlobals.java
+++ b/core/java/android/app/AppGlobals.java
@@ -18,6 +18,7 @@
import android.annotation.UnsupportedAppUsage;
import android.content.pm.IPackageManager;
+import android.permission.IPermissionManager;
/**
* Special private access for certain globals related to a process.
@@ -52,6 +53,14 @@
}
/**
+ * Return the raw interface to the permission manager.
+ * @return The permission manager.
+ */
+ public static IPermissionManager getPermissionManager() {
+ return ActivityThread.getPermissionManager();
+ }
+
+ /**
* Gets the value of an integer core setting.
*
* @param key The setting key.
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 525bc44b..1641afb 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -82,6 +82,7 @@
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
+import android.permission.IPermissionManager;
import android.provider.Settings;
import android.system.ErrnoException;
import android.system.Os;
@@ -320,30 +321,60 @@
}
@Override
- public PermissionInfo getPermissionInfo(String name, int flags)
+ @SuppressWarnings("unchecked")
+ public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
+ try {
+ final ParceledListSlice<PermissionGroupInfo> parceledList =
+ mPermissionManager.getAllPermissionGroups(flags);
+ if (parceledList == null) {
+ return Collections.emptyList();
+ }
+ return parceledList.getList();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
+ public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags)
throws NameNotFoundException {
try {
- PermissionInfo pi = mPM.getPermissionInfo(name,
- mContext.getOpPackageName(), flags);
+ final PermissionGroupInfo pgi =
+ mPermissionManager.getPermissionGroupInfo(groupName, flags);
+ if (pgi != null) {
+ return pgi;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ throw new NameNotFoundException(groupName);
+ }
+
+ @Override
+ public PermissionInfo getPermissionInfo(String permName, int flags)
+ throws NameNotFoundException {
+ try {
+ final String packageName = mContext.getOpPackageName();
+ final PermissionInfo pi =
+ mPermissionManager.getPermissionInfo(permName, packageName, flags);
if (pi != null) {
return pi;
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- throw new NameNotFoundException(name);
+ throw new NameNotFoundException(permName);
}
@Override
@SuppressWarnings("unchecked")
- public List<PermissionInfo> queryPermissionsByGroup(String group, int flags)
+ public List<PermissionInfo> queryPermissionsByGroup(String groupName, int flags)
throws NameNotFoundException {
try {
- ParceledListSlice<PermissionInfo> parceledList =
- mPM.queryPermissionsByGroup(group, flags);
+ final ParceledListSlice<PermissionInfo> parceledList =
+ mPermissionManager.queryPermissionsByGroup(groupName, flags);
if (parceledList != null) {
- List<PermissionInfo> pi = parceledList.getList();
+ final List<PermissionInfo> pi = parceledList.getList();
if (pi != null) {
return pi;
}
@@ -351,8 +382,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
- throw new NameNotFoundException(group);
+ throw new NameNotFoundException(groupName);
}
@Override
@@ -368,36 +398,6 @@
}
@Override
- public PermissionGroupInfo getPermissionGroupInfo(String name,
- int flags) throws NameNotFoundException {
- try {
- PermissionGroupInfo pgi = mPM.getPermissionGroupInfo(name, flags);
- if (pgi != null) {
- return pgi;
- }
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
- throw new NameNotFoundException(name);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public List<PermissionGroupInfo> getAllPermissionGroups(int flags) {
- try {
- ParceledListSlice<PermissionGroupInfo> parceledList =
- mPM.getAllPermissionGroups(flags);
- if (parceledList == null) {
- return Collections.emptyList();
- }
- return parceledList.getList();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- @Override
public ApplicationInfo getApplicationInfo(String packageName, int flags)
throws NameNotFoundException {
return getApplicationInfoAsUser(packageName, flags, getUserId());
@@ -661,7 +661,7 @@
@Override
public boolean addPermission(PermissionInfo info) {
try {
- return mPM.addPermission(info);
+ return mPermissionManager.addPermission(info, false);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -670,7 +670,7 @@
@Override
public boolean addPermissionAsync(PermissionInfo info) {
try {
- return mPM.addPermissionAsync(info);
+ return mPermissionManager.addPermission(info, true);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -679,7 +679,7 @@
@Override
public void removePermission(String name) {
try {
- mPM.removePermission(name);
+ mPermissionManager.removePermission(name);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1655,10 +1655,11 @@
}
@UnsupportedAppUsage
- protected ApplicationPackageManager(ContextImpl context,
- IPackageManager pm) {
+ protected ApplicationPackageManager(ContextImpl context, IPackageManager pm,
+ IPermissionManager permissionManager) {
mContext = context;
mPM = pm;
+ mPermissionManager = permissionManager;
}
/**
@@ -2930,6 +2931,7 @@
private final ContextImpl mContext;
@UnsupportedAppUsage
private final IPackageManager mPM;
+ private final IPermissionManager mPermissionManager;
/** Assume locked until we hear otherwise */
private volatile boolean mUserUnlocked = false;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 41a4fba..ef23d5e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -68,6 +68,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.permission.IPermissionManager;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -297,10 +298,11 @@
return mPackageManager;
}
- IPackageManager pm = ActivityThread.getPackageManager();
- if (pm != null) {
+ final IPackageManager pm = ActivityThread.getPackageManager();
+ final IPermissionManager permissionManager = ActivityThread.getPermissionManager();
+ if (pm != null && permissionManager != null) {
// Doesn't matter if we make more than one instance.
- return (mPackageManager = new ApplicationPackageManager(this, pm));
+ return (mPackageManager = new ApplicationPackageManager(this, pm, permissionManager));
}
return null;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a7eecd7..277e41d 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -78,15 +78,6 @@
@UnsupportedAppUsage
String[] canonicalToCurrentPackageNames(in String[] names);
- PermissionInfo getPermissionInfo(String name, String packageName, int flags);
-
- ParceledListSlice queryPermissionsByGroup(String group, int flags);
-
- @UnsupportedAppUsage
- PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
-
- ParceledListSlice getAllPermissionGroups(int flags);
-
@UnsupportedAppUsage
ApplicationInfo getApplicationInfo(String packageName, int flags ,int userId);
@@ -111,12 +102,6 @@
int checkUidPermission(String permName, int uid);
@UnsupportedAppUsage
- boolean addPermission(in PermissionInfo info);
-
- @UnsupportedAppUsage
- void removePermission(String name);
-
- @UnsupportedAppUsage
void grantRuntimePermission(String packageName, String permissionName, int userId);
void revokeRuntimePermission(String packageName, String permissionName, int userId);
@@ -171,9 +156,6 @@
boolean isUidPrivileged(int uid);
@UnsupportedAppUsage
- String[] getAppOpPermissionPackages(String permissionName);
-
- @UnsupportedAppUsage
ResolveInfo resolveIntent(in Intent intent, String resolvedType, int flags, int userId);
ResolveInfo findPersistentPreferredActivity(in Intent intent, int userId);
@@ -626,9 +608,6 @@
int movePackage(in String packageName, in String volumeUuid);
int movePrimaryStorage(in String volumeUuid);
- @UnsupportedAppUsage
- boolean addPermissionAsync(in PermissionInfo info);
-
boolean setInstallLocation(int loc);
@UnsupportedAppUsage
int getInstallLocation();
@@ -772,4 +751,24 @@
void setRuntimePermissionsVersion(int version, int userId);
void notifyPackagesReplacedReceived(in String[] packages);
+
+ //------------------------------------------------------------------------
+ //
+ // The following binder interfaces have been moved to IPermissionManager
+ //
+ //------------------------------------------------------------------------
+ @UnsupportedAppUsage
+ String[] getAppOpPermissionPackages(String permissionName);
+
+ @UnsupportedAppUsage
+ PermissionGroupInfo getPermissionGroupInfo(String name, int flags);
+
+ @UnsupportedAppUsage
+ boolean addPermission(in PermissionInfo info);
+
+ @UnsupportedAppUsage
+ boolean addPermissionAsync(in PermissionInfo info);
+
+ @UnsupportedAppUsage
+ void removePermission(String name);
}
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 672994e..1c1d709 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -999,4 +999,11 @@
* Migrates legacy obb data to its new location.
*/
public abstract void migrateLegacyObbData();
+
+ /**
+ * Writes all package manager settings to disk. If {@code async} is {@code true}, the
+ * settings are written at some point in the future. Otherwise, the call blocks until
+ * the settings have been written.
+ */
+ public abstract void writeSettings(boolean async);
}
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index b0b1874..23fbefb 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -17,7 +17,6 @@
package android.content.pm;
import android.Manifest;
-import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -177,8 +176,7 @@
mContext.registerReceiver(mUserRemovedReceiver, userFilter);
}
- @VisibleForTesting
- protected void handlePackageEvent(Intent intent, int userId) {
+ private void handlePackageEvent(Intent intent, int userId) {
// Don't regenerate the services map when the package is removed or its
// ASEC container unmounted as a step in replacement. The subsequent
// _ADDED / _AVAILABLE call will regenerate the map in the final state.
@@ -240,9 +238,6 @@
public void invalidateCache(int userId) {
synchronized (mServicesLock) {
- if (DEBUG) {
- Slog.d(TAG, "invalidating cache for " + userId + " " + mInterfaceName);
- }
final UserServices<V> user = findOrCreateUserLocked(userId);
user.services = null;
onServicesChangedLocked(userId);
@@ -472,48 +467,34 @@
* or null to assume that everything is affected.
* @param userId the user for whom to update the services map.
*/
- private void generateServicesMap(@Nullable int[] changedUids, int userId) {
+ private void generateServicesMap(int[] changedUids, int userId) {
if (DEBUG) {
Slog.d(TAG, "generateServicesMap() for " + userId + ", changed UIDs = "
+ Arrays.toString(changedUids));
}
+ final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<>();
+ final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ try {
+ ServiceInfo<V> info = parseServiceInfo(resolveInfo);
+ if (info == null) {
+ Log.w(TAG, "Unable to load service info " + resolveInfo.toString());
+ continue;
+ }
+ serviceInfos.add(info);
+ } catch (XmlPullParserException | IOException e) {
+ Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
+ }
+ }
+
synchronized (mServicesLock) {
final UserServices<V> user = findOrCreateUserLocked(userId);
- final boolean cacheInvalid = user.services == null;
- if (cacheInvalid) {
+ final boolean firstScan = user.services == null;
+ if (firstScan) {
user.services = Maps.newHashMap();
}
- final ArrayList<ServiceInfo<V>> serviceInfos = new ArrayList<>();
- final List<ResolveInfo> resolveInfos = queryIntentServices(userId);
-
- for (ResolveInfo resolveInfo : resolveInfos) {
- try {
- // when changedUids == null, we want to do a rescan of everything, this means
- // it's the initial scan, and containsUid will trivially return true
- // when changedUids != null, we got here because a package changed, but
- // invalidateCache could have been called (thus user.services == null), and we
- // should query from PackageManager again
- if (!cacheInvalid
- && !containsUid(
- changedUids, resolveInfo.serviceInfo.applicationInfo.uid)) {
- if (DEBUG) {
- Slog.d(TAG, "Skipping parseServiceInfo for " + resolveInfo);
- }
- continue;
- }
- ServiceInfo<V> info = parseServiceInfo(resolveInfo);
- if (info == null) {
- Log.w(TAG, "Unable to load service info " + resolveInfo.toString());
- continue;
- }
- serviceInfos.add(info);
- } catch (XmlPullParserException | IOException e) {
- Log.w(TAG, "Unable to load service info " + resolveInfo.toString(), e);
- }
- }
-
StringBuilder changes = new StringBuilder();
boolean changed = false;
for (ServiceInfo<V> info : serviceInfos) {
@@ -534,7 +515,7 @@
changed = true;
user.services.put(info.type, info);
user.persistentServices.put(info.type, info.uid);
- if (!(user.mPersistentServicesFileDidNotExist && cacheInvalid)) {
+ if (!(user.mPersistentServicesFileDidNotExist && firstScan)) {
notifyListener(info.type, userId, false /* removed */);
}
} else if (previousUid == info.uid) {
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index d05ba79..972ae2a 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -35,8 +35,10 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -61,7 +63,31 @@
private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF;
- private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+ /**
+ * A cache of the current device's physical address. When device's HDMI out port
+ * is not connected to any device, it is set to {@link #INVALID_PHYSICAL_ADDRESS}.
+ *
+ * <p>Otherwise it is updated by the {@link ClientHotplugEventListener} registered
+ * with {@link com.android.server.hdmi.HdmiControlService} by the
+ * {@link #addHotplugEventListener(HotplugEventListener)} and the address is from
+ * {@link com.android.server.hdmi.HdmiControlService#getPortInfo()}
+ */
+ @GuardedBy("mLock")
+ private int mLocalPhysicalAddress = INVALID_PHYSICAL_ADDRESS;
+
+ private void setLocalPhysicalAddress(int physicalAddress) {
+ synchronized (mLock) {
+ mLocalPhysicalAddress = physicalAddress;
+ }
+ }
+
+ private int getLocalPhysicalAddress() {
+ synchronized (mLock) {
+ return mLocalPhysicalAddress;
+ }
+ }
+
+ private final Object mLock = new Object();
/**
* Broadcast Action: Display OSD message.
@@ -318,6 +344,37 @@
mHasSwitchDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH);
mIsSwitchDevice = SystemProperties.getBoolean(
PROPERTY_HDMI_IS_DEVICE_HDMI_CEC_SWITCH, false);
+ addHotplugEventListener(new ClientHotplugEventListener());
+ }
+
+ private final class ClientHotplugEventListener implements HotplugEventListener {
+
+ @Override
+ public void onReceived(HdmiHotplugEvent event) {
+ List<HdmiPortInfo> ports = new ArrayList<>();
+ try {
+ ports = mService.getPortInfo();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ if (ports.isEmpty()) {
+ Log.e(TAG, "Can't find port info, not updating connected status. "
+ + "Hotplug event:" + event);
+ return;
+ }
+ // If the HDMI OUT port is plugged or unplugged, update the mLocalPhysicalAddress
+ for (HdmiPortInfo port : ports) {
+ if (port.getId() == event.getPort()) {
+ if (port.getType() == HdmiPortInfo.PORT_OUTPUT) {
+ setLocalPhysicalAddress(
+ event.isConnected()
+ ? port.getAddress()
+ : INVALID_PHYSICAL_ADDRESS);
+ }
+ break;
+ }
+ }
+ }
}
private static boolean hasDeviceType(int[] types, int type) {
@@ -616,15 +673,7 @@
*/
@SystemApi
public int getPhysicalAddress() {
- if (mPhysicalAddress != INVALID_PHYSICAL_ADDRESS) {
- return mPhysicalAddress;
- }
- try {
- mPhysicalAddress = mService.getPhysicalAddress();
- return mPhysicalAddress;
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getLocalPhysicalAddress();
}
/**
@@ -641,15 +690,15 @@
@SystemApi
public boolean isDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
Preconditions.checkNotNull(targetDevice);
- mPhysicalAddress = getPhysicalAddress();
- if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+ int physicalAddress = getLocalPhysicalAddress();
+ if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
int targetPhysicalAddress = targetDevice.getPhysicalAddress();
if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
- return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress)
+ return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, physicalAddress)
!= HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
}
@@ -662,15 +711,15 @@
@SystemApi
public boolean isRemoteDeviceConnected(@NonNull HdmiDeviceInfo targetDevice) {
Preconditions.checkNotNull(targetDevice);
- mPhysicalAddress = getPhysicalAddress();
- if (mPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
+ int physicalAddress = getLocalPhysicalAddress();
+ if (physicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
int targetPhysicalAddress = targetDevice.getPhysicalAddress();
if (targetPhysicalAddress == INVALID_PHYSICAL_ADDRESS) {
return false;
}
- return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, mPhysicalAddress)
+ return HdmiUtils.getLocalPortFromPhysicalAddress(targetPhysicalAddress, physicalAddress)
!= HdmiUtils.TARGET_NOT_UNDER_LOCAL_DEVICE;
}
diff --git a/core/java/android/os/IServiceManager.java b/core/java/android/os/IServiceManager.java
deleted file mode 100644
index 053c5ed..0000000
--- a/core/java/android/os/IServiceManager.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.annotation.UnsupportedAppUsage;
-
-/**
- * Basic interface for finding and publishing system services.
- *
- * An implementation of this interface is usually published as the
- * global context object, which can be retrieved via
- * BinderNative.getContextObject(). An easy way to retrieve this
- * is with the static method BnServiceManager.getDefault().
- *
- * @hide
- */
-public interface IServiceManager extends IInterface
-{
- /**
- * Retrieve an existing service called @a name from the
- * service manager. Blocks for a few seconds waiting for it to be
- * published if it does not already exist.
- */
- @UnsupportedAppUsage
- IBinder getService(String name) throws RemoteException;
-
- /**
- * Retrieve an existing service called @a name from the
- * service manager. Non-blocking.
- */
- @UnsupportedAppUsage
- IBinder checkService(String name) throws RemoteException;
-
- /**
- * Place a new @a service called @a name into the service
- * manager.
- */
- void addService(String name, IBinder service, boolean allowIsolated, int dumpFlags)
- throws RemoteException;
-
- /**
- * Return a list of all currently running services.
- */
- String[] listServices(int dumpFlags) throws RemoteException;
-
- static final String descriptor = "android.os.IServiceManager";
-
- int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
- int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
- int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
- int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
- int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
- int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;
-
- /*
- * Must update values in IServiceManager.h
- */
- /* Allows services to dump sections according to priorities. */
- int DUMP_FLAG_PRIORITY_CRITICAL = 1 << 0;
- int DUMP_FLAG_PRIORITY_HIGH = 1 << 1;
- int DUMP_FLAG_PRIORITY_NORMAL = 1 << 2;
- /**
- * Services are by default registered with a DEFAULT dump priority. DEFAULT priority has the
- * same priority as NORMAL priority but the services are not called with dump priority
- * arguments.
- */
- int DUMP_FLAG_PRIORITY_DEFAULT = 1 << 3;
- int DUMP_FLAG_PRIORITY_ALL = DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_HIGH
- | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PRIORITY_DEFAULT;
- /* Allows services to dump sections in protobuf format. */
- int DUMP_FLAG_PROTO = 1 << 4;
-
-}
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 011dfa0..7991cd4 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -18,8 +18,6 @@
import android.annotation.UnsupportedAppUsage;
-import java.util.ArrayList;
-
/**
* Native implementation of the service manager. Most clients will only
* care about asInterface().
@@ -32,26 +30,27 @@
/**
* Cast a Binder object into a service manager interface, generating
* a proxy if needed.
+ *
+ * TODO: delete this method and have clients use
+ * IServiceManager.Stub.asInterface instead
*/
@UnsupportedAppUsage
- static public IServiceManager asInterface(IBinder obj)
- {
+ public static IServiceManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
- IServiceManager in =
- (IServiceManager) obj.queryLocalInterface(IServiceManager.descriptor);
- if (in != null) {
- return in;
- }
+ // ServiceManager is never local
return new ServiceManagerProxy(obj);
}
}
+// This class should be deleted and replaced with IServiceManager.Stub whenever
+// mRemote is no longer used
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
+ mServiceManager = IServiceManager.Stub.asInterface(remote);
}
public IBinder asBinder() {
@@ -60,73 +59,30 @@
@UnsupportedAppUsage
public IBinder getService(String name) throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IServiceManager.descriptor);
- data.writeString(name);
- mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
- IBinder binder = reply.readStrongBinder();
- reply.recycle();
- data.recycle();
- return binder;
+ // Same as checkService (old versions of servicemanager had both methods).
+ return mServiceManager.checkService(name);
}
public IBinder checkService(String name) throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IServiceManager.descriptor);
- data.writeString(name);
- mRemote.transact(CHECK_SERVICE_TRANSACTION, data, reply, 0);
- IBinder binder = reply.readStrongBinder();
- reply.recycle();
- data.recycle();
- return binder;
+ return mServiceManager.checkService(name);
}
public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IServiceManager.descriptor);
- data.writeString(name);
- data.writeStrongBinder(service);
- data.writeInt(allowIsolated ? 1 : 0);
- data.writeInt(dumpPriority);
- mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
- reply.recycle();
- data.recycle();
+ mServiceManager.addService(name, service, allowIsolated, dumpPriority);
}
public String[] listServices(int dumpPriority) throws RemoteException {
- ArrayList<String> services = new ArrayList<String>();
- int n = 0;
- while (true) {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IServiceManager.descriptor);
- data.writeInt(n);
- data.writeInt(dumpPriority);
- n++;
- try {
- boolean res = mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
- if (!res) {
- break;
- }
- } catch (RuntimeException e) {
- // The result code that is returned by the C++ code can
- // cause the call to throw an exception back instead of
- // returning a nice result... so eat it here and go on.
- break;
- }
- services.add(reply.readString());
- reply.recycle();
- data.recycle();
- }
- String[] array = new String[services.size()];
- services.toArray(array);
- return array;
+ return mServiceManager.listServices(dumpPriority);
}
+ /**
+ * Same as mServiceManager but used by apps.
+ *
+ * Once this can be removed, ServiceManagerProxy should be removed entirely.
+ */
@UnsupportedAppUsage
private IBinder mRemote;
+
+ private IServiceManager mServiceManager;
}
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
new file mode 100644
index 0000000..3b69b12
--- /dev/null
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.permission;
+
+import android.content.pm.ParceledListSlice;
+import android.content.pm.PermissionGroupInfo;
+import android.content.pm.PermissionInfo;
+
+/**
+ * Interface to communicate directly with the permission manager service.
+ * @see PermissionManager
+ * @hide
+ */
+interface IPermissionManager {
+ String[] getAppOpPermissionPackages(String permName);
+
+ ParceledListSlice getAllPermissionGroups(int flags);
+
+ PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags);
+
+ PermissionInfo getPermissionInfo(String permName, String packageName, int flags);
+
+ ParceledListSlice queryPermissionsByGroup(String groupName, int flags);
+
+ boolean addPermission(in PermissionInfo info, boolean async);
+
+ void removePermission(String name);
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 01058f9..2ee6b7d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -42,6 +42,7 @@
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.Application;
+import android.app.AutomaticZenRule;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.SearchManager;
@@ -1313,7 +1314,17 @@
"android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
/**
- * @hide
+ * Activity Action: Show the automatic do not disturb rule listing page
+ * <p>
+ * Users can add, enable, disable, and remove automatic do not disturb rules from this
+ * screen. See {@link NotificationManager#addAutomaticZenRule(AutomaticZenRule)} for more
+ * details.
+ * </p>
+ * <p>
+ * Input: Nothing
+ * Output: Nothing
+ * </p>
+ *
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_CONDITION_PROVIDER_SETTINGS
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f661e06..6563e03 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -23,7 +23,6 @@
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.CompatibilityInfo.Translator;
-import android.content.res.Configuration;
import android.graphics.BlendMode;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -102,8 +101,7 @@
private static final boolean DEBUG = false;
@UnsupportedAppUsage
- final ArrayList<SurfaceHolder.Callback> mCallbacks
- = new ArrayList<SurfaceHolder.Callback>();
+ final ArrayList<SurfaceHolder.Callback> mCallbacks = new ArrayList<>();
final int[] mLocation = new int[2];
@@ -127,7 +125,6 @@
SurfaceControl mDeferredDestroySurfaceControl;
SurfaceControl mBackgroundControl;
final Rect mTmpRect = new Rect();
- final Configuration mConfiguration = new Configuration();
Paint mRoundedViewportPaint;
@@ -137,25 +134,16 @@
boolean mIsCreating = false;
private volatile boolean mRtHandlingPositionUpdates = false;
- private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener
- = new ViewTreeObserver.OnScrollChangedListener() {
- @Override
- public void onScrollChanged() {
- updateSurface();
- }
- };
+ private final ViewTreeObserver.OnScrollChangedListener mScrollChangedListener =
+ this::updateSurface;
@UnsupportedAppUsage
- private final ViewTreeObserver.OnPreDrawListener mDrawListener =
- new ViewTreeObserver.OnPreDrawListener() {
- @Override
- public boolean onPreDraw() {
- // reposition ourselves where the surface is
- mHaveFrame = getWidth() > 0 && getHeight() > 0;
- updateSurface();
- return true;
- }
- };
+ private final ViewTreeObserver.OnPreDrawListener mDrawListener = () -> {
+ // reposition ourselves where the surface is
+ mHaveFrame = getWidth() > 0 && getHeight() > 0;
+ updateSurface();
+ return true;
+ };
boolean mRequestedVisible = false;
boolean mWindowVisibility = false;
@@ -190,7 +178,6 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
final Rect mSurfaceFrame = new Rect();
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
- private Translator mTranslator;
private boolean mGlobalListenersAdded;
private boolean mAttachedToWindow;
@@ -555,9 +542,9 @@
return;
}
- mTranslator = viewRoot.mTranslator;
- if (mTranslator != null) {
- mSurface.setCompatibilityTranslator(mTranslator);
+ final Translator translator = viewRoot.mTranslator;
+ if (translator != null) {
+ mSurface.setCompatibilityTranslator(translator);
}
int myWidth = mRequestedWidth;
@@ -596,8 +583,8 @@
mScreenRect.top = mWindowSpaceTop;
mScreenRect.right = mWindowSpaceLeft + getWidth();
mScreenRect.bottom = mWindowSpaceTop + getHeight();
- if (mTranslator != null) {
- mTranslator.translateRectInAppWindowToScreen(mScreenRect);
+ if (translator != null) {
+ translator.translateRectInAppWindowToScreen(mScreenRect);
}
final Rect surfaceInsets = getParentSurfaceInsets();
@@ -683,11 +670,11 @@
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
- if (mTranslator == null) {
+ if (translator == null) {
mSurfaceFrame.right = mSurfaceWidth;
mSurfaceFrame.bottom = mSurfaceHeight;
} else {
- float appInvertedScale = mTranslator.applicationInvertedScale;
+ float appInvertedScale = translator.applicationInvertedScale;
mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
}
@@ -821,8 +808,8 @@
mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
- if (mTranslator != null) {
- mTranslator.translateRectInAppWindowToScreen(mScreenRect);
+ if (translator != null) {
+ translator.translateRectInAppWindowToScreen(mScreenRect);
}
if (mSurfaceControl == null) {
@@ -1037,7 +1024,7 @@
synchronized (mCallbacks) {
// This is a linear search, but in practice we'll
// have only a couple callbacks, so it doesn't matter.
- if (mCallbacks.contains(callback) == false) {
+ if (!mCallbacks.contains(callback)) {
mCallbacks.add(callback);
}
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f18aa81..a01e15e 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -288,9 +288,6 @@
// applied as translation when updating the root render node.
private int mInsetTop, mInsetLeft;
- // Whether the surface has insets. Used to protect opacity.
- private boolean mHasInsets;
-
// Light properties specified by the theme.
private final float mLightY;
private final float mLightZ;
@@ -480,7 +477,6 @@
if (surfaceInsets != null && (surfaceInsets.left != 0 || surfaceInsets.right != 0
|| surfaceInsets.top != 0 || surfaceInsets.bottom != 0)) {
- mHasInsets = true;
mInsetLeft = surfaceInsets.left;
mInsetTop = surfaceInsets.top;
mSurfaceWidth = width + mInsetLeft + surfaceInsets.right;
@@ -489,7 +485,6 @@
// If the surface has insets, it can't be opaque.
setOpaque(false);
} else {
- mHasInsets = false;
mInsetLeft = 0;
mInsetTop = 0;
mSurfaceWidth = width;
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 6f4f337..fe66cf9 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1311,7 +1311,7 @@
return semiTransparentBarColor;
} else if ((flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) == 0) {
return Color.BLACK;
- } else if (scrimTransparent && barColor == Color.TRANSPARENT) {
+ } else if (scrimTransparent && Color.alpha(barColor) == 0) {
boolean light = (sysuiVis & lightSysuiFlag) != 0;
return light ? SCRIM_LIGHT : semiTransparentBarColor;
} else {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 5eb8408..d42c43b 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -33,17 +33,14 @@
srcs: [
"android_animation_PropertyValuesHolder.cpp",
- "android_content_res_ApkAssets.cpp",
"android_graphics_Canvas.cpp",
"android_graphics_ColorSpace.cpp",
"android_graphics_drawable_AnimatedVectorDrawable.cpp",
"android_graphics_drawable_VectorDrawable.cpp",
"android_graphics_Picture.cpp",
"android_nio_utils.cpp",
- "android_os_MessageQueue.cpp",
"android_os_SystemClock.cpp",
"android_os_SystemProperties.cpp",
- "android_os_Trace.cpp",
"android_util_EventLog.cpp",
"android_util_Log.cpp",
"android_util_PathParser.cpp",
@@ -76,9 +73,6 @@
"android/graphics/fonts/FontFamily.cpp",
"android/graphics/text/LineBreaker.cpp",
"android/graphics/text/MeasuredText.cpp",
- "android_util_AssetManager.cpp",
- "android_util_StringBlock.cpp",
- "android_util_XmlBlock.cpp",
"com_android_internal_util_VirtualRefBasePtr.cpp",
"com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp",
],
@@ -176,18 +170,23 @@
"android_os_HwRemoteBinder.cpp",
"android_os_NativeHandle.cpp",
"android_os_MemoryFile.cpp",
+ "android_os_MessageQueue.cpp",
"android_os_Parcel.cpp",
"android_os_SELinux.cpp",
"android_os_SharedMemory.cpp",
+ "android_os_Trace.cpp",
"android_os_UEventObserver.cpp",
"android_os_VintfObject.cpp",
"android_os_VintfRuntimeInfo.cpp",
"android_net_LocalSocketImpl.cpp",
"android_net_NetUtils.cpp",
+ "android_util_AssetManager.cpp",
"android_util_Binder.cpp",
"android_util_StatsLog.cpp",
"android_util_MemoryIntArray.cpp",
"android_util_Process.cpp",
+ "android_util_StringBlock.cpp",
+ "android_util_XmlBlock.cpp",
"android_util_jar_StrictJarFile.cpp",
"android/graphics/AnimatedImageDrawable.cpp",
"android/graphics/Camera.cpp",
@@ -243,6 +242,7 @@
"android_backup_FileBackupHelperBase.cpp",
"android_backup_BackupHelperDispatcher.cpp",
"android_app_backup_FullBackup.cpp",
+ "android_content_res_ApkAssets.cpp",
"android_content_res_ObbScanner.cpp",
"android_content_res_Configuration.cpp",
"android_security_Scrypt.cpp",
@@ -355,5 +355,15 @@
"libutils",
],
},
+ linux_glibc: {
+ srcs: [
+ "android_content_res_ApkAssets.cpp",
+ "android_os_MessageQueue.cpp",
+ "android_os_Trace.cpp",
+ "android_util_AssetManager.cpp",
+ "android_util_StringBlock.cpp",
+ "android_util_XmlBlock.cpp",
+ ],
+ },
},
}
diff --git a/core/jni/LayoutlibLoader.cpp b/core/jni/LayoutlibLoader.cpp
index eb70035..549fd4d 100644
--- a/core/jni/LayoutlibLoader.cpp
+++ b/core/jni/LayoutlibLoader.cpp
@@ -91,10 +91,12 @@
// The actual list of registered classes will be determined at runtime via the 'native_classes' System property
static const std::unordered_map<std::string, RegJNIRec> gRegJNIMap = {
{"android.animation.PropertyValuesHolder", REG_JNI(register_android_animation_PropertyValuesHolder)},
+#ifdef __linux__
{"android.content.AssetManager", REG_JNI(register_android_content_AssetManager)},
{"android.content.StringBlock", REG_JNI(register_android_content_StringBlock)},
{"android.content.XmlBlock", REG_JNI(register_android_content_XmlBlock)},
{"android.content.res.ApkAssets", REG_JNI(register_android_content_res_ApkAssets)},
+#endif
{"android.graphics.Bitmap", REG_JNI(register_android_graphics_Bitmap)},
{"android.graphics.BitmapFactory", REG_JNI(register_android_graphics_BitmapFactory)},
{"android.graphics.ByteBufferStreamAdaptor", REG_JNI(register_android_graphics_ByteBufferStreamAdaptor)},
@@ -125,10 +127,14 @@
{"android.graphics.fonts.FontFamily", REG_JNI(register_android_graphics_fonts_FontFamily)},
{"android.graphics.text.LineBreaker", REG_JNI(register_android_graphics_text_LineBreaker)},
{"android.graphics.text.MeasuredText", REG_JNI(register_android_graphics_text_MeasuredText)},
+#ifdef __linux__
{"android.os.MessageQueue", REG_JNI(register_android_os_MessageQueue)},
+#endif
{"android.os.SystemClock", REG_JNI(register_android_os_SystemClock)},
{"android.os.SystemProperties", REG_JNI(register_android_os_SystemProperties)},
+#ifdef __linux__
{"android.os.Trace", REG_JNI(register_android_os_Trace)},
+#endif
{"android.util.EventLog", REG_JNI(register_android_util_EventLog)},
{"android.util.Log", REG_JNI(register_android_util_Log)},
{"android.util.PathParser", REG_JNI(register_android_util_PathParser)},
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index ccb840d..b0443a8 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -42,7 +42,6 @@
#include <system/window.h>
#include <FrameInfo.h>
-#include <IContextFactory.h>
#include <Picture.h>
#include <Properties.h>
#include <RootRenderNode.h>
diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto
index 5a57163..784e854 100644
--- a/core/proto/android/server/jobscheduler.proto
+++ b/core/proto/android/server/jobscheduler.proto
@@ -175,6 +175,11 @@
// is now set to 1, to prevent any batching at this level. Since we now do
// batching through doze, that is a much better mechanism.
optional int32 min_ready_jobs_count = 7;
+ // Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
+ optional int32 min_ready_non_active_jobs_count = 29;
+ // Don't batch a non-ACTIVE job if it's been delayed due to force batching attempts for
+ // at least this amount of time.
+ optional int64 max_non_active_job_batch_delay_ms = 30;
// This is the job execution factor that is considered to be heavy use of
// the system.
optional double heavy_use_factor = 8;
@@ -307,6 +312,8 @@
// In this time after screen turns on, we increase job concurrency.
optional int32 screen_off_job_concurrency_increase_delay_ms = 28;
+
+ // Next tag: 31
}
// Next tag: 4
@@ -938,7 +945,15 @@
optional int64 internal_flags = 24;
- // Next tag: 28
+ // Amount of time since this job was first deferred due to standby bucketing policy. Will be
+ // 0 if this job was never deferred.
+ optional int64 time_since_first_deferral_ms = 28;
+
+ // Amount of time since JobScheduler first tried to force batch this job. Will be 0 if there
+ // was no attempt.
+ optional int64 time_since_first_force_batch_attempt_ms = 29;
+
+ // Next tag: 30
}
// Dump from com.android.server.job.JobConcurrencyManager.
diff --git a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
index 4b0ed65..95da532 100644
--- a/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
+++ b/core/tests/coretests/src/android/app/ApplicationPackageManagerTest.java
@@ -90,7 +90,7 @@
private boolean mAllow3rdPartyOnInternal = true;
public MockedApplicationPackageManager() {
- super(null, null);
+ super(null, null, null);
}
public void setForceAllowOnExternal(boolean forceAllowOnExternal) {
diff --git a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
index c8150b1..365e97d 100644
--- a/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
+++ b/core/tests/coretests/src/android/content/pm/RegisteredServicesCacheTest.java
@@ -16,7 +16,6 @@
package android.content.pm;
-import android.content.Intent;
import android.content.res.Resources;
import android.os.FileUtils;
import android.os.Parcel;
@@ -190,36 +189,6 @@
assertEquals(0, cache.getPersistentServicesSize(u1));
}
- /**
- * Check that an optimization to skip a call to PackageManager handles an invalidated cache.
- *
- * We added an optimization in generateServicesMap to only query PackageManager for packages
- * that have been changed, because if a package is unchanged, we have already cached the
- * services info for it, so we can save a query to PackageManager (and save some memory).
- * However, if invalidateCache was called, we cannot optimize, and must do a full query.
- * The initial optimization was buggy because it failed to check for an invalidated cache, and
- * only scanned the changed packages, given in the ACTION_PACKAGE_CHANGED intent (b/122912184).
- */
- public void testParseServiceInfoOptimizationHandlesInvalidatedCache() {
- TestServicesCache cache = new TestServicesCache();
- cache.addServiceForQuerying(U0, r1, newServiceInfo(t1, UID1));
- cache.addServiceForQuerying(U0, r2, newServiceInfo(t2, UID2));
- assertEquals(2, cache.getAllServicesSize(U0));
-
- // simulate the client of the cache invalidating it
- cache.invalidateCache(U0);
-
- // there should be 0 services (userServices.services == null ) at this point, but we don't
- // call getAllServicesSize since that would force a full scan of packages,
- // instead we trigger a package change in a package that is in the list of services
- Intent intent = new Intent(Intent.ACTION_PACKAGE_CHANGED);
- intent.putExtra(Intent.EXTRA_UID, UID1);
- cache.handlePackageEvent(intent, U0);
-
- // check that the optimization does a full query and caches both services
- assertEquals(2, cache.getAllServicesSize(U0));
- }
-
private static RegisteredServicesCache.ServiceInfo<TestServiceType> newServiceInfo(
TestServiceType type, int uid) {
final ComponentInfo info = new ComponentInfo();
@@ -297,11 +266,6 @@
map = new HashMap<>();
mServices.put(userId, map);
}
- // in actual cases, resolveInfo should always have a serviceInfo, since we specifically
- // query for intent services
- resolveInfo.serviceInfo = new android.content.pm.ServiceInfo();
- resolveInfo.serviceInfo.applicationInfo =
- new ApplicationInfo(serviceInfo.componentInfo.applicationInfo);
map.put(resolveInfo, serviceInfo);
}
@@ -340,11 +304,6 @@
public void onUserRemoved(int userId) {
super.onUserRemoved(userId);
}
-
- @Override
- public void handlePackageEvent(Intent intent, int userId) {
- super.handlePackageEvent(intent, userId);
- }
}
static class TestSerializer implements XmlSerializerAndParser<TestServiceType> {
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index bfead1a..bf948b1 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -165,6 +165,9 @@
"pipeline/skia/SkiaRecordingCanvas.cpp",
"pipeline/skia/RenderNodeDrawable.cpp",
"pipeline/skia/ReorderBarrierDrawables.cpp",
+ "renderthread/Frame.cpp",
+ "renderthread/RenderTask.cpp",
+ "renderthread/TimeLord.cpp",
"hwui/AnimatedImageDrawable.cpp",
"hwui/AnimatedImageThread.cpp",
"hwui/Bitmap.cpp",
@@ -226,10 +229,7 @@
"renderthread/VulkanManager.cpp",
"renderthread/VulkanSurface.cpp",
"renderthread/RenderProxy.cpp",
- "renderthread/RenderTask.cpp",
"renderthread/RenderThread.cpp",
- "renderthread/TimeLord.cpp",
- "renderthread/Frame.cpp",
"service/GraphicsStatsService.cpp",
"surfacetexture/EGLConsumer.cpp",
"surfacetexture/ImageConsumer.cpp",
diff --git a/libs/hwui/RootRenderNode.cpp b/libs/hwui/RootRenderNode.cpp
index d8c1b57..2480192 100644
--- a/libs/hwui/RootRenderNode.cpp
+++ b/libs/hwui/RootRenderNode.cpp
@@ -16,6 +16,8 @@
#include "RootRenderNode.h"
+#include <utils/Looper.h>
+
namespace android::uirenderer {
class FinishAndInvokeListener : public MessageHandler {
diff --git a/libs/hwui/RootRenderNode.h b/libs/hwui/RootRenderNode.h
index ea10921..5c830e0 100644
--- a/libs/hwui/RootRenderNode.h
+++ b/libs/hwui/RootRenderNode.h
@@ -16,13 +16,12 @@
#pragma once
-#include <utils/Looper.h>
-
#include <set>
#include <vector>
#include "AnimationContext.h"
#include "Animator.h"
+#include <IContextFactory.h>
#include "PropertyValuesAnimatorSet.h"
#include "RenderNode.h"
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 3dd1d44..e50428b 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -30,8 +30,6 @@
#include "utils/TimeUtils.h"
#include "utils/TraceUtils.h"
-#include <ui/GraphicBuffer.h>
-
namespace android {
namespace uirenderer {
namespace renderthread {
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 1bdfe87..f5330b4 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -48,6 +48,7 @@
import android.util.Log;
import com.android.internal.location.ProviderProperties;
+import com.android.internal.util.Preconditions;
import java.util.ArrayList;
import java.util.List;
@@ -2298,18 +2299,19 @@
}
/**
- * Sends additional commands to a location provider.
- * Can be used to support provider specific extensions to the Location Manager API
+ * Sends additional commands to a location provider. Can be used to support provider specific
+ * extensions to the Location Manager API.
*
* @param provider name of the location provider.
- * @param command name of the command to send to the provider.
- * @param extras optional arguments for the command (or null).
- * The provider may optionally fill the extras Bundle with results from the command.
- *
- * @return true if the command succeeds.
+ * @param command name of the command to send to the provider.
+ * @param extras optional arguments for the command (or null).
+ * @return true always
*/
public boolean sendExtraCommand(
@NonNull String provider, @NonNull String command, @Nullable Bundle extras) {
+ Preconditions.checkArgument(provider != null, "invalid null provider");
+ Preconditions.checkArgument(command != null, "invalid null command");
+
try {
return mService.sendExtraCommand(provider, command, extras);
} catch (RemoteException e) {
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 4ac6d35..16ba63b 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -25,6 +25,7 @@
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.media.ExifInterface;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.RemoteException;
@@ -47,6 +48,7 @@
import com.google.android.collect.Sets;
import java.io.File;
+import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -799,6 +801,54 @@
}
@VisibleForNative
+ private boolean getThumbnailInfo(int handle, long[] outLongs) {
+ MtpStorageManager.MtpObject obj = mManager.getObject(handle);
+ if (obj == null) {
+ return false;
+ }
+
+ String path = obj.getPath().toString();
+ switch (obj.getFormat()) {
+ case MtpConstants.FORMAT_HEIF:
+ case MtpConstants.FORMAT_EXIF_JPEG:
+ case MtpConstants.FORMAT_JFIF:
+ try {
+ ExifInterface exif = new ExifInterface(path);
+ long[] thumbOffsetAndSize = exif.getThumbnailRange();
+ outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0;
+ outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0);
+ outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0);
+ return true;
+ } catch (IOException e) {
+ // ignore and fall through
+ }
+ }
+ return false;
+ }
+
+ @VisibleForNative
+ private byte[] getThumbnailData(int handle) {
+ MtpStorageManager.MtpObject obj = mManager.getObject(handle);
+ if (obj == null) {
+ return null;
+ }
+
+ String path = obj.getPath().toString();
+ switch (obj.getFormat()) {
+ case MtpConstants.FORMAT_HEIF:
+ case MtpConstants.FORMAT_EXIF_JPEG:
+ case MtpConstants.FORMAT_JFIF:
+ try {
+ ExifInterface exif = new ExifInterface(path);
+ return exif.getThumbnail();
+ } catch (IOException e) {
+ // ignore and fall through
+ }
+ }
+ return null;
+ }
+
+ @VisibleForNative
private int beginDeleteObject(int handle) {
MtpStorageManager.MtpObject obj = mManager.getObject(handle);
if (obj == null) {
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 10f76b0..c49b1e4 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -47,7 +47,6 @@
"libstagefright_foundation",
"libcamera_client",
"libmtp",
- "libexif",
"libpiex",
"libprocessgroup",
"libandroidfw",
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 1f89d86..0a3b47b 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -30,13 +30,6 @@
#include "src/piex_types.h"
#include "src/piex.h"
-extern "C" {
-#include "libexif/exif-content.h"
-#include "libexif/exif-data.h"
-#include "libexif/exif-tag.h"
-#include "libexif/exif-utils.h"
-}
-
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <jni.h>
@@ -70,6 +63,8 @@
static jmethodID method_getObjectPropertyList;
static jmethodID method_getObjectInfo;
static jmethodID method_getObjectFilePath;
+static jmethodID method_getThumbnailInfo;
+static jmethodID method_getThumbnailData;
static jmethodID method_beginDeleteObject;
static jmethodID method_endDeleteObject;
static jmethodID method_beginMoveObject;
@@ -219,7 +214,7 @@
return; // Already threw.
}
mIntBuffer = (jintArray)env->NewGlobalRef(intArray);
- jlongArray longArray = env->NewLongArray(2);
+ jlongArray longArray = env->NewLongArray(3);
if (!longArray) {
return; // Already threw.
}
@@ -780,57 +775,6 @@
return result;
}
-static void foreachentry(ExifEntry *entry, void* /* user */) {
- char buf[1024];
- ALOGI("entry %x, format %d, size %d: %s",
- entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf)));
-}
-
-static void foreachcontent(ExifContent *content, void *user) {
- ALOGI("content %d", exif_content_get_ifd(content));
- exif_content_foreach_entry(content, foreachentry, user);
-}
-
-static long getLongFromExifEntry(ExifEntry *e) {
- ExifByteOrder o = exif_data_get_byte_order(e->parent->parent);
- return exif_get_long(e->data, o);
-}
-
-static ExifData *getExifFromExtractor(const char *path) {
- std::unique_ptr<uint8_t[]> exifBuf;
- ExifData *exifdata = NULL;
-
- FILE *fp = fopen (path, "rb");
- if (!fp) {
- ALOGE("failed to open file");
- return NULL;
- }
-
- sp<NuMediaExtractor> extractor = new NuMediaExtractor();
- fseek(fp, 0L, SEEK_END);
- if (extractor->setDataSource(fileno(fp), 0, ftell(fp)) != OK) {
- ALOGE("failed to setDataSource");
- fclose(fp);
- return NULL;
- }
-
- off64_t offset;
- size_t size;
- if (extractor->getExifOffsetSize(&offset, &size) != OK) {
- fclose(fp);
- return NULL;
- }
-
- exifBuf.reset(new uint8_t[size]);
- fseek(fp, offset, SEEK_SET);
- if (fread(exifBuf.get(), 1, size, fp) == size) {
- exifdata = exif_data_new_from_data(exifBuf.get(), size);
- }
-
- fclose(fp);
- return exifdata;
-}
-
MtpResponseCode MtpDatabase::getObjectInfo(MtpObjectHandle handle,
MtpObjectInfo& info) {
MtpStringBuffer path;
@@ -877,26 +821,23 @@
case MTP_FORMAT_EXIF_JPEG:
case MTP_FORMAT_HEIF:
case MTP_FORMAT_JFIF: {
- ExifData *exifdata;
- if (info.mFormat == MTP_FORMAT_HEIF) {
- exifdata = getExifFromExtractor(path);
- } else {
- exifdata = exif_data_new_from_file(path);
- }
- if (exifdata) {
- if ((false)) {
- exif_data_foreach_content(exifdata, foreachcontent, NULL);
- }
+ env = AndroidRuntime::getJNIEnv();
+ if (env->CallBooleanMethod(
+ mDatabase, method_getThumbnailInfo, (jint)handle, mLongBuffer)) {
- ExifEntry *w = exif_content_get_entry(
- exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_X_DIMENSION);
- ExifEntry *h = exif_content_get_entry(
- exifdata->ifd[EXIF_IFD_EXIF], EXIF_TAG_PIXEL_Y_DIMENSION);
- info.mThumbCompressedSize = exifdata->data ? exifdata->size : 0;
- info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
- info.mImagePixWidth = w ? getLongFromExifEntry(w) : 0;
- info.mImagePixHeight = h ? getLongFromExifEntry(h) : 0;
- exif_data_unref(exifdata);
+ jlong* longValues = env->GetLongArrayElements(mLongBuffer, 0);
+ jlong size = longValues[0];
+ jlong w = longValues[1];
+ jlong h = longValues[2];
+ if (size > 0 && size <= UINT32_MAX &&
+ w > 0 && w <= UINT32_MAX &&
+ h > 0 && h <= UINT32_MAX) {
+ info.mThumbCompressedSize = size;
+ info.mThumbFormat = MTP_FORMAT_EXIF_JPEG;
+ info.mImagePixWidth = w;
+ info.mImagePixHeight = h;
+ }
+ env->ReleaseLongArrayElements(mLongBuffer, longValues, 0);
}
break;
}
@@ -941,22 +882,19 @@
case MTP_FORMAT_EXIF_JPEG:
case MTP_FORMAT_HEIF:
case MTP_FORMAT_JFIF: {
- ExifData *exifdata;
- if (format == MTP_FORMAT_HEIF) {
- exifdata = getExifFromExtractor(path);
- } else {
- exifdata = exif_data_new_from_file(path);
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jbyteArray thumbData = (jbyteArray) env->CallObjectMethod(
+ mDatabase, method_getThumbnailData, (jint)handle);
+ if (thumbData == NULL) {
+ return nullptr;
}
- if (exifdata) {
- if (exifdata->data) {
- result = malloc(exifdata->size);
- if (result) {
- memcpy(result, exifdata->data, exifdata->size);
- outThumbSize = exifdata->size;
- }
- }
- exif_data_unref(exifdata);
+ jsize thumbSize = env->GetArrayLength(thumbData);
+ result = malloc(thumbSize);
+ if (result) {
+ env->GetByteArrayRegion(thumbData, 0, thumbSize, (jbyte*)result);
+ outThumbSize = thumbSize;
}
+ env->DeleteLocalRef(thumbData);
break;
}
@@ -1389,6 +1327,8 @@
GET_METHOD_ID(getObjectPropertyList, clazz, "(IIIII)Landroid/mtp/MtpPropertyList;");
GET_METHOD_ID(getObjectInfo, clazz, "(I[I[C[J)Z");
GET_METHOD_ID(getObjectFilePath, clazz, "(I[C[J)I");
+ GET_METHOD_ID(getThumbnailInfo, clazz, "(I[J)Z");
+ GET_METHOD_ID(getThumbnailData, clazz, "(I)[B");
GET_METHOD_ID(beginDeleteObject, clazz, "(I)I");
GET_METHOD_ID(endDeleteObject, clazz, "(IZ)V");
GET_METHOD_ID(beginMoveObject, clazz, "(III)I");
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
index 44f0494..0f4cf21 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarFacetButton.java
@@ -118,6 +118,8 @@
options.setLaunchDisplayId(mContext.getDisplayId());
intent.putExtra(EXTRA_FACET_LAUNCH_PICKER, mSelected);
mContext.startActivityAsUser(intent, options.toBundle(), UserHandle.CURRENT);
+ mContext.sendBroadcastAsUser(
+ new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT);
});
if (longPressIntentString != null) {
@@ -128,6 +130,8 @@
options.setLaunchDisplayId(mContext.getDisplayId());
mContext.startActivityAsUser(longPressIntent, options.toBundle(),
UserHandle.CURRENT);
+ mContext.sendBroadcastAsUser(
+ new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), UserHandle.CURRENT);
return true;
});
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
index 1bc1e6f..9de4ef5 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationButton.java
@@ -95,6 +95,9 @@
try {
if (mBroadcastIntent) {
mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
+ mContext.sendBroadcastAsUser(
+ new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
+ UserHandle.CURRENT);
return;
}
ActivityOptions options = ActivityOptions.makeBasic();
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index 881f4b1..c11e1a0 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -34,6 +34,7 @@
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
+import android.permission.IPermissionManager;
import android.util.Log;
/**
@@ -45,12 +46,14 @@
private static final String DOWNLOADS_AUTHORITY = "downloads";
private IPackageManager mIPackageManager;
+ private IPermissionManager mIPermissionManager;
private boolean mAbortInstall = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIPackageManager = AppGlobals.getPackageManager();
+ mIPermissionManager = AppGlobals.getPermissionManager();
Intent intent = getIntent();
String callingPackage = getCallingPackage();
@@ -137,7 +140,7 @@
private boolean declaresAppOpPermission(int uid, String permission) {
try {
- final String[] packages = mIPackageManager.getAppOpPermissionPackages(permission);
+ final String[] packages = mIPermissionManager.getAppOpPermissionPackages(permission);
if (packages == null) {
return false;
}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index afe6d9c..f4970d0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -382,22 +382,16 @@
<!-- The width of the panel that holds the quick settings. -->
<dimen name="qs_panel_width">@dimen/notification_panel_width</dimen>
- <dimen name="volume_dialog_panel_transparent_padding_right">8dp</dimen>
+ <dimen name="volume_dialog_panel_transparent_padding_right">4dp</dimen>
<dimen name="volume_dialog_panel_transparent_padding">20dp</dimen>
<dimen name="volume_dialog_stream_padding">8dp</dimen>
- <!-- the amount the volume panel should be offset at the end from the view next to it (or
- the screen edge, in portrait-->
- <dimen name="volume_dialog_base_margin">8dp</dimen>
-
<dimen name="volume_dialog_panel_width">64dp</dimen>
<dimen name="volume_dialog_slider_height">116dp</dimen>
- <dimen name="volume_dialog_row_height">252dp</dimen>
-
<dimen name="volume_dialog_ringer_size">64dp</dimen>
<dimen name="volume_dialog_ringer_icon_padding">20dp</dimen>
@@ -414,8 +408,6 @@
<dimen name="volume_dialog_row_margin_bottom">8dp</dimen>
- <dimen name="volume_dialog_settings_icon_size">16dp</dimen>
-
<dimen name="volume_dialog_elevation">9dp</dimen>
<dimen name="volume_tool_tip_right_margin">76dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 776cd4d..22e3edb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -627,7 +627,7 @@
if (mOverviewProxyService.isEnabled()) {
// Force disable recents when not in legacy mode
disableRecent |= !QuickStepContract.isLegacyMode(mNavBarMode);
- if (pinningActive) {
+ if (pinningActive && !QuickStepContract.isGesturalMode(mNavBarMode)) {
disableBack = disableHome = false;
}
} else if (pinningActive) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
index 48a9fb6..e61a67c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SystemUIDialog.java
@@ -20,7 +20,6 @@
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.UserHandle;
@@ -34,10 +33,13 @@
/**
* Base class for dialogs that should appear over panels and keyguard.
+ * The SystemUIDialog registers a listener for the screen off / close system dialogs broadcast,
+ * and dismisses itself when it receives the broadcast.
*/
public class SystemUIDialog extends AlertDialog {
private final Context mContext;
+ private final DismissReceiver mDismissReceiver;
public SystemUIDialog(Context context) {
this(context, R.style.Theme_SystemUI_Dialog);
@@ -52,7 +54,19 @@
attrs.setTitle(getClass().getSimpleName());
getWindow().setAttributes(attrs);
- registerDismissListener(this);
+ mDismissReceiver = new DismissReceiver(this);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mDismissReceiver.register();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mDismissReceiver.unregister();
}
public void setShowForAllUsers(boolean show) {
@@ -100,12 +114,22 @@
return dialog;
}
+ /**
+ * Registers a listener that dismisses the given dialog when it receives
+ * the screen off / close system dialogs broadcast.
+ * <p>
+ * <strong>Note:</strong> Don't call dialog.setOnDismissListener() after
+ * calling this because it causes a leak of BroadcastReceiver.
+ *
+ * @param dialog The dialog to be associated with the listener.
+ */
public static void registerDismissListener(Dialog dialog) {
DismissReceiver dismissReceiver = new DismissReceiver(dialog);
+ dialog.setOnDismissListener(d -> dismissReceiver.unregister());
dismissReceiver.register();
}
- private static class DismissReceiver extends BroadcastReceiver implements OnDismissListener {
+ private static class DismissReceiver extends BroadcastReceiver {
private static final IntentFilter INTENT_FILTER = new IntentFilter();
static {
INTENT_FILTER.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
@@ -125,16 +149,16 @@
mRegistered = true;
}
- @Override
- public void onReceive(Context context, Intent intent) {
- mDialog.dismiss();
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
+ void unregister() {
if (mRegistered) {
mDialog.getContext().unregisterReceiver(this);
mRegistered = false;
}
}
- }}
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mDialog.dismiss();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
index 78e845a..40c3d9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BluetoothControllerImpl.java
@@ -294,6 +294,18 @@
}
@Override
+ public void onProfileConnectionStateChanged(CachedBluetoothDevice cachedDevice,
+ int state, int bluetoothProfile) {
+ if (DEBUG) {
+ Log.d(TAG, "ProfileConnectionStateChanged=" + cachedDevice.getAddress() + " "
+ + stateToString(state) + " profileId=" + bluetoothProfile);
+ }
+ mCachedState.remove(cachedDevice);
+ updateConnected();
+ mHandler.sendEmptyMessage(H.MSG_STATE_CHANGED);
+ }
+
+ @Override
public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
if (DEBUG) {
Log.d(TAG, "ACLConnectionStateChanged=" + cachedDevice.getAddress() + " "
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 69d2e31..3f3e1e3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -243,8 +243,11 @@
pw.print(" mState: "); pw.println(mState.toString(4));
pw.print(" mShowDndTile: "); pw.println(mShowDndTile);
pw.print(" mHasVibrator: "); pw.println(mHasVibrator);
- pw.print(" mRemoteStreams: "); pw.println(mMediaSessionsCallbacksW.mRemoteStreams
- .values());
+ synchronized (mMediaSessionsCallbacksW.mRemoteStreams) {
+ pw.print(" mRemoteStreams: ");
+ pw.println(mMediaSessionsCallbacksW.mRemoteStreams
+ .values());
+ }
pw.print(" mShowA11yStream: "); pw.println(mShowA11yStream);
pw.println();
mMediaSessions.dump(pw);
@@ -1075,7 +1078,10 @@
@Override
public void onRemoteUpdate(Token token, String name, PlaybackInfo pi) {
addStream(token, "onRemoteUpdate");
- final int stream = mRemoteStreams.get(token);
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ stream = mRemoteStreams.get(token);
+ }
boolean changed = mState.states.indexOfKey(stream) < 0;
final StreamState ss = streamStateW(stream);
ss.dynamic = true;
@@ -1100,7 +1106,10 @@
@Override
public void onRemoteVolumeChanged(Token token, int flags) {
addStream(token, "onRemoteVolumeChanged");
- final int stream = mRemoteStreams.get(token);
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ stream = mRemoteStreams.get(token);
+ }
final boolean showUI = shouldShowUI(flags);
boolean changed = updateActiveStreamW(stream);
if (showUI) {
@@ -1116,12 +1125,15 @@
@Override
public void onRemoteRemoved(Token token) {
- if (!mRemoteStreams.containsKey(token)) {
- if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
- + "aborting remote removed for token:" + token.toString());
- return;
+ int stream = 0;
+ synchronized (mRemoteStreams) {
+ if (!mRemoteStreams.containsKey(token)) {
+ if (D.BUG) Log.d(TAG, "onRemoteRemoved: stream doesn't exist, "
+ + "aborting remote removed for token:" + token.toString());
+ return;
+ }
+ stream = mRemoteStreams.get(token);
}
- final int stream = mRemoteStreams.get(token);
mState.states.remove(stream);
if (mState.activeStream == stream) {
updateActiveStreamW(-1);
@@ -1139,20 +1151,24 @@
}
private Token findToken(int stream) {
- for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
- if (entry.getValue().equals(stream)) {
- return entry.getKey();
+ synchronized (mRemoteStreams) {
+ for (Map.Entry<Token, Integer> entry : mRemoteStreams.entrySet()) {
+ if (entry.getValue().equals(stream)) {
+ return entry.getKey();
+ }
}
}
return null;
}
private void addStream(Token token, String triggeringMethod) {
- if (!mRemoteStreams.containsKey(token)) {
- mRemoteStreams.put(token, mNextStream);
- if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
- + " from token + "+ token.toString());
- mNextStream++;
+ synchronized (mRemoteStreams) {
+ if (!mRemoteStreams.containsKey(token)) {
+ mRemoteStreams.put(token, mNextStream);
+ if (D.BUG) Log.d(TAG, triggeringMethod + ": added stream " + mNextStream
+ + " from token + " + token.toString());
+ mNextStream++;
+ }
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index ca64823..a9a1392 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -17,9 +17,11 @@
import static junit.framework.Assert.assertTrue;
import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -52,13 +54,18 @@
@Test
public void testRegisterReceiver() {
+ final ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
final ArgumentCaptor<IntentFilter> intentFilterCaptor =
ArgumentCaptor.forClass(IntentFilter.class);
- verify(mContextSpy).registerReceiverAsUser(any(), any(),
+ mDialog.show();
+ verify(mContextSpy).registerReceiverAsUser(broadcastReceiverCaptor.capture(), any(),
intentFilterCaptor.capture(), any(), any());
assertTrue(intentFilterCaptor.getValue().hasAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
- }
+ mDialog.dismiss();
+ verify(mContextSpy).unregisterReceiver(eq(broadcastReceiverCaptor.getValue()));
+ }
}
diff --git a/packages/SystemUI/tools/lint/baseline.xml b/packages/SystemUI/tools/lint/baseline.xml
index 8c43222..096a639 100644
--- a/packages/SystemUI/tools/lint/baseline.xml
+++ b/packages/SystemUI/tools/lint/baseline.xml
@@ -2685,39 +2685,6 @@
<issue
id="UnusedResources"
- message="The resource `R.dimen.volume_dialog_base_margin` appears to be unused"
- errorLine1=" <dimen name="volume_dialog_base_margin">8dp</dimen>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/values/dimens.xml"
- line="308"
- column="12"/>
- </issue>
-
- <issue
- id="UnusedResources"
- message="The resource `R.dimen.volume_dialog_row_height` appears to be unused"
- errorLine1=" <dimen name="volume_dialog_row_height">252dp</dimen>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/values/dimens.xml"
- line="314"
- column="12"/>
- </issue>
-
- <issue
- id="UnusedResources"
- message="The resource `R.dimen.volume_dialog_settings_icon_size` appears to be unused"
- errorLine1=" <dimen name="volume_dialog_settings_icon_size">16dp</dimen>"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="res/values/dimens.xml"
- line="328"
- column="12"/>
- </issue>
-
- <issue
- id="UnusedResources"
message="The resource `R.dimen.carrier_label_height` appears to be unused"
errorLine1=" <dimen name="carrier_label_height">24dp</dimen>"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index a3f26ad..3ebe702 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1098,12 +1098,9 @@
@GuardedBy("mLock")
public void sendExtraCommandLocked(String command, Bundle extras) {
if (mProvider != null) {
- long identity = Binder.clearCallingIdentity();
- try {
- mProvider.sendExtraCommand(command, extras);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ // intentionally do not clear binder identity so that providers can evaluate who
+ // is sending the extra command
+ mProvider.sendExtraCommand(command, extras);
}
}
diff --git a/services/core/java/com/android/server/NewNetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
similarity index 98%
rename from services/core/java/com/android/server/NewNetworkTimeUpdateService.java
rename to services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
index d21741a..b0b45f4 100644
--- a/services/core/java/com/android/server/NewNetworkTimeUpdateService.java
+++ b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java
@@ -55,7 +55,7 @@
* available.
* </p>
*/
-public class NewNetworkTimeUpdateService extends Binder implements NetworkTimeUpdateService {
+public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeUpdateService {
private static final String TAG = "NetworkTimeUpdateService";
private static final boolean DBG = false;
@@ -98,7 +98,7 @@
// connection to happen.
private int mTryAgainCounter;
- public NewNetworkTimeUpdateService(Context context) {
+ public NetworkTimeUpdateServiceImpl(Context context) {
mContext = context;
mTime = NtpTrustedTime.getInstance(context);
mAlarmManager = mContext.getSystemService(AlarmManager.class);
diff --git a/services/core/java/com/android/server/OldNetworkTimeUpdateService.java b/services/core/java/com/android/server/OldNetworkTimeUpdateService.java
deleted file mode 100644
index 068b83d..0000000
--- a/services/core/java/com/android/server/OldNetworkTimeUpdateService.java
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.Network;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.NtpTrustedTime;
-import android.util.TimeUtils;
-
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.internal.util.DumpUtils;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Monitors the network time and updates the system time if it is out of sync
- * and there hasn't been any NITZ update from the carrier recently.
- * If looking up the network time fails for some reason, it tries a few times with a short
- * interval and then resets to checking on longer intervals.
- * <p>
- * If the user enables AUTO_TIME, it will check immediately for the network time, if NITZ wasn't
- * available.
- * </p>
- */
-public class OldNetworkTimeUpdateService extends Binder implements NetworkTimeUpdateService {
-
- private static final String TAG = "NetworkTimeUpdateService";
- private static final boolean DBG = false;
-
- private static final int EVENT_AUTO_TIME_CHANGED = 1;
- private static final int EVENT_POLL_NETWORK_TIME = 2;
- private static final int EVENT_NETWORK_CHANGED = 3;
-
- private static final String ACTION_POLL =
- "com.android.server.NetworkTimeUpdateService.action.POLL";
-
- private static final int POLL_REQUEST = 0;
-
- private static final long NOT_SET = -1;
- private long mNitzTimeSetTime = NOT_SET;
- private Network mDefaultNetwork = null;
-
- private final Context mContext;
- private final NtpTrustedTime mTime;
- private final AlarmManager mAlarmManager;
- private final ConnectivityManager mCM;
- private final PendingIntent mPendingPollIntent;
- private final PowerManager.WakeLock mWakeLock;
-
- // NTP lookup is done on this thread and handler
- private Handler mHandler;
- private SettingsObserver mSettingsObserver;
- private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback;
-
- // Normal polling frequency
- private final long mPollingIntervalMs;
- // Try-again polling interval, in case the network request failed
- private final long mPollingIntervalShorterMs;
- // Number of times to try again
- private final int mTryAgainTimesMax;
- // If the time difference is greater than this threshold, then update the time.
- private final int mTimeErrorThresholdMs;
- // Keeps track of how many quick attempts were made to fetch NTP time.
- // During bootup, the network may not have been up yet, or it's taking time for the
- // connection to happen.
- private int mTryAgainCounter;
-
- public OldNetworkTimeUpdateService(Context context) {
- mContext = context;
- mTime = NtpTrustedTime.getInstance(context);
- mAlarmManager = mContext.getSystemService(AlarmManager.class);
- mCM = mContext.getSystemService(ConnectivityManager.class);
-
- Intent pollIntent = new Intent(ACTION_POLL, null);
- mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
-
- mPollingIntervalMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingInterval);
- mPollingIntervalShorterMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpPollingIntervalShorter);
- mTryAgainTimesMax = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpRetry);
- mTimeErrorThresholdMs = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_ntpThreshold);
-
- mWakeLock = context.getSystemService(PowerManager.class).newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, TAG);
- }
-
- @Override
- public void systemRunning() {
- registerForTelephonyIntents();
- registerForAlarms();
-
- HandlerThread thread = new HandlerThread(TAG);
- thread.start();
- mHandler = new MyHandler(thread.getLooper());
- mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback();
- mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler);
-
- mSettingsObserver = new SettingsObserver(mHandler, EVENT_AUTO_TIME_CHANGED);
- mSettingsObserver.observe(mContext);
- }
-
- private void registerForTelephonyIntents() {
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
- mContext.registerReceiver(mNitzReceiver, intentFilter);
- }
-
- private void registerForAlarms() {
- mContext.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget();
- }
- }, new IntentFilter(ACTION_POLL));
- }
-
- private void onPollNetworkTime(int event) {
- // If Automatic time is not set, don't bother. Similarly, if we don't
- // have any default network, don't bother.
- if (mDefaultNetwork == null) return;
- mWakeLock.acquire();
- try {
- onPollNetworkTimeUnderWakeLock(event);
- } finally {
- mWakeLock.release();
- }
- }
-
- private void onPollNetworkTimeUnderWakeLock(int event) {
- // Force an NTP fix when outdated
- if (mTime.getCacheAge() >= mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh");
- mTime.forceRefresh();
- }
-
- if (mTime.getCacheAge() < mPollingIntervalMs) {
- // Obtained fresh fix; schedule next normal update
- resetAlarm(mPollingIntervalMs);
- if (isAutomaticTimeRequested()) {
- updateSystemClock(event);
- }
-
- } else {
- // No fresh fix; schedule retry
- mTryAgainCounter++;
- if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) {
- resetAlarm(mPollingIntervalShorterMs);
- } else {
- // Try much later
- mTryAgainCounter = 0;
- resetAlarm(mPollingIntervalMs);
- }
- }
- }
-
- private long getNitzAge() {
- if (mNitzTimeSetTime == NOT_SET) {
- return Long.MAX_VALUE;
- } else {
- return SystemClock.elapsedRealtime() - mNitzTimeSetTime;
- }
- }
-
- /**
- * Consider updating system clock based on current NTP fix, if requested by
- * user, significant enough delta, and we don't have a recent NITZ.
- */
- private void updateSystemClock(int event) {
- final boolean forceUpdate = (event == EVENT_AUTO_TIME_CHANGED);
- if (!forceUpdate) {
- if (getNitzAge() < mPollingIntervalMs) {
- if (DBG) Log.d(TAG, "Ignoring NTP update due to recent NITZ");
- return;
- }
-
- final long skew = Math.abs(mTime.currentTimeMillis() - System.currentTimeMillis());
- if (skew < mTimeErrorThresholdMs) {
- if (DBG) Log.d(TAG, "Ignoring NTP update due to low skew");
- return;
- }
- }
-
- SystemClock.setCurrentTimeMillis(mTime.currentTimeMillis());
- }
-
- /**
- * Cancel old alarm and starts a new one for the specified interval.
- *
- * @param interval when to trigger the alarm, starting from now.
- */
- private void resetAlarm(long interval) {
- mAlarmManager.cancel(mPendingPollIntent);
- long now = SystemClock.elapsedRealtime();
- long next = now + interval;
- mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
- }
-
- /**
- * Checks if the user prefers to automatically set the time.
- */
- private boolean isAutomaticTimeRequested() {
- return Settings.Global.getInt(
- mContext.getContentResolver(), Settings.Global.AUTO_TIME, 0) != 0;
- }
-
- /** Receiver for Nitz time events */
- private BroadcastReceiver mNitzReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (DBG) Log.d(TAG, "Received " + action);
- if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
- mNitzTimeSetTime = SystemClock.elapsedRealtime();
- }
- }
- };
-
- /** Handler to do the network accesses on */
- private class MyHandler extends Handler {
-
- public MyHandler(Looper l) {
- super(l);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case EVENT_AUTO_TIME_CHANGED:
- case EVENT_POLL_NETWORK_TIME:
- case EVENT_NETWORK_CHANGED:
- onPollNetworkTime(msg.what);
- break;
- }
- }
- }
-
- private class NetworkTimeUpdateCallback extends NetworkCallback {
- @Override
- public void onAvailable(Network network) {
- Log.d(TAG, String.format("New default network %s; checking time.", network));
- mDefaultNetwork = network;
- // Running on mHandler so invoke directly.
- onPollNetworkTime(EVENT_NETWORK_CHANGED);
- }
-
- @Override
- public void onLost(Network network) {
- if (network.equals(mDefaultNetwork)) mDefaultNetwork = null;
- }
- }
-
- /** Observer to watch for changes to the AUTO_TIME setting */
- private static class SettingsObserver extends ContentObserver {
-
- private int mMsg;
- private Handler mHandler;
-
- SettingsObserver(Handler handler, int msg) {
- super(handler);
- mHandler = handler;
- mMsg = msg;
- }
-
- void observe(Context context) {
- ContentResolver resolver = context.getContentResolver();
- resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME),
- false, this);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- mHandler.obtainMessage(mMsg).sendToTarget();
- }
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- pw.print("PollingIntervalMs: ");
- TimeUtils.formatDuration(mPollingIntervalMs, pw);
- pw.print("\nPollingIntervalShorterMs: ");
- TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
- pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
- pw.print("TimeErrorThresholdMs: ");
- TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
- pw.println("\nTryAgainCounter: " + mTryAgainCounter);
- pw.println("NTP cache age: " + mTime.getCacheAge());
- pw.println("NTP cache certainty: " + mTime.getCacheCertainty());
- pw.println();
- }
-}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f0243c3..8cd675c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -271,8 +271,8 @@
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
-import android.provider.Settings;
import android.provider.DeviceConfig.Properties;
+import android.provider.Settings;
import android.server.ServerProtoEnums;
import android.sysprop.VoldProperties;
import android.text.TextUtils;
@@ -2890,6 +2890,7 @@
if (mIsolatedAppBindArgs == null) {
mIsolatedAppBindArgs = new ArrayMap<>(1);
addServiceToMap(mIsolatedAppBindArgs, "package");
+ addServiceToMap(mIsolatedAppBindArgs, "permissionmgr");
}
return mIsolatedAppBindArgs;
}
@@ -2901,6 +2902,7 @@
// IMPORTANT: Before adding services here, make sure ephemeral apps can access them too.
// Enable the check in ApplicationThread.bindApplication() to make sure.
addServiceToMap(mAppBindArgs, "package");
+ addServiceToMap(mAppBindArgs, "permissionmgr");
addServiceToMap(mAppBindArgs, Context.WINDOW_SERVICE);
addServiceToMap(mAppBindArgs, Context.ALARM_SERVICE);
addServiceToMap(mAppBindArgs, Context.DISPLAY_SERVICE);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 746c250..56208a95 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -30,7 +30,6 @@
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ActivityInfo;
-import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
@@ -44,6 +43,7 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
+import android.permission.IPermissionManager;
import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -921,7 +921,7 @@
if (perms == null) {
return false;
}
- IPackageManager pm = AppGlobals.getPackageManager();
+ IPermissionManager pm = AppGlobals.getPermissionManager();
for (int i = perms.length-1; i >= 0; i--) {
try {
PermissionInfo pi = pm.getPermissionInfo(perms[i], "android", 0);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index d3cafb7..8ef5b07 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1917,8 +1917,8 @@
if (keyCode != KeyEvent.KEYCODE_UNKNOWN) {
final long ident = Binder.clearCallingIdentity();
try {
- mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
- mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
+ mHdmiPlaybackClient.sendVolumeKeyEvent(keyCode, true);
+ mHdmiPlaybackClient.sendVolumeKeyEvent(keyCode, false);
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
index 7ec890a..6d26934 100644
--- a/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcInitiationActionFromAvr.java
@@ -91,8 +91,8 @@
}
private void handleInitiateArcTimeout() {
+ // Keep ARC status as what it is when TV does not respond to ARC init
HdmiLogger.debug("handleInitiateArcTimeout");
- audioSystem().setArcStatus(false);
finish();
}
}
diff --git a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
index eb7c0cd..dedf2e2 100644
--- a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
@@ -76,6 +76,11 @@
sendCommand(HdmiCecMessageBuilder.buildTerminateArc(getSourceAddress(), Constants.ADDR_TV),
result -> {
if (result != SendMessageResult.SUCCESS) {
+ // If the physical connection is already off or TV does not handle
+ // Terminate ARC, turn off ARC internally.
+ if (result == SendMessageResult.NACK) {
+ audioSystem().setArcStatus(false);
+ }
HdmiLogger.debug("Terminate ARC was not successfully sent.");
finish();
}
diff --git a/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java b/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java
index 15ec486..46b4f48 100644
--- a/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java
+++ b/services/core/java/com/android/server/hdmi/DelayedMessageBuffer.java
@@ -64,7 +64,7 @@
}
}
- private void removeActiveSource() {
+ protected void removeActiveSource() {
// Uses iterator to remove elements while looping through the list.
for (Iterator<HdmiCecMessage> iter = mBuffer.iterator(); iter.hasNext(); ) {
HdmiCecMessage message = iter.next();
diff --git a/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java b/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
index 45ff261..dc53688 100644
--- a/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
+++ b/services/core/java/com/android/server/hdmi/DetectTvSystemAudioModeSupportAction.java
@@ -53,9 +53,14 @@
return false;
}
if (HdmiUtils.getAbortFeatureOpcode(cmd) == Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE) {
- if(HdmiUtils.getAbortReason(cmd) == Constants.ABORT_NOT_IN_CORRECT_MODE) {
+ if (HdmiUtils.getAbortReason(cmd) == Constants.ABORT_NOT_IN_CORRECT_MODE) {
mActionTimer.clearTimerMessage();
mState = STATE_WAITING_FOR_SET_SAM;
+ // Outgoing User Control Press 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. We also wait this much time to send the next
+ // retry of the System Audio Mode support detection message.
+ addTimer(mState, HdmiConfig.IRT_MS);
} else {
finishAction(false);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 30ec2ab..a358707 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -876,7 +876,7 @@
}
ActiveSource getActiveSource() {
- return mService.getActiveSource();
+ return mService.getLocalActiveSource();
}
void setActiveSource(ActiveSource newActive) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 0e47b3f..548553d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -110,6 +110,12 @@
// device id is used as key of container.
private final SparseArray<HdmiDeviceInfo> mDeviceInfos = new SparseArray<>();
+ // Message buffer used to buffer selected messages to process later. <Active Source>
+ // from a source device, for instance, needs to be buffered if the device is not
+ // discovered yet. The buffered commands are taken out and when they are ready to
+ // handle.
+ private final DelayedMessageBuffer mDelayedMessageBuffer = new DelayedMessageBuffer(this);
+
protected HdmiCecLocalDeviceAudioSystem(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
mRoutingControlFeatureEnabled =
@@ -151,6 +157,9 @@
}
mPortIdToTvInputs.put(info.getPortId(), inputId);
mTvInputsToDeviceInfo.put(inputId, info);
+ if (info.isCecDevice()) {
+ processDelayedActiveSource(info.getLogicalAddress());
+ }
}
}
@@ -167,6 +176,15 @@
}
}
+ @Override
+ @ServiceThreadOnly
+ protected boolean isInputReady(int portId) {
+ assertRunOnServiceThread();
+ String tvInputId = mPortIdToTvInputs.get(portId);
+ HdmiDeviceInfo info = mTvInputsToDeviceInfo.get(tvInputId);
+ return info != null;
+ }
+
/**
* Called when a device is newly added or a new device is detected or
* an existing device is updated.
@@ -233,6 +251,7 @@
@VisibleForTesting
protected HdmiDeviceInfo addDeviceInfo(HdmiDeviceInfo deviceInfo) {
assertRunOnServiceThread();
+ mService.checkLogicalAddressConflictAndReallocate(deviceInfo.getLogicalAddress());
HdmiDeviceInfo oldDeviceInfo = getCecDeviceInfo(deviceInfo.getLogicalAddress());
if (oldDeviceInfo != null) {
removeDeviceInfo(deviceInfo.getId());
@@ -304,6 +323,15 @@
}
if (mService.getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
mCecMessageCache.flushAll();
+ if (!connected) {
+ if (isSystemAudioActivated()) {
+ mTvSystemAudioModeSupport = null;
+ checkSupportAndSetSystemAudioMode(false);
+ }
+ if (isArcEnabled()) {
+ setArcStatus(false);
+ }
+ }
} else if (!connected && mPortIdToTvInputs.get(portId) != null) {
String tvInputId = mPortIdToTvInputs.get(portId);
HdmiDeviceInfo info = mTvInputsToDeviceInfo.get(tvInputId);
@@ -406,6 +434,32 @@
Constants.PROPERTY_PREFERRED_ADDRESS_AUDIO_SYSTEM, String.valueOf(addr));
}
+ @ServiceThreadOnly
+ void processDelayedActiveSource(int address) {
+ assertRunOnServiceThread();
+ mDelayedMessageBuffer.processActiveSource(address);
+ }
+
+ @Override
+ @ServiceThreadOnly
+ protected boolean handleActiveSource(HdmiCecMessage message) {
+ assertRunOnServiceThread();
+ int logicalAddress = message.getSource();
+ int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
+ HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress);
+ if (info == null) {
+ HdmiLogger.debug("Device info %X not found; buffering the command", logicalAddress);
+ mDelayedMessageBuffer.add(message);
+ } else if (!isInputReady(info.getPortId())){
+ HdmiLogger.debug("Input not ready for device: %X; buffering the command", info.getId());
+ mDelayedMessageBuffer.add(message);
+ } else {
+ mDelayedMessageBuffer.removeActiveSource();
+ super.handleActiveSource(message);
+ }
+ return true;
+ }
+
@Override
@ServiceThreadOnly
protected boolean handleReportPhysicalAddress(HdmiCecMessage message) {
@@ -791,7 +845,31 @@
int sourcePhysicalAddress = HdmiUtils.twoBytesToInt(message.getParams());
if (sourcePhysicalAddress != getActiveSource().physicalAddress) {
// If the Active Source recorded by the current device is not synced up with TV,
- // TODO(amyjojo): update Active Source internally
+ // update the Active Source internally.
+ if (sourcePhysicalAddress == mService.getPhysicalAddress()) {
+ // If the active path is the current device itself, update with local info
+ if (mService.playback() != null) {
+ setActiveSource(mService.playback().mAddress, sourcePhysicalAddress);
+ } else {
+ setActiveSource(mAddress, sourcePhysicalAddress);
+ }
+ } else {
+ // If it's not the current device, look for the device info from the list
+ for (HdmiDeviceInfo info : HdmiUtils.sparseArrayToList(mDeviceInfos)) {
+ if (info.getPhysicalAddress() == sourcePhysicalAddress) {
+ setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress());
+ break;
+ }
+ }
+ }
+ // If the Active path from TV's System Audio Mode request does not belong to any
+ // device in the local device list, record the new Active physicalAddress with an
+ // unregistered logical address first. Then query the Active Source again.
+ if (sourcePhysicalAddress != getActiveSource().physicalAddress) {
+ setActiveSource(Constants.ADDR_UNREGISTERED, sourcePhysicalAddress);
+ mService.sendCecCommand(
+ HdmiCecMessageBuilder.buildRequestActiveSource(mAddress));
+ }
}
switchInputOnReceivingNewActivePath(sourcePhysicalAddress);
}
@@ -930,6 +1008,19 @@
mService.announceSystemAudioModeChange(newSystemAudioMode);
}
}
+ // Since ARC is independent from System Audio Mode control, when the TV requests
+ // System Audio Mode off, it does not need to terminate ARC at the same time.
+ // When the current audio device is using ARC as a TV input and disables muting,
+ // it needs to automatically switch to the previous active input source when System
+ // Audio Mode is off even without terminating the ARC. This can stop the current
+ // audio device from playing audio when system audio mode is off.
+ if (mArcIntentUsed
+ && !mService.readBooleanSystemProperty(
+ Constants.PROPERTY_SYSTEM_AUDIO_MODE_MUTING_ENABLE, true)
+ && !newSystemAudioMode
+ && getLocalActivePort() == Constants.CEC_SWITCH_ARC) {
+ routeToInputFromPortId(getRoutingPort());
+ }
// Init arc whenever System Audio Mode is on
// Since some TVs don't request ARC on with System Audio Mode on request
if (SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)
@@ -1150,10 +1241,12 @@
}
// Wake up if the current device if ready to route.
mService.wakeUp();
+ if (getLocalActivePort() == portId) {
+ HdmiLogger.debug("Not switching to the same port " + portId);
+ return;
+ }
// Switch to HOME if the current active port is not HOME yet
- if (portId == Constants.CEC_SWITCH_HOME
- && mService.isPlaybackDevice()
- && getLocalActivePort() != Constants.CEC_SWITCH_HOME) {
+ if (portId == Constants.CEC_SWITCH_HOME && mService.isPlaybackDevice()) {
switchToHomeTvInput();
} else if (portId == Constants.CEC_SWITCH_ARC) {
switchToTvInput(SystemProperties.get(Constants.PROPERTY_SYSTEM_AUDIO_DEVICE_ARC_PORT));
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index 7eb669a..413e7a0 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -163,10 +163,17 @@
@ServiceThreadOnly
protected void onStandby(boolean initiatedByCec, int standbyAction) {
assertRunOnServiceThread();
+ if (!mService.isControlEnabled()) {
+ return;
+ }
+ if (mIsActiveSource) {
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
+ mAddress, mService.getPhysicalAddress()));
+ }
// Invalidate the internal active source record when goes to standby
// This set will also update mIsActiveSource
mService.setActiveSource(Constants.ADDR_INVALID, Constants.INVALID_PHYSICAL_ADDRESS);
- if (!mService.isControlEnabled() || initiatedByCec || !mAutoTvOff) {
+ if (initiatedByCec || !mAutoTvOff) {
return;
}
switch (standbyAction) {
@@ -349,11 +356,6 @@
super.disableDevice(initiatedByCec, callback);
assertRunOnServiceThread();
- if (!initiatedByCec && mIsActiveSource && mService.isControlEnabled()) {
- mService.sendCecCommand(HdmiCecMessageBuilder.buildInactiveSource(
- mAddress, mService.getPhysicalAddress()));
- }
- setIsActiveSource(false);
checkIfPendingActionsCleared();
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 9aaf33c..4d5dc6a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -56,6 +56,7 @@
import android.media.tv.TvInputManager.TvInputCallback;
import android.net.Uri;
import android.os.Build;
+import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -1172,6 +1173,29 @@
return mCecController.getLocalDeviceList();
}
+ /**
+ * Check if a logical address is conflict with the current device's. Reallocate the logical
+ * address of the current device if there is conflict.
+ *
+ * Android HDMI CEC 1.4 is handling logical address allocation in the framework side. This could
+ * introduce delay between the logical address allocation and notifying the driver that the
+ * address is occupied. Adding this check to avoid such case.
+ *
+ * @param logicalAddress logical address of the remote device that might have the same logical
+ * address as the current device.
+ */
+ protected void checkLogicalAddressConflictAndReallocate(int logicalAddress) {
+ for (HdmiCecLocalDevice device : getAllLocalDevices()) {
+ if (device.getDeviceInfo().getLogicalAddress() == logicalAddress) {
+ HdmiLogger.debug("allocate logical address for " + device.getDeviceInfo());
+ ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
+ localDevices.add(device);
+ allocateLogicalAddress(localDevices, HdmiControlService.INITIATED_BY_HOTPLUG);
+ return;
+ }
+ }
+ }
+
Object getServiceLock() {
return mLock;
}
@@ -1461,25 +1485,34 @@
return playback().getDeviceInfo();
}
// Otherwise get the active source and look for it from the device list
- ActiveSource activeSource = mActiveSource;
- // If the active source is not set yet, return null
- if (!activeSource.isValid()) {
+ ActiveSource activeSource = getLocalActiveSource();
+ // If the physical address is not set yet, return null
+ if (activeSource.physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) {
return null;
}
if (audioSystem() != null) {
HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
for (HdmiDeviceInfo info : audioSystem.getSafeCecDevicesLocked()) {
- if (info.getLogicalAddress() == activeSource.logicalAddress) {
+ if (info.getPhysicalAddress() == activeSource.physicalAddress) {
return info;
}
}
}
// If the device info is not in the list yet, return a device info with minimum
// information from mActiveSource.
- return new HdmiDeviceInfo(activeSource.logicalAddress,
- activeSource.physicalAddress, pathToPortId(activeSource.physicalAddress),
- HdmiUtils.getTypeFromAddress(activeSource.logicalAddress), 0,
- HdmiUtils.getDefaultDeviceName(activeSource.logicalAddress));
+ // If the Active Source has unregistered logical address, return with an
+ // HdmiDeviceInfo built from physical address information only.
+ return HdmiUtils.isValidAddress(activeSource.logicalAddress)
+ ?
+ new HdmiDeviceInfo(activeSource.logicalAddress,
+ activeSource.physicalAddress,
+ pathToPortId(activeSource.physicalAddress),
+ HdmiUtils.getTypeFromAddress(activeSource.logicalAddress), 0,
+ HdmiUtils.getDefaultDeviceName(activeSource.logicalAddress))
+ :
+ new HdmiDeviceInfo(activeSource.physicalAddress,
+ pathToPortId(activeSource.physicalAddress));
+
}
return null;
}
@@ -1630,6 +1663,8 @@
@Override
public void oneTouchPlay(final IHdmiControlCallback callback) {
enforceAccessPermission();
+ int pid = Binder.getCallingPid();
+ Slog.d(TAG, "Proccess pid: " + pid + " is calling oneTouchPlay.");
runOnServiceThread(new Runnable() {
@Override
public void run() {
@@ -2808,7 +2843,7 @@
setLastInputForMhl(Constants.INVALID_PORT_ID);
}
- ActiveSource getActiveSource() {
+ ActiveSource getLocalActiveSource() {
synchronized (mLock) {
return mActiveSource;
}
@@ -2819,6 +2854,21 @@
mActiveSource.logicalAddress = logicalAddress;
mActiveSource.physicalAddress = physicalAddress;
}
+ // If the current device is a source device, check if the current Active Source matches
+ // the local device info. Set mIsActiveSource of the local device accordingly.
+ for (HdmiCecLocalDevice device : getAllLocalDevices()) {
+ // mIsActiveSource only exists in source device, ignore this setting if the current
+ // device is not an HdmiCecLocalDeviceSource.
+ if (!(device instanceof HdmiCecLocalDeviceSource)) {
+ continue;
+ }
+ if (logicalAddress == device.getDeviceInfo().getLogicalAddress()
+ && physicalAddress == getPhysicalAddress()) {
+ ((HdmiCecLocalDeviceSource) device).setIsActiveSource(true);
+ } else {
+ ((HdmiCecLocalDeviceSource) device).setIsActiveSource(false);
+ }
+ }
}
// This method should only be called when the device can be the active source
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 8181900..e44e902 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -187,6 +187,9 @@
private final StorageController mStorageController;
/** Need directly for sending uid state changes */
private final DeviceIdleJobsController mDeviceIdleJobsController;
+ /** Needed to get remaining quota time. */
+ private final QuotaController mQuotaController;
+
/** Need directly for receiving thermal events */
private IThermalService mThermalService;
/** Thermal constraint. */
@@ -443,6 +446,10 @@
private static final String KEY_MIN_CONNECTIVITY_COUNT = "min_connectivity_count";
private static final String KEY_MIN_CONTENT_COUNT = "min_content_count";
private static final String KEY_MIN_READY_JOBS_COUNT = "min_ready_jobs_count";
+ private static final String KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT =
+ "min_ready_non_active_jobs_count";
+ private static final String KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS =
+ "max_non_active_job_batch_delay_ms";
private static final String KEY_HEAVY_USE_FACTOR = "heavy_use_factor";
private static final String KEY_MODERATE_USE_FACTOR = "moderate_use_factor";
@@ -473,6 +480,8 @@
private static final int DEFAULT_MIN_CONNECTIVITY_COUNT = 1;
private static final int DEFAULT_MIN_CONTENT_COUNT = 1;
private static final int DEFAULT_MIN_READY_JOBS_COUNT = 1;
+ private static final int DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT = 5;
+ private static final long DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = 31 * MINUTE_IN_MILLIS;
private static final float DEFAULT_HEAVY_USE_FACTOR = .9f;
private static final float DEFAULT_MODERATE_USE_FACTOR = .5f;
private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE;
@@ -524,6 +533,18 @@
* a much better mechanism.
*/
int MIN_READY_JOBS_COUNT = DEFAULT_MIN_READY_JOBS_COUNT;
+
+ /**
+ * Minimum # of non-ACTIVE jobs for which the JMS will be happy running some work early.
+ */
+ int MIN_READY_NON_ACTIVE_JOBS_COUNT = DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT;
+
+ /**
+ * Don't batch a non-ACTIVE job if it's been delayed due to force batching attempts for
+ * at least this amount of time.
+ */
+ long MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS;
+
/**
* This is the job execution factor that is considered to be heavy use of the system.
*/
@@ -657,6 +678,12 @@
DEFAULT_MIN_CONTENT_COUNT);
MIN_READY_JOBS_COUNT = mParser.getInt(KEY_MIN_READY_JOBS_COUNT,
DEFAULT_MIN_READY_JOBS_COUNT);
+ MIN_READY_NON_ACTIVE_JOBS_COUNT = mParser.getInt(
+ KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT,
+ DEFAULT_MIN_READY_NON_ACTIVE_JOBS_COUNT);
+ MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = mParser.getLong(
+ KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS,
+ DEFAULT_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS);
HEAVY_USE_FACTOR = mParser.getFloat(KEY_HEAVY_USE_FACTOR,
DEFAULT_HEAVY_USE_FACTOR);
MODERATE_USE_FACTOR = mParser.getFloat(KEY_MODERATE_USE_FACTOR,
@@ -707,6 +734,10 @@
pw.printPair(KEY_MIN_CONNECTIVITY_COUNT, MIN_CONNECTIVITY_COUNT).println();
pw.printPair(KEY_MIN_CONTENT_COUNT, MIN_CONTENT_COUNT).println();
pw.printPair(KEY_MIN_READY_JOBS_COUNT, MIN_READY_JOBS_COUNT).println();
+ pw.printPair(KEY_MIN_READY_NON_ACTIVE_JOBS_COUNT,
+ MIN_READY_NON_ACTIVE_JOBS_COUNT).println();
+ pw.printPair(KEY_MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS,
+ MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS).println();
pw.printPair(KEY_HEAVY_USE_FACTOR, HEAVY_USE_FACTOR).println();
pw.printPair(KEY_MODERATE_USE_FACTOR, MODERATE_USE_FACTOR).println();
@@ -749,6 +780,10 @@
proto.write(ConstantsProto.MIN_CONNECTIVITY_COUNT, MIN_CONNECTIVITY_COUNT);
proto.write(ConstantsProto.MIN_CONTENT_COUNT, MIN_CONTENT_COUNT);
proto.write(ConstantsProto.MIN_READY_JOBS_COUNT, MIN_READY_JOBS_COUNT);
+ proto.write(ConstantsProto.MIN_READY_NON_ACTIVE_JOBS_COUNT,
+ MIN_READY_NON_ACTIVE_JOBS_COUNT);
+ proto.write(ConstantsProto.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS,
+ MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS);
proto.write(ConstantsProto.HEAVY_USE_FACTOR, HEAVY_USE_FACTOR);
proto.write(ConstantsProto.MODERATE_USE_FACTOR, MODERATE_USE_FACTOR);
@@ -1338,7 +1373,8 @@
mControllers.add(new ContentObserverController(this));
mDeviceIdleJobsController = new DeviceIdleJobsController(this);
mControllers.add(mDeviceIdleJobsController);
- mControllers.add(new QuotaController(this));
+ mQuotaController = new QuotaController(this);
+ mControllers.add(mQuotaController);
// If the job store determined that it can't yet reschedule persisted jobs,
// we need to start watching the clock.
@@ -1494,16 +1530,16 @@
}
/**
- * Called when we want to remove a JobStatus object that we've finished executing. Returns the
- * object removed.
+ * Called when we want to remove a JobStatus object that we've finished executing.
+ * @return true if the job was removed.
*/
private boolean stopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
- boolean writeBack) {
+ boolean removeFromPersisted) {
// Deal with any remaining work items in the old job.
jobStatus.stopTrackingJobLocked(ActivityManager.getService(), incomingJob);
// Remove from store as well as controllers.
- final boolean removed = mJobs.remove(jobStatus, writeBack);
+ final boolean removed = mJobs.remove(jobStatus, removeFromPersisted);
if (removed && mReadyToRock) {
for (int i=0; i<mControllers.size(); i++) {
StateController controller = mControllers.get(i);
@@ -1985,7 +2021,7 @@
}
final class ReadyJobQueueFunctor implements Consumer<JobStatus> {
- ArrayList<JobStatus> newReadyJobs;
+ final ArrayList<JobStatus> newReadyJobs = new ArrayList<>();
@Override
public void accept(JobStatus job) {
@@ -1993,9 +2029,6 @@
if (DEBUG) {
Slog.d(TAG, " queued " + job.toShortString());
}
- if (newReadyJobs == null) {
- newReadyJobs = new ArrayList<JobStatus>();
- }
newReadyJobs.add(job);
} else {
evaluateControllerStatesLocked(job);
@@ -2003,14 +2036,13 @@
}
public void postProcess() {
- if (newReadyJobs != null) {
- noteJobsPending(newReadyJobs);
- mPendingJobs.addAll(newReadyJobs);
- if (mPendingJobs.size() > 1) {
- mPendingJobs.sort(mEnqueueTimeComparator);
- }
+ noteJobsPending(newReadyJobs);
+ mPendingJobs.addAll(newReadyJobs);
+ if (mPendingJobs.size() > 1) {
+ mPendingJobs.sort(mEnqueueTimeComparator);
}
- newReadyJobs = null;
+
+ newReadyJobs.clear();
}
}
private final ReadyJobQueueFunctor mReadyQueueFunctor = new ReadyJobQueueFunctor();
@@ -2027,7 +2059,9 @@
int backoffCount;
int connectivityCount;
int contentCount;
- List<JobStatus> runnableJobs;
+ int forceBatchedCount;
+ int unbatchedCount;
+ final List<JobStatus> runnableJobs = new ArrayList<>();
public MaybeReadyJobQueueFunctor() {
reset();
@@ -2047,29 +2081,39 @@
}
} catch (RemoteException e) {
}
- if (job.getNumFailures() > 0) {
- backoffCount++;
- }
- if (job.hasIdleConstraint()) {
- idleCount++;
- }
- if (job.hasConnectivityConstraint()) {
- connectivityCount++;
- }
- if (job.hasChargingConstraint()) {
- chargingCount++;
- }
- if (job.hasBatteryNotLowConstraint()) {
- batteryNotLowCount++;
- }
- if (job.hasStorageNotLowConstraint()) {
- storageNotLowCount++;
- }
- if (job.hasContentTriggerConstraint()) {
- contentCount++;
- }
- if (runnableJobs == null) {
- runnableJobs = new ArrayList<>();
+ if (mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT > 1
+ && job.getStandbyBucket() != ACTIVE_INDEX
+ && (job.getFirstForceBatchedTimeElapsed() == 0
+ || sElapsedRealtimeClock.millis() - job.getFirstForceBatchedTimeElapsed()
+ < mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS)) {
+ // Force batching non-ACTIVE jobs. Don't include them in the other counts.
+ forceBatchedCount++;
+ if (job.getFirstForceBatchedTimeElapsed() == 0) {
+ job.setFirstForceBatchedTimeElapsed(sElapsedRealtimeClock.millis());
+ }
+ } else {
+ unbatchedCount++;
+ if (job.getNumFailures() > 0) {
+ backoffCount++;
+ }
+ if (job.hasIdleConstraint()) {
+ idleCount++;
+ }
+ if (job.hasConnectivityConstraint()) {
+ connectivityCount++;
+ }
+ if (job.hasChargingConstraint()) {
+ chargingCount++;
+ }
+ if (job.hasBatteryNotLowConstraint()) {
+ batteryNotLowCount++;
+ }
+ if (job.hasStorageNotLowConstraint()) {
+ storageNotLowCount++;
+ }
+ if (job.hasContentTriggerConstraint()) {
+ contentCount++;
+ }
}
runnableJobs.add(job);
} else {
@@ -2085,8 +2129,9 @@
batteryNotLowCount >= mConstants.MIN_BATTERY_NOT_LOW_COUNT ||
storageNotLowCount >= mConstants.MIN_STORAGE_NOT_LOW_COUNT ||
contentCount >= mConstants.MIN_CONTENT_COUNT ||
- (runnableJobs != null
- && runnableJobs.size() >= mConstants.MIN_READY_JOBS_COUNT)) {
+ forceBatchedCount >= mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT ||
+ (unbatchedCount > 0 && (unbatchedCount + forceBatchedCount)
+ >= mConstants.MIN_READY_JOBS_COUNT)) {
if (DEBUG) {
Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: Running jobs.");
}
@@ -2105,7 +2150,8 @@
reset();
}
- private void reset() {
+ @VisibleForTesting
+ void reset() {
chargingCount = 0;
idleCount = 0;
backoffCount = 0;
@@ -2113,7 +2159,9 @@
batteryNotLowCount = 0;
storageNotLowCount = 0;
contentCount = 0;
- runnableJobs = null;
+ forceBatchedCount = 0;
+ unbatchedCount = 0;
+ runnableJobs.clear();
}
}
private final MaybeReadyJobQueueFunctor mMaybeQueueFunctor = new MaybeReadyJobQueueFunctor();
@@ -2222,7 +2270,8 @@
* - The job's standby bucket has come due to be runnable.
* - The component is enabled and runnable.
*/
- private boolean isReadyToBeExecutedLocked(JobStatus job) {
+ @VisibleForTesting
+ boolean isReadyToBeExecutedLocked(JobStatus job) {
final boolean jobReady = job.isReady();
if (DEBUG) {
@@ -2354,7 +2403,8 @@
return !appIsBad;
}
- private void evaluateControllerStatesLocked(final JobStatus job) {
+ @VisibleForTesting
+ void evaluateControllerStatesLocked(final JobStatus job) {
for (int c = mControllers.size() - 1; c >= 0; --c) {
final StateController sc = mControllers.get(c);
sc.evaluateStateLocked(job);
@@ -2397,6 +2447,17 @@
return isComponentUsable(job);
}
+ /** Returns the maximum amount of time this job could run for. */
+ public long getMaxJobExecutionTimeMs(JobStatus job) {
+ synchronized (mLock) {
+ if (mConstants.USE_HEARTBEATS) {
+ return JobServiceContext.EXECUTING_TIMESLICE_MILLIS;
+ }
+ return Math.min(mQuotaController.getMaxJobExecutionTimeMsLocked(job),
+ JobServiceContext.EXECUTING_TIMESLICE_MILLIS);
+ }
+ }
+
/**
* Reconcile jobs in the pending queue against available execution contexts.
* A controller can force a job into the pending queue even if it's already running, but
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 4ef37a2..d69faf3 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -235,10 +235,11 @@
/**
* Remove the provided job. Will also delete the job if it was persisted.
- * @param writeBack If true, the job will be deleted (if it was persisted) immediately.
+ * @param removeFromPersisted If true, the job will be removed from the persisted job list
+ * immediately (if it was persisted).
* @return Whether or not the job existed to be removed.
*/
- public boolean remove(JobStatus jobStatus, boolean writeBack) {
+ public boolean remove(JobStatus jobStatus, boolean removeFromPersisted) {
boolean removed = mJobSet.remove(jobStatus);
if (!removed) {
if (DEBUG) {
@@ -246,7 +247,7 @@
}
return false;
}
- if (writeBack && jobStatus.isPersisted()) {
+ if (removeFromPersisted && jobStatus.isPersisted()) {
maybeWriteStatusToDiskAsync();
}
return removed;
@@ -344,6 +345,19 @@
new ReadJobMapFromDiskRunnable(jobSet, rtcGood).run();
}
+ /** Write persisted JobStore state to disk synchronously. Should only be used for testing. */
+ @VisibleForTesting
+ public void writeStatusToDiskForTesting() {
+ synchronized (mWriteScheduleLock) {
+ if (mWriteScheduled) {
+ throw new IllegalStateException("An asynchronous write is already scheduled.");
+ }
+
+ mWriteScheduled = mWriteInProgress = true;
+ mWriteRunnable.run();
+ }
+ }
+
/**
* Wait for any pending write to the persistent store to clear
* @param maxWaitMillis Maximum time from present to wait
@@ -1049,7 +1063,9 @@
}
}
- static final class JobSet {
+ /** Set of all tracked jobs. */
+ @VisibleForTesting
+ public static final class JobSet {
@VisibleForTesting // Key is the getUid() originator of the jobs in each sheaf
final SparseArray<ArraySet<JobStatus>> mJobs;
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index 490e87f..f8cf6ae 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -88,8 +88,11 @@
@GuardedBy("mLock")
private final ArraySet<Network> mAvailableNetworks = new ArraySet<>();
+ private boolean mUseQuotaLimit;
+
private static final int MSG_DATA_SAVER_TOGGLED = 0;
private static final int MSG_UID_RULES_CHANGES = 1;
+ private static final int MSG_REEVALUATE_JOBS = 2;
private final Handler mHandler;
@@ -107,6 +110,8 @@
mConnManager.registerNetworkCallback(request, mNetworkCallback);
mNetPolicyManager.registerListener(mNetPolicyListener);
+
+ mUseQuotaLimit = !mConstants.USE_HEARTBEATS;
}
@GuardedBy("mLock")
@@ -149,6 +154,10 @@
}
mRequestedWhitelistJobs.clear();
}
+ if (mUseQuotaLimit == mConstants.USE_HEARTBEATS) {
+ mUseQuotaLimit = !mConstants.USE_HEARTBEATS;
+ mHandler.obtainMessage(MSG_REEVALUATE_JOBS).sendToTarget();
+ }
}
/**
@@ -318,9 +327,12 @@
* connection, it would take 10.4 minutes, and has no chance of succeeding
* before the job times out, so we'd be insane to try running it.
*/
- @SuppressWarnings("unused")
- private static boolean isInsane(JobStatus jobStatus, Network network,
+ private boolean isInsane(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
+ final long maxJobExecutionTimeMs = mUseQuotaLimit
+ ? mService.getMaxJobExecutionTimeMs(jobStatus)
+ : JobServiceContext.EXECUTING_TIMESLICE_MILLIS;
+
final long downloadBytes = jobStatus.getEstimatedNetworkDownloadBytes();
if (downloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
final long bandwidth = capabilities.getLinkDownstreamBandwidthKbps();
@@ -329,10 +341,11 @@
// Divide by 8 to convert bits to bytes.
final long estimatedMillis = ((downloadBytes * DateUtils.SECOND_IN_MILLIS)
/ (DataUnit.KIBIBYTES.toBytes(bandwidth) / 8));
- if (estimatedMillis > JobServiceContext.EXECUTING_TIMESLICE_MILLIS) {
+ if (estimatedMillis > maxJobExecutionTimeMs) {
// If we'd never finish before the timeout, we'd be insane!
Slog.w(TAG, "Estimated " + downloadBytes + " download bytes over " + bandwidth
- + " kbps network would take " + estimatedMillis + "ms; that's insane!");
+ + " kbps network would take " + estimatedMillis + "ms and job has "
+ + maxJobExecutionTimeMs + "ms to run; that's insane!");
return true;
}
}
@@ -346,10 +359,11 @@
// Divide by 8 to convert bits to bytes.
final long estimatedMillis = ((uploadBytes * DateUtils.SECOND_IN_MILLIS)
/ (DataUnit.KIBIBYTES.toBytes(bandwidth) / 8));
- if (estimatedMillis > JobServiceContext.EXECUTING_TIMESLICE_MILLIS) {
+ if (estimatedMillis > maxJobExecutionTimeMs) {
// If we'd never finish before the timeout, we'd be insane!
Slog.w(TAG, "Estimated " + uploadBytes + " upload bytes over " + bandwidth
- + " kbps network would take " + estimatedMillis + "ms; that's insane!");
+ + " kbps network would take " + estimatedMillis + "ms and job has "
+ + maxJobExecutionTimeMs + "ms to run; that's insane!");
return true;
}
}
@@ -358,7 +372,6 @@
return false;
}
- @SuppressWarnings("unused")
private static boolean isCongestionDelayed(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
// If network is congested, and job is less than 50% through the
@@ -370,14 +383,12 @@
}
}
- @SuppressWarnings("unused")
private static boolean isStrictSatisfied(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
return jobStatus.getJob().getRequiredNetwork().networkCapabilities
.satisfiedByNetworkCapabilities(capabilities);
}
- @SuppressWarnings("unused")
private static boolean isRelaxedSatisfied(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
// Only consider doing this for prefetching jobs
@@ -398,7 +409,7 @@
}
@VisibleForTesting
- static boolean isSatisfied(JobStatus jobStatus, Network network,
+ boolean isSatisfied(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
// Zeroth, we gotta have a network to think about being satisfied
if (network == null || capabilities == null) return false;
@@ -594,6 +605,9 @@
case MSG_UID_RULES_CHANGES:
updateTrackedJobs(msg.arg1, null);
break;
+ case MSG_REEVALUATE_JOBS:
+ updateTrackedJobs(-1, null);
+ break;
}
}
}
@@ -603,6 +617,8 @@
@Override
public void dumpControllerStateLocked(IndentingPrintWriter pw,
Predicate<JobStatus> predicate) {
+ pw.print("mUseQuotaLimit="); pw.println(mUseQuotaLimit);
+
if (mRequestedWhitelistJobs.size() > 0) {
pw.print("Requested standby exceptions:");
for (int i = 0; i < mRequestedWhitelistJobs.size(); i++) {
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index a628b17..d73c253 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -24,7 +24,6 @@
import android.app.job.JobWorkItem;
import android.content.ClipData;
import android.content.ComponentName;
-import android.content.pm.PackageManagerInternal;
import android.net.Network;
import android.net.Uri;
import android.os.RemoteException;
@@ -131,7 +130,6 @@
* that underly Sync Manager operation.
*/
final int callingUid;
- final int targetSdkVersion;
final String batteryName;
/**
@@ -188,6 +186,9 @@
*/
private long whenStandbyDeferred;
+ /** The first time this job was force batched. */
+ private long mFirstForceBatchedTimeElapsed;
+
// Constraints.
final int requiredConstraints;
private final int mRequiredConstraintsOfInterest;
@@ -344,7 +345,6 @@
* @param job The actual requested parameters for the job
* @param callingUid Identity of the app that is scheduling the job. This may not be the
* app in which the job is implemented; such as with sync jobs.
- * @param targetSdkVersion The targetSdkVersion of the app in which the job will run.
* @param sourcePackageName The package name of the app in which the job will run.
* @param sourceUserId The user in which the job will run
* @param standbyBucket The standby bucket that the source package is currently assigned to,
@@ -363,13 +363,12 @@
* @param lastFailedRunTime When did we last run this job only to have it stop incomplete?
* @param internalFlags Non-API property flags about this job
*/
- private JobStatus(JobInfo job, int callingUid, int targetSdkVersion, String sourcePackageName,
+ private JobStatus(JobInfo job, int callingUid, String sourcePackageName,
int sourceUserId, int standbyBucket, long heartbeat, String tag, int numFailures,
long earliestRunTimeElapsedMillis, long latestRunTimeElapsedMillis,
long lastSuccessfulRunTime, long lastFailedRunTime, int internalFlags) {
this.job = job;
this.callingUid = callingUid;
- this.targetSdkVersion = targetSdkVersion;
this.standbyBucket = standbyBucket;
this.baseHeartbeat = heartbeat;
@@ -439,7 +438,7 @@
/** Copy constructor: used specifically when cloning JobStatus objects for persistence,
* so we preserve RTC window bounds if the source object has them. */
public JobStatus(JobStatus jobStatus) {
- this(jobStatus.getJob(), jobStatus.getUid(), jobStatus.targetSdkVersion,
+ this(jobStatus.getJob(), jobStatus.getUid(),
jobStatus.getSourcePackageName(), jobStatus.getSourceUserId(),
jobStatus.getStandbyBucket(), jobStatus.getBaseHeartbeat(),
jobStatus.getSourceTag(), jobStatus.getNumFailures(),
@@ -468,7 +467,7 @@
long lastSuccessfulRunTime, long lastFailedRunTime,
Pair<Long, Long> persistedExecutionTimesUTC,
int innerFlags) {
- this(job, callingUid, resolveTargetSdkVersion(job), sourcePkgName, sourceUserId,
+ this(job, callingUid, sourcePkgName, sourceUserId,
standbyBucket, baseHeartbeat,
sourceTag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
@@ -491,7 +490,7 @@
long newEarliestRuntimeElapsedMillis,
long newLatestRuntimeElapsedMillis, int backoffAttempt,
long lastSuccessfulRunTime, long lastFailedRunTime) {
- this(rescheduling.job, rescheduling.getUid(), resolveTargetSdkVersion(rescheduling.job),
+ this(rescheduling.job, rescheduling.getUid(),
rescheduling.getSourcePackageName(), rescheduling.getSourceUserId(),
rescheduling.getStandbyBucket(), newBaseHeartbeat,
rescheduling.getSourceTag(), backoffAttempt, newEarliestRuntimeElapsedMillis,
@@ -533,7 +532,7 @@
long currentHeartbeat = js != null
? js.baseHeartbeatForApp(jobPackage, sourceUserId, standbyBucket)
: 0;
- return new JobStatus(job, callingUid, resolveTargetSdkVersion(job), sourcePkg, sourceUserId,
+ return new JobStatus(job, callingUid, sourcePkg, sourceUserId,
standbyBucket, currentHeartbeat, tag, 0,
earliestRunTimeElapsedMillis, latestRunTimeElapsedMillis,
0 /* lastSuccessfulRunTime */, 0 /* lastFailedRunTime */,
@@ -681,10 +680,6 @@
return job.getId();
}
- public int getTargetSdkVersion() {
- return targetSdkVersion;
- }
-
public void printUniqueId(PrintWriter pw) {
UserHandle.formatUid(pw, callingUid);
pw.print("/");
@@ -737,6 +732,18 @@
whenStandbyDeferred = now;
}
+ /**
+ * Returns the first time this job was force batched, in the elapsed realtime timebase. Will be
+ * 0 if this job was never force batched.
+ */
+ public long getFirstForceBatchedTimeElapsed() {
+ return mFirstForceBatchedTimeElapsed;
+ }
+
+ public void setFirstForceBatchedTimeElapsed(long now) {
+ mFirstForceBatchedTimeElapsed = now;
+ }
+
public String getSourceTag() {
return sourceTag;
}
@@ -1441,11 +1448,6 @@
}
}
- private static int resolveTargetSdkVersion(JobInfo job) {
- return LocalServices.getService(PackageManagerInternal.class)
- .getPackageTargetSdkVersion(job.getService().getPackageName());
- }
-
// Dumpsys infrastructure
public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
pw.print(prefix); UserHandle.formatUid(pw, callingUid);
@@ -1638,6 +1640,12 @@
TimeUtils.formatDuration(whenStandbyDeferred, elapsedRealtimeMillis, pw);
pw.println();
}
+ if (mFirstForceBatchedTimeElapsed != 0) {
+ pw.print(prefix);
+ pw.print(" Time since first force batch attempt: ");
+ TimeUtils.formatDuration(mFirstForceBatchedTimeElapsed, elapsedRealtimeMillis, pw);
+ pw.println();
+ }
pw.print(prefix); pw.print("Enqueue time: ");
TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
pw.println();
@@ -1830,6 +1838,11 @@
proto.write(JobStatusDumpProto.STANDBY_BUCKET, standbyBucket);
proto.write(JobStatusDumpProto.ENQUEUE_DURATION_MS, elapsedRealtimeMillis - enqueueTime);
+ proto.write(JobStatusDumpProto.TIME_SINCE_FIRST_DEFERRAL_MS,
+ whenStandbyDeferred == 0 ? 0 : elapsedRealtimeMillis - whenStandbyDeferred);
+ proto.write(JobStatusDumpProto.TIME_SINCE_FIRST_FORCE_BATCH_ATTEMPT_MS,
+ mFirstForceBatchedTimeElapsed == 0
+ ? 0 : elapsedRealtimeMillis - mFirstForceBatchedTimeElapsed);
if (earliestRunTimeElapsedMillis == NO_EARLIEST_RUNTIME) {
proto.write(JobStatusDumpProto.TIME_UNTIL_EARLIEST_RUNTIME_MS, 0);
} else {
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index 18d193a..b8cfac4 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -68,6 +68,7 @@
import com.android.server.LocalServices;
import com.android.server.job.ConstantsProto;
import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobServiceContext;
import com.android.server.job.StateControllerProto;
import java.util.ArrayList;
@@ -737,6 +738,18 @@
return mTopStartedJobs.contains(jobStatus);
}
+ /** Returns the maximum amount of time this job could run for. */
+ public long getMaxJobExecutionTimeMsLocked(@NonNull final JobStatus jobStatus) {
+ // If quota is currently "free", then the job can run for the full amount of time.
+ if (mChargeTracker.isCharging()
+ || mInParole
+ || isTopStartedJobLocked(jobStatus)
+ || isUidInForeground(jobStatus.getSourceUid())) {
+ return JobServiceContext.EXECUTING_TIMESLICE_MILLIS;
+ }
+ return getRemainingExecutionTimeLocked(jobStatus);
+ }
+
/**
* Returns an appropriate standby bucket for the job, taking into account any standby
* exemptions.
@@ -2278,8 +2291,10 @@
mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
changed = true;
}
- long newQuotaBufferMs = Math.max(0,
- Math.min(5 * MINUTE_IN_MILLIS, IN_QUOTA_BUFFER_MS));
+ // Make sure quota buffer is non-negative, not greater than allowed time per period,
+ // and no more than 5 minutes.
+ long newQuotaBufferMs = Math.max(0, Math.min(mAllowedTimePerPeriodMs,
+ Math.min(5 * MINUTE_IN_MILLIS, IN_QUOTA_BUFFER_MS)));
if (mQuotaBufferMs != newQuotaBufferMs) {
mQuotaBufferMs = newQuotaBufferMs;
mAllowedTimeIntoQuotaMs = mAllowedTimePerPeriodMs - mQuotaBufferMs;
diff --git a/services/core/java/com/android/server/location/AbstractLocationProvider.java b/services/core/java/com/android/server/location/AbstractLocationProvider.java
index 0edd17b..8107e9f 100644
--- a/services/core/java/com/android/server/location/AbstractLocationProvider.java
+++ b/services/core/java/com/android/server/location/AbstractLocationProvider.java
@@ -142,6 +142,9 @@
return 0;
}
- /** Sends a custom command to this provider. */
+ /**
+ * Sends a custom command to this provider. Called with the original binder identity of the
+ * caller.
+ */
public abstract void sendExtraCommand(String command, Bundle extras);
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index c312b76..8857618 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -182,7 +182,6 @@
private static final int INJECT_NTP_TIME = 5;
// PSDS stands for Predicted Satellite Data Service
private static final int DOWNLOAD_PSDS_DATA = 6;
- private static final int UPDATE_LOCATION = 7; // Handle external location from network listener
private static final int DOWNLOAD_PSDS_DATA_FINISHED = 11;
private static final int INITIALIZE_HANDLER = 13;
private static final int REQUEST_LOCATION = 16;
@@ -877,7 +876,7 @@
});
}
- private void handleUpdateLocation(Location location) {
+ private void injectLocation(Location location) {
if (location.hasAccuracy()) {
if (DEBUG) {
Log.d(TAG, "injectLocation: " + location);
@@ -2034,9 +2033,6 @@
case DOWNLOAD_PSDS_DATA_FINISHED:
mDownloadPsdsDataPending = STATE_IDLE;
break;
- case UPDATE_LOCATION:
- handleUpdateLocation((Location) msg.obj);
- break;
case INITIALIZE_HANDLER:
handleInitialize();
break;
@@ -2132,7 +2128,7 @@
public void onLocationChanged(Location location) {
// this callback happens on mHandler looper
if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
- handleUpdateLocation(location);
+ injectLocation(location);
}
}
}
@@ -2161,8 +2157,6 @@
return "DOWNLOAD_PSDS_DATA";
case DOWNLOAD_PSDS_DATA_FINISHED:
return "DOWNLOAD_PSDS_DATA_FINISHED";
- case UPDATE_LOCATION:
- return "UPDATE_LOCATION";
case INITIALIZE_HANDLER:
return "INITIALIZE_HANDLER";
case REPORT_LOCATION:
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7529434..f032fa6 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2256,7 +2256,7 @@
final int callingUid = Binder.getCallingUid();
final boolean isSystemToast = isCallerSystemOrPhone()
|| PackageManagerService.PLATFORM_PACKAGE_NAME.equals(pkg);
- final boolean isPackageSuspended = isPackageSuspendedForUser(pkg, callingUid);
+ final boolean isPackageSuspended = isPackagePaused(pkg);
final boolean notificationsDisabledForPackage = !areNotificationsEnabledForPackage(pkg,
callingUid);
@@ -4104,17 +4104,7 @@
Preconditions.checkNotNull(pkg);
checkCallerIsSameApp(pkg);
- boolean isPaused;
-
- final PackageManagerInternal pmi = LocalServices.getService(
- PackageManagerInternal.class);
- int flags = pmi.getDistractingPackageRestrictions(
- pkg, Binder.getCallingUserHandle().getIdentifier());
- isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
-
- isPaused |= isPackageSuspendedForUser(pkg, Binder.getCallingUid());
-
- return isPaused;
+ return isPackagePausedOrSuspended(pkg, Binder.getCallingUid());
}
private void verifyPrivilegedListener(INotificationListener token, UserHandle user,
@@ -5375,11 +5365,18 @@
}
@GuardedBy("mNotificationLock")
- private boolean isPackageSuspendedLocked(NotificationRecord r) {
- final String pkg = r.sbn.getPackageName();
- final int callingUid = r.sbn.getUid();
+ boolean isPackagePausedOrSuspended(String pkg, int uid) {
+ boolean isPaused;
- return isPackageSuspendedForUser(pkg, callingUid);
+ final PackageManagerInternal pmi = LocalServices.getService(
+ PackageManagerInternal.class);
+ int flags = pmi.getDistractingPackageRestrictions(
+ pkg, Binder.getCallingUserHandle().getIdentifier());
+ isPaused = ((flags & PackageManager.RESTRICTION_HIDE_NOTIFICATIONS) != 0);
+
+ isPaused |= isPackageSuspendedForUser(pkg, uid);
+
+ return isPaused;
}
protected class PostNotificationRunnable implements Runnable {
@@ -5412,7 +5409,8 @@
return;
}
- final boolean isPackageSuspended = isPackageSuspendedLocked(r);
+ final boolean isPackageSuspended =
+ isPackagePausedOrSuspended(r.sbn.getPackageName(), r.getUid());
r.setHidden(isPackageSuspended);
if (isPackageSuspended) {
mUsageStats.registerSuspendedByAdmin(r);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b0f73c3..232bca8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -238,6 +238,7 @@
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
+import android.permission.IPermissionManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings.Global;
@@ -961,7 +962,10 @@
// TODO remove this and go through mPermissonManager directly
final DefaultPermissionGrantPolicy mDefaultPermissionPolicy;
+ // Internal interface for permission manager
private final PermissionManagerServiceInternal mPermissionManager;
+ // Public interface for permission manager
+ private final IPermissionManager mPermissionManagerService;
private final ComponentResolver mComponentResolver;
// List of packages names to keep cached, even if they are uninstalled for all users
@@ -2419,6 +2423,8 @@
mPackages);
mPermissionManager = PermissionManagerService.create(context,
mPackages /*externalLock*/);
+ mPermissionManagerService =
+ (IPermissionManager) ServiceManager.getService("permissionmgr");
mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
mSettings = new Settings(Environment.getDataDirectory(),
mPermissionManager.getPermissionSettings(), mPackages);
@@ -4624,30 +4630,15 @@
return null;
}
- @Override
- public PermissionInfo getPermissionInfo(String name, String packageName, int flags) {
- return mPermissionManager.getPermissionInfo(name, packageName, flags, getCallingUid());
- }
-
- @Override
- public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
- int flags) {
- final List<PermissionInfo> permissionList =
- mPermissionManager.getPermissionInfoByGroup(groupName, flags, getCallingUid());
- return (permissionList == null) ? null : new ParceledListSlice<>(permissionList);
- }
-
+ // NOTE: Can't remove due to unsupported app usage
@Override
public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) {
- return mPermissionManager.getPermissionGroupInfo(groupName, flags, getCallingUid());
- }
-
- @Override
- public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) {
- final List<PermissionGroupInfo> permissionList =
- mPermissionManager.getAllPermissionGroups(flags, getCallingUid());
- return (permissionList == null)
- ? ParceledListSlice.emptyList() : new ParceledListSlice<>(permissionList);
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mPermissionManagerService.getPermissionGroupInfo(groupName, flags);
+ } catch (RemoteException ignore) { }
+ return null;
}
@GuardedBy("mPackages")
@@ -5704,37 +5695,36 @@
}
}
- private boolean addDynamicPermission(PermissionInfo info, final boolean async) {
- return mPermissionManager.addDynamicPermission(
- info, async, getCallingUid(), new PermissionCallback() {
- @Override
- public void onPermissionChanged() {
- if (!async) {
- mSettings.writeLPr();
- } else {
- scheduleWriteSettingsLocked();
- }
- }
- });
- }
-
+ // NOTE: Can't remove due to unsupported app usage
@Override
public boolean addPermission(PermissionInfo info) {
- synchronized (mPackages) {
- return addDynamicPermission(info, false);
- }
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mPermissionManagerService.addPermission(info, false);
+ } catch (RemoteException ignore) { }
+ return false;
}
+ // NOTE: Can't remove due to unsupported app usage
@Override
public boolean addPermissionAsync(PermissionInfo info) {
- synchronized (mPackages) {
- return addDynamicPermission(info, true);
- }
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mPermissionManagerService.addPermission(info, true);
+ } catch (RemoteException ignore) { }
+ return false;
}
+ // NOTE: Can't remove due to unsupported app usage
@Override
public void removePermission(String permName) {
- mPermissionManager.removeDynamicPermission(permName, getCallingUid(), mPermissionCallback);
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ mPermissionManagerService.removePermission(permName);
+ } catch (RemoteException ignore) { }
}
@Override
@@ -6565,9 +6555,15 @@
return false;
}
+ // NOTE: Can't remove due to unsupported app usage
@Override
public String[] getAppOpPermissionPackages(String permName) {
- return mPermissionManager.getAppOpPermissionPackages(permName);
+ try {
+ // Because this is accessed via the package manager service AIDL,
+ // go through the permission manager service AIDL
+ return mPermissionManagerService.getAppOpPermissionPackages(permName);
+ } catch (RemoteException ignore) { }
+ return null;
}
@Override
@@ -21747,7 +21743,7 @@
public void onShellCommand(FileDescriptor in, FileDescriptor out,
FileDescriptor err, String[] args, ShellCallback callback,
ResultReceiver resultReceiver) {
- (new PackageManagerShellCommand(this)).exec(
+ (new PackageManagerShellCommand(this, mPermissionManagerService)).exec(
this, in, out, err, args, callback, resultReceiver);
}
@@ -25009,6 +25005,17 @@
Slog.wtf(TAG, e);
}
}
+
+ @Override
+ public void writeSettings(boolean async) {
+ synchronized (mPackages) {
+ if (async) {
+ scheduleWriteSettingsLocked();
+ } else {
+ mSettings.writeLPr();
+ }
+ }
+ }
}
@GuardedBy("mPackages")
@@ -25286,7 +25293,8 @@
return false;
}
String appOpPermission = Manifest.permission.REQUEST_INSTALL_PACKAGES;
- String[] packagesDeclaringPermission = getAppOpPermissionPackages(appOpPermission);
+ String[] packagesDeclaringPermission =
+ mPermissionManager.getAppOpPermissionPackages(appOpPermission, callingUid);
if (!ArrayUtils.contains(packagesDeclaringPermission, packageName)) {
if (throwIfPermNotDeclared) {
throw new SecurityException("Need to declare " + appOpPermission
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 5b80556..a25c68f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -87,6 +87,7 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
+import android.permission.IPermissionManager;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
@@ -132,6 +133,7 @@
private static final int DEFAULT_WAIT_MS = 60 * 1000;
final IPackageManager mInterface;
+ final IPermissionManager mPermissionManager;
final private WeakHashMap<String, Resources> mResourceCache =
new WeakHashMap<String, Resources>();
int mTargetUser;
@@ -139,8 +141,10 @@
boolean mComponents;
int mQueryFlags;
- PackageManagerShellCommand(PackageManagerService service) {
+ PackageManagerShellCommand(
+ PackageManagerService service, IPermissionManager permissionManager) {
mInterface = service;
+ mPermissionManager = permissionManager;
}
@Override
@@ -786,7 +790,8 @@
private int runListPermissionGroups() throws RemoteException {
final PrintWriter pw = getOutPrintWriter();
- final List<PermissionGroupInfo> pgs = mInterface.getAllPermissionGroups(0).getList();
+ final List<PermissionGroupInfo> pgs =
+ mPermissionManager.getAllPermissionGroups(0).getList();
final int count = pgs.size();
for (int p = 0; p < count ; p++) {
@@ -833,7 +838,7 @@
final ArrayList<String> groupList = new ArrayList<String>();
if (groups) {
final List<PermissionGroupInfo> infos =
- mInterface.getAllPermissionGroups(0 /*flags*/).getList();
+ mPermissionManager.getAllPermissionGroups(0 /*flags*/).getList();
final int count = infos.size();
for (int i = 0; i < count; i++) {
groupList.add(infos.get(i).name);
@@ -2933,8 +2938,8 @@
}
prefix = " ";
}
- List<PermissionInfo> ps =
- mInterface.queryPermissionsByGroup(groupList.get(i), 0 /*flags*/).getList();
+ List<PermissionInfo> ps = mPermissionManager
+ .queryPermissionsByGroup(groupList.get(i), 0 /*flags*/).getList();
final int count = ps.size();
boolean first = true;
for (int p = 0 ; p < count ; p++) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 1287085..43a8373 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -51,10 +51,13 @@
import android.app.ApplicationPackageManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.PermissionGroupInfoFlags;
+import android.content.pm.PackageManager.PermissionInfoFlags;
import android.content.pm.PackageManager.PermissionWhitelistFlags;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.Package;
+import android.content.pm.ParceledListSlice;
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.metrics.LogMaker;
@@ -63,12 +66,14 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Process;
+import android.os.ServiceManager;
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.os.storage.StorageManagerInternal;
+import android.permission.IPermissionManager;
import android.permission.PermissionControllerManager;
import android.permission.PermissionManager;
import android.permission.PermissionManagerInternal;
@@ -122,7 +127,7 @@
/**
* Manages all permissions and handles permissions related tasks.
*/
-public class PermissionManagerService {
+public class PermissionManagerService extends IPermissionManager.Stub {
private static final String TAG = "PackageManager";
/** Permission grant: not grant the permission. */
@@ -283,7 +288,13 @@
if (permMgrInt != null) {
return permMgrInt;
}
- new PermissionManagerService(context, externalLock);
+ PermissionManagerService permissionService =
+ (PermissionManagerService) ServiceManager.getService("permissionmgr");
+ if (permissionService == null) {
+ permissionService =
+ new PermissionManagerService(context, externalLock);
+ ServiceManager.addService("permissionmgr", permissionService);
+ }
return LocalServices.getService(PermissionManagerServiceInternal.class);
}
@@ -293,6 +304,158 @@
}
}
+ @Override
+ public String[] getAppOpPermissionPackages(String permName) {
+ return getAppOpPermissionPackagesInternal(permName, getCallingUid());
+ }
+
+ private String[] getAppOpPermissionPackagesInternal(String permName, int callingUid) {
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ synchronized (mLock) {
+ final ArraySet<String> pkgs = mSettings.mAppOpPermissionPackages.get(permName);
+ if (pkgs == null) {
+ return null;
+ }
+ return pkgs.toArray(new String[pkgs.size()]);
+ }
+ }
+
+ @Override
+ @NonNull
+ public ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(
+ @PermissionGroupInfoFlags int flags) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return ParceledListSlice.emptyList();
+ }
+ synchronized (mLock) {
+ final int n = mSettings.mPermissionGroups.size();
+ final ArrayList<PermissionGroupInfo> out =
+ new ArrayList<PermissionGroupInfo>(n);
+ for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) {
+ out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
+ }
+ return new ParceledListSlice<>(out);
+ }
+ }
+
+
+ @Override
+ @Nullable
+ public PermissionGroupInfo getPermissionGroupInfo(String groupName,
+ @PermissionGroupInfoFlags int flags) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ synchronized (mLock) {
+ return PackageParser.generatePermissionGroupInfo(
+ mSettings.mPermissionGroups.get(groupName), flags);
+ }
+ }
+
+
+ @Override
+ @Nullable
+ public PermissionInfo getPermissionInfo(String permName, String packageName,
+ @PermissionInfoFlags int flags) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ synchronized (mLock) {
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+ if (bp == null) {
+ return null;
+ }
+ final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
+ bp.getProtectionLevel(), packageName, callingUid);
+ return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
+ }
+ }
+
+ @Override
+ @Nullable
+ public ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName,
+ @PermissionInfoFlags int flags) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ return null;
+ }
+ synchronized (mLock) {
+ if (groupName != null && !mSettings.mPermissionGroups.containsKey(groupName)) {
+ return null;
+ }
+ final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
+ for (BasePermission bp : mSettings.mPermissions.values()) {
+ final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
+ if (pi != null) {
+ out.add(pi);
+ }
+ }
+ return new ParceledListSlice<>(out);
+ }
+ }
+
+ @Override
+ public boolean addPermission(PermissionInfo info, boolean async) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ throw new SecurityException("Instant apps can't add permissions");
+ }
+ if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
+ throw new SecurityException("Label must be specified in permission");
+ }
+ final BasePermission tree = mSettings.enforcePermissionTree(info.name, callingUid);
+ final boolean added;
+ final boolean changed;
+ synchronized (mLock) {
+ BasePermission bp = mSettings.getPermissionLocked(info.name);
+ added = bp == null;
+ int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
+ if (added) {
+ enforcePermissionCapLocked(info, tree);
+ bp = new BasePermission(info.name, tree.getSourcePackageName(),
+ BasePermission.TYPE_DYNAMIC);
+ } else if (!bp.isDynamic()) {
+ throw new SecurityException("Not allowed to modify non-dynamic permission "
+ + info.name);
+ }
+ changed = bp.addToTree(fixedLevel, info, tree);
+ if (added) {
+ mSettings.putPermissionLocked(info.name, bp);
+ }
+ }
+ if (changed) {
+ mPackageManagerInt.writeSettings(async);
+ }
+ return added;
+ }
+
+ @Override
+ public void removePermission(String permName) {
+ final int callingUid = getCallingUid();
+ if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
+ throw new SecurityException("Instant applications don't have access to this method");
+ }
+ final BasePermission tree = mSettings.enforcePermissionTree(permName, callingUid);
+ synchronized (mLock) {
+ final BasePermission bp = mSettings.getPermissionLocked(permName);
+ if (bp == null) {
+ return;
+ }
+ if (bp.isDynamic()) {
+ // TODO: switch this back to SecurityException
+ Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
+ + permName);
+ }
+ mSettings.removePermissionLocked(permName);
+ mPackageManagerInt.writeSettings(false);
+ }
+ }
+
private int checkPermission(String permName, String pkgName, int callingUid, int userId) {
if (!mUserManagerInt.exists(userId)) {
return PackageManager.PERMISSION_DENIED;
@@ -491,69 +654,6 @@
&& permissionsState.hasPermission(FULLER_PERMISSION_MAP.get(permName), userId);
}
- private PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
- int callingUid) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- synchronized (mLock) {
- return PackageParser.generatePermissionGroupInfo(
- mSettings.mPermissionGroups.get(groupName), flags);
- }
- }
-
- private List<PermissionGroupInfo> getAllPermissionGroups(int flags, int callingUid) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- synchronized (mLock) {
- final int N = mSettings.mPermissionGroups.size();
- final ArrayList<PermissionGroupInfo> out
- = new ArrayList<PermissionGroupInfo>(N);
- for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) {
- out.add(PackageParser.generatePermissionGroupInfo(pg, flags));
- }
- return out;
- }
- }
-
- private PermissionInfo getPermissionInfo(String permName, String packageName, int flags,
- int callingUid) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- // reader
- synchronized (mLock) {
- final BasePermission bp = mSettings.getPermissionLocked(permName);
- if (bp == null) {
- return null;
- }
- final int adjustedProtectionLevel = adjustPermissionProtectionFlagsLocked(
- bp.getProtectionLevel(), packageName, callingUid);
- return bp.generatePermissionInfo(adjustedProtectionLevel, flags);
- }
- }
-
- private List<PermissionInfo> getPermissionInfoByGroup(
- String groupName, int flags, int callingUid) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- return null;
- }
- synchronized (mLock) {
- if (groupName != null && !mSettings.mPermissionGroups.containsKey(groupName)) {
- return null;
- }
- final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10);
- for (BasePermission bp : mSettings.mPermissions.values()) {
- final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags);
- if (pi != null) {
- out.add(pi);
- }
- }
- return out;
- }
- }
-
private int adjustPermissionProtectionFlagsLocked(
int protectionLevel, String packageName, int uid) {
// Signature permission flags area always reported
@@ -799,63 +899,6 @@
}
}
- private boolean addDynamicPermission(
- PermissionInfo info, int callingUid, PermissionCallback callback) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- throw new SecurityException("Instant apps can't add permissions");
- }
- if (info.labelRes == 0 && info.nonLocalizedLabel == null) {
- throw new SecurityException("Label must be specified in permission");
- }
- final BasePermission tree = mSettings.enforcePermissionTree(info.name, callingUid);
- final boolean added;
- final boolean changed;
- synchronized (mLock) {
- BasePermission bp = mSettings.getPermissionLocked(info.name);
- added = bp == null;
- int fixedLevel = PermissionInfo.fixProtectionLevel(info.protectionLevel);
- if (added) {
- enforcePermissionCapLocked(info, tree);
- bp = new BasePermission(info.name, tree.getSourcePackageName(),
- BasePermission.TYPE_DYNAMIC);
- } else if (!bp.isDynamic()) {
- throw new SecurityException("Not allowed to modify non-dynamic permission "
- + info.name);
- }
- changed = bp.addToTree(fixedLevel, info, tree);
- if (added) {
- mSettings.putPermissionLocked(info.name, bp);
- }
- }
- if (changed && callback != null) {
- callback.onPermissionChanged();
- }
- return added;
- }
-
- private void removeDynamicPermission(
- String permName, int callingUid, PermissionCallback callback) {
- if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
- throw new SecurityException("Instant applications don't have access to this method");
- }
- final BasePermission tree = mSettings.enforcePermissionTree(permName, callingUid);
- synchronized (mLock) {
- final BasePermission bp = mSettings.getPermissionLocked(permName);
- if (bp == null) {
- return;
- }
- if (bp.isDynamic()) {
- // TODO: switch this back to SecurityException
- Slog.wtf(TAG, "Not allowed to modify non-dynamic permission "
- + permName);
- }
- mSettings.removePermissionLocked(permName);
- if (callback != null) {
- callback.onPermissionRemoved();
- }
- }
- }
-
/**
* Restore the permission state for a package.
*
@@ -2327,12 +2370,8 @@
final String permissionName = pkg.requestedPermissions.get(i);
final BasePermission bp = mSettings.getPermissionLocked(permissionName);
- if (bp == null) {
- Slog.w(TAG, "Cannot whitelist unknown permission: " + permissionName);
- continue;
- }
- if (!bp.isHardOrSoftRestricted()) {
+ if (bp == null || !bp.isHardOrSoftRestricted()) {
continue;
}
@@ -2497,19 +2536,6 @@
return runtimePermissionChangedUserIds;
}
- private String[] getAppOpPermissionPackages(String permName) {
- if (mPackageManagerInt.getInstantAppPackageName(Binder.getCallingUid()) != null) {
- return null;
- }
- synchronized (mLock) {
- final ArraySet<String> pkgs = mSettings.mAppOpPermissionPackages.get(permName);
- if (pkgs == null) {
- return null;
- }
- return pkgs.toArray(new String[pkgs.size()]);
- }
- }
-
private int getPermissionFlags(
String permName, String packageName, int callingUid, int userId) {
if (!mUserManagerInt.exists(userId)) {
@@ -3137,16 +3163,6 @@
PermissionManagerService.this.removeAllPermissions(pkg, chatty);
}
@Override
- public boolean addDynamicPermission(PermissionInfo info, boolean async, int callingUid,
- PermissionCallback callback) {
- return PermissionManagerService.this.addDynamicPermission(info, callingUid, callback);
- }
- @Override
- public void removeDynamicPermission(String permName, int callingUid,
- PermissionCallback callback) {
- PermissionManagerService.this.removeDynamicPermission(permName, callingUid, callback);
- }
- @Override
public void grantRuntimePermission(String permName, String packageName,
boolean overridePolicy, int callingUid, int userId,
PermissionCallback callback) {
@@ -3200,8 +3216,9 @@
volumeUuid, sdkUpdated, allPackages, callback);
}
@Override
- public String[] getAppOpPermissionPackages(String permName) {
- return PermissionManagerService.this.getAppOpPermissionPackages(permName);
+ public String[] getAppOpPermissionPackages(String permName, int callingUid) {
+ return PermissionManagerService.this
+ .getAppOpPermissionPackagesInternal(permName, callingUid);
}
@Override
public int getPermissionFlags(String permName, String packageName, int callingUid,
@@ -3252,27 +3269,6 @@
return PermissionManagerService.this.checkUidPermission(permName, pkg, uid, callingUid);
}
@Override
- public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags,
- int callingUid) {
- return PermissionManagerService.this.getPermissionGroupInfo(
- groupName, flags, callingUid);
- }
- @Override
- public List<PermissionGroupInfo> getAllPermissionGroups(int flags, int callingUid) {
- return PermissionManagerService.this.getAllPermissionGroups(flags, callingUid);
- }
- @Override
- public PermissionInfo getPermissionInfo(String permName, String packageName, int flags,
- int callingUid) {
- return PermissionManagerService.this.getPermissionInfo(
- permName, packageName, flags, callingUid);
- }
- @Override
- public List<PermissionInfo> getPermissionInfoByGroup(String group, int flags,
- int callingUid) {
- return PermissionManagerService.this.getPermissionInfoByGroup(group, flags, callingUid);
- }
- @Override
public PermissionSettings getPermissionSettings() {
return mSettings;
}
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 0f7d07a..23d0114 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -20,9 +20,7 @@
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.PermissionInfoFlags;
import android.content.pm.PackageParser;
-import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.permission.PermissionManagerInternal;
@@ -150,35 +148,13 @@
public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty);
public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty);
- public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async,
- int callingUid, @Nullable PermissionCallback callback);
- public abstract void removeDynamicPermission(@NonNull String permName, int callingUid,
- @Nullable PermissionCallback callback);
- public abstract @Nullable String[] getAppOpPermissionPackages(@NonNull String permName);
+ /** Retrieve the packages that have requested the given app op permission */
+ public abstract @Nullable String[] getAppOpPermissionPackages(
+ @NonNull String permName, int callingUid);
public abstract int getPermissionFlags(@NonNull String permName,
@NonNull String packageName, int callingUid, int userId);
- /**
- * Retrieve all of the information we know about a particular group of permissions.
- */
- public abstract @Nullable PermissionGroupInfo getPermissionGroupInfo(
- @NonNull String groupName, int flags, int callingUid);
- /**
- * Retrieve all of the known permission groups in the system.
- */
- public abstract @Nullable List<PermissionGroupInfo> getAllPermissionGroups(int flags,
- int callingUid);
- /**
- * Retrieve all of the information we know about a particular permission.
- */
- public abstract @Nullable PermissionInfo getPermissionInfo(@NonNull String permName,
- @NonNull String packageName, @PermissionInfoFlags int flags, int callingUid);
- /**
- * Retrieve all of the permissions associated with a particular group.
- */
- public abstract @Nullable List<PermissionInfo> getPermissionInfoByGroup(@NonNull String group,
- @PermissionInfoFlags int flags, int callingUid);
/**
* Updates the flags associated with a permission by replacing the flags in
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index de3e89f..eb2f648 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -75,6 +75,7 @@
import java.util.List;
import java.util.Random;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -114,9 +115,8 @@
private final Set<NewRollback> mNewRollbacks = new ArraySet<>();
// The list of all rollbacks, including available and committed rollbacks.
- // This list is null until the rollback data has been loaded.
@GuardedBy("mLock")
- private List<RollbackData> mRollbacks;
+ private final List<RollbackData> mRollbacks;
private final RollbackStore mRollbackStore;
@@ -138,25 +138,24 @@
// SystemService#onStart.
mInstaller = new Installer(mContext);
mInstaller.onStart();
- mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
- mHandlerThread.start();
-
- // Monitor the handler thread
- Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
- // Kick off loading of the rollback data from strorage in a background
- // thread.
- // TODO: Consider loading the rollback data directly here instead, to
- // avoid the need to call ensureRollbackDataLoaded every time before
- // accessing the rollback data?
- // TODO: Test that this kicks off initial scheduling of rollback
- // expiration.
- getHandler().post(() -> ensureRollbackDataLoaded());
+ // Load rollback data from device storage.
+ synchronized (mLock) {
+ mRollbacks = mRollbackStore.loadAllRollbackData();
+ for (RollbackData data : mRollbacks) {
+ mAllocatedRollbackIds.put(data.info.getRollbackId(), true);
+ }
+ }
+
+ // Kick off and start monitoring the handler thread.
+ mHandlerThread = new HandlerThread("RollbackManagerServiceHandler");
+ mHandlerThread.start();
+ Watchdog.getInstance().addThread(getHandler(), HANDLER_THREAD_TIMEOUT_DURATION_MILLIS);
// TODO: Make sure to register these call backs when a new user is
// added too.
@@ -299,20 +298,15 @@
// to get the most up-to-date results. This is intended to reduce test
// flakiness when checking available rollbacks immediately after
// installing a package with rollback enabled.
- final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
- getHandler().post(() -> result.offer(true));
-
+ CountDownLatch latch = new CountDownLatch(1);
+ getHandler().post(() -> latch.countDown());
try {
- result.take();
+ latch.await();
} catch (InterruptedException ie) {
- // We may not get the most up-to-date information, but whatever we
- // can get now is better than nothing, so log but otherwise ignore
- // the exception.
- Slog.w(TAG, "Interrupted while waiting for handler thread in getAvailableRollbacks");
+ throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
}
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
@@ -329,7 +323,6 @@
enforceManageRollbacks("getRecentlyCommittedRollbacks");
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
List<RollbackInfo> rollbacks = new ArrayList<>();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
@@ -364,8 +357,6 @@
final long timeDifference = mRelativeBootTime - oldRelativeBootTime;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
-
Iterator<RollbackData> iter = mRollbacks.iterator();
while (iter.hasNext()) {
RollbackData data = iter.next();
@@ -544,13 +535,21 @@
Manifest.permission.TEST_MANAGE_ROLLBACKS,
"reloadPersistedData");
- synchronized (mLock) {
- mRollbacks = null;
- }
+ CountDownLatch latch = new CountDownLatch(1);
getHandler().post(() -> {
updateRollbackLifetimeDurationInMillis();
- ensureRollbackDataLoaded();
+ synchronized (mLock) {
+ mRollbacks.clear();
+ mRollbacks.addAll(mRollbackStore.loadAllRollbackData());
+ }
+ latch.countDown();
});
+
+ try {
+ latch.await();
+ } catch (InterruptedException ie) {
+ throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
+ }
}
@Override
@@ -559,7 +558,6 @@
Manifest.permission.TEST_MANAGE_ROLLBACKS,
"expireRollbackForPackage");
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
Iterator<RollbackData> iter = mRollbacks.iterator();
while (iter.hasNext()) {
RollbackData data = iter.next();
@@ -583,7 +581,7 @@
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
- // ignored.
+ throw new IllegalStateException("RollbackManagerHandlerThread interrupted");
}
});
}
@@ -626,7 +624,6 @@
List<RollbackData> restoreInProgress = new ArrayList<>();
Set<String> apexPackageNames = new HashSet<>();
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (RollbackData data : mRollbacks) {
if (data.isStaged()) {
if (data.state == RollbackData.ROLLBACK_STATE_ENABLING) {
@@ -648,17 +645,14 @@
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
PackageInstaller.SessionInfo session = installer.getSessionInfo(
data.stagedSessionId);
- // TODO: What if session is null?
- if (session != null) {
- if (session.isStagedSessionApplied()) {
- makeRollbackAvailable(data);
- } else if (session.isStagedSessionFailed()) {
- // TODO: Do we need to remove this from
- // mRollbacks, or is it okay to leave as
- // unavailable until the next reboot when it will go
- // away on its own?
- deleteRollback(data);
- }
+ if (session == null || session.isStagedSessionFailed()) {
+ // TODO: Do we need to remove this from
+ // mRollbacks, or is it okay to leave as
+ // unavailable until the next reboot when it will go
+ // away on its own?
+ deleteRollback(data);
+ } else if (session.isStagedSessionApplied()) {
+ makeRollbackAvailable(data);
}
}
@@ -689,41 +683,6 @@
}
/**
- * Load rollback data from storage if it has not already been loaded.
- * After calling this function, mRollbacks will be non-null.
- */
- private void ensureRollbackDataLoaded() {
- synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
- }
- }
-
- /**
- * Load rollback data from storage if it has not already been loaded.
- * After calling this function, mRollbacks will be non-null.
- */
- @GuardedBy("mLock")
- private void ensureRollbackDataLoadedLocked() {
- if (mRollbacks == null) {
- loadAllRollbackDataLocked();
- }
- }
-
- /**
- * Load all rollback data from storage.
- * Note: We do potentially heavy IO here while holding mLock, because we
- * have to have the rollback data loaded before we can do anything else
- * meaningful.
- */
- @GuardedBy("mLock")
- private void loadAllRollbackDataLocked() {
- mRollbacks = mRollbackStore.loadAllRollbackData();
- for (RollbackData data : mRollbacks) {
- mAllocatedRollbackIds.put(data.info.getRollbackId(), true);
- }
- }
-
- /**
* Called when a package has been replaced with a different version.
* Removes all backups for the package not matching the currently
* installed package version.
@@ -734,7 +693,6 @@
VersionedPackage installedVersion = getInstalledPackageVersion(packageName);
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
Iterator<RollbackData> iter = mRollbacks.iterator();
while (iter.hasNext()) {
RollbackData data = iter.next();
@@ -803,8 +761,6 @@
Instant now = Instant.now();
Instant oldest = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
-
Iterator<RollbackData> iter = mRollbacks.iterator();
while (iter.hasNext()) {
RollbackData data = iter.next();
@@ -924,7 +880,6 @@
// TODO: This check could be made more efficient.
RollbackData rd = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
if (data.apkSessionId == parentSession.getSessionId()) {
@@ -1080,7 +1035,6 @@
private void snapshotUserDataInternal(String packageName) {
synchronized (mLock) {
// staged installs
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); i++) {
RollbackData data = mRollbacks.get(i);
if (data.state != RollbackData.ROLLBACK_STATE_ENABLING) {
@@ -1113,7 +1067,6 @@
PackageRollbackInfo info = null;
RollbackData rollbackData = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
if (data.restoreUserDataInProgress) {
@@ -1209,7 +1162,6 @@
getHandler().post(() -> {
RollbackData rd = null;
synchronized (mLock) {
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
if (data.stagedSessionId == originalSessionId) {
@@ -1380,7 +1332,6 @@
// device reboots between when the session is
// committed and this point. Revisit this after
// adding support for rollback of staged installs.
- ensureRollbackDataLoadedLocked();
mRollbacks.add(data);
}
@@ -1417,9 +1368,6 @@
*/
private RollbackData getRollbackForId(int rollbackId) {
synchronized (mLock) {
- // TODO: Have ensureRollbackDataLoadedLocked return the list of
- // available rollbacks, to hopefully avoid forgetting to call it?
- ensureRollbackDataLoadedLocked();
for (int i = 0; i < mRollbacks.size(); ++i) {
RollbackData data = mRollbacks.get(i);
if (data.info.getRollbackId() == rollbackId) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6665381..f6eb8ea 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -108,6 +108,7 @@
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESTARTING_PROCESS;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityStack.LAUNCH_TICK;
@@ -1922,6 +1923,15 @@
return state1 == mState || state2 == mState || state3 == mState || state4 == mState;
}
+ /**
+ * Returns {@code true} if the Activity is in one of the specified states.
+ */
+ boolean isState(ActivityState state1, ActivityState state2, ActivityState state3,
+ ActivityState state4, ActivityState state5) {
+ return state1 == mState || state2 == mState || state3 == mState || state4 == mState
+ || state5 == mState;
+ }
+
void notifyAppResumed(boolean wasStopped) {
if (mAppWindowToken == null) {
Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: "
@@ -2037,12 +2047,10 @@
mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken,
WindowVisibilityItem.obtain(true /* showWindow */));
makeActiveIfNeeded(null /* activeActivity*/);
- if (isState(STOPPING, STOPPED) && isFocusable()) {
- // #shouldMakeActive() only evaluates the topmost activities in task, so
- // activities that are not the topmost in task are not being resumed or paused.
- // For activities that are still in STOPPING or STOPPED state, updates the state
- // to PAUSE at least when making it visible.
- setState(PAUSED, "makeClientVisible");
+ if (isState(STOPPING, STOPPED)) {
+ // Set state to STARTED in order to have consistent state with client while
+ // making an non-active activity visible from stopped.
+ setState(STARTED, "makeClientVisible");
}
} catch (Exception e) {
Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e);
@@ -2118,7 +2126,7 @@
// calls will lead to noticeable jank. A later call to
// ActivityStack#ensureActivitiesVisibleLocked will bring the activity to a proper
// active state.
- if (!isState(RESUMED, PAUSED, STOPPED, STOPPING)
+ if (!isState(STARTED, RESUMED, PAUSED, STOPPED, STOPPING)
|| getActivityStack().mTranslucentActivityWaiting != null) {
return false;
}
@@ -2646,7 +2654,7 @@
compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
allowTaskSnapshot(),
- mState.ordinal() >= RESUMED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
+ mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal(),
fromRecents);
if (shown) {
mStartingWindowState = STARTING_WINDOW_SHOWN;
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index df3712f..6d902fc 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -62,6 +62,7 @@
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
@@ -164,6 +165,8 @@
import com.android.server.am.EventLogTags;
import com.android.server.am.PendingIntentRecord;
+import com.google.android.collect.Sets;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -292,6 +295,7 @@
enum ActivityState {
INITIALIZING,
+ STARTED,
RESUMED,
PAUSING,
PAUSED,
@@ -1608,7 +1612,7 @@
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- if (r.isState(STOPPING, STOPPED, PAUSED, PAUSING)) {
+ if (r.isState(STARTED, STOPPING, STOPPED, PAUSED, PAUSING)) {
r.setSleeping(true);
}
}
@@ -2435,6 +2439,7 @@
case RESUMED:
case PAUSING:
case PAUSED:
+ case STARTED:
addToStopping(r, true /* scheduleIdle */,
canEnterPictureInPicture /* idleDelayed */, "makeInvisible");
break;
@@ -3882,7 +3887,7 @@
}
if (activityNdx >= 0) {
r = mTaskHistory.get(taskNdx).mActivities.get(activityNdx);
- if (r.isState(RESUMED, PAUSING, PAUSED)) {
+ if (r.isState(STARTED, RESUMED, PAUSING, PAUSED)) {
if (!r.isActivityTypeHome() || mService.mHomeProcess != r.app) {
Slog.w(TAG, " Force finishing activity "
+ r.intent.getComponent().flattenToShortString());
@@ -4031,6 +4036,14 @@
}
getDisplay().mDisplayContent.prepareAppTransition(transit, false);
+ // When finishing the activity pre-emptively take the snapshot before the app window
+ // is marked as hidden and any configuration changes take place
+ if (mWindowManager.mTaskSnapshotController != null) {
+ final ArraySet<Task> tasks = Sets.newArraySet(task.mTask);
+ mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
+ mWindowManager.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(tasks);
+ }
+
// Tell window manager to prepare for this one to be removed.
r.setVisibility(false);
@@ -4146,6 +4159,7 @@
|| (prevState == PAUSED
&& (mode == FINISH_AFTER_PAUSE || inPinnedWindowingMode()))
|| finishingInNonFocusedStackOrNoRunning
+ || prevState == STARTED
|| prevState == STOPPING
|| prevState == STOPPED
|| prevState == ActivityState.INITIALIZING) {
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index bc5e328..932e44e 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -27,6 +27,7 @@
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
@@ -731,10 +732,10 @@
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Abort release; already destroying: " + r);
return null;
}
- // Don't consider any activies that are currently not in a state where they
+ // Don't consider any activities that are currently not in a state where they
// can be destroyed.
if (r.visible || !r.stopped || !r.haveState
- || r.isState(RESUMED, PAUSING, PAUSED, STOPPING)) {
+ || r.isState(STARTED, RESUMED, PAUSING, PAUSED, STOPPING)) {
if (DEBUG_RELEASE) Slog.d(TAG_RELEASE, "Not releasing in-use activity: " + r);
continue;
}
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index da17579..21bdc43 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -357,6 +357,33 @@
return value ? JNI_TRUE : JNI_FALSE;
}
+template<class T>
+static inline void logHidlError(Return<T>& result, const char* errorMessage) {
+ ALOGE("%s HIDL transport error: %s", errorMessage, result.description().c_str());
+}
+
+template<class T>
+static jboolean checkHidlReturn(Return<T>& result, const char* errorMessage) {
+ if (!result.isOk()) {
+ logHidlError(result, errorMessage);
+ return JNI_FALSE;
+ } else {
+ return JNI_TRUE;
+ }
+}
+
+static jboolean checkHidlReturn(Return<bool>& result, const char* errorMessage) {
+ if (!result.isOk()) {
+ logHidlError(result, errorMessage);
+ return JNI_FALSE;
+ } else if (!result) {
+ ALOGE("%s", errorMessage);
+ return JNI_FALSE;
+ } else {
+ return JNI_TRUE;
+ }
+}
+
static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
if (env->ExceptionCheck()) {
ALOGE("An exception was thrown by callback '%s'.", methodName);
@@ -1913,8 +1940,7 @@
result = gnssHal->setCallback(gnssCbIface);
}
- if (!result.isOk() || !result) {
- ALOGE("SetCallback for IGnss interface failed.");
+ if (!checkHidlReturn(result, "IGnss setCallback() failed.")) {
return JNI_FALSE;
}
@@ -1924,35 +1950,29 @@
} else {
sp<IGnssXtraCallback> gnssXtraCbIface = new GnssXtraCallback();
result = gnssXtraIface->setCallback(gnssXtraCbIface);
- if (!result.isOk() || !result) {
+ if (!checkHidlReturn(result, "IGnssXtra setCallback() failed.")) {
gnssXtraIface = nullptr;
- ALOGI("SetCallback for IGnssXtra interface failed.");
}
}
// Set IAGnss.hal callback.
- Return<void> agnssStatus;
if (agnssIface_V2_0 != nullptr) {
sp<IAGnssCallback_V2_0> aGnssCbIface = new AGnssCallback_V2_0();
- agnssStatus = agnssIface_V2_0->setCallback(aGnssCbIface);
+ auto agnssStatus = agnssIface_V2_0->setCallback(aGnssCbIface);
+ checkHidlReturn(agnssStatus, "IAGnss 2.0 setCallback() failed.");
} else if (agnssIface != nullptr) {
sp<IAGnssCallback_V1_0> aGnssCbIface = new AGnssCallback_V1_0();
- agnssStatus = agnssIface->setCallback(aGnssCbIface);
+ auto agnssStatus = agnssIface->setCallback(aGnssCbIface);
+ checkHidlReturn(agnssStatus, "IAGnss setCallback() failed.");
} else {
ALOGI("Unable to initialize IAGnss interface.");
}
- if (!agnssStatus.isOk()) {
- ALOGI("SetCallback for IAGnss interface failed.");
- }
-
// Set IGnssGeofencing.hal callback.
sp<IGnssGeofenceCallback> gnssGeofencingCbIface = new GnssGeofenceCallback();
if (gnssGeofencingIface != nullptr) {
auto status = gnssGeofencingIface->setCallback(gnssGeofencingCbIface);
- if (!status.isOk()) {
- ALOGI("SetCallback for IGnssGeofencing interface failed.");
- }
+ checkHidlReturn(status, "IGnssGeofencing setCallback() failed.");
} else {
ALOGI("Unable to initialize IGnssGeofencing interface.");
}
@@ -1961,9 +1981,7 @@
sp<IGnssNiCallback> gnssNiCbIface = new GnssNiCallback();
if (gnssNiIface != nullptr) {
auto status = gnssNiIface->setCallback(gnssNiCbIface);
- if (!status.isOk()) {
- ALOGI("SetCallback for IGnssNi interface failed.");
- }
+ checkHidlReturn(status, "IGnssNi setCallback() failed.");
} else {
ALOGI("Unable to initialize IGnssNi interface.");
}
@@ -1972,9 +1990,7 @@
sp<IAGnssRilCallback> aGnssRilCbIface = new AGnssRilCallback();
if (agnssRilIface != nullptr) {
auto status = agnssRilIface->setCallback(aGnssRilCbIface);
- if (!status.isOk()) {
- ALOGI("SetCallback for IAGnssRil interface failed.");
- }
+ checkHidlReturn(status, "IAGnssRil setCallback() failed.");
} else {
ALOGI("Unable to initialize IAGnssRil interface.");
}
@@ -1984,9 +2000,7 @@
sp<IGnssVisibilityControlCallback> gnssVisibilityControlCbIface =
new GnssVisibilityControlCallback();
result = gnssVisibilityControlIface->setCallback(gnssVisibilityControlCbIface);
- if (!result.isOk() || !result) {
- ALOGI("SetCallback for IGnssVisibilityControl interface failed.");
- }
+ checkHidlReturn(result, "IGnssVisibilityControl setCallback() failed.");
}
// Set IMeasurementCorrections.hal callback.
@@ -1994,18 +2008,19 @@
sp<IMeasurementCorrectionsCallback> gnssCorrectionsIfaceCbIface =
new MeasurementCorrectionsCallback();
result = gnssCorrectionsIface->setCallback(gnssCorrectionsIfaceCbIface);
- if (!result.isOk() || !result) {
- ALOGI("SetCallback for IMeasurementCorrections interface failed.");
- }
+ checkHidlReturn(result, "IMeasurementCorrections setCallback() failed.");
}
return JNI_TRUE;
}
static void android_location_GnssLocationProvider_cleanup(JNIEnv* /* env */, jobject /* obj */) {
- if (gnssHal != nullptr) {
- gnssHal->cleanup();
+ if (gnssHal == nullptr) {
+ return;
}
+
+ auto result = gnssHal->cleanup();
+ checkHidlReturn(result, "IGnss cleanup() failed.");
}
static jboolean android_location_GnssLocationProvider_set_position_mode(JNIEnv* /* env */,
@@ -2026,48 +2041,37 @@
preferred_accuracy,
preferred_time);
}
- if (!result.isOk()) {
- ALOGE("%s: GNSS setPositionMode failed\n", __func__);
- return JNI_FALSE;
- } else {
- return result;
- }
+
+ return checkHidlReturn(result, "IGnss setPositionMode() failed.");
}
static jboolean android_location_GnssLocationProvider_start(JNIEnv* /* env */, jobject /* obj */) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->start();
- if (!result.isOk()) {
- return JNI_FALSE;
- } else {
- return result;
- }
- } else {
+ if (gnssHal == nullptr) {
return JNI_FALSE;
}
+
+ auto result = gnssHal->start();
+ return checkHidlReturn(result, "IGnss start() failed.");
}
static jboolean android_location_GnssLocationProvider_stop(JNIEnv* /* env */, jobject /* obj */) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->stop();
- if (!result.isOk()) {
- return JNI_FALSE;
- } else {
- return result;
- }
- } else {
+ if (gnssHal == nullptr) {
return JNI_FALSE;
}
+
+ auto result = gnssHal->stop();
+ return checkHidlReturn(result, "IGnss stop() failed.");
}
+
static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /* env */,
jobject /* obj */,
jint flags) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->deleteAidingData(static_cast<IGnss_V1_0::GnssAidingData>(flags));
- if (!result.isOk()) {
- ALOGE("Error in deleting aiding data");
- }
+ if (gnssHal == nullptr) {
+ return;
}
+
+ auto result = gnssHal->deleteAidingData(static_cast<IGnss_V1_0::GnssAidingData>(flags));
+ checkHidlReturn(result, "IGnss deleteAidingData() failed.");
}
static void android_location_GnssLocationProvider_agps_set_reference_location_cellid(
@@ -2075,7 +2079,7 @@
IAGnssRil_V1_0::AGnssRefLocation location;
if (agnssRilIface == nullptr) {
- ALOGE("No AGPS RIL interface in agps_set_reference_location_cellid");
+ ALOGE("%s: IAGnssRil interface not available.", __func__);
return;
}
@@ -2094,18 +2098,20 @@
break;
}
- agnssRilIface->setRefLocation(location);
+ auto result = agnssRilIface->setRefLocation(location);
+ checkHidlReturn(result, "IAGnssRil setRefLocation() failed.");
}
static void android_location_GnssLocationProvider_agps_set_id(JNIEnv* env, jobject /* obj */,
jint type, jstring setid_string) {
if (agnssRilIface == nullptr) {
- ALOGE("no AGPS RIL interface in agps_set_id");
+ ALOGE("%s: IAGnssRil interface not available.", __func__);
return;
}
ScopedJniString jniSetId{env, setid_string};
- agnssRilIface->setSetId((IAGnssRil_V1_0::SetIDType)type, jniSetId);
+ auto result = agnssRilIface->setSetId((IAGnssRil_V1_0::SetIDType)type, jniSetId);
+ checkHidlReturn(result, "IAGnssRil setSetId() failed.");
}
static jint android_location_GnssLocationProvider_read_nmea(JNIEnv* env, jobject /* obj */,
@@ -2122,12 +2128,12 @@
static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */, jobject /* obj */,
jlong time, jlong timeReference, jint uncertainty) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->injectTime(time, timeReference, uncertainty);
- if (!result.isOk() || !result) {
- ALOGE("%s: Gnss injectTime() failed", __func__);
- }
+ if (gnssHal == nullptr) {
+ return;
}
+
+ auto result = gnssHal->injectTime(time, timeReference, uncertainty);
+ checkHidlReturn(result, "IGnss injectTime() failed.");
}
static void android_location_GnssLocationProvider_inject_best_location(
@@ -2164,10 +2170,7 @@
elapsedRealtimeNanos,
elapsedRealtimeUncertaintyNanos);
auto result = gnssHal_V2_0->injectBestLocation_2_0(location);
-
- if (!result.isOk() || !result) {
- ALOGE("%s: Gnss injectBestLocation() failed.", __func__);
- }
+ checkHidlReturn(result, "IGnss injectBestLocation_2_0() failed.");
return;
}
@@ -2185,24 +2188,20 @@
bearingAccuracyDegrees,
timestamp);
auto result = gnssHal_V1_1->injectBestLocation(location);
-
- if (!result.isOk() || !result) {
- ALOGE("%s: Gnss injectBestLocation() failed.", __func__);
- }
- return;
+ checkHidlReturn(result, "IGnss injectBestLocation() failed.");
}
- ALOGE("%s: injectBestLocation() is called but gnssHal_V1_1 is not available.", __func__);
+ ALOGE("IGnss injectBestLocation() is called but gnssHal_V1_1 is not available.");
}
static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env */,
jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
- if (gnssHal != nullptr) {
- auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
- if (!result.isOk() || !result) {
- ALOGE("%s: Gnss injectLocation() failed", __func__);
- }
+ if (gnssHal == nullptr) {
+ return;
}
+
+ auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
+ checkHidlReturn(result, "IGnss injectLocation() failed.");
}
static jboolean android_location_GnssLocationProvider_supports_psds(
@@ -2213,12 +2212,13 @@
static void android_location_GnssLocationProvider_inject_psds_data(JNIEnv* env, jobject /* obj */,
jbyteArray data, jint length) {
if (gnssXtraIface == nullptr) {
- ALOGE("XTRA Interface not supported");
+ ALOGE("%s: IGnssXtra interface not available.", __func__);
return;
}
jbyte* bytes = reinterpret_cast<jbyte *>(env->GetPrimitiveArrayCritical(data, 0));
- gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+ auto result = gnssXtraIface->injectXtraData(std::string((const char*)bytes, length));
+ checkHidlReturn(result, "IGnssXtra injectXtraData() failed.");
env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
}
@@ -2245,9 +2245,7 @@
ScopedJniString jniApn{env, apn};
auto result = agnssIface->dataConnOpen(jniApn,
static_cast<IAGnss_V1_0::ApnIpType>(apnIpType));
- if (!result.isOk() || !result){
- ALOGE("%s: Failed to set APN and its IP type", __func__);
- }
+ checkHidlReturn(result, "IAGnss dataConnOpen() failed. APN and its IP type not set.");
}
void AGnssDispatcher::dataConnOpen(sp<IAGnss_V2_0> agnssIface_V2_0, JNIEnv* env,
@@ -2255,25 +2253,19 @@
ScopedJniString jniApn{env, apn};
auto result = agnssIface_V2_0->dataConnOpen(static_cast<uint64_t>(networkHandle), jniApn,
static_cast<IAGnss_V2_0::ApnIpType>(apnIpType));
- if (!result.isOk() || !result){
- ALOGE("%s: Failed to set APN and its IP type", __func__);
- }
+ checkHidlReturn(result, "IAGnss 2.0 dataConnOpen() failed. APN and its IP type not set.");
}
template<class T>
void AGnssDispatcher::dataConnClosed(sp<T> agnssIface) {
auto result = agnssIface->dataConnClosed();
- if (!result.isOk() || !result) {
- ALOGE("%s: Failed to close AGnss data connection", __func__);
- }
+ checkHidlReturn(result, "IAGnss dataConnClosed() failed.");
}
template<class T>
void AGnssDispatcher::dataConnFailed(sp<T> agnssIface) {
auto result = agnssIface->dataConnFailed();
- if (!result.isOk() || !result) {
- ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__);
- }
+ checkHidlReturn(result, "IAGnss dataConnFailed() failed.");
}
template <class T, class U>
@@ -2282,9 +2274,7 @@
ScopedJniString jniHostName{env, hostname};
auto result = agnssIface->setServer(static_cast<typename U::AGnssType>(type),
jniHostName, port);
- if (!result.isOk() || !result) {
- ALOGE("%s: Failed to set AGnss host name and port", __func__);
- }
+ checkHidlReturn(result, "IAGnss setServer() failed. Host name and port not set.");
}
static void android_location_GnssNetworkConnectivityHandler_agps_data_conn_open(
@@ -2299,7 +2289,7 @@
} else if (agnssIface != nullptr) {
AGnssDispatcher::dataConnOpen(agnssIface, env, apn, apnIpType);
} else {
- ALOGE("%s: AGPS interface not supported", __func__);
+ ALOGE("%s: IAGnss interface not available.", __func__);
return;
}
}
@@ -2311,7 +2301,7 @@
} else if (agnssIface != nullptr) {
AGnssDispatcher::dataConnClosed(agnssIface);
} else {
- ALOGE("%s: AGPS interface not supported", __func__);
+ ALOGE("%s: IAGnss interface not available.", __func__);
return;
}
}
@@ -2323,7 +2313,7 @@
} else if (agnssIface != nullptr) {
AGnssDispatcher::dataConnFailed(agnssIface);
} else {
- ALOGE("%s: AGPS interface not supported", __func__);
+ ALOGE("%s: IAGnss interface not available.", __func__);
return;
}
}
@@ -2337,26 +2327,30 @@
AGnssDispatcher::setServer<IAGnss_V1_0, IAGnssCallback_V1_0>(agnssIface, env, type,
hostname, port);
} else {
- ALOGE("%s: AGPS interface not supported", __func__);
+ ALOGE("%s: IAGnss interface not available.", __func__);
return;
}
}
static void android_location_GnssLocationProvider_send_ni_response(JNIEnv* /* env */,
- jobject /* obj */, jint notifId, jint response) {
+ jobject /* obj */, jint notifId, jint response) {
if (gnssNiIface == nullptr) {
- ALOGE("no NI interface in send_ni_response");
+ ALOGE("%s: IGnssNi interface not available.", __func__);
return;
}
- gnssNiIface->respond(notifId, static_cast<IGnssNiCallback::GnssUserResponseType>(response));
+ auto result = gnssNiIface->respond(notifId,
+ static_cast<IGnssNiCallback::GnssUserResponseType>(response));
+ checkHidlReturn(result, "IGnssNi respond() failed.");
}
-const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) {
+const IGnssDebug_V1_0::SatelliteData& getSatelliteData(
+ const hidl_vec<IGnssDebug_V1_0::SatelliteData>& satelliteDataArray, size_t i) {
return satelliteDataArray[i];
}
-const IGnssDebug_V1_0::SatelliteData& getSatelliteData(const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) {
+const IGnssDebug_V1_0::SatelliteData& getSatelliteData(
+ const hidl_vec<IGnssDebug_V2_0::SatelliteData>& satelliteDataArray, size_t i) {
return satelliteDataArray[i].v1_0;
}
@@ -2424,7 +2418,7 @@
static jstring android_location_GnssLocationProvider_get_internal_state(JNIEnv* env,
jobject /* obj */) {
- jstring result = nullptr;
+ jstring internalStateStr = nullptr;
/*
* TODO: Create a jobject to represent GnssDebug.
*/
@@ -2432,21 +2426,27 @@
std::stringstream internalState;
if (gnssDebugIface == nullptr) {
- internalState << "Gnss Debug Interface not available" << std::endl;
+ ALOGE("%s: IGnssDebug interface not available.", __func__);
} else if (gnssDebugIface_V2_0 != nullptr) {
IGnssDebug_V2_0::DebugData data;
- gnssDebugIface_V2_0->getDebugData_2_0([&data](const IGnssDebug_V2_0::DebugData& debugData) {
- data = debugData;
- });
- result = parseDebugData(env, internalState, data);
+ auto result = gnssDebugIface_V2_0->getDebugData_2_0(
+ [&data](const IGnssDebug_V2_0::DebugData& debugData) {
+ data = debugData;
+ });
+ if (checkHidlReturn(result, "IGnssDebug getDebugData_2_0() failed.")) {
+ internalStateStr = parseDebugData(env, internalState, data);
+ }
} else {
IGnssDebug_V1_0::DebugData data;
- gnssDebugIface->getDebugData([&data](const IGnssDebug_V1_0::DebugData& debugData) {
- data = debugData;
- });
- result = parseDebugData(env, internalState, data);
+ auto result = gnssDebugIface->getDebugData(
+ [&data](const IGnssDebug_V1_0::DebugData& debugData) {
+ data = debugData;
+ });
+ if (checkHidlReturn(result, "IGnssDebug getDebugData() failed.")) {
+ internalStateStr = parseDebugData(env, internalState, data);
+ }
}
- return result;
+ return internalStateStr;
}
static jboolean android_location_GnssLocationProvider_is_gnss_visibility_control_supported(
@@ -2473,26 +2473,20 @@
};
auto result = agnssRilIface_V2_0->updateNetworkState_2_0(networkAttributes);
- if (!result.isOk() || !result) {
- ALOGE("updateNetworkState_2_0 failed");
- }
+ checkHidlReturn(result, "IAGnssRil updateNetworkState_2_0() failed.");
} else if (agnssRilIface != nullptr) {
ScopedJniString jniApn{env, apn};
hidl_string hidlApn{jniApn};
auto result = agnssRilIface->updateNetworkState(connected,
static_cast<IAGnssRil_V1_0::NetworkType>(type), roaming);
- if (!result.isOk() || !result) {
- ALOGE("updateNetworkState failed");
- }
+ checkHidlReturn(result, "IAGnssRil updateNetworkState() failed.");
if (!hidlApn.empty()) {
result = agnssRilIface->updateNetworkAvailability(available, hidlApn);
- if (!result.isOk() || !result) {
- ALOGE("updateNetworkAvailability failed");
- }
+ checkHidlReturn(result, "IAGnssRil updateNetworkAvailability() failed.");
}
} else {
- ALOGE("AGnssRilInterface does not exist");
+ ALOGE("%s: IAGnssRil interface not available.", __func__);
}
}
@@ -2505,49 +2499,49 @@
jobject /* obj */, jint geofenceId, jdouble latitude, jdouble longitude, jdouble radius,
jint last_transition, jint monitor_transition, jint notification_responsiveness,
jint unknown_timer) {
- if (gnssGeofencingIface != nullptr) {
- auto result = gnssGeofencingIface->addGeofence(
- geofenceId, latitude, longitude, radius,
- static_cast<IGnssGeofenceCallback::GeofenceTransition>(last_transition),
- monitor_transition, notification_responsiveness, unknown_timer);
- return boolToJbool(result.isOk());
- } else {
- ALOGE("Geofence Interface not available");
+ if (gnssGeofencingIface == nullptr) {
+ ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+ return JNI_FALSE;
}
- return JNI_FALSE;
+
+ auto result = gnssGeofencingIface->addGeofence(
+ geofenceId, latitude, longitude, radius,
+ static_cast<IGnssGeofenceCallback::GeofenceTransition>(last_transition),
+ monitor_transition, notification_responsiveness, unknown_timer);
+ return checkHidlReturn(result, "IGnssGeofencing addGeofence() failed.");
}
static jboolean android_location_GnssGeofenceProvider_remove_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofenceId) {
- if (gnssGeofencingIface != nullptr) {
- auto result = gnssGeofencingIface->removeGeofence(geofenceId);
- return boolToJbool(result.isOk());
- } else {
- ALOGE("Geofence interface not available");
+ if (gnssGeofencingIface == nullptr) {
+ ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+ return JNI_FALSE;
}
- return JNI_FALSE;
+
+ auto result = gnssGeofencingIface->removeGeofence(geofenceId);
+ return checkHidlReturn(result, "IGnssGeofencing removeGeofence() failed.");
}
static jboolean android_location_GnssGeofenceProvider_pause_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofenceId) {
- if (gnssGeofencingIface != nullptr) {
- auto result = gnssGeofencingIface->pauseGeofence(geofenceId);
- return boolToJbool(result.isOk());
- } else {
- ALOGE("Geofence interface not available");
+ if (gnssGeofencingIface == nullptr) {
+ ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+ return JNI_FALSE;
}
- return JNI_FALSE;
+
+ auto result = gnssGeofencingIface->pauseGeofence(geofenceId);
+ return checkHidlReturn(result, "IGnssGeofencing pauseGeofence() failed.");
}
static jboolean android_location_GnssGeofenceProvider_resume_geofence(JNIEnv* /* env */,
jobject /* obj */, jint geofenceId, jint monitor_transition) {
- if (gnssGeofencingIface != nullptr) {
- auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition);
- return boolToJbool(result.isOk());
- } else {
- ALOGE("Geofence interface not available");
+ if (gnssGeofencingIface == nullptr) {
+ ALOGE("%s: IGnssGeofencing interface not available.", __func__);
+ return JNI_FALSE;
}
- return JNI_FALSE;
+
+ auto result = gnssGeofencingIface->resumeGeofence(geofenceId, monitor_transition);
+ return checkHidlReturn(result, "IGnssGeofencing resumeGeofence() failed.");
}
static jboolean android_location_GnssMeasurementsProvider_is_measurement_supported(
@@ -2564,12 +2558,12 @@
jobject /* obj */,
jboolean enableFullTracking) {
if (gnssMeasurementIface == nullptr) {
- ALOGE("GNSS Measurement interface is not available.");
+ ALOGE("%s: IGnssMeasurement interface not available.", __func__);
return JNI_FALSE;
}
sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback();
- IGnssMeasurement_V1_0::GnssMeasurementStatus result =
+ Return<IGnssMeasurement_V1_0::GnssMeasurementStatus> result =
IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC;
if (gnssMeasurementIface_V2_0 != nullptr) {
result = gnssMeasurementIface_V2_0->setCallback_2_0(cbIface, enableFullTracking);
@@ -2578,14 +2572,20 @@
} else {
if (enableFullTracking == JNI_TRUE) {
// full tracking mode not supported in 1.0 HAL
+ result.assertOk(); // isOk() must be called before result destructor is invoked.
return JNI_FALSE;
}
result = gnssMeasurementIface->setCallback(cbIface);
}
- if (result != IGnssMeasurement_V1_0::GnssMeasurementStatus::SUCCESS) {
+ if (!checkHidlReturn(result, "IGnssMeasurement setCallback() failed.")) {
+ return JNI_FALSE;
+ }
+
+ IGnssMeasurement_V1_0::GnssMeasurementStatus initRet = result;
+ if (initRet != IGnssMeasurement_V1_0::GnssMeasurementStatus::SUCCESS) {
ALOGE("An error has been found on GnssMeasurementInterface::init, status=%d",
- static_cast<int32_t>(result));
+ static_cast<int32_t>(initRet));
return JNI_FALSE;
} else {
ALOGD("gnss measurement infc has been enabled");
@@ -2598,12 +2598,12 @@
JNIEnv* env,
jobject obj) {
if (gnssMeasurementIface == nullptr) {
- ALOGE("Measurement interface not available");
+ ALOGE("%s: IGnssMeasurement interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssMeasurementIface->close();
- return boolToJbool(result.isOk());
+ return checkHidlReturn(result, "IGnssMeasurement close() failed.");
}
static jboolean
@@ -2718,8 +2718,8 @@
.satCorrections = list,
};
- gnssCorrectionsIface->setCorrections(measurementCorrections);
- return JNI_TRUE;
+ auto result = gnssCorrectionsIface->setCorrections(measurementCorrections);
+ return checkHidlReturn(result, "IMeasurementCorrections setCorrections() failed.");
}
static jboolean android_location_GnssNavigationMessageProvider_is_navigation_message_supported(
@@ -2735,17 +2735,20 @@
JNIEnv* env,
jobject obj) {
if (gnssNavigationMessageIface == nullptr) {
- ALOGE("Navigation Message interface is not available.");
+ ALOGE("%s: IGnssNavigationMessage interface not available.", __func__);
return JNI_FALSE;
}
sp<IGnssNavigationMessageCallback> gnssNavigationMessageCbIface =
new GnssNavigationMessageCallback();
- IGnssNavigationMessage::GnssNavigationMessageStatus result =
- gnssNavigationMessageIface->setCallback(gnssNavigationMessageCbIface);
+ auto result = gnssNavigationMessageIface->setCallback(gnssNavigationMessageCbIface);
+ if (!checkHidlReturn(result, "IGnssNavigationMessage setCallback() failed.")) {
+ return JNI_FALSE;
+ }
- if (result != IGnssNavigationMessage::GnssNavigationMessageStatus::SUCCESS) {
- ALOGE("An error has been found in %s: %d", __FUNCTION__, static_cast<int32_t>(result));
+ IGnssNavigationMessage::GnssNavigationMessageStatus initRet = result;
+ if (initRet != IGnssNavigationMessage::GnssNavigationMessageStatus::SUCCESS) {
+ ALOGE("An error has been found in %s: %d", __FUNCTION__, static_cast<int32_t>(initRet));
return JNI_FALSE;
}
@@ -2756,43 +2759,35 @@
JNIEnv* env,
jobject obj) {
if (gnssNavigationMessageIface == nullptr) {
- ALOGE("Navigation Message interface is not available.");
+ ALOGE("%s: IGnssNavigationMessage interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssNavigationMessageIface->close();
- return boolToJbool(result.isOk());
+ return checkHidlReturn(result, "IGnssNavigationMessage close() failed.");
}
static jboolean android_location_GnssConfiguration_set_emergency_supl_pdn(JNIEnv*,
jobject,
jint emergencySuplPdn) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setEmergencySuplPdn(emergencySuplPdn);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setEmergencySuplPdn() failed.");
}
static jboolean android_location_GnssConfiguration_set_supl_version(JNIEnv*,
jobject,
jint version) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setSuplVersion(version);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setSuplVersion() failed.");
}
static jboolean android_location_GnssConfiguration_set_supl_es(JNIEnv*,
@@ -2804,32 +2799,24 @@
}
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setSuplEs(suplEs);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setSuplEs() failed.");
}
static jboolean android_location_GnssConfiguration_set_supl_mode(JNIEnv*,
jobject,
jint mode) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setSuplMode(mode);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setSuplMode() failed.");
}
static jboolean android_location_GnssConfiguration_set_gps_lock(JNIEnv*,
@@ -2841,55 +2828,42 @@
}
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setGpsLock(gpsLock);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setGpsLock() failed.");
}
static jboolean android_location_GnssConfiguration_set_lpp_profile(JNIEnv*,
jobject,
jint lppProfile) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setLppProfile(lppProfile);
-
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setLppProfile() failed.");
}
static jboolean android_location_GnssConfiguration_set_gnss_pos_protocol_select(JNIEnv*,
jobject,
jint gnssPosProtocol) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
auto result = gnssConfigurationIface->setGlonassPositioningProtocol(gnssPosProtocol);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setGlonassPositioningProtocol() failed.");
}
static jboolean android_location_GnssConfiguration_set_satellite_blacklist(
JNIEnv* env, jobject, jintArray constellations, jintArray sv_ids) {
if (gnssConfigurationIface_V1_1 == nullptr) {
- ALOGI("No GNSS Satellite Blacklist interface available");
+ ALOGI("IGnssConfiguration interface does not support satellite blacklist.");
return JNI_FALSE;
}
@@ -2920,17 +2894,13 @@
}
auto result = gnssConfigurationIface_V1_1->setBlacklist(sources);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setBlacklist() failed.");
}
static jboolean android_location_GnssConfiguration_set_es_extension_sec(
JNIEnv*, jobject, jint emergencyExtensionSeconds) {
if (gnssConfigurationIface == nullptr) {
- ALOGE("no GNSS configuration interface available");
+ ALOGE("%s: IGnssConfiguration interface not available.", __func__);
return JNI_FALSE;
}
@@ -2941,11 +2911,7 @@
}
auto result = gnssConfigurationIface_V2_0->setEsExtensionSec(emergencyExtensionSeconds);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssConfiguration setEsExtensionSec() failed.");
}
static jint android_location_GnssBatchingProvider_get_batch_size(JNIEnv*, jclass) {
@@ -2953,20 +2919,22 @@
return 0; // batching not supported, size = 0
}
auto result = gnssBatchingIface->getBatchSize();
- if (result.isOk()) {
- return static_cast<jint>(result);
- } else {
+ if (!checkHidlReturn(result, "IGnssBatching getBatchSize() failed.")) {
return 0; // failure in binder, don't support batching
}
+
+ return static_cast<jint>(result);
}
static jboolean android_location_GnssBatchingProvider_init_batching(JNIEnv*, jclass) {
if (gnssBatchingIface_V2_0 != nullptr) {
sp<IGnssBatchingCallback_V2_0> gnssBatchingCbIface_V2_0 = new GnssBatchingCallback_V2_0();
- return static_cast<jboolean>(gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0));
+ auto result = gnssBatchingIface_V2_0->init_2_0(gnssBatchingCbIface_V2_0);
+ return checkHidlReturn(result, "IGnssBatching init_2_0() failed.");
} else if (gnssBatchingIface != nullptr) {
sp<IGnssBatchingCallback_V1_0> gnssBatchingCbIface_V1_0 = new GnssBatchingCallback_V1_0();
- return static_cast<jboolean>(gnssBatchingIface->init(gnssBatchingCbIface_V1_0));
+ auto result = gnssBatchingIface->init(gnssBatchingCbIface_V1_0);
+ return checkHidlReturn(result, "IGnssBatching init() failed.");
} else {
return JNI_FALSE; // batching not supported
}
@@ -2976,7 +2944,8 @@
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
- gnssBatchingIface->cleanup();
+ auto result = gnssBatchingIface->cleanup();
+ checkHidlReturn(result, "IGnssBatching cleanup() failed.");
}
static jboolean android_location_GnssBatchingProvider_start_batch(JNIEnv*, jclass,
@@ -2993,29 +2962,30 @@
options.flags = 0;
}
- return static_cast<jboolean>(gnssBatchingIface->start(options));
+ auto result = gnssBatchingIface->start(options);
+ return checkHidlReturn(result, "IGnssBatching start() failed.");
}
static void android_location_GnssBatchingProvider_flush_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return; // batching not supported
}
-
- gnssBatchingIface->flush();
+ auto result = gnssBatchingIface->flush();
+ checkHidlReturn(result, "IGnssBatching flush() failed.");
}
static jboolean android_location_GnssBatchingProvider_stop_batch(JNIEnv*, jclass) {
if (gnssBatchingIface == nullptr) {
return JNI_FALSE; // batching not supported
}
-
- return gnssBatchingIface->stop();
+ auto result = gnssBatchingIface->stop();
+ return checkHidlReturn(result, "IGnssBatching stop() failed.");
}
static jboolean android_location_GnssVisibilityControl_enable_nfw_location_access(
JNIEnv* env, jobject, jobjectArray proxyApps) {
if (gnssVisibilityControlIface == nullptr) {
- ALOGI("No GNSS Visibility Control interface available");
+ ALOGI("IGnssVisibilityControl interface not available.");
return JNI_FALSE;
}
@@ -3028,11 +2998,7 @@
}
auto result = gnssVisibilityControlIface->enableNfwLocationAccess(hidlProxyApps);
- if (result.isOk()) {
- return result;
- } else {
- return JNI_FALSE;
- }
+ return checkHidlReturn(result, "IGnssVisibilityControl enableNfwLocationAccess() failed.");
}
static const JNINativeMethod sMethods[] = {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c7e1518..48921ea 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4119,9 +4119,8 @@
@Override
public boolean isSeparateProfileChallengeAllowed(int userHandle) {
- if (!isCallerWithSystemUid()) {
- throw new SecurityException("Caller must be system");
- }
+ enforceSystemCaller("query separate challenge support");
+
ComponentName profileOwner = getProfileOwner(userHandle);
// Profile challenge is supported on N or newer release.
return profileOwner != null &&
@@ -5943,10 +5942,7 @@
@Override
public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias,
final IBinder response) {
- // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers.
- if (!isCallerWithSystemUid()) {
- return;
- }
+ enforceSystemCaller("choose private key alias");
final UserHandle caller = mInjector.binderGetCallingUserHandle();
// If there is a profile owner, redirect to that; otherwise query the device owner.
@@ -6044,7 +6040,7 @@
*
* @param who the device owner or profile owner.
* @param delegatePackage the name of the delegate package.
- * @param scopes the list of delegation scopes to be given to the delegate package.
+ * @param scopeList the list of delegation scopes to be given to the delegate package.
*/
@Override
public void setDelegatedScopes(ComponentName who, String delegatePackage,
@@ -6677,36 +6673,28 @@
if (!mHasFeature || !mLockPatternUtils.hasSecureLockScreen()) {
return;
}
- enforceFullCrossUsersPermission(userId);
+ enforceSystemCaller("report password change");
// Managed Profile password can only be changed when it has a separate challenge.
if (!isSeparateProfileChallengeEnabled(userId)) {
enforceNotManagedProfile(userId, "set the active password");
}
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.BIND_DEVICE_ADMIN, null);
-
DevicePolicyData policy = getUserData(userId);
- long ident = mInjector.binderClearCallingIdentity();
- try {
- synchronized (getLockObject()) {
- policy.mFailedPasswordAttempts = 0;
- updatePasswordValidityCheckpointLocked(userId, /* parent */ false);
- saveSettingsLocked(userId);
- updatePasswordExpirationsLocked(userId);
- setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false);
+ synchronized (getLockObject()) {
+ policy.mFailedPasswordAttempts = 0;
+ updatePasswordValidityCheckpointLocked(userId, /* parent */ false);
+ saveSettingsLocked(userId);
+ updatePasswordExpirationsLocked(userId);
+ setExpirationAlarmCheckLocked(mContext, userId, /* parent */ false);
- // Send a broadcast to each profile using this password as its primary unlock.
- sendAdminCommandForLockscreenPoliciesLocked(
- DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
- DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userId);
- }
- removeCaApprovalsIfNeeded(userId);
- } finally {
- mInjector.binderRestoreCallingIdentity(ident);
+ // Send a broadcast to each profile using this password as its primary unlock.
+ sendAdminCommandForLockscreenPoliciesLocked(
+ DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
+ DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userId);
}
+ removeCaApprovalsIfNeeded(userId);
}
/**
@@ -8787,8 +8775,7 @@
private void ensureCallerPackage(@Nullable String packageName) {
if (packageName == null) {
- Preconditions.checkState(isCallerWithSystemUid(),
- "Only caller can omit package name");
+ enforceSystemCaller("omit package name");
} else {
final int callingUid = mInjector.binderGetCallingUid();
final int userId = mInjector.userHandleGetCallingUserId();
@@ -9100,10 +9087,8 @@
@Override
public ComponentName getRestrictionsProvider(int userHandle) {
+ enforceSystemCaller("query the permission provider");
synchronized (getLockObject()) {
- if (!isCallerWithSystemUid()) {
- throw new SecurityException("Only the system can query the permission provider");
- }
DevicePolicyData userData = getUserData(userHandle);
return userData != null ? userData.mRestrictionsProvider : null;
}
@@ -9368,10 +9353,8 @@
}
Preconditions.checkNotNull(who, "ComponentName is null");
Preconditions.checkStringNotEmpty(packageName, "packageName is null");
- if (!isCallerWithSystemUid()){
- throw new SecurityException(
- "Only the system can query if an accessibility service is disabled by admin");
- }
+ enforceSystemCaller("query if an accessibility service is disabled by admin");
+
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
if (admin == null) {
@@ -9531,10 +9514,8 @@
}
Preconditions.checkNotNull(who, "ComponentName is null");
Preconditions.checkStringNotEmpty(packageName, "packageName is null");
- if (!isCallerWithSystemUid()) {
- throw new SecurityException(
- "Only the system can query if an input method is disabled by admin");
- }
+ enforceSystemCaller("query if an input method is disabled by admin");
+
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
if (admin == null) {
@@ -9591,10 +9572,8 @@
}
Preconditions.checkStringNotEmpty(packageName, "packageName is null or empty");
- if (!isCallerWithSystemUid()) {
- throw new SecurityException(
- "Only the system can query if a notification listener service is permitted");
- }
+ enforceSystemCaller("query if a notification listener service is permitted");
+
synchronized (getLockObject()) {
ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
if (profileOwner == null || profileOwner.permittedNotificationListeners == null) {
@@ -9606,6 +9585,12 @@
}
}
+ private void enforceSystemCaller(String action) {
+ if (!isCallerWithSystemUid()) {
+ throw new SecurityException("Only the system can " + action);
+ }
+ }
+
private void maybeSendAdminEnabledBroadcastLocked(int userHandle) {
DevicePolicyData policyData = getUserData(userHandle);
if (policyData.mAdminBroadcastPending) {
@@ -10760,9 +10745,7 @@
@Override
public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) {
- if (!isCallerWithSystemUid()) {
- throw new SecurityException("notifyLockTaskModeChanged can only be called by system");
- }
+ enforceSystemCaller("call notifyLockTaskModeChanged");
synchronized (getLockObject()) {
final DevicePolicyData policy = getUserData(userHandle);
@@ -12119,8 +12102,7 @@
final ApplicationInfo ai;
try {
ai = mIPackageManager.getApplicationInfo(packageName, 0, userId);
- final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion;
- return targetSdkVersion;
+ return ai == null ? 0 : ai.targetSdkVersion;
} catch (RemoteException e) {
// Shouldn't happen
return 0;
@@ -12169,8 +12151,7 @@
Preconditions.checkNotNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForUidLocked(who,
- mInjector.binderGetCallingUid());
+ ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
if (!TextUtils.equals(admin.shortSupportMessage, message)) {
admin.shortSupportMessage = message;
saveSettingsLocked(userHandle);
@@ -12189,8 +12170,7 @@
}
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForUidLocked(who,
- mInjector.binderGetCallingUid());
+ ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
return admin.shortSupportMessage;
}
}
@@ -12203,8 +12183,7 @@
Preconditions.checkNotNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForUidLocked(who,
- mInjector.binderGetCallingUid());
+ ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
if (!TextUtils.equals(admin.longSupportMessage, message)) {
admin.longSupportMessage = message;
saveSettingsLocked(userHandle);
@@ -12223,8 +12202,7 @@
}
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (getLockObject()) {
- ActiveAdmin admin = getActiveAdminForUidLocked(who,
- mInjector.binderGetCallingUid());
+ ActiveAdmin admin = getActiveAdminForUidLocked(who, mInjector.binderGetCallingUid());
return admin.longSupportMessage;
}
}
@@ -12235,9 +12213,8 @@
return null;
}
Preconditions.checkNotNull(who, "ComponentName is null");
- if (!isCallerWithSystemUid()) {
- throw new SecurityException("Only the system can query support message for user");
- }
+ enforceSystemCaller("query support message for user");
+
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
if (admin != null) {
@@ -12253,9 +12230,8 @@
return null;
}
Preconditions.checkNotNull(who, "ComponentName is null");
- if (!isCallerWithSystemUid()) {
- throw new SecurityException("Only the system can query support message for user");
- }
+ enforceSystemCaller("query support message for user");
+
synchronized (getLockObject()) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
if (admin != null) {
@@ -12462,10 +12438,8 @@
if (!mHasFeature) {
return false;
}
- if (!isCallerWithSystemUid()) {
- throw new SecurityException(
- "Only the system can query restricted pkgs for a specific user");
- }
+ enforceSystemCaller("query restricted pkgs for a specific user");
+
synchronized (getLockObject()) {
final ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userId);
if (admin != null && admin.meteredDisabledPackages != null) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 47539d3..a04875f 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1449,16 +1449,13 @@
}
t.traceEnd();
- final boolean useNewTimeServices = true;
- if (useNewTimeServices) {
- t.traceBegin("StartTimeDetectorService");
- try {
- mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
- } catch (Throwable e) {
- reportWtf("starting StartTimeDetectorService service", e);
- }
- t.traceEnd();
+ t.traceBegin("StartTimeDetectorService");
+ try {
+ mSystemServiceManager.startService(TIME_DETECTOR_SERVICE_CLASS);
+ } catch (Throwable e) {
+ reportWtf("starting StartTimeDetectorService service", e);
}
+ t.traceEnd();
if (!isWatch) {
t.traceBegin("StartSearchManagerService");
@@ -1656,12 +1653,7 @@
if (!isWatch && !disableNetworkTime) {
t.traceBegin("StartNetworkTimeUpdateService");
try {
- if (useNewTimeServices) {
- networkTimeUpdater = new NewNetworkTimeUpdateService(context);
- } else {
- networkTimeUpdater = new OldNetworkTimeUpdateService(context);
- }
- Slog.d(TAG, "Using networkTimeUpdater class=" + networkTimeUpdater.getClass());
+ networkTimeUpdater = new NetworkTimeUpdateServiceImpl(context);
ServiceManager.addService("network_time_update_service", networkTimeUpdater);
} catch (Throwable e) {
reportWtf("starting NetworkTimeUpdate service", e);
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
index 748c23a..22cd3d3 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/JobSchedulerServiceTest.java
@@ -25,6 +25,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.job.JobSchedulerService.ACTIVE_INDEX;
+import static com.android.server.job.JobSchedulerService.RARE_INDEX;
import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static org.junit.Assert.assertEquals;
@@ -662,4 +664,86 @@
assertEquals(nextWindowStartTime, rescheduledJob.getEarliestRunTime());
assertEquals(nextWindowEndTime, rescheduledJob.getLatestRunTimeElapsed());
}
+
+ /** Tests that rare job batching works as expected. */
+ @Test
+ public void testRareJobBatching() {
+ spyOn(mService);
+ doNothing().when(mService).evaluateControllerStatesLocked(any());
+ doNothing().when(mService).noteJobsPending(any());
+ doReturn(true).when(mService).isReadyToBeExecutedLocked(any());
+ advanceElapsedClock(24 * HOUR_IN_MILLIS);
+
+ JobSchedulerService.MaybeReadyJobQueueFunctor maybeQueueFunctor =
+ mService.new MaybeReadyJobQueueFunctor();
+ mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT = 5;
+ mService.mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS = HOUR_IN_MILLIS;
+ mService.mConstants.MIN_CONNECTIVITY_COUNT = 2;
+ mService.mConstants.MIN_READY_JOBS_COUNT = 1;
+
+ JobStatus job = createJobStatus(
+ "testRareJobBatching",
+ createJobInfo().setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ job.setStandbyBucket(RARE_INDEX);
+
+ // Not enough RARE jobs to run.
+ mService.mPendingJobs.clear();
+ maybeQueueFunctor.reset();
+ for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT / 2; ++i) {
+ maybeQueueFunctor.accept(job);
+ assertEquals(i + 1, maybeQueueFunctor.forceBatchedCount);
+ assertEquals(i + 1, maybeQueueFunctor.runnableJobs.size());
+ assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
+ }
+ maybeQueueFunctor.postProcess();
+ assertEquals(0, mService.mPendingJobs.size());
+
+ // Enough RARE jobs to run.
+ mService.mPendingJobs.clear();
+ maybeQueueFunctor.reset();
+ for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT; ++i) {
+ maybeQueueFunctor.accept(job);
+ assertEquals(i + 1, maybeQueueFunctor.forceBatchedCount);
+ assertEquals(i + 1, maybeQueueFunctor.runnableJobs.size());
+ assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
+ }
+ maybeQueueFunctor.postProcess();
+ assertEquals(5, mService.mPendingJobs.size());
+
+ // Not enough RARE jobs to run, but a non-batched job saves the day.
+ mService.mPendingJobs.clear();
+ maybeQueueFunctor.reset();
+ JobStatus activeJob = createJobStatus(
+ "testRareJobBatching",
+ createJobInfo().setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY));
+ activeJob.setStandbyBucket(ACTIVE_INDEX);
+ for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT / 2; ++i) {
+ maybeQueueFunctor.accept(job);
+ assertEquals(i + 1, maybeQueueFunctor.forceBatchedCount);
+ assertEquals(i + 1, maybeQueueFunctor.runnableJobs.size());
+ assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
+ }
+ maybeQueueFunctor.accept(activeJob);
+ maybeQueueFunctor.postProcess();
+ assertEquals(3, mService.mPendingJobs.size());
+
+ // Not enough RARE jobs to run, but an old RARE job saves the day.
+ mService.mPendingJobs.clear();
+ maybeQueueFunctor.reset();
+ JobStatus oldRareJob = createJobStatus("testRareJobBatching", createJobInfo());
+ oldRareJob.setStandbyBucket(RARE_INDEX);
+ final long oldBatchTime = sElapsedRealtimeClock.millis()
+ - 2 * mService.mConstants.MAX_NON_ACTIVE_JOB_BATCH_DELAY_MS;
+ oldRareJob.setFirstForceBatchedTimeElapsed(oldBatchTime);
+ for (int i = 0; i < mService.mConstants.MIN_READY_NON_ACTIVE_JOBS_COUNT / 2; ++i) {
+ maybeQueueFunctor.accept(job);
+ assertEquals(i + 1, maybeQueueFunctor.forceBatchedCount);
+ assertEquals(i + 1, maybeQueueFunctor.runnableJobs.size());
+ assertEquals(sElapsedRealtimeClock.millis(), job.getFirstForceBatchedTimeElapsed());
+ }
+ maybeQueueFunctor.accept(oldRareJob);
+ assertEquals(oldBatchTime, oldRareJob.getFirstForceBatchedTimeElapsed());
+ maybeQueueFunctor.postProcess();
+ assertEquals(3, mService.mPendingJobs.size());
+ }
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
index 823cc66..328e8f4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/ConnectivityControllerTest.java
@@ -59,6 +59,7 @@
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobSchedulerService.Constants;
+import com.android.server.job.JobServiceContext;
import com.android.server.net.NetworkPolicyManagerInternal;
import org.junit.Before;
@@ -138,22 +139,53 @@
DataUnit.MEBIBYTES.toBytes(1))
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ final ConnectivityController controller = new ConnectivityController(mService);
+ when(mService.getMaxJobExecutionTimeMs(any()))
+ .thenReturn(JobServiceContext.EXECUTING_TIMESLICE_MILLIS);
+
// Slow network is too slow
- assertFalse(ConnectivityController.isSatisfied(createJobStatus(job), net,
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilities().setLinkUpstreamBandwidthKbps(1)
.setLinkDownstreamBandwidthKbps(1), mConstants));
// Slow downstream
- assertFalse(ConnectivityController.isSatisfied(createJobStatus(job), net,
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilities().setLinkUpstreamBandwidthKbps(1024)
.setLinkDownstreamBandwidthKbps(1), mConstants));
// Slow upstream
- assertFalse(ConnectivityController.isSatisfied(createJobStatus(job), net,
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
createCapabilities().setLinkUpstreamBandwidthKbps(1)
.setLinkDownstreamBandwidthKbps(1024), mConstants));
// Fast network looks great
- assertTrue(ConnectivityController.isSatisfied(createJobStatus(job), net,
+ assertTrue(controller.isSatisfied(createJobStatus(job), net,
createCapabilities().setLinkUpstreamBandwidthKbps(1024)
.setLinkDownstreamBandwidthKbps(1024), mConstants));
+ // Slow network still good given time
+ assertTrue(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilities().setLinkUpstreamBandwidthKbps(130)
+ .setLinkDownstreamBandwidthKbps(130), mConstants));
+
+ when(mService.getMaxJobExecutionTimeMs(any())).thenReturn(60_000L);
+
+ // Slow network is too slow
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilities().setLinkUpstreamBandwidthKbps(1)
+ .setLinkDownstreamBandwidthKbps(1), mConstants));
+ // Slow downstream
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilities().setLinkUpstreamBandwidthKbps(137)
+ .setLinkDownstreamBandwidthKbps(1), mConstants));
+ // Slow upstream
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilities().setLinkUpstreamBandwidthKbps(1)
+ .setLinkDownstreamBandwidthKbps(137), mConstants));
+ // Network good enough
+ assertTrue(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilities().setLinkUpstreamBandwidthKbps(137)
+ .setLinkDownstreamBandwidthKbps(137), mConstants));
+ // Network slightly too slow given reduced time
+ assertFalse(controller.isSatisfied(createJobStatus(job), net,
+ createCapabilities().setLinkUpstreamBandwidthKbps(130)
+ .setLinkDownstreamBandwidthKbps(130), mConstants));
}
@Test
@@ -166,21 +198,23 @@
final JobStatus early = createJobStatus(job, now - 1000, now + 2000);
final JobStatus late = createJobStatus(job, now - 2000, now + 1000);
+ final ConnectivityController controller = new ConnectivityController(mService);
+
// Uncongested network is whenever
{
final Network net = new Network(101);
final NetworkCapabilities caps = createCapabilities()
.addCapability(NET_CAPABILITY_NOT_CONGESTED);
- assertTrue(ConnectivityController.isSatisfied(early, net, caps, mConstants));
- assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(early, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(late, net, caps, mConstants));
}
// Congested network is more selective
{
final Network net = new Network(101);
final NetworkCapabilities caps = createCapabilities();
- assertFalse(ConnectivityController.isSatisfied(early, net, caps, mConstants));
- assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(early, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(late, net, caps, mConstants));
}
}
@@ -198,16 +232,18 @@
final JobStatus earlyPrefetch = createJobStatus(job, now - 1000, now + 2000);
final JobStatus latePrefetch = createJobStatus(job, now - 2000, now + 1000);
+ final ConnectivityController controller = new ConnectivityController(mService);
+
// Unmetered network is whenever
{
final Network net = new Network(101);
final NetworkCapabilities caps = createCapabilities()
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_METERED);
- assertTrue(ConnectivityController.isSatisfied(early, net, caps, mConstants));
- assertTrue(ConnectivityController.isSatisfied(late, net, caps, mConstants));
- assertTrue(ConnectivityController.isSatisfied(earlyPrefetch, net, caps, mConstants));
- assertTrue(ConnectivityController.isSatisfied(latePrefetch, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(early, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(late, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(earlyPrefetch, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(latePrefetch, net, caps, mConstants));
}
// Metered network is only when prefetching and late
@@ -215,10 +251,10 @@
final Network net = new Network(101);
final NetworkCapabilities caps = createCapabilities()
.addCapability(NET_CAPABILITY_NOT_CONGESTED);
- assertFalse(ConnectivityController.isSatisfied(early, net, caps, mConstants));
- assertFalse(ConnectivityController.isSatisfied(late, net, caps, mConstants));
- assertFalse(ConnectivityController.isSatisfied(earlyPrefetch, net, caps, mConstants));
- assertTrue(ConnectivityController.isSatisfied(latePrefetch, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(early, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(late, net, caps, mConstants));
+ assertFalse(controller.isSatisfied(earlyPrefetch, net, caps, mConstants));
+ assertTrue(controller.isSatisfied(latePrefetch, net, caps, mConstants));
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index 9f31289..2d70231 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -28,6 +28,7 @@
import static com.android.server.job.JobSchedulerService.NEVER_INDEX;
import static com.android.server.job.JobSchedulerService.RARE_INDEX;
import static com.android.server.job.JobSchedulerService.WORKING_INDEX;
+import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -73,6 +74,7 @@
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.JobSchedulerService.Constants;
+import com.android.server.job.JobServiceContext;
import com.android.server.job.JobStore;
import com.android.server.job.controllers.QuotaController.ExecutionStats;
import com.android.server.job.controllers.QuotaController.TimingSession;
@@ -975,6 +977,37 @@
assertEquals(expectedStats, newStatsRare);
}
+ @Test
+ public void testGetMaxJobExecutionTimeLocked() {
+ mQuotaController.saveTimingSession(0, SOURCE_PACKAGE,
+ createTimingSession(sElapsedRealtimeClock.millis() - (6 * MINUTE_IN_MILLIS),
+ 3 * MINUTE_IN_MILLIS, 5));
+ JobStatus job = createJobStatus("testGetMaxJobExecutionTimeLocked", 0);
+ job.setStandbyBucket(RARE_INDEX);
+
+ setCharging();
+ assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+
+ setDischarging();
+ setProcessState(ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+ assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+
+ // Top-started job
+ setProcessState(ActivityManager.PROCESS_STATE_TOP);
+ mQuotaController.maybeStartTrackingJobLocked(job, null);
+ mQuotaController.prepareForExecutionLocked(job);
+ setProcessState(ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND);
+ assertEquals(JobServiceContext.EXECUTING_TIMESLICE_MILLIS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked((job)));
+ mQuotaController.maybeStopTrackingJobLocked(job, null, false);
+
+ setProcessState(ActivityManager.PROCESS_STATE_RECEIVER);
+ assertEquals(7 * MINUTE_IN_MILLIS,
+ mQuotaController.getMaxJobExecutionTimeMsLocked(job));
+ }
+
/**
* Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket
* window.
@@ -1892,6 +1925,16 @@
assertEquals(1, mQuotaController.getBucketMaxSessionCounts()[RARE_INDEX]);
assertEquals(0, mQuotaController.getTimingSessionCoalescingDurationMs());
+ // Invalid configurations.
+ // In_QUOTA_BUFFER should never be greater than ALLOWED_TIME_PER_PERIOD
+ mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 2 * MINUTE_IN_MILLIS;
+ mQcConstants.IN_QUOTA_BUFFER_MS = 5 * MINUTE_IN_MILLIS;
+
+ mQcConstants.updateConstants();
+
+ assertTrue(mQuotaController.getInQuotaBufferMs()
+ <= mQuotaController.getAllowedTimePerPeriodMs());
+
// Test larger than a day. Controller should cap at one day.
mQcConstants.ALLOWED_TIME_PER_PERIOD_MS = 25 * HOUR_IN_MILLIS;
mQcConstants.IN_QUOTA_BUFFER_MS = 25 * HOUR_IN_MILLIS;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 8fbb7f5..efbae2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -31,9 +31,9 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING;
-import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.ActivityState.STARTED;
import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
@@ -166,7 +166,13 @@
final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build();
mStack.mTranslucentActivityWaiting = topActivity;
mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
- assertTrue(mActivity.isState(PAUSED));
+ assertTrue(mActivity.isState(STARTED));
+
+ mStack.mTranslucentActivityWaiting = null;
+ topActivity.changeWindowTranslucency(false);
+ mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque");
+ mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */);
+ assertTrue(mActivity.isState(STARTED));
}
private void ensureActivityConfiguration() {
@@ -442,7 +448,7 @@
topActivity.changeWindowTranslucency(false);
mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
mActivity.makeClientVisible();
- assertEquals(PAUSED, mActivity.getState());
+ assertEquals(STARTED, mActivity.getState());
}
@Test
diff --git a/tests/JobSchedulerPerfTests/Android.bp b/tests/JobSchedulerPerfTests/Android.bp
new file mode 100644
index 0000000..2230807
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/Android.bp
@@ -0,0 +1,25 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "JobSchedulerPerfTests",
+ srcs: ["src/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "apct-perftests-utils",
+ "services",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/tests/JobSchedulerPerfTests/AndroidManifest.xml b/tests/JobSchedulerPerfTests/AndroidManifest.xml
new file mode 100644
index 0000000..39e751c
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.perftests.job">
+ <uses-sdk
+ android:minSdkVersion="21" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.perftests.job"/>
+</manifest>
diff --git a/tests/JobSchedulerPerfTests/AndroidTest.xml b/tests/JobSchedulerPerfTests/AndroidTest.xml
new file mode 100644
index 0000000..ca4b6c8
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs JobScheduler Performance Tests">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="JobSchedulerPerfTests.apk"/>
+ <option name="cleanup-apks" value="true"/>
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct"/>
+ <option name="test-tag" value="JobSchedulerPerfTests"/>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="com.android.frameworks.perftests.job"/>
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+ </test>
+</configuration>
diff --git a/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java b/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
new file mode 100644
index 0000000..e956be3
--- /dev/null
+++ b/tests/JobSchedulerPerfTests/src/com/android/frameworks/perftests/job/JobStorePerfTests.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.frameworks.perftests.job;
+
+
+import android.app.job.JobInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.SystemClock;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.PerfManualStatusReporter;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.job.JobStore;
+import com.android.server.job.JobStore.JobSet;
+import com.android.server.job.controllers.JobStatus;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class JobStorePerfTests {
+ private static final String SOURCE_PACKAGE = "com.android.frameworks.perftests.job";
+ private static final int SOURCE_USER_ID = 0;
+ private static final int CALLING_UID = 10079;
+
+ private static Context sContext;
+ private static File sTestDir;
+ private static JobStore sJobStore;
+
+ private static List<JobStatus> sFewJobs = new ArrayList<>();
+ private static List<JobStatus> sManyJobs = new ArrayList<>();
+
+ @Rule
+ public PerfManualStatusReporter mPerfManualStatusReporter = new PerfManualStatusReporter();
+
+ @BeforeClass
+ public static void setUpOnce() {
+ sContext = InstrumentationRegistry.getTargetContext();
+ sTestDir = new File(sContext.getFilesDir(), "JobStorePerfTests");
+ sJobStore = JobStore.initAndGetForTesting(sContext, sTestDir);
+
+ for (int i = 0; i < 50; i++) {
+ sFewJobs.add(createJobStatus("fewJobs", i));
+ }
+ for (int i = 0; i < 500; i++) {
+ sManyJobs.add(createJobStatus("manyJobs", i));
+ }
+ }
+
+ @AfterClass
+ public static void tearDownOnce() {
+ sTestDir.deleteOnExit();
+ }
+
+ private void runPersistedJobWriting(List<JobStatus> jobList) {
+ final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
+
+ long elapsedTimeNs = 0;
+ while (benchmarkState.keepRunning(elapsedTimeNs)) {
+ sJobStore.clear();
+ for (JobStatus job : jobList) {
+ sJobStore.add(job);
+ }
+ sJobStore.waitForWriteToCompleteForTesting(10_000);
+
+ final long startTime = SystemClock.elapsedRealtimeNanos();
+ sJobStore.writeStatusToDiskForTesting();
+ final long endTime = SystemClock.elapsedRealtimeNanos();
+ elapsedTimeNs = endTime - startTime;
+ }
+ }
+
+ @Test
+ public void testPersistedJobWriting_fewJobs() {
+ runPersistedJobWriting(sFewJobs);
+ }
+
+ @Test
+ public void testPersistedJobWriting_manyJobs() {
+ runPersistedJobWriting(sManyJobs);
+ }
+
+ private void runPersistedJobReading(List<JobStatus> jobList, boolean rtcIsGood) {
+ final ManualBenchmarkState benchmarkState = mPerfManualStatusReporter.getBenchmarkState();
+
+ long elapsedTimeNs = 0;
+ while (benchmarkState.keepRunning(elapsedTimeNs)) {
+ sJobStore.clear();
+ for (JobStatus job : jobList) {
+ sJobStore.add(job);
+ }
+ sJobStore.waitForWriteToCompleteForTesting(10_000);
+
+ JobSet jobSet = new JobSet();
+
+ final long startTime = SystemClock.elapsedRealtimeNanos();
+ sJobStore.readJobMapFromDisk(jobSet, rtcIsGood);
+ final long endTime = SystemClock.elapsedRealtimeNanos();
+ elapsedTimeNs = endTime - startTime;
+ }
+ }
+
+ @Test
+ public void testPersistedJobReading_fewJobs_goodRTC() {
+ runPersistedJobReading(sFewJobs, true);
+ }
+
+ @Test
+ public void testPersistedJobReading_fewJobs_badRTC() {
+ runPersistedJobReading(sFewJobs, false);
+ }
+
+ @Test
+ public void testPersistedJobReading_manyJobs_goodRTC() {
+ runPersistedJobReading(sManyJobs, true);
+ }
+
+ @Test
+ public void testPersistedJobReading_manyJobs_badRTC() {
+ runPersistedJobReading(sManyJobs, false);
+ }
+
+ private static JobStatus createJobStatus(String testTag, int jobId) {
+ JobInfo jobInfo = new JobInfo.Builder(jobId,
+ new ComponentName(sContext, "JobStorePerfTestJobService"))
+ .setPersisted(true)
+ .build();
+ return JobStatus.createFromJobInfo(
+ jobInfo, CALLING_UID, SOURCE_PACKAGE, SOURCE_USER_ID, testTag);
+ }
+}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
index 1f1eac1..db81831 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/StagedRollbackTest.java
@@ -21,14 +21,19 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.fail;
+
import android.Manifest;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
+import android.text.TextUtils;
import androidx.test.InstrumentationRegistry;
@@ -39,8 +44,7 @@
import com.android.cts.install.lib.Uninstall;
import com.android.cts.rollback.lib.Rollback;
import com.android.cts.rollback.lib.RollbackUtils;
-
-import static org.junit.Assert.fail;
+import com.android.internal.R;
import org.junit.After;
import org.junit.Before;
@@ -59,10 +63,11 @@
@RunWith(JUnit4.class)
public class StagedRollbackTest {
- private static final String TAG = "RollbackTest";
private static final String NETWORK_STACK_CONNECTOR_CLASS =
"android.net.INetworkStackConnector";
+ private static final String MODULE_META_DATA_PACKAGE = getModuleMetadataPackageName();
+
/**
* Adopts common shell permissions needed for rollback tests.
*/
@@ -183,6 +188,21 @@
}
@Test
+ public void installModuleMetadataPackage() throws Exception {
+ resetModuleMetadataPackage();
+ Context context = InstrumentationRegistry.getContext();
+ PackageInfo metadataPackageInfo = context.getPackageManager().getPackageInfo(
+ MODULE_META_DATA_PACKAGE, 0);
+ String metadataApkPath = metadataPackageInfo.applicationInfo.sourceDir;
+ assertThat(metadataApkPath).isNotNull();
+ assertThat(metadataApkPath).isNotEqualTo("");
+
+ runShellCommand("pm install "
+ + "-r --enable-rollback --staged --wait "
+ + metadataApkPath);
+ }
+
+ @Test
public void assertNetworkStackRollbackAvailable() throws Exception {
RollbackManager rm = RollbackUtils.getRollbackManager();
assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
@@ -203,6 +223,20 @@
getNetworkStackPackageName())).isNull();
}
+ @Test
+ public void assertModuleMetadataRollbackAvailable() throws Exception {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ MODULE_META_DATA_PACKAGE)).isNotNull();
+ }
+
+ @Test
+ public void assertModuleMetadataRollbackCommitted() throws Exception {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+ assertThat(getUniqueRollbackInfoForPackage(rm.getRecentlyCommittedRollbacks(),
+ MODULE_META_DATA_PACKAGE)).isNotNull();
+ }
+
private String getNetworkStackPackageName() {
Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
ComponentName comp = intent.resolveSystemService(
@@ -245,4 +279,29 @@
InstallUtils.processUserData(TestApp.A);
Uninstall.packages(TestApp.A);
}
-}
\ No newline at end of file
+
+ @Nullable
+ private static String getModuleMetadataPackageName() {
+ String packageName = InstrumentationRegistry.getContext().getResources().getString(
+ R.string.config_defaultModuleMetadataProvider);
+ if (TextUtils.isEmpty(packageName)) {
+ return null;
+ }
+ return packageName;
+ }
+
+ private void resetModuleMetadataPackage() {
+ RollbackManager rm = RollbackUtils.getRollbackManager();
+
+ assertThat(MODULE_META_DATA_PACKAGE).isNotNull();
+ rm.expireRollbackForPackage(MODULE_META_DATA_PACKAGE);
+
+ assertThat(getUniqueRollbackInfoForPackage(rm.getAvailableRollbacks(),
+ MODULE_META_DATA_PACKAGE)).isNull();
+ }
+
+ private void runShellCommand(String cmd) {
+ InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .executeShellCommand(cmd);
+ }
+}
diff --git a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
index ddef4b9..b2e5a62 100644
--- a/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
+++ b/tests/RollbackTest/StagedRollbackTest/src/com/android/tests/rollback/host/StagedRollbackTest.java
@@ -33,6 +33,8 @@
*/
@RunWith(DeviceJUnit4ClassRunner.class)
public class StagedRollbackTest extends BaseHostJUnit4Test {
+ private static final int NATIVE_CRASHES_THRESHOLD = 5;
+
/**
* Runs the given phase of a test by calling into the device.
* Throws an exception if the test phase fails.
@@ -83,6 +85,29 @@
runPhase("testBadApkOnlyConfirmRollback");
}
+ @Test
+ public void testNativeWatchdogTriggersRollback() throws Exception {
+ //Stage install ModuleMetadata package - this simulates a Mainline module update
+ runPhase("installModuleMetadataPackage");
+
+ // Reboot device to activate staged package
+ getDevice().reboot();
+ getDevice().waitForDeviceAvailable();
+
+ runPhase("assertModuleMetadataRollbackAvailable");
+
+ // crash system_server enough times to trigger a rollback
+ crashProcess("system_server", NATIVE_CRASHES_THRESHOLD);
+
+ // Rollback should be committed automatically now
+ // Give time for rollback to be committed
+ assertTrue(getDevice().waitForDeviceNotAvailable(60000));
+ getDevice().waitForDeviceAvailable();
+
+ // verify rollback committed
+ runPhase("assertModuleMetadataRollbackCommitted");
+ }
+
/**
* Tests failed network health check triggers watchdog staged rollbacks.
*/
@@ -177,4 +202,18 @@
getDevice().reboot();
runPhase("testPreviouslyAbandonedRollbacksCheckUserdataRollback");
}
+
+ private void crashProcess(String processName, int numberOfCrashes) throws Exception {
+ String pid = "";
+ String lastPid = "invalid";
+ for (int i = 0; i < numberOfCrashes; ++i) {
+ // This condition makes sure before we kill the process, the process is running AND
+ // the last crash was finished.
+ while ("".equals(pid) || lastPid.equals(pid)) {
+ pid = getDevice().executeShellCommand("pidof " + processName);
+ }
+ getDevice().executeShellCommand("kill " + pid);
+ lastPid = pid;
+ }
+ }
}
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 135bf90..5260b30 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -3,22 +3,6 @@
//########################################################################
java_defaults {
name: "FrameworksNetTests-jni-defaults",
- static_libs: [
- "FrameworksNetCommonTests",
- "frameworks-base-testutils",
- "framework-protos",
- "androidx.test.rules",
- "mockito-target-minus-junit4",
- "net-tests-utils",
- "platform-test-annotations",
- "services.core",
- "services.net",
- ],
- libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
- ],
jni_libs: [
"ld-android",
"libartbase",
@@ -44,20 +28,20 @@
"libnativehelper",
"libnetdbpf",
"libnetdutils",
+ "libnetworkstatsfactorytestjni",
"libpackagelistparser",
"libpcre2",
"libprocessgroup",
"libselinux",
- "libui",
- "libutils",
- "libvndksupport",
"libtinyxml2",
+ "libui",
"libunwindstack",
+ "libutils",
"libutilscallstack",
+ "libvndksupport",
"libziparchive",
"libz",
"netd_aidl_interface-V2-cpp",
- "libnetworkstatsfactorytestjni",
],
}
@@ -68,4 +52,20 @@
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
+ static_libs: [
+ "androidx.test.rules",
+ "FrameworksNetCommonTests",
+ "frameworks-base-testutils",
+ "framework-protos",
+ "mockito-target-minus-junit4",
+ "net-tests-utils",
+ "platform-test-annotations",
+ "services.core",
+ "services.net",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ "android.test.mock",
+ ],
}
diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp
index ef1ad2c..84ae2b5 100644
--- a/tests/net/smoketest/Android.bp
+++ b/tests/net/smoketest/Android.bp
@@ -14,4 +14,9 @@
defaults: ["FrameworksNetTests-jni-defaults"],
srcs: ["java/SmokeTest.java"],
test_suites: ["device-tests"],
-}
+ static_libs: [
+ "androidx.test.rules",
+ "mockito-target-minus-junit4",
+ "services.core",
+ ],
+}
\ No newline at end of file