Merge "Update clearData flow for notification settings" into qt-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 13add09..9cd42a5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5719,14 +5719,18 @@
if (packages == null) {
break;
}
+
+ List<String> packagesHandled = new ArrayList<>();
+
synchronized (mResourcesManager) {
for (int i = packages.length - 1; i >= 0; i--) {
- WeakReference<LoadedApk> ref = mPackages.get(packages[i]);
+ String packageName = packages[i];
+ WeakReference<LoadedApk> ref = mPackages.get(packageName);
LoadedApk pkgInfo = ref != null ? ref.get() : null;
if (pkgInfo != null) {
hasPkgInfo = true;
} else {
- ref = mResourcePackages.get(packages[i]);
+ ref = mResourcePackages.get(packageName);
pkgInfo = ref != null ? ref.get() : null;
if (pkgInfo != null) {
hasPkgInfo = true;
@@ -5737,8 +5741,8 @@
// Adjust it's internal references to the application info and
// resources.
if (pkgInfo != null) {
+ packagesHandled.add(packageName);
try {
- final String packageName = packages[i];
final ApplicationInfo aInfo =
sPackageManager.getApplicationInfo(
packageName,
@@ -5770,6 +5774,13 @@
}
}
}
+
+ try {
+ getPackageManager().notifyPackagesReplacedReceived(
+ packagesHandled.toArray(new String[0]));
+ } catch (RemoteException ignored) {
+ }
+
break;
}
}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index cf704d5..6ab4657 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -770,4 +770,6 @@
int getRuntimePermissionsVersion(int userId);
void setRuntimePermissionsVersion(int version, int userId);
+
+ void notifyPackagesReplacedReceived(in String[] packages);
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index a51a871..232869d 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -453,14 +453,22 @@
final boolean appIsProfileable = isProfileable(context);
final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
if (appIsDebuggable || appIsProfileable || deviceIsDebuggable) {
+ String debugPackage;
- String debugPackage =
- coreSettings.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
+ if (coreSettings != null) {
+ debugPackage =
+ coreSettings.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
+ } else {
+ ContentResolver contentResolver = context.getContentResolver();
+ debugPackage = Settings.Global.getString(contentResolver,
+ Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
+ }
if ((debugPackage != null) && (!debugPackage.isEmpty())) {
return debugPackage;
}
}
+
return "";
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 3410d8d..44fc45e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -88,6 +88,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
@@ -3567,6 +3568,10 @@
return;
}
pw.println("Current Location Manager state:");
+ pw.print(" Current System Time: "
+ + TimeUtils.logTimeOfDay(System.currentTimeMillis()));
+ pw.println(", Current Elapsed Time: "
+ + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
pw.println(" Current user: " + mCurrentUserId + " " + Arrays.toString(
mCurrentUserProfiles));
pw.println(" Location mode: " + isLocationEnabled());
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 1bcc4c8..a93f218 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -3172,15 +3172,28 @@
@GuardedBy("mService")
void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
+ boolean foundProcess = false;
for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
ProcessRecord r = mLruProcesses.get(i);
if (r.thread != null && (userId == UserHandle.USER_ALL || r.userId == userId)) {
try {
+ for (int index = packages.length - 1; index >= 0 && !foundProcess; index--) {
+ if (packages[index].equals(r.info.packageName)) {
+ foundProcess = true;
+ }
+ }
r.thread.dispatchPackageBroadcast(cmd, packages);
} catch (RemoteException ex) {
}
}
}
+
+ if (!foundProcess) {
+ try {
+ AppGlobals.getPackageManager().notifyPackagesReplacedReceived(packages);
+ } catch (RemoteException ignored) {
+ }
+ }
}
/** Returns the uid's process state or PROCESS_STATE_NONEXISTENT if not running */
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index c5733322..4ce6d91 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -43,7 +43,6 @@
import com.android.internal.annotations.GuardedBy;
-import java.util.ArrayList;
/** @hide */
/*package*/ final class AudioDeviceBroker {
@@ -376,24 +375,29 @@
mAudioService.postAccessoryPlugMediaUnmute(device);
}
- /*package*/ AudioService.VolumeStreamState getStreamState(int streamType) {
- return mAudioService.getStreamState(streamType);
+ /*package*/ int getVssVolumeForDevice(int streamType, int device) {
+ return mAudioService.getVssVolumeForDevice(streamType, device);
}
- /*package*/ ArrayList<AudioService.SetModeDeathHandler> getSetModeDeathHandlers() {
- return mAudioService.mSetModeDeathHandlers;
+ /*package*/ int getModeOwnerPid() {
+ return mAudioService.getModeOwnerPid();
}
/*package*/ int getDeviceForStream(int streamType) {
return mAudioService.getDeviceForStream(streamType);
}
- /*package*/ void setDeviceVolume(AudioService.VolumeStreamState streamState, int device) {
- mAudioService.setDeviceVolume(streamState, device);
+ /*package*/ void postApplyVolumeOnDevice(int streamType, int device, String caller) {
+ mAudioService.postApplyVolumeOnDevice(streamType, device, caller);
}
- /*packages*/ void observeDevicesForAllStreams() {
- mAudioService.observeDevicesForAllStreams();
+ /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
+ String caller) {
+ mAudioService.postSetVolumeIndexOnDevice(streamType, vssVolIndex, device, caller);
+ }
+
+ /*packages*/ void postObserveDevicesForAllStreams() {
+ mAudioService.postObserveDevicesForAllStreams();
}
/*package*/ boolean isInCommunication() {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 91b51b4..f9dbdd5 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -198,14 +198,10 @@
}
}
if (a2dpVolume != -1) {
- AudioService.VolumeStreamState streamState =
- mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC);
- // Convert index to internal representation in VolumeStreamState
- a2dpVolume = a2dpVolume * 10;
- streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
- "onSetA2dpSinkConnectionState");
- mDeviceBroker.setDeviceVolume(
- streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+ mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+ // convert index to internal representation in VolumeStreamState
+ a2dpVolume * 10,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, "onSetA2dpSinkConnectionState");
}
makeA2dpDeviceAvailable(address, BtHelper.getName(btDevice),
"onSetA2dpSinkConnectionState", a2dpCodec);
@@ -302,14 +298,11 @@
if (event == BtHelper.EVENT_ACTIVE_DEVICE_CHANGE) {
// Device is connected
if (a2dpVolume != -1) {
- final AudioService.VolumeStreamState streamState =
- mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC);
- // Convert index to internal representation in VolumeStreamState
- a2dpVolume = a2dpVolume * 10;
- streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+ mDeviceBroker.postSetVolumeIndexOnDevice(AudioSystem.STREAM_MUSIC,
+ // convert index to internal representation in VolumeStreamState
+ a2dpVolume * 10,
+ AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
"onBluetoothA2dpActiveDeviceChange");
- mDeviceBroker.setDeviceVolume(
- streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
}
} else if (event == BtHelper.EVENT_DEVICE_CONFIG_CHANGE) {
if (di.mDeviceCodecFormat != a2dpCodec) {
@@ -352,7 +345,7 @@
}
}
mRoutesObservers.finishBroadcast();
- mDeviceBroker.observeDevicesForAllStreams();
+ mDeviceBroker.postObserveDevicesForAllStreams();
}
private static final int DEVICE_OVERRIDE_A2DP_ROUTE_ON_PLUG =
@@ -655,8 +648,6 @@
int a2dpCodec) {
// enable A2DP before notifying A2DP connection to avoid unnecessary processing in
// audio policy manager
- AudioService.VolumeStreamState streamState =
- mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC);
mDeviceBroker.setBluetoothA2dpOnInt(true, eventSource);
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
AudioSystem.DEVICE_STATE_AVAILABLE, address, name, a2dpCodec);
@@ -727,8 +718,8 @@
@GuardedBy("mConnectedDevices")
private void makeHearingAidDeviceAvailable(String address, String name, String eventSource) {
- final int hearingAidVolIndex = mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC)
- .getIndex(AudioSystem.DEVICE_OUT_HEARING_AID);
+ final int hearingAidVolIndex = mDeviceBroker.getVssVolumeForDevice(AudioSystem.STREAM_MUSIC,
+ AudioSystem.DEVICE_OUT_HEARING_AID);
mDeviceBroker.postSetHearingAidVolumeIndex(hearingAidVolIndex, AudioSystem.STREAM_MUSIC);
AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_HEARING_AID,
@@ -739,9 +730,8 @@
new DeviceInfo(AudioSystem.DEVICE_OUT_HEARING_AID, name,
address, AudioSystem.AUDIO_FORMAT_DEFAULT));
mDeviceBroker.postAccessoryPlugMediaUnmute(AudioSystem.DEVICE_OUT_HEARING_AID);
- mDeviceBroker.setDeviceVolume(
- mDeviceBroker.getStreamState(AudioSystem.STREAM_MUSIC),
- AudioSystem.DEVICE_OUT_HEARING_AID);
+ mDeviceBroker.postApplyVolumeOnDevice(AudioSystem.STREAM_MUSIC,
+ AudioSystem.DEVICE_OUT_HEARING_AID, "makeHearingAidDeviceAvailable");
setCurrentAudioRouteNameIfPossible(name);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 2d00f29..b6879a3 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -258,6 +258,8 @@
private static final int MSG_DISPATCH_AUDIO_SERVER_STATE = 23;
private static final int MSG_ENABLE_SURROUND_FORMATS = 24;
private static final int MSG_UPDATE_RINGER_MODE = 25;
+ private static final int MSG_SET_DEVICE_STREAM_VOLUME = 26;
+ private static final int MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS = 27;
// start of messages handled under wakelock
// these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
// and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
@@ -274,8 +276,8 @@
/** @see VolumeStreamState */
private VolumeStreamState[] mStreamStates;
- /*package*/ VolumeStreamState getStreamState(int stream) {
- return mStreamStates[stream];
+ /*package*/ int getVssVolumeForDevice(int stream, int device) {
+ return mStreamStates[stream].getIndex(device);
}
private SettingsObserver mSettingsObserver;
@@ -2936,7 +2938,21 @@
}
- /*package*/ class SetModeDeathHandler implements IBinder.DeathRecipient {
+ /**
+ * Return the pid of the current audio mode owner
+ * @return 0 if nobody owns the mode
+ */
+ /*package*/ int getModeOwnerPid() {
+ int modeOwnerPid = 0;
+ try {
+ modeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
+ } catch (Exception e) {
+ // nothing to do, modeOwnerPid is not modified
+ }
+ return modeOwnerPid;
+ }
+
+ private class SetModeDeathHandler implements IBinder.DeathRecipient {
private IBinder mCb; // To be notified of client's death
private int mPid;
private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
@@ -4096,8 +4112,14 @@
}
}
+ /*package*/ void postObserveDevicesForAllStreams() {
+ sendMsg(mAudioHandler,
+ MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS,
+ SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/, null /*obj*/,
+ 0 /*delay*/);
+ }
- /*package*/ void observeDevicesForAllStreams() {
+ private void onObserveDevicesForAllStreams() {
observeDevicesForStreams(-1);
}
@@ -4270,7 +4292,7 @@
// 2 mSetModeLock
// 3 mSettingsLock
// 4 VolumeStreamState.class
- public class VolumeStreamState {
+ private class VolumeStreamState {
private final int mStreamType;
private int mIndexMin;
private int mIndexMax;
@@ -4740,6 +4762,74 @@
}
}
+ private static final class DeviceVolumeUpdate {
+ final int mStreamType;
+ final int mDevice;
+ final @NonNull String mCaller;
+ private static final int NO_NEW_INDEX = -2049;
+ private final int mVssVolIndex;
+
+ // Constructor with volume index, meant to cause this volume to be set and applied for the
+ // given stream type on the given device
+ DeviceVolumeUpdate(int streamType, int vssVolIndex, int device, @NonNull String caller) {
+ mStreamType = streamType;
+ mVssVolIndex = vssVolIndex;
+ mDevice = device;
+ mCaller = caller;
+ }
+
+ // Constructor with no volume index, meant to cause re-apply of volume for the given
+ // stream type on the given device
+ DeviceVolumeUpdate(int streamType, int device, @NonNull String caller) {
+ mStreamType = streamType;
+ mVssVolIndex = NO_NEW_INDEX;
+ mDevice = device;
+ mCaller = caller;
+ }
+
+ boolean hasVolumeIndex() {
+ return mVssVolIndex != NO_NEW_INDEX;
+ }
+
+ int getVolumeIndex() throws IllegalStateException {
+ Preconditions.checkState(mVssVolIndex != NO_NEW_INDEX);
+ return mVssVolIndex;
+ }
+ }
+
+ /*package*/ void postSetVolumeIndexOnDevice(int streamType, int vssVolIndex, int device,
+ String caller) {
+ sendMsg(mAudioHandler,
+ MSG_SET_DEVICE_STREAM_VOLUME,
+ SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/,
+ new DeviceVolumeUpdate(streamType, vssVolIndex, device, caller),
+ 0 /*delay*/);
+ }
+
+ /*package*/ void postApplyVolumeOnDevice(int streamType, int device, @NonNull String caller) {
+ sendMsg(mAudioHandler,
+ MSG_SET_DEVICE_STREAM_VOLUME,
+ SENDMSG_QUEUE, 0 /*arg1*/, 0 /*arg2*/,
+ new DeviceVolumeUpdate(streamType, device, caller),
+ 0 /*delay*/);
+ }
+
+ private void onSetVolumeIndexOnDevice(@NonNull DeviceVolumeUpdate update) {
+ synchronized (VolumeStreamState.class) {
+ final VolumeStreamState streamState = mStreamStates[update.mStreamType];
+ if (update.hasVolumeIndex()) {
+ final int index = update.getVolumeIndex();
+ streamState.setIndex(index, update.mDevice, update.mCaller);
+ sVolumeLogger.log(new AudioEventLogger.StringEvent(update.mCaller + " dev:0x"
+ + Integer.toHexString(update.mDevice) + " volIdx:" + index));
+ } else {
+ sVolumeLogger.log(new AudioEventLogger.StringEvent(update.mCaller
+ + " update vol on dev:0x" + Integer.toHexString(update.mDevice)));
+ }
+ setDeviceVolume(streamState, update.mDevice);
+ }
+ }
+
/*package*/ void setDeviceVolume(VolumeStreamState streamState, int device) {
final boolean isAvrcpAbsVolSupported = mDeviceBroker.isAvrcpAbsoluteVolumeSupported();
@@ -5180,6 +5270,14 @@
case MSG_UPDATE_RINGER_MODE:
onUpdateRingerModeServiceInt();
break;
+
+ case MSG_SET_DEVICE_STREAM_VOLUME:
+ onSetVolumeIndexOnDevice((DeviceVolumeUpdate) msg.obj);
+ break;
+
+ case MSG_OBSERVE_DEVICES_FOR_ALL_STREAMS:
+ onObserveDevicesForAllStreams();
+ break;
}
}
}
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 332ff36..068c3d8 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -765,8 +765,7 @@
broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
// Accept SCO audio activation only in NORMAL audio mode or if the mode is
// currently controlled by the same client process.
- int modeOwnerPid = mDeviceBroker.getSetModeDeathHandlers().isEmpty()
- ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid();
+ final int modeOwnerPid = mDeviceBroker.getModeOwnerPid();
if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) {
Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid "
+ modeOwnerPid + " != creatorPid " + mCreatorPid);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 96fc6ec..ff0af13 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -66,6 +66,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.StatsLog;
+import android.util.TimeUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
@@ -332,9 +333,16 @@
// true if low power mode for the GNSS chipset is part of the latest request.
private boolean mLowPowerMode = false;
- // true if we started navigation
+ // true if we started navigation in the HAL, only change value of this in setStarted
private boolean mStarted;
+ // for logging of latest change, and warning of ongoing location after a stop
+ private long mStartedChangedElapsedRealtime;
+
+ // threshold for delay in GNSS engine turning off before warning & error
+ private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000;
+ private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000;
+
// capabilities reported through the top level IGnssCallback.hal
private volatile int mTopHalCapabilities;
@@ -1192,7 +1200,7 @@
if (DEBUG) Log.d(TAG, "startNavigating");
mTimeToFirstFix = 0;
mLastFixTime = 0;
- mStarted = true;
+ setStarted(true);
mPositionMode = GPS_POSITION_MODE_STANDALONE;
// Notify about suppressed output, if speed limit was previously exceeded.
// Elsewhere, we check again with every speed output reported.
@@ -1230,12 +1238,12 @@
mLowPowerMode = mProviderRequest.lowPowerMode;
if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
interval, 0, 0, mLowPowerMode)) {
- mStarted = false;
+ setStarted(false);
Log.e(TAG, "set_position_mode failed in startNavigating()");
return;
}
if (!native_start()) {
- mStarted = false;
+ setStarted(false);
Log.e(TAG, "native_start failed in startNavigating()");
return;
}
@@ -1258,7 +1266,7 @@
private void stopNavigating() {
if (DEBUG) Log.d(TAG, "stopNavigating");
if (mStarted) {
- mStarted = false;
+ setStarted(false);
native_stop();
mLastFixTime = 0;
// native_stop() may reset the position mode in hardware.
@@ -1270,6 +1278,13 @@
}
}
+ private void setStarted(boolean started) {
+ if (mStarted != started) {
+ mStarted = started;
+ mStartedChangedElapsedRealtime = SystemClock.elapsedRealtime();
+ }
+ }
+
private void hibernate() {
// stop GPS until our next fix interval arrives
stopNavigating();
@@ -1319,6 +1334,21 @@
mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
}
}
+ } else {
+ // Warn or error about long delayed GNSS engine shutdown as this generally wastes
+ // power and sends location when not expected.
+ long locationAfterStartedFalseMillis =
+ SystemClock.elapsedRealtime() - mStartedChangedElapsedRealtime;
+ if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS) {
+ String logMessage = "Unexpected GNSS Location report "
+ + TimeUtils.formatDuration(locationAfterStartedFalseMillis)
+ + " after location turned off";
+ if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS) {
+ Log.e(TAG, logMessage);
+ } else {
+ Log.w(TAG, logMessage);
+ }
+ }
}
mLastFixTime = SystemClock.elapsedRealtime();
@@ -1538,7 +1568,7 @@
private void restartLocationRequest() {
if (DEBUG) Log.d(TAG, "restartLocationRequest");
- mStarted = false;
+ setStarted(false);
updateRequirements();
}
@@ -2152,7 +2182,10 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
StringBuilder s = new StringBuilder();
- s.append(" mStarted=").append(mStarted).append('\n');
+ s.append(" mStarted=").append(mStarted).append(" (changed ");
+ TimeUtils.formatDuration(SystemClock.elapsedRealtime()
+ - mStartedChangedElapsedRealtime, s);
+ s.append(" ago)").append('\n');
s.append(" mFixInterval=").append(mFixInterval).append('\n');
s.append(" mLowPowerMode=").append(mLowPowerMode).append('\n');
s.append(" mGnssMeasurementsProvider.isRegistered()=")
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c4d4106..3c336ea 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -952,6 +952,9 @@
ActivityInfo mInstantAppInstallerActivity;
final ResolveInfo mInstantAppInstallerInfo = new ResolveInfo();
+ private final Map<String, Pair<PackageInstalledInfo, IPackageInstallObserver2>>
+ mNoKillInstallObservers = Collections.synchronizedMap(new HashMap<>());
+
final SparseArray<IntentFilterVerificationState> mIntentFilterVerificationStates
= new SparseArray<>();
@@ -1319,6 +1322,11 @@
static final int INSTANT_APP_RESOLUTION_PHASE_TWO = 20;
static final int ENABLE_ROLLBACK_STATUS = 21;
static final int ENABLE_ROLLBACK_TIMEOUT = 22;
+ static final int DEFERRED_NO_KILL_POST_DELETE = 23;
+ static final int DEFERRED_NO_KILL_INSTALL_OBSERVER = 24;
+
+ static final int DEFERRED_NO_KILL_POST_DELETE_DELAY_MS = 3 * 1000;
+ static final int DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS = 500;
static final int WRITE_SETTINGS_DELAY = 10*1000; // 10 seconds
@@ -1525,6 +1533,20 @@
Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "postInstall", msg.arg1);
} break;
+ case DEFERRED_NO_KILL_POST_DELETE: {
+ synchronized (mInstallLock) {
+ InstallArgs args = (InstallArgs) msg.obj;
+ if (args != null) {
+ args.doPostDeleteLI(true);
+ }
+ }
+ } break;
+ case DEFERRED_NO_KILL_INSTALL_OBSERVER: {
+ String packageName = (String) msg.obj;
+ if (packageName != null) {
+ notifyInstallObserver(packageName);
+ }
+ } break;
case WRITE_SETTINGS: {
Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
synchronized (mPackages) {
@@ -1791,7 +1813,10 @@
String[] grantedPermissions, List<String> whitelistedRestrictedPermissions,
boolean launchedForRestore, String installerPackage,
IPackageInstallObserver2 installObserver) {
- if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
+ final boolean succeeded = res.returnCode == PackageManager.INSTALL_SUCCEEDED;
+ final boolean update = res.removedInfo != null && res.removedInfo.removedPackage != null;
+
+ if (succeeded) {
// Send the removed broadcasts
if (res.removedInfo != null) {
res.removedInfo.sendPackageRemovedBroadcasts(killApp);
@@ -1819,8 +1844,6 @@
mPermissionCallback);
}
- final boolean update = res.removedInfo != null
- && res.removedInfo.removedPackage != null;
final String installerPackageName =
res.installerPackageName != null
? res.installerPackageName
@@ -2029,11 +2052,18 @@
getUnknownSourcesSettings());
// Remove the replaced package's older resources safely now
- // We delete after a gc for applications on sdcard.
- if (res.removedInfo != null && res.removedInfo.args != null) {
- Runtime.getRuntime().gc();
- synchronized (mInstallLock) {
- res.removedInfo.args.doPostDeleteLI(true);
+ InstallArgs args = res.removedInfo != null ? res.removedInfo.args : null;
+ if (args != null) {
+ if (!killApp) {
+ // If we didn't kill the app, defer the deletion of code/resource files, since
+ // they may still be in use by the running application. This mitigates problems
+ // in cases where resources or code is loaded by a new Activity before
+ // ApplicationInfo changes have propagated to all application threads.
+ scheduleDeferredNoKillPostDelete(args);
+ } else {
+ synchronized (mInstallLock) {
+ args.doPostDeleteLI(true);
+ }
}
} else {
// Force a gc to clear up things. Ask for a background one, it's fine to go on
@@ -2056,18 +2086,62 @@
}
}
- // If someone is watching installs - notify them
+ final boolean deferInstallObserver = succeeded && update && !killApp;
+ if (deferInstallObserver) {
+ scheduleDeferredNoKillInstallObserver(res, installObserver);
+ } else {
+ notifyInstallObserver(res, installObserver);
+ }
+ }
+
+ @Override
+ public void notifyPackagesReplacedReceived(String[] packages) {
+ final int callingUid = Binder.getCallingUid();
+ final int callingUserId = UserHandle.getUserId(callingUid);
+
+ for (String packageName : packages) {
+ PackageSetting setting = mSettings.mPackages.get(packageName);
+ if (setting != null && filterAppAccessLPr(setting, callingUid, callingUserId)) {
+ notifyInstallObserver(packageName);
+ }
+ }
+ }
+
+ private void notifyInstallObserver(String packageName) {
+ Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
+ mNoKillInstallObservers.remove(packageName);
+
+ if (pair != null) {
+ notifyInstallObserver(pair.first, pair.second);
+ }
+ }
+
+ private void notifyInstallObserver(PackageInstalledInfo info,
+ IPackageInstallObserver2 installObserver) {
if (installObserver != null) {
try {
- Bundle extras = extrasForInstallResult(res);
- installObserver.onPackageInstalled(res.name, res.returnCode,
- res.returnMsg, extras);
+ Bundle extras = extrasForInstallResult(info);
+ installObserver.onPackageInstalled(info.name, info.returnCode,
+ info.returnMsg, extras);
} catch (RemoteException e) {
Slog.i(TAG, "Observer no longer exists.");
}
}
}
+ private void scheduleDeferredNoKillPostDelete(InstallArgs args) {
+ Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_POST_DELETE, args);
+ mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_POST_DELETE_DELAY_MS);
+ }
+
+ private void scheduleDeferredNoKillInstallObserver(PackageInstalledInfo info,
+ IPackageInstallObserver2 observer) {
+ String packageName = info.pkg.packageName;
+ mNoKillInstallObservers.put(packageName, Pair.create(info, observer));
+ Message message = mHandler.obtainMessage(DEFERRED_NO_KILL_INSTALL_OBSERVER, packageName);
+ mHandler.sendMessageDelayed(message, DEFERRED_NO_KILL_INSTALL_OBSERVER_DELAY_MS);
+ }
+
/**
* Gets the type of the external storage a package is installed on.
* @param packageVolume The storage volume of the package.
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index db2fba9..2a9cb89 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2687,7 +2687,7 @@
private void writePackageListLPrInternal(int creatingUserId) {
// Only derive GIDs for active users (not dying)
- final List<UserInfo> users = UserManagerService.getInstance().getUsers(true);
+ final List<UserInfo> users = getUsers(UserManagerService.getInstance(), true);
int[] userIds = new int[users.size()];
for (int i = 0; i < userIds.length; i++) {
userIds[i] = users.get(i).id;
@@ -4357,10 +4357,26 @@
return pkgSetting.getHarmfulAppWarning(userId);
}
+ /**
+ * Return all users on the device, including partial or dying users.
+ * @param userManager UserManagerService instance
+ * @return the list of users
+ */
private static List<UserInfo> getAllUsers(UserManagerService userManager) {
+ return getUsers(userManager, false);
+ }
+
+ /**
+ * Return the list of users on the device. Clear the calling identity before calling into
+ * UserManagerService.
+ * @param userManager UserManagerService instance
+ * @param excludeDying Indicates whether to exclude any users marked for deletion.
+ * @return the list of users
+ */
+ private static List<UserInfo> getUsers(UserManagerService userManager, boolean excludeDying) {
long id = Binder.clearCallingIdentity();
try {
- return userManager.getUsers(false);
+ return userManager.getUsers(excludeDying);
} catch (NullPointerException npe) {
// packagemanager not yet initialized
} finally {