summaryrefslogtreecommitdiffstats
path: root/services/java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java')
-rw-r--r--services/java/com/android/server/BackupManagerService.java521
-rw-r--r--services/java/com/android/server/ConnectivityService.java142
-rw-r--r--services/java/com/android/server/LocationManagerService.java5
-rw-r--r--services/java/com/android/server/NetworkManagementService.java4
-rw-r--r--services/java/com/android/server/NotificationManagerService.java37
-rwxr-xr-xservices/java/com/android/server/am/ActiveServices.java50
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java30
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java21
-rw-r--r--[-rwxr-xr-x]services/java/com/android/server/am/ActivityStackSupervisor.java25
-rw-r--r--services/java/com/android/server/am/TaskRecord.java23
-rw-r--r--services/java/com/android/server/connectivity/Vpn.java101
-rw-r--r--services/java/com/android/server/content/SyncManager.java2
-rw-r--r--services/java/com/android/server/content/SyncOperation.java50
-rw-r--r--services/java/com/android/server/content/SyncQueue.java6
-rw-r--r--services/java/com/android/server/content/SyncStorageEngine.java2
-rw-r--r--services/java/com/android/server/display/DisplayManagerService.java82
-rw-r--r--services/java/com/android/server/display/WifiDisplayAdapter.java50
-rw-r--r--services/java/com/android/server/display/WifiDisplayController.java163
-rwxr-xr-xservices/java/com/android/server/pm/PackageManagerService.java120
-rw-r--r--services/java/com/android/server/pm/Settings.java72
-rw-r--r--services/java/com/android/server/power/DisplayPowerController.java110
-rw-r--r--services/java/com/android/server/power/DisplayPowerState.java9
-rw-r--r--services/java/com/android/server/power/PowerManagerService.java3
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java31
-rw-r--r--services/java/com/android/server/wifi/WifiController.java12
-rw-r--r--services/java/com/android/server/wifi/WifiService.java2
-rw-r--r--services/java/com/android/server/wm/AppWindowToken.java2
-rw-r--r--services/java/com/android/server/wm/TaskStack.java2
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java48
-rw-r--r--services/java/com/android/server/wm/WindowState.java7
30 files changed, 1209 insertions, 523 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index baef607..6d65a70 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -82,7 +82,7 @@ import android.util.StringBuilderPrinter;
import com.android.internal.backup.BackupConstants;
import com.android.internal.backup.IBackupTransport;
import com.android.internal.backup.IObbBackupService;
-import com.android.internal.backup.LocalTransport;
+import com.android.server.EventLogTags;
import com.android.server.PackageManagerBackupAgent.Metadata;
import java.io.BufferedInputStream;
@@ -140,11 +140,16 @@ class BackupManagerService extends IBackupManager.Stub {
private static final boolean DEBUG = true;
private static final boolean MORE_DEBUG = false;
+ // Historical and current algorithm names
+ static final String PBKDF_CURRENT = "PBKDF2WithHmacSHA1";
+ static final String PBKDF_FALLBACK = "PBKDF2WithHmacSHA1And8bit";
+
// Name and current contents version of the full-backup manifest file
static final String BACKUP_MANIFEST_FILENAME = "_manifest";
static final int BACKUP_MANIFEST_VERSION = 1;
static final String BACKUP_FILE_HEADER_MAGIC = "ANDROID BACKUP\n";
- static final int BACKUP_FILE_VERSION = 1;
+ static final int BACKUP_FILE_VERSION = 2;
+ static final int BACKUP_PW_FILE_VERSION = 2;
static final boolean COMPRESS_FULL_BACKUPS = true; // should be true in production
static final String SHARED_BACKUP_AGENT_PACKAGE = "com.android.sharedstoragebackup";
@@ -161,6 +166,9 @@ class BackupManagerService extends IBackupManager.Stub {
// the first backup pass.
private static final long FIRST_BACKUP_INTERVAL = 12 * AlarmManager.INTERVAL_HOUR;
+ // Retry interval for clear/init when the transport is unavailable
+ private static final long TRANSPORT_RETRY_INTERVAL = 1 * AlarmManager.INTERVAL_HOUR;
+
private static final String RUN_BACKUP_ACTION = "android.app.backup.intent.RUN";
private static final String RUN_INITIALIZE_ACTION = "android.app.backup.intent.INIT";
private static final String RUN_CLEAR_ACTION = "android.app.backup.intent.CLEAR";
@@ -174,6 +182,8 @@ class BackupManagerService extends IBackupManager.Stub {
private static final int MSG_RESTORE_TIMEOUT = 8;
private static final int MSG_FULL_CONFIRMATION_TIMEOUT = 9;
private static final int MSG_RUN_FULL_RESTORE = 10;
+ private static final int MSG_RETRY_INIT = 11;
+ private static final int MSG_RETRY_CLEAR = 12;
// backup task state machine tick
static final int MSG_BACKUP_RESTORE_STEP = 20;
@@ -306,6 +316,7 @@ class BackupManagerService extends IBackupManager.Stub {
class RestoreParams {
public IBackupTransport transport;
+ public String dirName;
public IRestoreObserver observer;
public long token;
public PackageInfo pkgInfo;
@@ -313,9 +324,10 @@ class BackupManagerService extends IBackupManager.Stub {
public boolean needFullBackup;
public String[] filterSet;
- RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
+ RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
transport = _transport;
+ dirName = _dirName;
observer = _obs;
token = _token;
pkgInfo = _pkg;
@@ -324,9 +336,10 @@ class BackupManagerService extends IBackupManager.Stub {
filterSet = null;
}
- RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
- boolean _needFullBackup) {
+ RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
+ long _token, boolean _needFullBackup) {
transport = _transport;
+ dirName = _dirName;
observer = _obs;
token = _token;
pkgInfo = null;
@@ -335,9 +348,10 @@ class BackupManagerService extends IBackupManager.Stub {
filterSet = null;
}
- RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
- String[] _filterSet, boolean _needFullBackup) {
+ RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
+ long _token, String[] _filterSet, boolean _needFullBackup) {
transport = _transport;
+ dirName = _dirName;
observer = _obs;
token = _token;
pkgInfo = null;
@@ -357,6 +371,16 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ class ClearRetryParams {
+ public String transportName;
+ public String packageName;
+
+ ClearRetryParams(String transport, String pkg) {
+ transportName = transport;
+ packageName = pkg;
+ }
+ }
+
class FullParams {
public ParcelFileDescriptor fd;
public final AtomicBoolean latch;
@@ -431,6 +455,8 @@ class BackupManagerService extends IBackupManager.Stub {
private final SecureRandom mRng = new SecureRandom();
private String mPasswordHash;
private File mPasswordHashFile;
+ private int mPasswordVersion;
+ private File mPasswordVersionFile;
private byte[] mPasswordSalt;
// Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys
@@ -516,13 +542,28 @@ class BackupManagerService extends IBackupManager.Stub {
// When it completes successfully, that old journal file will be
// deleted. If we crash prior to that, the old journal is parsed
// at next boot and the journaled requests fulfilled.
+ boolean staged = true;
if (queue.size() > 0) {
// Spin up a backup state sequence and set it running
- PerformBackupTask pbt = new PerformBackupTask(transport, queue, oldJournal);
- Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
- sendMessage(pbtMessage);
+ try {
+ String dirName = transport.transportDirName();
+ PerformBackupTask pbt = new PerformBackupTask(transport, dirName,
+ queue, oldJournal);
+ Message pbtMessage = obtainMessage(MSG_BACKUP_RESTORE_STEP, pbt);
+ sendMessage(pbtMessage);
+ } catch (RemoteException e) {
+ // unable to ask the transport its dir name -- transient failure, since
+ // the above check succeeded. Try again next time.
+ Slog.e(TAG, "Transport became unavailable attempting backup");
+ staged = false;
+ }
} else {
Slog.v(TAG, "Backup requested but nothing pending");
+ staged = false;
+ }
+
+ if (!staged) {
+ // if we didn't actually hand off the wakelock, rewind until next time
synchronized (mQueueLock) {
mBackupRunning = false;
}
@@ -572,7 +613,7 @@ class BackupManagerService extends IBackupManager.Stub {
RestoreParams params = (RestoreParams)msg.obj;
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
PerformRestoreTask task = new PerformRestoreTask(
- params.transport, params.observer,
+ params.transport, params.dirName, params.observer,
params.token, params.pkgInfo, params.pmToken,
params.needFullBackup, params.filterSet);
Message restoreMsg = obtainMessage(MSG_BACKUP_RESTORE_STEP, task);
@@ -599,6 +640,14 @@ class BackupManagerService extends IBackupManager.Stub {
break;
}
+ case MSG_RETRY_CLEAR:
+ {
+ // reenqueues if the transport remains unavailable
+ ClearRetryParams params = (ClearRetryParams)msg.obj;
+ clearBackupData(params.transportName, params.packageName);
+ break;
+ }
+
case MSG_RUN_INITIALIZE:
{
HashSet<String> queue;
@@ -613,6 +662,16 @@ class BackupManagerService extends IBackupManager.Stub {
break;
}
+ case MSG_RETRY_INIT:
+ {
+ synchronized (mQueueLock) {
+ recordInitPendingLocked(msg.arg1 != 0, (String)msg.obj);
+ mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
+ mRunInitIntent);
+ }
+ break;
+ }
+
case MSG_RUN_GET_RESTORE_SETS:
{
// Like other async operations, this is entered with the wakelock held
@@ -758,6 +817,27 @@ class BackupManagerService extends IBackupManager.Stub {
}
mDataDir = Environment.getDownloadCacheDirectory();
+ mPasswordVersion = 1; // unless we hear otherwise
+ mPasswordVersionFile = new File(mBaseStateDir, "pwversion");
+ if (mPasswordVersionFile.exists()) {
+ FileInputStream fin = null;
+ DataInputStream in = null;
+ try {
+ fin = new FileInputStream(mPasswordVersionFile);
+ in = new DataInputStream(fin);
+ mPasswordVersion = in.readInt();
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to read backup pw version");
+ } finally {
+ try {
+ if (in != null) in.close();
+ if (fin != null) fin.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Error closing pw version files");
+ }
+ }
+ }
+
mPasswordHashFile = new File(mBaseStateDir, "pwhash");
if (mPasswordHashFile.exists()) {
FileInputStream fin = null;
@@ -1058,13 +1138,13 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- private SecretKey buildPasswordKey(String pw, byte[] salt, int rounds) {
- return buildCharArrayKey(pw.toCharArray(), salt, rounds);
+ private SecretKey buildPasswordKey(String algorithm, String pw, byte[] salt, int rounds) {
+ return buildCharArrayKey(algorithm, pw.toCharArray(), salt, rounds);
}
- private SecretKey buildCharArrayKey(char[] pwArray, byte[] salt, int rounds) {
+ private SecretKey buildCharArrayKey(String algorithm, char[] pwArray, byte[] salt, int rounds) {
try {
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
+ SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);
KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);
return keyFactory.generateSecret(ks);
} catch (InvalidKeySpecException e) {
@@ -1075,8 +1155,8 @@ class BackupManagerService extends IBackupManager.Stub {
return null;
}
- private String buildPasswordHash(String pw, byte[] salt, int rounds) {
- SecretKey key = buildPasswordKey(pw, salt, rounds);
+ private String buildPasswordHash(String algorithm, String pw, byte[] salt, int rounds) {
+ SecretKey key = buildPasswordKey(algorithm, pw, salt, rounds);
if (key != null) {
return byteArrayToHex(key.getEncoded());
}
@@ -1104,13 +1184,13 @@ class BackupManagerService extends IBackupManager.Stub {
return result;
}
- private byte[] makeKeyChecksum(byte[] pwBytes, byte[] salt, int rounds) {
+ private byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds) {
char[] mkAsChar = new char[pwBytes.length];
for (int i = 0; i < pwBytes.length; i++) {
mkAsChar[i] = (char) pwBytes[i];
}
- Key checksum = buildCharArrayKey(mkAsChar, salt, rounds);
+ Key checksum = buildCharArrayKey(algorithm, mkAsChar, salt, rounds);
return checksum.getEncoded();
}
@@ -1122,7 +1202,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
// Backup password management
- boolean passwordMatchesSaved(String candidatePw, int rounds) {
+ boolean passwordMatchesSaved(String algorithm, String candidatePw, int rounds) {
// First, on an encrypted device we require matching the device pw
final boolean isEncrypted;
try {
@@ -1165,7 +1245,7 @@ class BackupManagerService extends IBackupManager.Stub {
} else {
// hash the stated current pw and compare to the stored one
if (candidatePw != null && candidatePw.length() > 0) {
- String currentPwHash = buildPasswordHash(candidatePw, mPasswordSalt, rounds);
+ String currentPwHash = buildPasswordHash(algorithm, candidatePw, mPasswordSalt, rounds);
if (mPasswordHash.equalsIgnoreCase(currentPwHash)) {
// candidate hash matches the stored hash -- the password matches
return true;
@@ -1180,11 +1260,37 @@ class BackupManagerService extends IBackupManager.Stub {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
"setBackupPassword");
- // If the supplied pw doesn't hash to the the saved one, fail
- if (!passwordMatchesSaved(currentPw, PBKDF2_HASH_ROUNDS)) {
+ // When processing v1 passwords we may need to try two different PBKDF2 checksum regimes
+ final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
+
+ // If the supplied pw doesn't hash to the the saved one, fail. The password
+ // might be caught in the legacy crypto mismatch; verify that too.
+ if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
+ && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
+ currentPw, PBKDF2_HASH_ROUNDS))) {
return false;
}
+ // Snap up to current on the pw file version
+ mPasswordVersion = BACKUP_PW_FILE_VERSION;
+ FileOutputStream pwFout = null;
+ DataOutputStream pwOut = null;
+ try {
+ pwFout = new FileOutputStream(mPasswordVersionFile);
+ pwOut = new DataOutputStream(pwFout);
+ pwOut.writeInt(mPasswordVersion);
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to write backup pw version; password not changed");
+ return false;
+ } finally {
+ try {
+ if (pwOut != null) pwOut.close();
+ if (pwFout != null) pwFout.close();
+ } catch (IOException e) {
+ Slog.w(TAG, "Unable to close pw version record");
+ }
+ }
+
// Clearing the password is okay
if (newPw == null || newPw.isEmpty()) {
if (mPasswordHashFile.exists()) {
@@ -1202,7 +1308,7 @@ class BackupManagerService extends IBackupManager.Stub {
try {
// Okay, build the hash of the new backup password
byte[] salt = randomBytes(PBKDF2_SALT_SIZE);
- String newPwHash = buildPasswordHash(newPw, salt, PBKDF2_HASH_ROUNDS);
+ String newPwHash = buildPasswordHash(PBKDF_CURRENT, newPw, salt, PBKDF2_HASH_ROUNDS);
OutputStream pwf = null, buffer = null;
DataOutputStream out = null;
@@ -1245,34 +1351,65 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
+ private boolean backupPasswordMatches(String currentPw) {
+ if (hasBackupPassword()) {
+ final boolean pbkdf2Fallback = (mPasswordVersion < BACKUP_PW_FILE_VERSION);
+ if (!passwordMatchesSaved(PBKDF_CURRENT, currentPw, PBKDF2_HASH_ROUNDS)
+ && !(pbkdf2Fallback && passwordMatchesSaved(PBKDF_FALLBACK,
+ currentPw, PBKDF2_HASH_ROUNDS))) {
+ if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
+ return false;
+ }
+ }
+ return true;
+ }
+
// Maintain persistent state around whether need to do an initialize operation.
// Must be called with the queue lock held.
void recordInitPendingLocked(boolean isPending, String transportName) {
if (DEBUG) Slog.i(TAG, "recordInitPendingLocked: " + isPending
+ " on transport " + transportName);
+ mBackupHandler.removeMessages(MSG_RETRY_INIT);
+
try {
IBackupTransport transport = getTransport(transportName);
- String transportDirName = transport.transportDirName();
- File stateDir = new File(mBaseStateDir, transportDirName);
- File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
-
- if (isPending) {
- // We need an init before we can proceed with sending backup data.
- // Record that with an entry in our set of pending inits, as well as
- // journaling it via creation of a sentinel file.
- mPendingInits.add(transportName);
- try {
- (new FileOutputStream(initPendingFile)).close();
- } catch (IOException ioe) {
- // Something is badly wrong with our permissions; just try to move on
+ if (transport != null) {
+ String transportDirName = transport.transportDirName();
+ File stateDir = new File(mBaseStateDir, transportDirName);
+ File initPendingFile = new File(stateDir, INIT_SENTINEL_FILE_NAME);
+
+ if (isPending) {
+ // We need an init before we can proceed with sending backup data.
+ // Record that with an entry in our set of pending inits, as well as
+ // journaling it via creation of a sentinel file.
+ mPendingInits.add(transportName);
+ try {
+ (new FileOutputStream(initPendingFile)).close();
+ } catch (IOException ioe) {
+ // Something is badly wrong with our permissions; just try to move on
+ }
+ } else {
+ // No more initialization needed; wipe the journal and reset our state.
+ initPendingFile.delete();
+ mPendingInits.remove(transportName);
}
- } else {
- // No more initialization needed; wipe the journal and reset our state.
- initPendingFile.delete();
- mPendingInits.remove(transportName);
+ return; // done; don't fall through to the error case
}
} catch (RemoteException e) {
- // can't happen; the transport is local
+ // transport threw when asked its name; fall through to the lookup-failed case
+ }
+
+ // The named transport doesn't exist or threw. This operation is
+ // important, so we record the need for a an init and post a message
+ // to retry the init later.
+ if (isPending) {
+ mPendingInits.add(transportName);
+ mBackupHandler.sendMessageDelayed(
+ mBackupHandler.obtainMessage(MSG_RETRY_INIT,
+ (isPending ? 1 : 0),
+ 0,
+ transportName),
+ TRANSPORT_RETRY_INTERVAL);
}
}
@@ -1348,7 +1485,10 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
} catch (RemoteException e) {
- // can't happen, the transport is local
+ // the transport threw when asked its file naming prefs; declare it invalid
+ Slog.e(TAG, "Unable to register transport as " + name);
+ mTransportNames.remove(component);
+ mTransports.remove(name);
}
}
@@ -1668,7 +1808,7 @@ class BackupManagerService extends IBackupManager.Stub {
agent = mConnectedAgent;
}
} catch (RemoteException e) {
- // can't happen
+ // can't happen - ActivityManager is local
}
}
return agent;
@@ -1844,17 +1984,13 @@ class BackupManagerService extends IBackupManager.Stub {
int mStatus;
boolean mFinished;
- public PerformBackupTask(IBackupTransport transport, ArrayList<BackupRequest> queue,
- File journal) {
+ public PerformBackupTask(IBackupTransport transport, String dirName,
+ ArrayList<BackupRequest> queue, File journal) {
mTransport = transport;
mOriginalQueue = queue;
mJournal = journal;
- try {
- mStateDir = new File(mBaseStateDir, transport.transportDirName());
- } catch (RemoteException e) {
- // can't happen; the transport is local
- }
+ mStateDir = new File(mBaseStateDir, dirName);
mCurrentState = BackupState.INITIAL;
mFinished = false;
@@ -2100,8 +2236,12 @@ class BackupManagerService extends IBackupManager.Stub {
addBackupTrace("success; recording token");
try {
mCurrentToken = mTransport.getCurrentRestoreSet();
- } catch (RemoteException e) {} // can't happen
- writeRestoreTokens();
+ writeRestoreTokens();
+ } catch (RemoteException e) {
+ // nothing for it at this point, unfortunately, but this will be
+ // recorded the next time we fully succeed.
+ addBackupTrace("transport threw returning token");
+ }
}
// Set up the next backup pass - at this point we can set mBackupRunning
@@ -2322,7 +2462,7 @@ class BackupManagerService extends IBackupManager.Stub {
addBackupTrace("unbinding " + mCurrentPackage.packageName);
try { // unbind even on timeout, just in case
mActivityManager.unbindBackupAgent(mCurrentPackage.applicationInfo);
- } catch (RemoteException e) {}
+ } catch (RemoteException e) { /* can't happen; activity manager is local */ }
}
}
@@ -2644,11 +2784,9 @@ class BackupManagerService extends IBackupManager.Stub {
// Verify that the given password matches the currently-active
// backup password, if any
- if (hasBackupPassword()) {
- if (!passwordMatchesSaved(mCurrentPassword, PBKDF2_HASH_ROUNDS)) {
- if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
- return;
- }
+ if (!backupPasswordMatches(mCurrentPassword)) {
+ if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
+ return;
}
// Write the global file header. All strings are UTF-8 encoded; lines end
@@ -2656,7 +2794,7 @@ class BackupManagerService extends IBackupManager.Stub {
// final '\n'.
//
// line 1: "ANDROID BACKUP"
- // line 2: backup file format version, currently "1"
+ // line 2: backup file format version, currently "2"
// line 3: compressed? "0" if not compressed, "1" if compressed.
// line 4: name of encryption algorithm [currently only "none" or "AES-256"]
//
@@ -2764,7 +2902,7 @@ class BackupManagerService extends IBackupManager.Stub {
OutputStream ofstream) throws Exception {
// User key will be used to encrypt the master key.
byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);
- SecretKey userKey = buildPasswordKey(mEncryptPassword, newUserSalt,
+ SecretKey userKey = buildPasswordKey(PBKDF_CURRENT, mEncryptPassword, newUserSalt,
PBKDF2_HASH_ROUNDS);
// the master key is random for each backup
@@ -2811,7 +2949,7 @@ class BackupManagerService extends IBackupManager.Stub {
// stated number of PBKDF2 rounds
IV = c.getIV();
byte[] mk = masterKeySpec.getEncoded();
- byte[] checksum = makeKeyChecksum(masterKeySpec.getEncoded(),
+ byte[] checksum = makeKeyChecksum(PBKDF_CURRENT, masterKeySpec.getEncoded(),
checksumSalt, PBKDF2_HASH_ROUNDS);
ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length
@@ -3154,11 +3292,9 @@ class BackupManagerService extends IBackupManager.Stub {
FileInputStream rawInStream = null;
DataInputStream rawDataIn = null;
try {
- if (hasBackupPassword()) {
- if (!passwordMatchesSaved(mCurrentPassword, PBKDF2_HASH_ROUNDS)) {
- if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
- return;
- }
+ if (!backupPasswordMatches(mCurrentPassword)) {
+ if (DEBUG) Slog.w(TAG, "Backup password mismatch; aborting");
+ return;
}
mBytes = 0;
@@ -3179,8 +3315,12 @@ class BackupManagerService extends IBackupManager.Stub {
if (Arrays.equals(magicBytes, streamHeader)) {
// okay, header looks good. now parse out the rest of the fields.
String s = readHeaderLine(rawInStream);
- if (Integer.parseInt(s) == BACKUP_FILE_VERSION) {
- // okay, it's a version we recognize
+ final int archiveVersion = Integer.parseInt(s);
+ if (archiveVersion <= BACKUP_FILE_VERSION) {
+ // okay, it's a version we recognize. if it's version 1, we may need
+ // to try two different PBKDF2 regimes to compare checksums.
+ final boolean pbkdf2Fallback = (archiveVersion == 1);
+
s = readHeaderLine(rawInStream);
compressed = (Integer.parseInt(s) != 0);
s = readHeaderLine(rawInStream);
@@ -3188,7 +3328,8 @@ class BackupManagerService extends IBackupManager.Stub {
// no more header to parse; we're good to go
okay = true;
} else if (mDecryptPassword != null && mDecryptPassword.length() > 0) {
- preCompressStream = decodeAesHeaderAndInitialize(s, rawInStream);
+ preCompressStream = decodeAesHeaderAndInitialize(s, pbkdf2Fallback,
+ rawInStream);
if (preCompressStream != null) {
okay = true;
}
@@ -3248,7 +3389,71 @@ class BackupManagerService extends IBackupManager.Stub {
return buffer.toString();
}
- InputStream decodeAesHeaderAndInitialize(String encryptionName, InputStream rawInStream) {
+ InputStream attemptMasterKeyDecryption(String algorithm, byte[] userSalt, byte[] ckSalt,
+ int rounds, String userIvHex, String masterKeyBlobHex, InputStream rawInStream,
+ boolean doLog) {
+ InputStream result = null;
+
+ try {
+ Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ SecretKey userKey = buildPasswordKey(algorithm, mDecryptPassword, userSalt,
+ rounds);
+ byte[] IV = hexToByteArray(userIvHex);
+ IvParameterSpec ivSpec = new IvParameterSpec(IV);
+ c.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec(userKey.getEncoded(), "AES"),
+ ivSpec);
+ byte[] mkCipher = hexToByteArray(masterKeyBlobHex);
+ byte[] mkBlob = c.doFinal(mkCipher);
+
+ // first, the master key IV
+ int offset = 0;
+ int len = mkBlob[offset++];
+ IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
+ offset += len;
+ // then the master key itself
+ len = mkBlob[offset++];
+ byte[] mk = Arrays.copyOfRange(mkBlob,
+ offset, offset + len);
+ offset += len;
+ // and finally the master key checksum hash
+ len = mkBlob[offset++];
+ byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
+ offset, offset + len);
+
+ // now validate the decrypted master key against the checksum
+ byte[] calculatedCk = makeKeyChecksum(algorithm, mk, ckSalt, rounds);
+ if (Arrays.equals(calculatedCk, mkChecksum)) {
+ ivSpec = new IvParameterSpec(IV);
+ c.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec(mk, "AES"),
+ ivSpec);
+ // Only if all of the above worked properly will 'result' be assigned
+ result = new CipherInputStream(rawInStream, c);
+ } else if (doLog) Slog.w(TAG, "Incorrect password");
+ } catch (InvalidAlgorithmParameterException e) {
+ if (doLog) Slog.e(TAG, "Needed parameter spec unavailable!", e);
+ } catch (BadPaddingException e) {
+ // This case frequently occurs when the wrong password is used to decrypt
+ // the master key. Use the identical "incorrect password" log text as is
+ // used in the checksum failure log in order to avoid providing additional
+ // information to an attacker.
+ if (doLog) Slog.w(TAG, "Incorrect password");
+ } catch (IllegalBlockSizeException e) {
+ if (doLog) Slog.w(TAG, "Invalid block size in master key");
+ } catch (NoSuchAlgorithmException e) {
+ if (doLog) Slog.e(TAG, "Needed decryption algorithm unavailable!");
+ } catch (NoSuchPaddingException e) {
+ if (doLog) Slog.e(TAG, "Needed padding mechanism unavailable!");
+ } catch (InvalidKeyException e) {
+ if (doLog) Slog.w(TAG, "Illegal password; aborting");
+ }
+
+ return result;
+ }
+
+ InputStream decodeAesHeaderAndInitialize(String encryptionName, boolean pbkdf2Fallback,
+ InputStream rawInStream) {
InputStream result = null;
try {
if (encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) {
@@ -3265,59 +3470,13 @@ class BackupManagerService extends IBackupManager.Stub {
String masterKeyBlobHex = readHeaderLine(rawInStream); // 9
// decrypt the master key blob
- Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
- SecretKey userKey = buildPasswordKey(mDecryptPassword, userSalt,
- rounds);
- byte[] IV = hexToByteArray(userIvHex);
- IvParameterSpec ivSpec = new IvParameterSpec(IV);
- c.init(Cipher.DECRYPT_MODE,
- new SecretKeySpec(userKey.getEncoded(), "AES"),
- ivSpec);
- byte[] mkCipher = hexToByteArray(masterKeyBlobHex);
- byte[] mkBlob = c.doFinal(mkCipher);
-
- // first, the master key IV
- int offset = 0;
- int len = mkBlob[offset++];
- IV = Arrays.copyOfRange(mkBlob, offset, offset + len);
- offset += len;
- // then the master key itself
- len = mkBlob[offset++];
- byte[] mk = Arrays.copyOfRange(mkBlob,
- offset, offset + len);
- offset += len;
- // and finally the master key checksum hash
- len = mkBlob[offset++];
- byte[] mkChecksum = Arrays.copyOfRange(mkBlob,
- offset, offset + len);
-
- // now validate the decrypted master key against the checksum
- byte[] calculatedCk = makeKeyChecksum(mk, ckSalt, rounds);
- if (Arrays.equals(calculatedCk, mkChecksum)) {
- ivSpec = new IvParameterSpec(IV);
- c.init(Cipher.DECRYPT_MODE,
- new SecretKeySpec(mk, "AES"),
- ivSpec);
- // Only if all of the above worked properly will 'result' be assigned
- result = new CipherInputStream(rawInStream, c);
- } else Slog.w(TAG, "Incorrect password");
+ result = attemptMasterKeyDecryption(PBKDF_CURRENT, userSalt, ckSalt,
+ rounds, userIvHex, masterKeyBlobHex, rawInStream, false);
+ if (result == null && pbkdf2Fallback) {
+ result = attemptMasterKeyDecryption(PBKDF_FALLBACK, userSalt, ckSalt,
+ rounds, userIvHex, masterKeyBlobHex, rawInStream, true);
+ }
} else Slog.w(TAG, "Unsupported encryption method: " + encryptionName);
- } catch (InvalidAlgorithmParameterException e) {
- Slog.e(TAG, "Needed parameter spec unavailable!", e);
- } catch (BadPaddingException e) {
- // This case frequently occurs when the wrong password is used to decrypt
- // the master key. Use the identical "incorrect password" log text as is
- // used in the checksum failure log in order to avoid providing additional
- // information to an attacker.
- Slog.w(TAG, "Incorrect password");
- } catch (IllegalBlockSizeException e) {
- Slog.w(TAG, "Invalid block size in master key");
- } catch (NoSuchAlgorithmException e) {
- Slog.e(TAG, "Needed decryption algorithm unavailable!");
- } catch (NoSuchPaddingException e) {
- Slog.e(TAG, "Needed padding mechanism unavailable!");
- } catch (InvalidKeyException e) {
- Slog.w(TAG, "Illegal password; aborting");
} catch (NumberFormatException e) {
Slog.w(TAG, "Can't parse restore data header");
} catch (IOException e) {
@@ -4337,7 +4496,7 @@ class BackupManagerService extends IBackupManager.Stub {
}
}
- PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
+ PerformRestoreTask(IBackupTransport transport, String dirName, IRestoreObserver observer,
long restoreSetToken, PackageInfo targetPackage, int pmToken,
boolean needFullBackup, String[] filterSet) {
mCurrentState = RestoreState.INITIAL;
@@ -4360,11 +4519,7 @@ class BackupManagerService extends IBackupManager.Stub {
mFilterSet = null;
}
- try {
- mStateDir = new File(mBaseStateDir, transport.transportDirName());
- } catch (RemoteException e) {
- // can't happen; the transport is local
- }
+ mStateDir = new File(mBaseStateDir, dirName);
}
// Execute one tick of whatever state machine the task implements
@@ -5090,8 +5245,8 @@ class BackupManagerService extends IBackupManager.Stub {
}
// Clear the given package's backup data from the current transport
- public void clearBackupData(String packageName) {
- if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName);
+ public void clearBackupData(String transportName, String packageName) {
+ if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
PackageInfo info;
try {
info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
@@ -5122,13 +5277,22 @@ class BackupManagerService extends IBackupManager.Stub {
// Is the given app an available participant?
if (apps.contains(packageName)) {
- if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
// found it; fire off the clear request
+ if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
+ mBackupHandler.removeMessages(MSG_RETRY_CLEAR);
synchronized (mQueueLock) {
+ final IBackupTransport transport = getTransport(transportName);
+ if (transport == null) {
+ // transport is currently unavailable -- make sure to retry
+ Message msg = mBackupHandler.obtainMessage(MSG_RETRY_CLEAR,
+ new ClearRetryParams(transportName, packageName));
+ mBackupHandler.sendMessageDelayed(msg, TRANSPORT_RETRY_INTERVAL);
+ return;
+ }
long oldId = Binder.clearCallingIdentity();
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
- new ClearParams(getTransport(mCurrentTransport), info));
+ new ClearParams(transport, info));
mBackupHandler.sendMessage(msg);
Binder.restoreCallingIdentity(oldId);
}
@@ -5620,31 +5784,55 @@ class BackupManagerService extends IBackupManager.Stub {
return;
}
+ boolean skip = false;
+
long restoreSet = getAvailableRestoreToken(packageName);
if (DEBUG) Slog.v(TAG, "restoreAtInstall pkg=" + packageName
+ " token=" + Integer.toHexString(token)
+ " restoreSet=" + Long.toHexString(restoreSet));
+ if (restoreSet == 0) {
+ if (MORE_DEBUG) Slog.i(TAG, "No restore set");
+ skip = true;
+ }
- if (mAutoRestore && mProvisioned && restoreSet != 0) {
- // okay, we're going to attempt a restore of this package from this restore set.
- // The eventual message back into the Package Manager to run the post-install
- // steps for 'token' will be issued from the restore handling code.
+ // Do we have a transport to fetch data for us?
+ IBackupTransport transport = getTransport(mCurrentTransport);
+ if (transport == null) {
+ if (DEBUG) Slog.w(TAG, "No transport");
+ skip = true;
+ }
- // We can use a synthetic PackageInfo here because:
- // 1. We know it's valid, since the Package Manager supplied the name
- // 2. Only the packageName field will be used by the restore code
- PackageInfo pkg = new PackageInfo();
- pkg.packageName = packageName;
+ if (!skip && mAutoRestore && mProvisioned) {
+ try {
+ // okay, we're going to attempt a restore of this package from this restore set.
+ // The eventual message back into the Package Manager to run the post-install
+ // steps for 'token' will be issued from the restore handling code.
- mWakelock.acquire();
- Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(getTransport(mCurrentTransport), null,
- restoreSet, pkg, token, true);
- mBackupHandler.sendMessage(msg);
- } else {
+ // This can throw and so *must* happen before the wakelock is acquired
+ String dirName = transport.transportDirName();
+
+ // We can use a synthetic PackageInfo here because:
+ // 1. We know it's valid, since the Package Manager supplied the name
+ // 2. Only the packageName field will be used by the restore code
+ PackageInfo pkg = new PackageInfo();
+ pkg.packageName = packageName;
+
+ mWakelock.acquire();
+ Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(transport, dirName, null,
+ restoreSet, pkg, token, true);
+ mBackupHandler.sendMessage(msg);
+ } catch (RemoteException e) {
+ // Binding to the transport broke; back off and proceed with the installation.
+ Slog.e(TAG, "Unable to contact transport");
+ skip = true;
+ }
+ }
+
+ if (skip) {
// Auto-restore disabled or no way to attempt a restore; just tell the Package
// Manager to proceed with the post-install handling for this package.
- if (DEBUG) Slog.v(TAG, "No restore set -- skipping restore");
+ if (DEBUG) Slog.v(TAG, "Skipping");
try {
mPackageManagerBinder.finishPackageInstall(token);
} catch (RemoteException e) { /* can't happen */ }
@@ -5797,13 +5985,23 @@ class BackupManagerService extends IBackupManager.Stub {
return -1;
}
+ String dirName;
+ try {
+ dirName = mRestoreTransport.transportDirName();
+ } catch (RemoteException e) {
+ // Transport went AWOL; fail.
+ Slog.e(TAG, "Unable to contact transport for restore");
+ return -1;
+ }
+
synchronized (mQueueLock) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
long oldId = Binder.clearCallingIdentity();
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, observer, token, true);
+ msg.obj = new RestoreParams(mRestoreTransport, dirName,
+ observer, token, true);
mBackupHandler.sendMessage(msg);
Binder.restoreCallingIdentity(oldId);
return 0;
@@ -5857,13 +6055,22 @@ class BackupManagerService extends IBackupManager.Stub {
return -1;
}
+ String dirName;
+ try {
+ dirName = mRestoreTransport.transportDirName();
+ } catch (RemoteException e) {
+ // Transport went AWOL; fail.
+ Slog.e(TAG, "Unable to contact transport for restore");
+ return -1;
+ }
+
synchronized (mQueueLock) {
for (int i = 0; i < mRestoreSets.length; i++) {
if (token == mRestoreSets[i].token) {
long oldId = Binder.clearCallingIdentity();
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, observer, token,
+ msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token,
packages, true);
mBackupHandler.sendMessage(msg);
Binder.restoreCallingIdentity(oldId);
@@ -5929,11 +6136,21 @@ class BackupManagerService extends IBackupManager.Stub {
return -1;
}
+ String dirName;
+ try {
+ dirName = mRestoreTransport.transportDirName();
+ } catch (RemoteException e) {
+ // Transport went AWOL; fail.
+ Slog.e(TAG, "Unable to contact transport for restore");
+ return -1;
+ }
+
// Ready to go: enqueue the restore request and claim success
long oldId = Binder.clearCallingIdentity();
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, observer, token, app, 0, false);
+ msg.obj = new RestoreParams(mRestoreTransport, dirName,
+ observer, token, app, 0, false);
mBackupHandler.sendMessage(msg);
Binder.restoreCallingIdentity(oldId);
return 0;
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index d42ae3a..b7a1a55 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -32,6 +32,7 @@ import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import android.app.AlarmManager;
+import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -43,7 +44,9 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -412,6 +415,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private SettingsObserver mSettingsObserver;
+ private AppOpsManager mAppOpsManager;
+
NetworkConfig[] mNetConfigs;
int mNetworksDefined;
@@ -695,6 +700,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
filter = new IntentFilter();
filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION);
mContext.registerReceiver(mProvisioningReceiver, filter);
+
+ mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
}
/**
@@ -1527,6 +1534,40 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
/**
+ * Check if the address falls into any of currently running VPN's route's.
+ */
+ private boolean isAddressUnderVpn(InetAddress address) {
+ synchronized (mVpns) {
+ synchronized (mRoutesLock) {
+ int uid = UserHandle.getCallingUserId();
+ Vpn vpn = mVpns.get(uid);
+ if (vpn == null) {
+ return false;
+ }
+
+ // Check if an exemption exists for this address.
+ for (LinkAddress destination : mExemptAddresses) {
+ if (!NetworkUtils.addressTypeMatches(address, destination.getAddress())) {
+ continue;
+ }
+
+ int prefix = destination.getNetworkPrefixLength();
+ InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix);
+ InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(),
+ prefix);
+
+ if (addrMasked.equals(destMasked)) {
+ return false;
+ }
+ }
+
+ // Finally check if the address is covered by the VPN.
+ return vpn.isAddressCovered(address);
+ }
+ }
+ }
+
+ /**
* @deprecated use requestRouteToHostAddress instead
*
* Ensure that a network route exists to deliver traffic to the specified
@@ -1537,14 +1578,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* desired
* @return {@code true} on success, {@code false} on failure
*/
- public boolean requestRouteToHost(int networkType, int hostAddress) {
+ public boolean requestRouteToHost(int networkType, int hostAddress, String packageName) {
InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress);
if (inetAddress == null) {
return false;
}
- return requestRouteToHostAddress(networkType, inetAddress.getAddress());
+ return requestRouteToHostAddress(networkType, inetAddress.getAddress(), packageName);
}
/**
@@ -1556,11 +1597,40 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* desired
* @return {@code true} on success, {@code false} on failure
*/
- public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
+ public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress,
+ String packageName) {
enforceChangePermission();
if (mProtectedNetworks.contains(networkType)) {
enforceConnectivityInternalPermission();
}
+ boolean exempt;
+ InetAddress addr;
+ try {
+ addr = InetAddress.getByAddress(hostAddress);
+ } catch (UnknownHostException e) {
+ if (DBG) log("requestRouteToHostAddress got " + e.toString());
+ return false;
+ }
+ // System apps may request routes bypassing the VPN to keep other networks working.
+ if (Binder.getCallingUid() == Process.SYSTEM_UID) {
+ exempt = true;
+ } else {
+ mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName);
+ try {
+ ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName,
+ 0);
+ exempt = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ } catch (NameNotFoundException e) {
+ throw new IllegalArgumentException("Failed to find calling package details", e);
+ }
+ }
+
+ // Non-exempt routeToHost's can only be added if the host is not covered by the VPN.
+ // This can be either because the VPN's routes do not cover the destination or a
+ // system application added an exemption that covers this destination.
+ if (!exempt && isAddressUnderVpn(addr)) {
+ return false;
+ }
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType);
@@ -1587,18 +1657,13 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
final long token = Binder.clearCallingIdentity();
try {
- InetAddress addr = InetAddress.getByAddress(hostAddress);
LinkProperties lp = tracker.getLinkProperties();
- boolean ok = addRouteToAddress(lp, addr, EXEMPT);
+ boolean ok = addRouteToAddress(lp, addr, exempt);
if (DBG) log("requestRouteToHostAddress ok=" + ok);
return ok;
- } catch (UnknownHostException e) {
- if (DBG) log("requestRouteToHostAddress got " + e.toString());
} finally {
Binder.restoreCallingIdentity(token);
}
- if (DBG) log("requestRouteToHostAddress X bottom return false");
- return false;
}
private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable,
@@ -2308,9 +2373,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mInetConditionChangeInFlight = false;
// Don't do this - if we never sign in stay, grey
//reportNetworkCondition(mActiveDefaultNetwork, 100);
+ updateNetworkSettings(thisNet);
}
thisNet.setTeardownRequested(false);
- updateNetworkSettings(thisNet);
updateMtuSizeSettings(thisNet);
handleConnectivityChange(newNetType, false);
sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());
@@ -2695,6 +2760,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
setBufferSize(bufferSizes);
}
+
+ final String defaultRwndKey = "net.tcp.default_init_rwnd";
+ int defaultRwndValue = SystemProperties.getInt(defaultRwndKey, 0);
+ Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.TCP_DEFAULT_INIT_RWND, defaultRwndValue);
+ final String sysctlKey = "sys.sysctl.tcp_def_init_rwnd";
+ if (rwndValue != 0) {
+ SystemProperties.set(sysctlKey, rwndValue.toString());
+ }
}
/**
@@ -3037,7 +3111,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: {
info = (NetworkInfo) msg.obj;
int type = info.getType();
- updateNetworkSettings(mNetTrackers[type]);
+ if (mNetConfigs[type].isDefault()) updateNetworkSettings(mNetTrackers[type]);
break;
}
}
@@ -3596,8 +3670,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
int user = UserHandle.getUserId(Binder.getCallingUid());
if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) {
synchronized(mVpns) {
- mVpns.get(user).protect(socket,
- mNetTrackers[type].getLinkProperties().getInterfaceName());
+ mVpns.get(user).protect(socket);
}
return true;
}
@@ -3837,7 +3910,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
boolean forwardDns) {
try {
mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd);
- if (forwardDns) mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd);
+ if (forwardDns) mNetd.clearDnsInterfaceForUidRange(interfaze, uidStart, uidEnd);
} catch (RemoteException e) {
}
@@ -3992,6 +4065,14 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5;
+ /**
+ * The mobile network is provisioning
+ */
+ private static final int CMP_RESULT_CODE_IS_PROVISIONING = 6;
+
+ private AtomicBoolean mIsProvisioningNetwork = new AtomicBoolean(false);
+ private AtomicBoolean mIsStartingProvisioning = new AtomicBoolean(false);
+
private AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false);
@Override
@@ -4062,11 +4143,25 @@ public class ConnectivityService extends IConnectivityManager.Stub {
setProvNotificationVisible(true,
ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(),
url);
+ // Mark that we've got a provisioning network and
+ // Disable Mobile Data until user actually starts provisioning.
+ mIsProvisioningNetwork.set(true);
+ MobileDataStateTracker mdst = (MobileDataStateTracker)
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+ mdst.setInternalDataEnable(false);
} else {
if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url");
}
break;
}
+ case CMP_RESULT_CODE_IS_PROVISIONING: {
+ // FIXME: Need to know when provisioning is done. Probably we can
+ // check the completion status if successful we're done if we
+ // "timedout" or still connected to provisioning APN turn off data?
+ if (DBG) log("CheckMp.onComplete: provisioning started");
+ mIsStartingProvisioning.set(false);
+ break;
+ }
default: {
loge("CheckMp.onComplete: ignore unexpected result=" + result);
break;
@@ -4216,6 +4311,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return result;
}
+ if (mCs.mIsStartingProvisioning.get()) {
+ result = CMP_RESULT_CODE_IS_PROVISIONING;
+ log("isMobileOk: X is provisioning result=" + result);
+ return result;
+ }
+
// See if we've already determined we've got a provisioning connection,
// if so we don't need to do anything active.
MobileDataStateTracker mdstDefault = (MobileDataStateTracker)
@@ -4354,7 +4455,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
// Make a route to host so we check the specific interface.
if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI,
- hostAddr.getAddress())) {
+ hostAddr.getAddress(), null)) {
// Wait a short time to be sure the route is established ??
log("isMobileOk:"
+ " wait to establish route to hostAddr=" + hostAddr);
@@ -4550,19 +4651,20 @@ public class ConnectivityService extends IConnectivityManager.Stub {
};
private void handleMobileProvisioningAction(String url) {
- // Notication mark notification as not visible
+ // Mark notification as not visible
setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null);
// If provisioning network handle as a special case,
// otherwise launch browser with the intent directly.
- NetworkInfo ni = getProvisioningNetworkInfo();
- if ((ni != null) && ni.isConnectedToProvisioningNetwork()) {
- if (DBG) log("handleMobileProvisioningAction: on provisioning network");
+ if (mIsProvisioningNetwork.get()) {
+ if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch");
+ mIsStartingProvisioning.set(true);
MobileDataStateTracker mdst = (MobileDataStateTracker)
mNetTrackers[ConnectivityManager.TYPE_MOBILE];
+ mdst.setEnableFailFastMobileData(DctConstants.ENABLED);
mdst.enableMobileProvisioning(url);
} else {
- if (DBG) log("handleMobileProvisioningAction: on default network");
+ if (DBG) log("handleMobileProvisioningAction: not prov network, launch browser directly");
Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
Intent.CATEGORY_APP_BROWSER);
newIntent.setData(Uri.parse(url));
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index b4a982e..e0b568b 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1151,6 +1151,11 @@ public class LocationManagerService extends ILocationManager.Stub {
boolean shouldBeEnabled = isAllowedByCurrentUserSettingsLocked(name);
if (isEnabled && !shouldBeEnabled) {
updateProviderListenersLocked(name, false, mCurrentUserId);
+ // If any provider has been disabled, clear all last locations for all providers.
+ // This is to be on the safe side in case a provider has location derived from
+ // this disabled provider.
+ mLastLocation.clear();
+ mLastLocationCoarseInterval.clear();
changesMade = true;
} else if (!isEnabled && shouldBeEnabled) {
updateProviderListenersLocked(name, true, mCurrentUserId);
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index e6c5422..e83d376 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -1613,10 +1613,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
@Override
- public void clearDnsInterfaceForUidRange(int uid_start, int uid_end) {
+ public void clearDnsInterfaceForUidRange(String iface, int uid_start, int uid_end) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
try {
- mConnector.execute("resolver", "clearifaceforuidrange", uid_start, uid_end);
+ mConnector.execute("resolver", "clearifaceforuidrange", iface, uid_start, uid_end);
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 0438675..dedc9bd 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -260,10 +260,11 @@ public class NotificationManagerService extends INotificationManager.Stub
@Override
public void binderDied() {
- if (connection == null) {
- // This is not a service; it won't be recreated. We can give up this connection.
- unregisterListener(this.listener, this.userid);
- }
+ // Remove the listener, but don't unbind from the service. The system will bring the
+ // service back up, and the onServiceConnected handler will readd the listener with the
+ // new binding. If this isn't a bound service, and is just a registered
+ // INotificationListener, just removing it from the list is all we need to do anyway.
+ removeListenerImpl(this.listener, this.userid);
}
/** convenience method for looking in mEnabledListenersForCurrentUser */
@@ -757,26 +758,36 @@ public class NotificationManagerService extends INotificationManager.Stub
}
/**
- * Remove a listener binder directly
+ * Removes a listener from the list and unbinds from its service.
*/
- @Override
- public void unregisterListener(INotificationListener listener, int userid) {
- // no need to check permissions; if your listener binder is in the list,
- // that's proof that you had permission to add it in the first place
+ public void unregisterListener(final INotificationListener listener, final int userid) {
+ if (listener == null) return;
+
+ NotificationListenerInfo info = removeListenerImpl(listener, userid);
+ if (info != null && info.connection != null) {
+ mContext.unbindService(info.connection);
+ }
+ }
+ /**
+ * Removes a listener from the list but does not unbind from the listener's service.
+ *
+ * @return the removed listener.
+ */
+ NotificationListenerInfo removeListenerImpl(
+ final INotificationListener listener, final int userid) {
+ NotificationListenerInfo listenerInfo = null;
synchronized (mNotificationList) {
final int N = mListeners.size();
for (int i=N-1; i>=0; i--) {
final NotificationListenerInfo info = mListeners.get(i);
if (info.listener.asBinder() == listener.asBinder()
&& info.userid == userid) {
- mListeners.remove(i);
- if (info.connection != null) {
- mContext.unbindService(info.connection);
- }
+ listenerInfo = mListeners.remove(i);
}
}
}
+ return listenerInfo;
}
/**
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index e06b8c5..d66c5a7 100755
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -64,7 +64,7 @@ public final class ActiveServices {
static final boolean DEBUG_SERVICE = ActivityManagerService.DEBUG_SERVICE;
static final boolean DEBUG_SERVICE_EXECUTING = ActivityManagerService.DEBUG_SERVICE_EXECUTING;
static final boolean DEBUG_DELAYED_SERVICE = ActivityManagerService.DEBUG_SERVICE;
- static final boolean DEBUG_DELAYED_STATS = DEBUG_DELAYED_SERVICE;
+ static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
static final String TAG = ActivityManagerService.TAG;
static final String TAG_MU = ActivityManagerService.TAG_MU;
@@ -186,11 +186,11 @@ public final class ActiveServices {
void ensureNotStartingBackground(ServiceRecord r) {
if (mStartingBackground.remove(r)) {
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "No longer background starting: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer background starting: " + r);
rescheduleDelayedStarts();
}
if (mDelayedStartList.remove(r)) {
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "No longer delaying start: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "No longer delaying start: " + r);
}
}
@@ -209,7 +209,7 @@ public final class ActiveServices {
while (mDelayedStartList.size() > 0
&& mStartingBackground.size() < mMaxStartingBackground) {
ServiceRecord r = mDelayedStartList.remove(0);
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (exec next): " + r);
if (r.pendingStarts.size() <= 0) {
Slog.w(TAG, "**** NO PENDING STARTS! " + r + " startReq=" + r.startRequested
+ " delayedStop=" + r.delayedStop);
@@ -277,7 +277,7 @@ public final class ActiveServices {
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "startService: " + service
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "startService: " + service
+ " type=" + resolvedType + " args=" + service.getExtras());
final boolean callerFg;
@@ -337,7 +337,7 @@ public final class ActiveServices {
if (r.delayed) {
// This service is already scheduled for a delayed start; just leave
// it still waiting.
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Continuing to delay: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Continuing to delay: " + r);
return r.name;
}
if (smap.mStartingBackground.size() >= mMaxStartingBackground) {
@@ -347,15 +347,15 @@ public final class ActiveServices {
r.delayed = true;
return r.name;
}
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying: " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying: " + r);
addToStarting = true;
} else if (proc.curProcState >= ActivityManager.PROCESS_STATE_SERVICE) {
// We slightly loosen when we will enqueue this new service as a background
// starting service we are waiting for, to also include processes that are
// currently running other services or receivers.
addToStarting = true;
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
- } else if (DEBUG_DELAYED_STATS) {
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Not delaying, but counting as bg: " + r);
+ } else if (DEBUG_DELAYED_STARTS) {
StringBuilder sb = new StringBuilder(128);
sb.append("Not potential delay (state=").append(proc.curProcState)
.append(' ').append(proc.adjType);
@@ -368,7 +368,7 @@ public final class ActiveServices {
sb.append(r.toString());
Slog.v(TAG, sb.toString());
}
- } else if (DEBUG_DELAYED_STATS) {
+ } else if (DEBUG_DELAYED_STARTS) {
if (callerFg) {
Slog.v(TAG, "Not potential delay (callerFg=" + callerFg + " uid="
+ callingUid + " pid=" + callingPid + "): " + r);
@@ -405,7 +405,7 @@ public final class ActiveServices {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.v(TAG, "Starting background (first=" + first + "): " + r, here);
- } else if (DEBUG_DELAYED_STATS) {
+ } else if (DEBUG_DELAYED_STARTS) {
Slog.v(TAG, "Starting background (first=" + first + "): " + r);
}
if (first) {
@@ -423,7 +423,7 @@ public final class ActiveServices {
// If service isn't actually running, but is is being held in the
// delayed list, then we need to keep it started but note that it
// should be stopped once no longer delayed.
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Delaying stop of pending: " + service);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Delaying stop of pending: " + service);
service.delayedStop = true;
return;
}
@@ -1279,7 +1279,7 @@ public final class ActiveServices {
// Make sure this service is no longer considered delayed, we are starting it now.
if (r.delayed) {
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
@@ -1362,7 +1362,7 @@ public final class ActiveServices {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
stopServiceLocked(r);
}
}
@@ -1433,7 +1433,7 @@ public final class ActiveServices {
sendServiceArgsLocked(r, execInFg, true);
if (r.delayed) {
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false;
}
@@ -1442,7 +1442,7 @@ public final class ActiveServices {
// Oh and hey we've already been asked to stop!
r.delayedStop = false;
if (r.startRequested) {
- if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
+ if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
@@ -1848,7 +1848,7 @@ public final class ActiveServices {
}
}
if (finishing) {
- if (r.app != null) {
+ if (r.app != null && !r.app.persistent) {
r.app.services.remove(r);
}
r.app = null;
@@ -1931,7 +1931,9 @@ public final class ActiveServices {
Slog.i(TAG, " Force stopping service " + service);
if (service.app != null) {
service.app.removed = true;
- service.app.services.remove(service);
+ if (!service.app.persistent) {
+ service.app.services.remove(service);
+ }
}
service.app = null;
service.isolatedProc = null;
@@ -2033,7 +2035,7 @@ public final class ActiveServices {
synchronized (sr.stats.getBatteryStats()) {
sr.stats.stopLaunchedLocked();
}
- if (sr.app != null) {
+ if (sr.app != app && sr.app != null && !sr.app.persistent) {
sr.app.services.remove(sr);
}
sr.app = null;
@@ -2066,13 +2068,19 @@ public final class ActiveServices {
// Now do remaining service cleanup.
for (int i=app.services.size()-1; i>=0; i--) {
ServiceRecord sr = app.services.valueAt(i);
+
+ // Unless the process is persistent, this process record is going away,
+ // so make sure the service is cleaned out of it.
+ if (!app.persistent) {
+ app.services.removeAt(i);
+ }
+
// Sanity check: if the service listed for the app is not one
- // we actually are maintaining, drop it.
+ // we actually are maintaining, just let it drop.
if (smap.mServicesByName.get(sr.name) != sr) {
ServiceRecord cur = smap.mServicesByName.get(sr.name);
Slog.wtf(TAG, "Service " + sr + " in process " + app
+ " not same as in map: " + cur);
- app.services.removeAt(i);
continue;
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8a32bfd..80145c7 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1328,7 +1328,7 @@ public final class ActivityManagerService extends ActivityManagerNative
String pkg = bundle.getString("pkg");
String reason = bundle.getString("reason");
forceStopPackageLocked(pkg, appid, restart, false, true, false,
- UserHandle.USER_ALL, reason);
+ false, UserHandle.USER_ALL, reason);
}
} break;
case FINALIZE_PENDING_INTENT_MSG: {
@@ -4515,7 +4515,7 @@ public final class ActivityManagerService extends ActivityManagerNative
private void forceStopPackageLocked(final String packageName, int uid, String reason) {
forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
- false, true, false, UserHandle.getUserId(uid), reason);
+ false, true, false, false, UserHandle.getUserId(uid), reason);
Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
Uri.fromParts("package", packageName, null));
if (!mProcessesReady) {
@@ -4531,7 +4531,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private void forceStopUserLocked(int userId, String reason) {
- forceStopPackageLocked(null, -1, false, false, true, false, userId, reason);
+ forceStopPackageLocked(null, -1, false, false, true, false, false, userId, reason);
Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
@@ -4616,7 +4616,7 @@ public final class ActivityManagerService extends ActivityManagerNative
private final boolean forceStopPackageLocked(String name, int appId,
boolean callerWillRestart, boolean purgeCache, boolean doit,
- boolean evenPersistent, int userId, String reason) {
+ boolean evenPersistent, boolean uninstalling, int userId, String reason) {
int i;
int N;
@@ -4708,7 +4708,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// Remove transient permissions granted from/to this package/user
removeUriPermissionsForPackageLocked(name, userId, false);
- if (name == null) {
+ if (name == null || uninstalling) {
// Remove pending intents. For now we only do this when force
// stopping users, because we have some problems when doing this
// for packages -- app widgets are not currently cleaned up for
@@ -5153,7 +5153,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (pkgs != null) {
for (String pkg : pkgs) {
synchronized (ActivityManagerService.this) {
- if (forceStopPackageLocked(pkg, -1, false, false, false, false, 0,
+ if (forceStopPackageLocked(pkg, -1, false, false, false, false, false, 0,
"finished booting")) {
setResultCode(Activity.RESULT_OK);
return;
@@ -8466,7 +8466,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mDebugTransient = !persistent;
if (packageName != null) {
forceStopPackageLocked(packageName, -1, false, false, true, true,
- UserHandle.USER_ALL, "set debug app");
+ false, UserHandle.USER_ALL, "set debug app");
}
}
} finally {
@@ -9246,8 +9246,13 @@ public final class ActivityManagerService extends ActivityManagerNative
ActivityInfo ai = ris.get(i).activityInfo;
ComponentName comp = new ComponentName(ai.packageName, ai.name);
if (lastDoneReceivers.contains(comp)) {
+ // We already did the pre boot receiver for this app with the current
+ // platform version, so don't do it again...
ris.remove(i);
i--;
+ // ...however, do keep it as one that has been done, so we don't
+ // forget about it when rewriting the file of last done receivers.
+ doneReceivers.add(comp);
}
}
@@ -13395,7 +13400,7 @@ public final class ActivityManagerService extends ActivityManagerNative
String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
if (list != null && (list.length > 0)) {
for (String pkg : list) {
- forceStopPackageLocked(pkg, -1, false, true, true, false, userId,
+ forceStopPackageLocked(pkg, -1, false, true, true, false, false, userId,
"storage unmount");
}
sendPackageBroadcastLocked(
@@ -13407,10 +13412,13 @@ public final class ActivityManagerService extends ActivityManagerNative
if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(
intent.getAction());
+ boolean fullUninstall = removed &&
+ !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
forceStopPackageLocked(ssp, UserHandle.getAppId(
intent.getIntExtra(Intent.EXTRA_UID, -1)), false, true, true,
- false, userId, removed ? "pkg removed" : "pkg changed");
+ false, fullUninstall, userId,
+ removed ? "pkg removed" : "pkg changed");
}
if (removed) {
sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
@@ -13897,7 +13905,7 @@ public final class ActivityManagerService extends ActivityManagerNative
final long origId = Binder.clearCallingIdentity();
// Instrumentation can kill and relaunch even persistent processes
- forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId,
+ forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, false, userId,
"start instr");
ProcessRecord app = addAppLocked(ai, false);
app.instrumentationClass = className;
@@ -13965,7 +13973,7 @@ public final class ActivityManagerService extends ActivityManagerNative
app.instrumentationProfileFile = null;
app.instrumentationArguments = null;
- forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, app.userId,
+ forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId,
"finished inst");
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index 07c2201..4d6727c 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -1289,17 +1289,7 @@ final class ActivityStack {
if (prevTask != null && prevTask.mOnTopOfHome && prev.finishing && prev.frontOfTask) {
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
if (prevTask == nextTask) {
- ArrayList<ActivityRecord> activities = prevTask.mActivities;
- final int numActivities = activities.size();
- for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- // r is usually the same as next, but what if two activities were launched
- // before prev finished?
- if (!r.finishing) {
- r.frontOfTask = true;
- break;
- }
- }
+ prevTask.setFrontOfTask();
} else if (prevTask != topTask()) {
// This task is going away but it was supposed to return to the home task.
// Now the task above it has to return to the home task instead.
@@ -1751,9 +1741,9 @@ final class ActivityStack {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Adding activity " + r + " to stack to task " + task,
new RuntimeException("here").fillInStackTrace());
task.addActivityToTop(r);
+ task.setFrontOfTask();
r.putInHistory();
- r.frontOfTask = newTask;
if (!isHomeStack() || numActivities() > 0) {
// We want to show the starting preview window if we are
// switching to a new task, or the next activity's process is
@@ -2414,15 +2404,12 @@ final class ActivityStack {
final ArrayList<ActivityRecord> activities = r.task.mActivities;
final int index = activities.indexOf(r);
if (index < (activities.size() - 1)) {
- ActivityRecord next = activities.get(index+1);
- if (r.frontOfTask) {
- // The next activity is now the front of the task.
- next.frontOfTask = true;
- }
+ r.task.setFrontOfTask();
if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
// If the caller asked that this activity (and all above it)
// be cleared when the task is reset, don't lose that information,
// but propagate it up to the next activity.
+ ActivityRecord next = activities.get(index+1);
next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
}
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index 93de0a6..d616f1b 100755..100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1134,6 +1134,19 @@ public final class ActivityStackSupervisor {
resultRecord.removeResultsLocked(
sourceRecord, resultWho, requestCode);
}
+ if (sourceRecord.launchedFromUid == callingUid) {
+ // The new activity is being launched from the same uid as the previous
+ // activity in the flow, and asking to forward its result back to the
+ // previous. In this case the activity is serving as a trampoline between
+ // the two, so we also want to update its launchedFromPackage to be the
+ // same as the previous activity. Note that this is safe, since we know
+ // these two packages come from the same uid; the caller could just as
+ // well have supplied that same package name itself. This specifially
+ // deals with the case of an intent picker/chooser being launched in the app
+ // flow to redirect to an activity picked by the user, where we want the final
+ // activity to consider it to have been launched by the previous app activity.
+ callingPackage = sourceRecord.launchedFromPackage;
+ }
}
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
@@ -1425,7 +1438,6 @@ public final class ActivityStackSupervisor {
r.resultTo = null;
}
- boolean switchStackFromBg = false;
boolean addingToTask = false;
boolean movedHome = false;
TaskRecord reuseTask = null;
@@ -1487,11 +1499,6 @@ public final class ActivityStackSupervisor {
}
options = null;
}
- } else {
- switchStackFromBg = lastStack != targetStack;
- if (DEBUG_TASKS) Slog.d(TAG, "Caller " + sourceRecord
- + " is not top task, it may not move " + r
- + " to front, switchStack=" + switchStackFromBg);
}
// If the caller has requested that the target task be
// reset, then do so.
@@ -1599,10 +1606,6 @@ public final class ActivityStackSupervisor {
// don't use that intent!) And for paranoia, make
// sure we have correctly resumed the top activity.
if (doResume) {
- if (switchStackFromBg) {
- moveHomeStack(lastStack.isHomeStack());
- targetStack = lastStack;
- }
targetStack.resumeTopActivityLocked(null, options);
} else {
ActivityOptions.abort(options);
@@ -1706,6 +1709,7 @@ public final class ActivityStackSupervisor {
TaskRecord sourceTask = sourceRecord.task;
targetStack = sourceTask.stack;
moveHomeStack(targetStack.isHomeStack());
+ mWindowManager.moveTaskToTop(sourceTask.taskId);
if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
// In this case, we are adding the activity to an existing
@@ -1764,6 +1768,7 @@ public final class ActivityStackSupervisor {
r.setTask(prev != null ? prev.task
: targetStack.createTaskRecord(getNextTaskId(), r.info, intent, true),
null, true);
+ mWindowManager.moveTaskToTop(r.task.taskId);
if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
+ " in new guessed " + r.task);
}
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 3d568ff..9105103 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -159,18 +159,33 @@ final class TaskRecord extends ThumbnailHolder {
return null;
}
+ /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
+ final void setFrontOfTask() {
+ boolean foundFront = false;
+ final int numActivities = mActivities.size();
+ for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
+ final ActivityRecord r = mActivities.get(activityNdx);
+ if (foundFront || r.finishing) {
+ r.frontOfTask = false;
+ } else {
+ r.frontOfTask = true;
+ // Set frontOfTask false for every following activity.
+ foundFront = true;
+ }
+ }
+ }
+
/**
- * Reorder the history stack so that the activity at the given index is
- * brought to the front.
+ * Reorder the history stack so that the passed activity is brought to the front.
*/
final void moveActivityToFrontLocked(ActivityRecord newTop) {
if (DEBUG_ADD_REMOVE) Slog.i(TAG, "Removing and adding activity " + newTop
+ " to stack at top", new RuntimeException("here").fillInStackTrace());
- getTopActivity().frontOfTask = false;
mActivities.remove(newTop);
mActivities.add(newTop);
- newTop.frontOfTask = true;
+
+ setFrontOfTask();
}
void addActivityAtBottom(ActivityRecord r) {
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 2ca2cc5..376414b 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -45,6 +45,7 @@ import android.net.LinkProperties;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.net.NetworkInfo;
+import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.NetworkInfo.DetailedState;
import android.os.Binder;
@@ -77,6 +78,7 @@ import com.android.server.net.BaseNetworkObserver;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
@@ -282,13 +284,12 @@ public class Vpn extends BaseNetworkStateTracker {
}
/**
- * Protect a socket from routing changes by binding it to the given
- * interface. The socket is NOT closed by this method.
+ * Protect a socket from VPN rules by binding it to the main routing table.
+ * The socket is NOT closed by this method.
*
* @param socket The socket to be bound.
- * @param interfaze The name of the interface.
*/
- public void protect(ParcelFileDescriptor socket, String interfaze) throws Exception {
+ public void protect(ParcelFileDescriptor socket) throws Exception {
PackageManager pm = mContext.getPackageManager();
int appUid = pm.getPackageUid(mPackage, mUserId);
@@ -302,8 +303,6 @@ public class Vpn extends BaseNetworkStateTracker {
} finally {
Binder.restoreCallingIdentity(token);
}
- // bind the socket to the interface
- jniProtect(socket.getFd(), interfaze);
}
@@ -353,6 +352,12 @@ public class Vpn extends BaseNetworkStateTracker {
Binder.restoreCallingIdentity(token);
}
+ // Save the old config in case we need to go back.
+ VpnConfig oldConfig = mConfig;
+ String oldInterface = mInterface;
+ Connection oldConnection = mConnection;
+ SparseBooleanArray oldUsers = mVpnUsers;
+
// Configure the interface. Abort if any of these steps fails.
ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
try {
@@ -372,12 +377,7 @@ public class Vpn extends BaseNetworkStateTracker {
new UserHandle(mUserId))) {
throw new IllegalStateException("Cannot bind " + config.user);
}
- if (mConnection != null) {
- mContext.unbindService(mConnection);
- }
- if (mInterface != null && !mInterface.equals(interfaze)) {
- jniReset(mInterface);
- }
+
mConnection = connection;
mInterface = interfaze;
@@ -386,55 +386,91 @@ public class Vpn extends BaseNetworkStateTracker {
config.interfaze = mInterface;
config.startTime = SystemClock.elapsedRealtime();
mConfig = config;
+
// Set up forwarding and DNS rules.
mVpnUsers = new SparseBooleanArray();
token = Binder.clearCallingIdentity();
try {
mCallback.setMarkedForwarding(mInterface);
- mCallback.setRoutes(interfaze, config.routes);
+ mCallback.setRoutes(mInterface, config.routes);
mCallback.override(mInterface, config.dnsServers, config.searchDomains);
addVpnUserLocked(mUserId);
-
+ // If we are owner assign all Restricted Users to this VPN
+ if (mUserId == UserHandle.USER_OWNER) {
+ for (UserInfo user : mgr.getUsers()) {
+ if (user.isRestricted()) {
+ try {
+ addVpnUserLocked(user.id);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Failed to add user " + user.id + " to owner's VPN");
+ }
+ }
+ }
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
+ if (oldConnection != null) {
+ mContext.unbindService(oldConnection);
+ }
+ if (oldInterface != null && !oldInterface.equals(interfaze)) {
+ // Remove the old tun's user forwarding rules
+ // The new tun's user rules have already been added so they will take over
+ // as rules are deleted. This prevents data leakage as the rules are moved over.
+ token = Binder.clearCallingIdentity();
+ try {
+ final int size = oldUsers.size();
+ final boolean forwardDns = (oldConfig.dnsServers != null &&
+ oldConfig.dnsServers.size() != 0);
+ for (int i = 0; i < size; i++) {
+ int user = oldUsers.keyAt(i);
+ mCallback.clearUserForwarding(oldInterface, user, forwardDns);
+ }
+ mCallback.clearMarkedForwarding(oldInterface);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ jniReset(oldInterface);
+ }
} catch (RuntimeException e) {
updateState(DetailedState.FAILED, "establish");
IoUtils.closeQuietly(tun);
// make sure marked forwarding is cleared if it was set
+ token = Binder.clearCallingIdentity();
try {
mCallback.clearMarkedForwarding(mInterface);
} catch (Exception ingored) {
// ignored
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
+ // restore old state
+ mConfig = oldConfig;
+ mConnection = oldConnection;
+ mVpnUsers = oldUsers;
+ mInterface = oldInterface;
throw e;
}
Log.i(TAG, "Established by " + config.user + " on " + mInterface);
-
- // If we are owner assign all Restricted Users to this VPN
- if (mUserId == UserHandle.USER_OWNER) {
- token = Binder.clearCallingIdentity();
- try {
- for (UserInfo user : mgr.getUsers()) {
- if (user.isRestricted()) {
- try {
- addVpnUserLocked(user.id);
- } catch (Exception e) {
- Log.wtf(TAG, "Failed to add user " + user.id + " to owner's VPN");
- }
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
// TODO: ensure that contract class eventually marks as connected
updateState(DetailedState.AUTHENTICATING, "establish");
return tun;
}
+ /**
+ * Check if a given address is covered by the VPN's routing rules.
+ */
+ public boolean isAddressCovered(InetAddress address) {
+ synchronized (Vpn.this) {
+ if (!isRunningLocked()) {
+ return false;
+ }
+ return RouteInfo.selectBestRoute(mConfig.routes, address) != null;
+ }
+ }
+
private boolean isRunningLocked() {
return mVpnUsers != null;
}
@@ -670,7 +706,6 @@ public class Vpn extends BaseNetworkStateTracker {
private native int jniSetRoutes(String interfaze, String routes);
private native void jniReset(String interfaze);
private native int jniCheck(String interfaze);
- private native void jniProtect(int socket, String interfaze);
private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) {
for (RouteInfo route : prop.getAllRoutes()) {
diff --git a/services/java/com/android/server/content/SyncManager.java b/services/java/com/android/server/content/SyncManager.java
index 71d8d99..9e3dad6 100644
--- a/services/java/com/android/server/content/SyncManager.java
+++ b/services/java/com/android/server/content/SyncManager.java
@@ -2352,7 +2352,7 @@ public class SyncManager {
Log.v(TAG, "canceling and rescheduling sync since an initialization "
+ "takes higher priority, " + conflict);
}
- } else if (candidate.expedited && !conflict.mSyncOperation.expedited
+ } else if (candidate.isExpedited() && !conflict.mSyncOperation.isExpedited()
&& (candidateIsInitialization
== conflict.mSyncOperation.isInitialization())) {
toReschedule = conflict;
diff --git a/services/java/com/android/server/content/SyncOperation.java b/services/java/com/android/server/content/SyncOperation.java
index 4856747..67e3b09 100644
--- a/services/java/com/android/server/content/SyncOperation.java
+++ b/services/java/com/android/server/content/SyncOperation.java
@@ -66,7 +66,8 @@ public class SyncOperation implements Comparable {
public final boolean allowParallelSyncs;
public Bundle extras;
public final String key;
- public boolean expedited;
+ /** Internal boolean to avoid reading a bundle everytime we want to compare operations. */
+ private final boolean expedited;
public SyncStorageEngine.PendingOperation pendingOperation;
/** Elapsed real time in millis at which to run this sync. */
public long latestRunTime;
@@ -79,7 +80,7 @@ public class SyncOperation implements Comparable {
* Depends on max(backoff, latestRunTime, and delayUntil).
*/
public long effectiveRunTime;
- /** Amount of time before {@link effectiveRunTime} from which this sync can run. */
+ /** Amount of time before {@link #effectiveRunTime} from which this sync can run. */
public long flexTime;
public SyncOperation(Account account, int userId, int reason, int source, String authority,
@@ -98,11 +99,16 @@ public class SyncOperation implements Comparable {
this.backoff = backoff;
final long now = SystemClock.elapsedRealtime();
// Checks the extras bundle. Must occur after we set the internal bundle.
- if (runTimeFromNow < 0 || isExpedited()) {
+ if (runTimeFromNow < 0) {
+ // Sanity check: Will always be true.
+ if (!this.extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
+ this.extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ }
this.expedited = true;
this.latestRunTime = now;
this.flexTime = 0;
} else {
+ this.extras.remove(ContentResolver.SYNC_EXTRAS_EXPEDITED);
this.expedited = false;
this.latestRunTime = now + runTimeFromNow;
this.flexTime = flexTime;
@@ -111,6 +117,24 @@ public class SyncOperation implements Comparable {
this.key = toKey();
}
+ /** Only used to immediately reschedule a sync. */
+ SyncOperation(SyncOperation other) {
+ this.service = other.service;
+ this.account = other.account;
+ this.authority = other.authority;
+ this.userId = other.userId;
+ this.reason = other.reason;
+ this.syncSource = other.syncSource;
+ this.extras = new Bundle(other.extras);
+ this.expedited = other.expedited;
+ this.latestRunTime = SystemClock.elapsedRealtime();
+ this.flexTime = 0L;
+ this.backoff = other.backoff;
+ this.allowParallelSyncs = other.allowParallelSyncs;
+ this.updateEffectiveRunTime();
+ this.key = toKey();
+ }
+
/**
* Make sure the bundle attached to this SyncOperation doesn't have unnecessary
* flags set.
@@ -138,24 +162,6 @@ public class SyncOperation implements Comparable {
}
}
- /** Only used to immediately reschedule a sync. */
- SyncOperation(SyncOperation other) {
- this.service = other.service;
- this.account = other.account;
- this.authority = other.authority;
- this.userId = other.userId;
- this.reason = other.reason;
- this.syncSource = other.syncSource;
- this.extras = new Bundle(other.extras);
- this.expedited = other.expedited;
- this.latestRunTime = SystemClock.elapsedRealtime();
- this.flexTime = 0L;
- this.backoff = other.backoff;
- this.allowParallelSyncs = other.allowParallelSyncs;
- this.updateEffectiveRunTime();
- this.key = toKey();
- }
-
@Override
public String toString() {
return dump(null, true);
@@ -220,7 +226,7 @@ public class SyncOperation implements Comparable {
}
public boolean isExpedited() {
- return extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false) || expedited;
+ return expedited;
}
public boolean ignoreBackoff() {
diff --git a/services/java/com/android/server/content/SyncQueue.java b/services/java/com/android/server/content/SyncQueue.java
index 6f3fe6e..22fa2de 100644
--- a/services/java/com/android/server/content/SyncQueue.java
+++ b/services/java/com/android/server/content/SyncQueue.java
@@ -73,10 +73,9 @@ public class SyncQueue {
}
SyncOperation syncOperation = new SyncOperation(
op.account, op.userId, op.reason, op.syncSource, op.authority, op.extras,
- 0 /* delay */, 0 /* flex */, backoff != null ? backoff.first : 0,
+ op.expedited ? -1: 0 /* delay */, 0 /* flex */, backoff != null ? backoff.first : 0,
mSyncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
syncAdapterInfo.type.allowParallelSyncs());
- syncOperation.expedited = op.expedited;
syncOperation.pendingOperation = op;
add(syncOperation, op);
}
@@ -104,7 +103,6 @@ public class SyncQueue {
if (existingOperation != null) {
boolean changed = false;
if (operation.compareTo(existingOperation) <= 0 ) {
- existingOperation.expedited = operation.expedited;
long newRunTime =
Math.min(existingOperation.latestRunTime, operation.latestRunTime);
// Take smaller runtime.
@@ -123,7 +121,7 @@ public class SyncQueue {
if (operation.pendingOperation == null) {
pop = new SyncStorageEngine.PendingOperation(
operation.account, operation.userId, operation.reason, operation.syncSource,
- operation.authority, operation.extras, operation.expedited);
+ operation.authority, operation.extras, operation.isExpedited());
pop = mSyncStorageEngine.insertIntoPending(pop);
if (pop == null) {
throw new IllegalStateException("error adding pending sync operation "
diff --git a/services/java/com/android/server/content/SyncStorageEngine.java b/services/java/com/android/server/content/SyncStorageEngine.java
index 124bc60..178c372 100644
--- a/services/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/java/com/android/server/content/SyncStorageEngine.java
@@ -501,7 +501,7 @@ public class SyncStorageEngine extends Handler {
* @return amount of seconds before syncTimeSeconds that the sync can occur.
* I.e.
* earliest_sync_time = syncTimeSeconds - calculateDefaultFlexTime(syncTimeSeconds)
- * The flex time is capped at a percentage of the {@link DEFAULT_POLL_FREQUENCY_SECONDS}.
+ * The flex time is capped at a percentage of the {@link #DEFAULT_POLL_FREQUENCY_SECONDS}.
*/
public static long calculateDefaultFlexTime(long syncTimeSeconds) {
if (syncTimeSeconds < DEFAULT_MIN_FLEX_ALLOWED_SECS) {
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 02f26b3..bcb677f 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -35,6 +35,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.text.TextUtils;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -173,6 +174,9 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
// The Wifi display adapter, or null if not registered.
private WifiDisplayAdapter mWifiDisplayAdapter;
+ // The number of active wifi display scan requests.
+ private int mWifiDisplayScanRequestCount;
+
// The virtual display adapter, or null if not registered.
private VirtualDisplayAdapter mVirtualDisplayAdapter;
@@ -458,29 +462,81 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
}
- private void onCallbackDied(int pid) {
+ private void onCallbackDied(CallbackRecord record) {
synchronized (mSyncRoot) {
- mCallbacks.remove(pid);
+ mCallbacks.remove(record.mPid);
+ stopWifiDisplayScanLocked(record);
}
}
@Override // Binder call
- public void scanWifiDisplays() {
+ public void startWifiDisplayScan() {
mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
- "Permission required to scan wifi displays");
+ "Permission required to start wifi display scans");
+ final int callingPid = Binder.getCallingPid();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
+ CallbackRecord record = mCallbacks.get(callingPid);
+ if (record == null) {
+ throw new IllegalStateException("The calling process has not "
+ + "registered an IDisplayManagerCallback.");
+ }
+ startWifiDisplayScanLocked(record);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private void startWifiDisplayScanLocked(CallbackRecord record) {
+ if (!record.mWifiDisplayScanRequested) {
+ record.mWifiDisplayScanRequested = true;
+ if (mWifiDisplayScanRequestCount++ == 0) {
if (mWifiDisplayAdapter != null) {
- mWifiDisplayAdapter.requestScanLocked();
+ mWifiDisplayAdapter.requestStartScanLocked();
}
}
+ }
+ }
+
+ @Override // Binder call
+ public void stopWifiDisplayScan() {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.CONFIGURE_WIFI_DISPLAY,
+ "Permission required to stop wifi display scans");
+
+ final int callingPid = Binder.getCallingPid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ synchronized (mSyncRoot) {
+ CallbackRecord record = mCallbacks.get(callingPid);
+ if (record == null) {
+ throw new IllegalStateException("The calling process has not "
+ + "registered an IDisplayManagerCallback.");
+ }
+ stopWifiDisplayScanLocked(record);
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
}
+ private void stopWifiDisplayScanLocked(CallbackRecord record) {
+ if (record.mWifiDisplayScanRequested) {
+ record.mWifiDisplayScanRequested = false;
+ if (--mWifiDisplayScanRequestCount == 0) {
+ if (mWifiDisplayAdapter != null) {
+ mWifiDisplayAdapter.requestStopScanLocked();
+ }
+ } else if (mWifiDisplayScanRequestCount < 0) {
+ Log.wtf(TAG, "mWifiDisplayScanRequestCount became negative: "
+ + mWifiDisplayScanRequestCount);
+ mWifiDisplayScanRequestCount = 0;
+ }
+ }
+ }
+
@Override // Binder call
public void connectWifiDisplay(String address) {
if (address == null) {
@@ -1107,6 +1163,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
pw.println(" mDefaultViewport=" + mDefaultViewport);
pw.println(" mExternalTouchViewport=" + mExternalTouchViewport);
pw.println(" mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
+ pw.println(" mWifiDisplayScanRequestCount=" + mWifiDisplayScanRequestCount);
IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
ipw.increaseIndent();
@@ -1134,6 +1191,15 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
pw.println(" Display " + displayId + ":");
display.dumpLocked(ipw);
}
+
+ final int callbackCount = mCallbacks.size();
+ pw.println();
+ pw.println("Callbacks: size=" + callbackCount);
+ for (int i = 0; i < callbackCount; i++) {
+ CallbackRecord callback = mCallbacks.valueAt(i);
+ pw.println(" " + i + ": mPid=" + callback.mPid
+ + ", mWifiDisplayScanRequested=" + callback.mWifiDisplayScanRequested);
+ }
}
}
@@ -1234,9 +1300,11 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
}
private final class CallbackRecord implements DeathRecipient {
- private final int mPid;
+ public final int mPid;
private final IDisplayManagerCallback mCallback;
+ public boolean mWifiDisplayScanRequested;
+
public CallbackRecord(int pid, IDisplayManagerCallback callback) {
mPid = pid;
mCallback = callback;
@@ -1247,7 +1315,7 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
if (DEBUG) {
Slog.d(TAG, "Display listener for pid " + mPid + " died.");
}
- onCallbackDied(mPid);
+ onCallbackDied(this);
}
public void notifyDisplayEventAsync(int displayId, int event) {
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index fdef039..cd57941 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -127,7 +127,7 @@ final class WifiDisplayAdapter extends DisplayAdapter {
pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
pw.println("mPendingNotificationUpdate=" + mPendingNotificationUpdate);
pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
-
+
// Try to dump the controller state.
if (mDisplayController == null) {
pw.println("mDisplayController=null");
@@ -157,43 +157,49 @@ final class WifiDisplayAdapter extends DisplayAdapter {
});
}
- public void requestScanLocked() {
+ public void requestStartScanLocked() {
if (DEBUG) {
- Slog.d(TAG, "requestScanLocked");
+ Slog.d(TAG, "requestStartScanLocked");
}
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
- mDisplayController.requestScan();
+ mDisplayController.requestStartScan();
}
}
});
}
- public void requestConnectLocked(final String address) {
+ public void requestStopScanLocked() {
if (DEBUG) {
- Slog.d(TAG, "requestConnectLocked: address=" + address);
+ Slog.d(TAG, "requestStopScanLocked");
}
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
- mDisplayController.requestConnect(address);
+ mDisplayController.requestStopScan();
}
}
});
}
- private boolean isRememberedDisplayLocked(String address) {
- for (WifiDisplay display : mRememberedDisplays) {
- if (display.getDeviceAddress().equals(address)) {
- return true;
- }
+ public void requestConnectLocked(final String address) {
+ if (DEBUG) {
+ Slog.d(TAG, "requestConnectLocked: address=" + address);
}
- return false;
+
+ getHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ if (mDisplayController != null) {
+ mDisplayController.requestConnect(address);
+ }
+ }
+ });
}
public void requestPauseLocked() {
@@ -552,20 +558,20 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
@Override
- public void onScanFinished(WifiDisplay[] availableDisplays) {
+ public void onScanResults(WifiDisplay[] availableDisplays) {
synchronized (getSyncRoot()) {
availableDisplays = mPersistentDataStore.applyWifiDisplayAliases(
availableDisplays);
- // check if any of the available displays changed canConnect status
boolean changed = !Arrays.equals(mAvailableDisplays, availableDisplays);
+
+ // Check whether any of the available displays changed canConnect status.
for (int i = 0; !changed && i<availableDisplays.length; i++) {
changed = availableDisplays[i].canConnect()
!= mAvailableDisplays[i].canConnect();
}
- if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING || changed) {
- mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
+ if (changed) {
mAvailableDisplays = availableDisplays;
fixRememberedDisplayNamesFromAvailableDisplaysLocked();
updateDisplaysLocked();
@@ -575,6 +581,16 @@ final class WifiDisplayAdapter extends DisplayAdapter {
}
@Override
+ public void onScanFinished() {
+ synchronized (getSyncRoot()) {
+ if (mScanState != WifiDisplayStatus.SCAN_STATE_NOT_SCANNING) {
+ mScanState = WifiDisplayStatus.SCAN_STATE_NOT_SCANNING;
+ scheduleStatusChangedBroadcastLocked();
+ }
+ }
+ }
+
+ @Override
public void onDisplayConnecting(WifiDisplay display) {
synchronized (getSyncRoot()) {
display = mPersistentDataStore.applyWifiDisplayAlias(display);
diff --git a/services/java/com/android/server/display/WifiDisplayController.java b/services/java/com/android/server/display/WifiDisplayController.java
index b2939fe..dbb59b2 100644
--- a/services/java/com/android/server/display/WifiDisplayController.java
+++ b/services/java/com/android/server/display/WifiDisplayController.java
@@ -27,7 +27,6 @@ import android.database.ContentObserver;
import android.hardware.display.WifiDisplay;
import android.hardware.display.WifiDisplaySessionInfo;
import android.hardware.display.WifiDisplayStatus;
-import android.media.AudioManager;
import android.media.RemoteDisplay;
import android.net.NetworkInfo;
import android.net.Uri;
@@ -75,12 +74,19 @@ final class WifiDisplayController implements DumpUtils.Dump {
private static final int DEFAULT_CONTROL_PORT = 7236;
private static final int MAX_THROUGHPUT = 50;
- private static final int CONNECTION_TIMEOUT_SECONDS = 60;
+ private static final int CONNECTION_TIMEOUT_SECONDS = 30;
private static final int RTSP_TIMEOUT_SECONDS = 30;
private static final int RTSP_TIMEOUT_SECONDS_CERT_MODE = 120;
- private static final int DISCOVER_PEERS_MAX_RETRIES = 10;
- private static final int DISCOVER_PEERS_RETRY_DELAY_MILLIS = 500;
+ // We repeatedly issue calls to discover peers every so often for a few reasons.
+ // 1. The initial request may fail and need to retried.
+ // 2. Discovery will self-abort after any group is initiated, which may not necessarily
+ // be what we want to have happen.
+ // 3. Discovery will self-timeout after 2 minutes, whereas we want discovery to
+ // be occur for as long as a client is requesting it be.
+ // 4. We don't seem to get updated results for displays we've already found until
+ // we ask to discover again, particularly for the isSessionAvailable() property.
+ private static final int DISCOVER_PEERS_INTERVAL_MILLIS = 10000;
private static final int CONNECT_MAX_RETRIES = 3;
private static final int CONNECT_RETRY_DELAY_MILLIS = 500;
@@ -103,12 +109,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
// True if Wifi display is enabled by the user.
private boolean mWifiDisplayOnSetting;
+ // True if a scan was requested independent of whether one is actually in progress.
+ private boolean mScanRequested;
+
// True if there is a call to discoverPeers in progress.
private boolean mDiscoverPeersInProgress;
- // Number of discover peers retries remaining.
- private int mDiscoverPeersRetriesLeft;
-
// The device to which we want to connect, or null if we want to be disconnected.
private WifiP2pDevice mDesiredDevice;
@@ -209,8 +215,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
pw.println("mWfdEnabled=" + mWfdEnabled);
pw.println("mWfdEnabling=" + mWfdEnabling);
pw.println("mNetworkInfo=" + mNetworkInfo);
+ pw.println("mScanRequested=" + mScanRequested);
pw.println("mDiscoverPeersInProgress=" + mDiscoverPeersInProgress);
- pw.println("mDiscoverPeersRetriesLeft=" + mDiscoverPeersRetriesLeft);
pw.println("mDesiredDevice=" + describeWifiP2pDevice(mDesiredDevice));
pw.println("mConnectingDisplay=" + describeWifiP2pDevice(mConnectingDevice));
pw.println("mDisconnectingDisplay=" + describeWifiP2pDevice(mDisconnectingDevice));
@@ -232,8 +238,18 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
- public void requestScan() {
- discoverPeers();
+ public void requestStartScan() {
+ if (!mScanRequested) {
+ mScanRequested = true;
+ updateScanState();
+ }
+ }
+
+ public void requestStopScan() {
+ if (mScanRequested) {
+ mScanRequested = false;
+ updateScanState();
+ }
}
public void requestConnect(String address) {
@@ -282,6 +298,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mWfdEnabling = false;
mWfdEnabled = true;
reportFeatureState();
+ updateScanState();
}
}
@@ -318,6 +335,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
mWfdEnabling = false;
mWfdEnabled = false;
reportFeatureState();
+ updateScanState();
disconnect();
}
}
@@ -340,12 +358,29 @@ final class WifiDisplayController implements DumpUtils.Dump {
WifiDisplayStatus.FEATURE_STATE_OFF;
}
- private void discoverPeers() {
- if (!mDiscoverPeersInProgress) {
- mDiscoverPeersInProgress = true;
- mDiscoverPeersRetriesLeft = DISCOVER_PEERS_MAX_RETRIES;
- handleScanStarted();
- tryDiscoverPeers();
+ private void updateScanState() {
+ if (mScanRequested && mWfdEnabled && mDesiredDevice == null) {
+ if (!mDiscoverPeersInProgress) {
+ Slog.i(TAG, "Starting Wifi display scan.");
+ mDiscoverPeersInProgress = true;
+ handleScanStarted();
+ tryDiscoverPeers();
+ }
+ } else {
+ if (mDiscoverPeersInProgress) {
+ // Cancel automatic retry right away.
+ mHandler.removeCallbacks(mDiscoverPeers);
+
+ // Defer actually stopping discovery if we have a connection attempt in progress.
+ // The wifi display connection attempt often fails if we are not in discovery
+ // mode. So we allow discovery to continue until we give up trying to connect.
+ if (mDesiredDevice == null || mDesiredDevice == mConnectedDevice) {
+ Slog.i(TAG, "Stopping Wifi display scan.");
+ mDiscoverPeersInProgress = false;
+ stopPeerDiscovery();
+ handleScanFinished();
+ }
+ }
}
}
@@ -357,8 +392,9 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Discover peers succeeded. Requesting peers now.");
}
- mDiscoverPeersInProgress = false;
- requestPeers();
+ if (mDiscoverPeersInProgress) {
+ requestPeers();
+ }
}
@Override
@@ -367,30 +403,28 @@ final class WifiDisplayController implements DumpUtils.Dump {
Slog.d(TAG, "Discover peers failed with reason " + reason + ".");
}
- if (mDiscoverPeersInProgress) {
- if (reason == 0 && mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- if (mDiscoverPeersInProgress) {
- if (mDiscoverPeersRetriesLeft > 0 && mWfdEnabled) {
- mDiscoverPeersRetriesLeft -= 1;
- if (DEBUG) {
- Slog.d(TAG, "Retrying discovery. Retries left: "
- + mDiscoverPeersRetriesLeft);
- }
- tryDiscoverPeers();
- } else {
- handleScanFinished();
- mDiscoverPeersInProgress = false;
- }
- }
- }
- }, DISCOVER_PEERS_RETRY_DELAY_MILLIS);
- } else {
- handleScanFinished();
- mDiscoverPeersInProgress = false;
- }
+ // Ignore the error.
+ // We will retry automatically in a little bit.
+ }
+ });
+
+ // Retry discover peers periodically until stopped.
+ mHandler.postDelayed(mDiscoverPeers, DISCOVER_PEERS_INTERVAL_MILLIS);
+ }
+
+ private void stopPeerDiscovery() {
+ mWifiP2pManager.stopPeerDiscovery(mWifiP2pChannel, new ActionListener() {
+ @Override
+ public void onSuccess() {
+ if (DEBUG) {
+ Slog.d(TAG, "Stop peer discovery succeeded.");
+ }
+ }
+
+ @Override
+ public void onFailure(int reason) {
+ if (DEBUG) {
+ Slog.d(TAG, "Stop peer discovery failed with reason " + reason + ".");
}
}
});
@@ -415,7 +449,9 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
- handleScanFinished();
+ if (mDiscoverPeersInProgress) {
+ handleScanResults();
+ }
}
});
}
@@ -429,7 +465,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
});
}
- private void handleScanFinished() {
+ private void handleScanResults() {
final int count = mAvailableWifiDisplayPeers.size();
final WifiDisplay[] displays = WifiDisplay.CREATOR.newArray(count);
for (int i = 0; i < count; i++) {
@@ -441,7 +477,16 @@ final class WifiDisplayController implements DumpUtils.Dump {
mHandler.post(new Runnable() {
@Override
public void run() {
- mListener.onScanFinished(displays);
+ mListener.onScanResults(displays);
+ }
+ });
+ }
+
+ private void handleScanFinished() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onScanFinished();
}
});
}
@@ -484,6 +529,12 @@ final class WifiDisplayController implements DumpUtils.Dump {
return;
}
+ if (!mWfdEnabled) {
+ Slog.i(TAG, "Ignoring request to connect to Wifi display because the "
+ +" feature is currently disabled: " + device.deviceName);
+ return;
+ }
+
mDesiredDevice = device;
mConnectionRetriesLeft = CONNECT_MAX_RETRIES;
updateConnection();
@@ -508,6 +559,10 @@ final class WifiDisplayController implements DumpUtils.Dump {
* connection is established (or not).
*/
private void updateConnection() {
+ // Step 0. Stop scans if necessary to prevent interference while connected.
+ // Resume scans later when no longer attempting to connect.
+ updateScanState();
+
// Step 1. Before we try to connect to a new device, tell the system we
// have disconnected from the old one.
if (mRemoteDisplay != null && mConnectedDevice != mDesiredDevice) {
@@ -661,7 +716,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
return; // wait for asynchronous callback
}
- // Step 6. Listen for incoming connections.
+ // Step 6. Listen for incoming RTSP connection.
if (mConnectedDevice != null && mRemoteDisplay == null) {
Inet4Address addr = getInterfaceAddress(mConnectedDeviceGroupInfo);
if (addr == null) {
@@ -817,7 +872,11 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
} else {
mConnectedDeviceGroupInfo = null;
- disconnect();
+
+ // Disconnect if we lost the network while connecting or connected to a display.
+ if (mConnectingDevice != null || mConnectedDevice != null) {
+ disconnect();
+ }
// After disconnection for a group, for some reason we have a tendency
// to get a peer change notification with an empty list of peers.
@@ -828,6 +887,13 @@ final class WifiDisplayController implements DumpUtils.Dump {
}
}
+ private final Runnable mDiscoverPeers = new Runnable() {
+ @Override
+ public void run() {
+ tryDiscoverPeers();
+ }
+ };
+
private final Runnable mConnectionTimeout = new Runnable() {
@Override
public void run() {
@@ -1033,7 +1099,8 @@ final class WifiDisplayController implements DumpUtils.Dump {
void onFeatureStateChanged(int featureState);
void onScanStarted();
- void onScanFinished(WifiDisplay[] availableDisplays);
+ void onScanResults(WifiDisplay[] availableDisplays);
+ void onScanFinished();
void onDisplayConnecting(WifiDisplay display);
void onDisplayConnectionFailed();
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 5d69ba3..309378a 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -229,6 +229,7 @@ public class PackageManagerService extends IPackageManager.Stub {
static final int SCAN_DEFER_DEX = 1<<7;
static final int SCAN_BOOTING = 1<<8;
static final int SCAN_TRUSTED_OVERLAY = 1<<9;
+ static final int SCAN_DELETE_DATA_ON_FAILURES = 1<<10;
static final int REMOVE_CHATTY = 1<<16;
@@ -354,7 +355,6 @@ public class PackageManagerService extends IPackageManager.Stub {
new HashMap<String, PackageParser.Package>();
// Information for the parser to write more useful error messages.
- File mScanningPath;
int mLastScanError;
// ----------------------------------------------------------------
@@ -1036,7 +1036,7 @@ public class PackageManagerService extends IPackageManager.Stub {
int[] uidArray = new int[] { res.pkg.applicationInfo.uid };
ArrayList<String> pkgList = new ArrayList<String>(1);
pkgList.add(res.pkg.applicationInfo.packageName);
- sendResourcesChangedBroadcast(true, false,
+ sendResourcesChangedBroadcast(true, true,
pkgList,uidArray, null);
}
}
@@ -4597,7 +4597,6 @@ public class PackageManagerService extends IPackageManager.Stub {
mLastScanError = PackageManager.INSTALL_FAILED_INVALID_APK;
return null;
}
- mScanningPath = scanFile;
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
@@ -4617,7 +4616,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (mAndroidApplication != null) {
Slog.w(TAG, "*************************************************");
Slog.w(TAG, "Core android package being redefined. Skipping.");
- Slog.w(TAG, " file=" + mScanningPath);
+ Slog.w(TAG, " file=" + scanFile);
Slog.w(TAG, "*************************************************");
mLastScanError = PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
return null;
@@ -5149,6 +5148,10 @@ public class PackageManagerService extends IPackageManager.Stub {
if ((scanMode&SCAN_NO_DEX) == 0) {
if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
== DEX_OPT_FAILED) {
+ if ((scanMode & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
+ removeDataDirsLI(pkg.packageName);
+ }
+
mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
return null;
}
@@ -5225,6 +5228,10 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageParser.Package clientPkg = clientLibPkgs.get(i);
if (performDexOptLI(clientPkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0, false)
== DEX_OPT_FAILED) {
+ if ((scanMode & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
+ removeDataDirsLI(pkg.packageName);
+ }
+
mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
return null;
}
@@ -9800,7 +9807,7 @@ public class PackageManagerService extends IPackageManager.Stub {
replacePackageLI(pkg, parseFlags, scanMode, args.user,
installerPackageName, res);
} else {
- installNewPackageLI(pkg, parseFlags, scanMode, args.user,
+ installNewPackageLI(pkg, parseFlags, scanMode | SCAN_DELETE_DATA_ON_FAILURES, args.user,
installerPackageName, res);
}
synchronized (mPackages) {
@@ -11327,7 +11334,8 @@ public class PackageManagerService extends IPackageManager.Stub {
DumpState dumpState = new DumpState();
boolean fullPreferred = false;
-
+ boolean checkin = false;
+
String packageName = null;
int opti = 0;
@@ -11341,7 +11349,8 @@ public class PackageManagerService extends IPackageManager.Stub {
// Right now we only know how to print all.
} else if ("-h".equals(opt)) {
pw.println("Package manager dump options:");
- pw.println(" [-h] [-f] [cmd] ...");
+ pw.println(" [-h] [-f] [--checkin] [cmd] ...");
+ pw.println(" --checkin: dump for a checkin");
pw.println(" -f: print details of intent filters");
pw.println(" -h: print this help");
pw.println(" cmd may be one of:");
@@ -11359,13 +11368,15 @@ public class PackageManagerService extends IPackageManager.Stub {
pw.println(" <package.name>: info about given package");
pw.println(" k[eysets]: print known keysets");
return;
+ } else if ("--checkin".equals(opt)) {
+ checkin = true;
} else if ("-f".equals(opt)) {
dumpState.setOptionEnabled(DumpState.OPTION_SHOW_FILTERS);
} else {
pw.println("Unknown argument: " + opt + "; use -h for help");
}
}
-
+
// Is the caller requesting to dump a particular piece of data?
if (opti < args.length) {
String cmd = args[opti];
@@ -11407,17 +11418,26 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ if (checkin) {
+ pw.println("vers,1");
+ }
+
// reader
synchronized (mPackages) {
if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Verifiers:");
- pw.print(" Required: ");
- pw.print(mRequiredVerifierPackage);
- pw.print(" (uid=");
- pw.print(getPackageUid(mRequiredVerifierPackage, 0));
- pw.println(")");
+ if (!checkin) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Verifiers:");
+ pw.print(" Required: ");
+ pw.print(mRequiredVerifierPackage);
+ pw.print(" (uid=");
+ pw.print(getPackageUid(mRequiredVerifierPackage, 0));
+ pw.println(")");
+ } else if (mRequiredVerifierPackage != null) {
+ pw.print("vrfy,"); pw.print(mRequiredVerifierPackage);
+ pw.print(","); pw.println(getPackageUid(mRequiredVerifierPackage, 0));
+ }
}
if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
@@ -11426,21 +11446,37 @@ public class PackageManagerService extends IPackageManager.Stub {
while (it.hasNext()) {
String name = it.next();
SharedLibraryEntry ent = mSharedLibraries.get(name);
- if (!printedHeader) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Libraries:");
- printedHeader = true;
+ if (!checkin) {
+ if (!printedHeader) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Libraries:");
+ printedHeader = true;
+ }
+ pw.print(" ");
+ } else {
+ pw.print("lib,");
}
- pw.print(" ");
pw.print(name);
- pw.print(" -> ");
+ if (!checkin) {
+ pw.print(" -> ");
+ }
if (ent.path != null) {
- pw.print("(jar) ");
- pw.print(ent.path);
+ if (!checkin) {
+ pw.print("(jar) ");
+ pw.print(ent.path);
+ } else {
+ pw.print(",jar,");
+ pw.print(ent.path);
+ }
} else {
- pw.print("(apk) ");
- pw.print(ent.apk);
+ if (!checkin) {
+ pw.print("(apk) ");
+ pw.print(ent.apk);
+ } else {
+ pw.print(",apk,");
+ pw.print(ent.apk);
+ }
}
pw.println();
}
@@ -11449,16 +11485,22 @@ public class PackageManagerService extends IPackageManager.Stub {
if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
if (dumpState.onTitlePrinted())
pw.println();
- pw.println("Features:");
+ if (!checkin) {
+ pw.println("Features:");
+ }
Iterator<String> it = mAvailableFeatures.keySet().iterator();
while (it.hasNext()) {
String name = it.next();
- pw.print(" ");
+ if (!checkin) {
+ pw.print(" ");
+ } else {
+ pw.print("feat,");
+ }
pw.println(name);
}
}
- if (dumpState.isDumping(DumpState.DUMP_RESOLVERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_RESOLVERS)) {
if (mActivities.dump(pw, dumpState.getTitlePrinted() ? "\nActivity Resolver Table:"
: "Activity Resolver Table:", " ", packageName,
dumpState.isOptionEnabled(DumpState.OPTION_SHOW_FILTERS))) {
@@ -11481,7 +11523,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- if (dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
int user = mSettings.mPreferredActivities.keyAt(i);
@@ -11495,7 +11537,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- if (dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
pw.flush();
FileOutputStream fout = new FileOutputStream(fd);
BufferedOutputStream str = new BufferedOutputStream(fout);
@@ -11517,11 +11559,11 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- if (dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
mSettings.dumpPermissionsLPr(pw, packageName, dumpState);
}
- if (dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
boolean printedSomething = false;
for (PackageParser.Provider p : mProviders.mProviders.values()) {
if (packageName != null && !packageName.equals(p.info.packageName)) {
@@ -11558,19 +11600,19 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
- if (dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
mSettings.mKeySetManager.dump(pw, packageName, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
- mSettings.dumpPackagesLPr(pw, packageName, dumpState);
+ mSettings.dumpPackagesLPr(pw, packageName, dumpState, checkin);
}
- if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
mSettings.dumpSharedUsersLPr(pw, packageName, dumpState);
}
- if (dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
if (dumpState.onTitlePrinted())
pw.println();
mSettings.dumpReadMessagesLPr(pw, dumpState);
@@ -11816,7 +11858,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (uidArr != null) {
extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr);
}
- if (replacing && !mediaStatus) {
+ if (replacing) {
extras.putBoolean(Intent.EXTRA_REPLACING, replacing);
}
String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 14f38fb..34a4e1d 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2914,8 +2914,44 @@ final class Settings {
ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
};
- void dumpPackageLPr(PrintWriter pw, String prefix, PackageSetting ps, SimpleDateFormat sdf,
- Date date, List<UserInfo> users) {
+ void dumpPackageLPr(PrintWriter pw, String prefix, String checkinTag, PackageSetting ps,
+ SimpleDateFormat sdf, Date date, List<UserInfo> users) {
+ if (checkinTag != null) {
+ pw.print(checkinTag);
+ pw.print(",");
+ pw.print(ps.realName != null ? ps.realName : ps.name);
+ pw.print(",");
+ pw.print(ps.appId);
+ pw.print(",");
+ pw.print(ps.versionCode);
+ pw.print(",");
+ pw.print(ps.firstInstallTime);
+ pw.print(",");
+ pw.print(ps.lastUpdateTime);
+ pw.print(",");
+ pw.print(ps.installerPackageName != null ? ps.installerPackageName : "?");
+ pw.println();
+ for (UserInfo user : users) {
+ pw.print(checkinTag);
+ pw.print("-");
+ pw.print("usr");
+ pw.print(",");
+ pw.print(user.id);
+ pw.print(",");
+ pw.print(ps.getInstalled(user.id) ? "I" : "i");
+ pw.print(ps.getBlocked(user.id) ? "B" : "b");
+ pw.print(ps.getStopped(user.id) ? "S" : "s");
+ pw.print(ps.getNotLaunched(user.id) ? "l" : "L");
+ pw.print(",");
+ pw.print(ps.getEnabled(user.id));
+ String lastDisabledAppCaller = ps.getLastDisabledAppCaller(user.id);
+ pw.print(",");
+ pw.print(lastDisabledAppCaller != null ? lastDisabledAppCaller : "?");
+ pw.println();
+ }
+ return;
+ }
+
pw.print(prefix); pw.print("Package [");
pw.print(ps.realName != null ? ps.realName : ps.name);
pw.print("] (");
@@ -3078,7 +3114,7 @@ final class Settings {
}
}
- void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) {
+ void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState, boolean checkin) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
final Date date = new Date();
boolean printedSomething = false;
@@ -3089,35 +3125,39 @@ final class Settings {
continue;
}
- if (packageName != null) {
+ if (!checkin && packageName != null) {
dumpState.setSharedUser(ps.sharedUser);
}
- if (!printedSomething) {
+ if (!checkin && !printedSomething) {
if (dumpState.onTitlePrinted())
pw.println();
pw.println("Packages:");
printedSomething = true;
}
- dumpPackageLPr(pw, " ", ps, sdf, date, users);
+ dumpPackageLPr(pw, " ", checkin ? "pkg" : null, ps, sdf, date, users);
}
printedSomething = false;
- if (mRenamedPackages.size() > 0) {
+ if (!checkin && mRenamedPackages.size() > 0) {
for (final Map.Entry<String, String> e : mRenamedPackages.entrySet()) {
if (packageName != null && !packageName.equals(e.getKey())
&& !packageName.equals(e.getValue())) {
continue;
}
- if (!printedSomething) {
- if (dumpState.onTitlePrinted())
- pw.println();
- pw.println("Renamed packages:");
- printedSomething = true;
+ if (!checkin) {
+ if (!printedSomething) {
+ if (dumpState.onTitlePrinted())
+ pw.println();
+ pw.println("Renamed packages:");
+ printedSomething = true;
+ }
+ pw.print(" ");
+ } else {
+ pw.print("ren,");
}
- pw.print(" ");
pw.print(e.getKey());
- pw.print(" -> ");
+ pw.print(checkin ? " -> " : ",");
pw.println(e.getValue());
}
}
@@ -3129,13 +3169,13 @@ final class Settings {
&& !packageName.equals(ps.name)) {
continue;
}
- if (!printedSomething) {
+ if (!checkin && !printedSomething) {
if (dumpState.onTitlePrinted())
pw.println();
pw.println("Hidden system packages:");
printedSomething = true;
}
- dumpPackageLPr(pw, " ", ps, sdf, date, users);
+ dumpPackageLPr(pw, " ", checkin ? "dis" : null, ps, sdf, date, users);
}
}
}
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 60d44c7..30bc922 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -610,7 +610,6 @@ final class DisplayPowerController {
&& mProximity == PROXIMITY_POSITIVE) {
mScreenOffBecauseOfProximity = true;
sendOnProximityPositiveWithWakelock();
- setScreenOn(false);
}
} else if (mWaitingForNegativeProximity
&& mScreenOffBecauseOfProximity
@@ -670,59 +669,62 @@ final class DisplayPowerController {
mUsingScreenAutoBrightness = false;
}
- // Animate the screen on or off.
- if (!mScreenOffBecauseOfProximity) {
- if (wantScreenOn(mPowerRequest.screenState)) {
- // Want screen on.
- // Wait for previous off animation to complete beforehand.
- // It is relatively short but if we cancel it and switch to the
- // on animation immediately then the results are pretty ugly.
- if (!mElectronBeamOffAnimator.isStarted()) {
- // Turn the screen on. The contents of the screen may not yet
- // be visible if the electron beam has not been dismissed because
- // its last frame of animation is solid black.
- setScreenOn(true);
-
- if (mPowerRequest.blockScreenOn
- && mPowerState.getElectronBeamLevel() == 0.0f) {
- blockScreenOn();
- } else {
- unblockScreenOn();
- if (USE_ELECTRON_BEAM_ON_ANIMATION) {
- if (!mElectronBeamOnAnimator.isStarted()) {
- if (mPowerState.getElectronBeamLevel() == 1.0f) {
- mPowerState.dismissElectronBeam();
- } else if (mPowerState.prepareElectronBeam(
- mElectronBeamFadesConfig ?
- ElectronBeam.MODE_FADE :
- ElectronBeam.MODE_WARM_UP)) {
- mElectronBeamOnAnimator.start();
- } else {
- mElectronBeamOnAnimator.end();
- }
+ // Animate the screen on or off unless blocked.
+ if (mScreenOffBecauseOfProximity) {
+ // Screen off due to proximity.
+ setScreenOn(false);
+ unblockScreenOn();
+ } else if (wantScreenOn(mPowerRequest.screenState)) {
+ // Want screen on.
+ // Wait for previous off animation to complete beforehand.
+ // It is relatively short but if we cancel it and switch to the
+ // on animation immediately then the results are pretty ugly.
+ if (!mElectronBeamOffAnimator.isStarted()) {
+ // Turn the screen on. The contents of the screen may not yet
+ // be visible if the electron beam has not been dismissed because
+ // its last frame of animation is solid black.
+ setScreenOn(true);
+
+ if (mPowerRequest.blockScreenOn
+ && mPowerState.getElectronBeamLevel() == 0.0f) {
+ blockScreenOn();
+ } else {
+ unblockScreenOn();
+ if (USE_ELECTRON_BEAM_ON_ANIMATION) {
+ if (!mElectronBeamOnAnimator.isStarted()) {
+ if (mPowerState.getElectronBeamLevel() == 1.0f) {
+ mPowerState.dismissElectronBeam();
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamFadesConfig ?
+ ElectronBeam.MODE_FADE :
+ ElectronBeam.MODE_WARM_UP)) {
+ mElectronBeamOnAnimator.start();
+ } else {
+ mElectronBeamOnAnimator.end();
}
- } else {
- mPowerState.setElectronBeamLevel(1.0f);
- mPowerState.dismissElectronBeam();
}
+ } else {
+ mPowerState.setElectronBeamLevel(1.0f);
+ mPowerState.dismissElectronBeam();
}
}
- } else {
- // Want screen off.
- // Wait for previous on animation to complete beforehand.
- if (!mElectronBeamOnAnimator.isStarted()) {
- if (!mElectronBeamOffAnimator.isStarted()) {
- if (mPowerState.getElectronBeamLevel() == 0.0f) {
- setScreenOn(false);
- } else if (mPowerState.prepareElectronBeam(
- mElectronBeamFadesConfig ?
- ElectronBeam.MODE_FADE :
- ElectronBeam.MODE_COOL_DOWN)
- && mPowerState.isScreenOn()) {
- mElectronBeamOffAnimator.start();
- } else {
- mElectronBeamOffAnimator.end();
- }
+ }
+ } else {
+ // Want screen off.
+ // Wait for previous on animation to complete beforehand.
+ unblockScreenOn();
+ if (!mElectronBeamOnAnimator.isStarted()) {
+ if (!mElectronBeamOffAnimator.isStarted()) {
+ if (mPowerState.getElectronBeamLevel() == 0.0f) {
+ setScreenOn(false);
+ } else if (mPowerState.prepareElectronBeam(
+ mElectronBeamFadesConfig ?
+ ElectronBeam.MODE_FADE :
+ ElectronBeam.MODE_COOL_DOWN)
+ && mPowerState.isScreenOn()) {
+ mElectronBeamOffAnimator.start();
+ } else {
+ mElectronBeamOffAnimator.end();
}
}
}
@@ -762,15 +764,15 @@ final class DisplayPowerController {
private void unblockScreenOn() {
if (mScreenOnWasBlocked) {
mScreenOnWasBlocked = false;
- if (DEBUG) {
- Slog.d(TAG, "Unblocked screen on after " +
- (SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime) + " ms");
+ long delay = SystemClock.elapsedRealtime() - mScreenOnBlockStartRealTime;
+ if (delay > 1000 || DEBUG) {
+ Slog.d(TAG, "Unblocked screen on after " + delay + " ms");
}
}
}
private void setScreenOn(boolean on) {
- if (!mPowerState.isScreenOn() == on) {
+ if (mPowerState.isScreenOn() != on) {
mPowerState.setScreenOn(on);
if (on) {
mNotifier.onScreenOn();
diff --git a/services/java/com/android/server/power/DisplayPowerState.java b/services/java/com/android/server/power/DisplayPowerState.java
index fa318f8..5c048f1 100644
--- a/services/java/com/android/server/power/DisplayPowerState.java
+++ b/services/java/com/android/server/power/DisplayPowerState.java
@@ -304,8 +304,15 @@ final class DisplayPowerState {
int brightness = mScreenOn && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
if (mPhotonicModulator.setState(mScreenOn, brightness)) {
+ if (DEBUG) {
+ Slog.d(TAG, "Screen ready");
+ }
mScreenReady = true;
invokeCleanListenerIfNeeded();
+ } else {
+ if (DEBUG) {
+ Slog.d(TAG, "Screen not ready");
+ }
}
}
};
@@ -355,7 +362,7 @@ final class DisplayPowerState {
AsyncTask.THREAD_POOL_EXECUTOR.execute(mTask);
}
}
- return mChangeInProgress;
+ return !mChangeInProgress;
}
}
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index da9548f..134718b 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -1135,6 +1135,9 @@ public final class PowerManagerService extends IPowerManager.Stub
if (!mSystemReady || mDirty == 0) {
return;
}
+ if (!Thread.holdsLock(mLock)) {
+ Slog.wtf(TAG, "Power manager lock was not held when calling updatePowerStateLocked");
+ }
// Phase 0: Basic state updates.
updateIsPoweredLocked(mDirty);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 5f07517..b932632 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -98,6 +98,13 @@ public class UsbDeviceManager {
// which need debouncing.
private static final int UPDATE_DELAY = 1000;
+ // Time we received a request to enter USB accessory mode
+ private long mAccessoryModeRequestTime = 0;
+
+ // Timeout for entering USB request mode.
+ // Request is cancelled if host does not configure device within 10 seconds.
+ private static final int ACCESSORY_REQUEST_TIMEOUT = 10 * 1000;
+
private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
private UsbHandler mHandler;
@@ -205,6 +212,8 @@ public class UsbDeviceManager {
}
private void startAccessoryMode() {
+ if (!mHasUsbAccessory) return;
+
mAccessoryStrings = nativeGetAccessoryStrings();
boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
// don't start accessory mode if our mandatory strings have not been set
@@ -223,6 +232,7 @@ public class UsbDeviceManager {
}
if (functions != null) {
+ mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
setCurrentFunctions(functions, false);
}
}
@@ -456,6 +466,8 @@ public class UsbDeviceManager {
}
private void setEnabledFunctions(String functions, boolean makeDefault) {
+ if (DEBUG) Slog.d(TAG, "setEnabledFunctions " + functions
+ + " makeDefault: " + makeDefault);
// Do not update persystent.sys.usb.config if the device is booted up
// with OEM specific mode.
@@ -517,9 +529,16 @@ public class UsbDeviceManager {
}
private void updateCurrentAccessory() {
- if (!mHasUsbAccessory) return;
+ // We are entering accessory mode if we have received a request from the host
+ // and the request has not timed out yet.
+ boolean enteringAccessoryMode =
+ mAccessoryModeRequestTime > 0 &&
+ SystemClock.elapsedRealtime() <
+ mAccessoryModeRequestTime + ACCESSORY_REQUEST_TIMEOUT;
+
+ if (mConfigured && enteringAccessoryMode) {
+ // successfully entered accessory mode
- if (mConfigured) {
if (mAccessoryStrings != null) {
mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
@@ -530,7 +549,7 @@ public class UsbDeviceManager {
} else {
Slog.e(TAG, "nativeGetAccessoryStrings failed");
}
- } else if (!mConnected) {
+ } else if (!enteringAccessoryMode) {
// make sure accessory mode is off
// and restore default functions
Slog.d(TAG, "exited USB accessory mode");
@@ -560,6 +579,8 @@ public class UsbDeviceManager {
}
}
+ if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " connected: " + mConnected
+ + " configured: " + mConfigured);
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
@@ -604,9 +625,7 @@ public class UsbDeviceManager {
if (containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
- }
-
- if (!mConnected) {
+ } else if (!mConnected) {
// restore defaults when USB is disconnected
setEnabledFunctions(mDefaultFunctions, false);
}
diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java
index a3d514e..bdb0a5e 100644
--- a/services/java/com/android/server/wifi/WifiController.java
+++ b/services/java/com/android/server/wifi/WifiController.java
@@ -152,11 +152,21 @@ class WifiController extends StateMachine {
addState(mStaDisabledWithScanState, mDefaultState);
addState(mApEnabledState, mDefaultState);
addState(mEcmState, mDefaultState);
- if (mSettingsStore.isScanAlwaysAvailable()) {
+
+ boolean isAirplaneModeOn = mSettingsStore.isAirplaneModeOn();
+ boolean isWifiEnabled = mSettingsStore.isWifiToggleEnabled();
+ boolean isScanningAlwaysAvailable = mSettingsStore.isScanAlwaysAvailable();
+
+ log("isAirplaneModeOn = " + isAirplaneModeOn +
+ ", isWifiEnabled = " + isWifiEnabled +
+ ", isScanningAvailable = " + isScanningAlwaysAvailable);
+
+ if (isWifiEnabled && isScanningAlwaysAvailable) {
setInitialState(mStaDisabledWithScanState);
} else {
setInitialState(mApStaDisabledState);
}
+
setLogRecSize(100);
setLogOnlyTransitions(false);
diff --git a/services/java/com/android/server/wifi/WifiService.java b/services/java/com/android/server/wifi/WifiService.java
index f2efde1..aecf9ae 100644
--- a/services/java/com/android/server/wifi/WifiService.java
+++ b/services/java/com/android/server/wifi/WifiService.java
@@ -870,7 +870,7 @@ public final class WifiService extends IWifiManager.Stub {
public void setCountryCode(String countryCode, boolean persist) {
Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
" with persist set to " + persist);
- enforceChangePermission();
+ enforceConnectivityInternalPermission();
final long token = Binder.clearCallingIdentity();
try {
mWifiStateMachine.setCountryCode(countryCode, persist);
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index b1d67de..e98014b 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -53,7 +53,7 @@ class AppWindowToken extends WindowToken {
int groupId = -1;
boolean appFullscreen;
int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
- int configChanges;
+ boolean layoutConfigChanges;
boolean showWhenLocked;
// The input dispatching timeout for this application token in nanoseconds.
diff --git a/services/java/com/android/server/wm/TaskStack.java b/services/java/com/android/server/wm/TaskStack.java
index e65aecb..cb29df4 100644
--- a/services/java/com/android/server/wm/TaskStack.java
+++ b/services/java/com/android/server/wm/TaskStack.java
@@ -271,6 +271,8 @@ public class TaskStack {
for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
final WindowState win = windows.get(winNdx);
if (!resizingWindows.contains(win)) {
+ if (WindowManagerService.DEBUG_RESIZE) Slog.d(TAG,
+ "setBounds: Resizing " + win);
resizingWindows.add(win);
}
win.mUnderStatusBar = underStatusBar;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b6c6770..096921d 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -437,8 +437,15 @@ public class WindowManagerService extends IWindowManager.Stub
int mRotation = 0;
int mForcedAppOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
boolean mAltOrientation = false;
- ArrayList<IRotationWatcher> mRotationWatchers
- = new ArrayList<IRotationWatcher>();
+ class RotationWatcher {
+ IRotationWatcher watcher;
+ IBinder.DeathRecipient dr;
+ RotationWatcher(IRotationWatcher w, IBinder.DeathRecipient d) {
+ watcher = w;
+ dr = d;
+ }
+ }
+ ArrayList<RotationWatcher> mRotationWatchers = new ArrayList<RotationWatcher>();
int mDeferredRotationPauseCount;
int mSystemDecorLayer = 0;
@@ -3444,7 +3451,8 @@ public class WindowManagerService extends IWindowManager.Stub
atoken.appFullscreen = fullscreen;
atoken.showWhenLocked = showWhenLocked;
atoken.requestedOrientation = requestedOrientation;
- atoken.configChanges = configChanges;
+ atoken.layoutConfigChanges = (configChanges &
+ (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + atoken
+ " to stack=" + stackId + " task=" + taskId + " at " + addPos);
@@ -5992,7 +6000,7 @@ public class WindowManagerService extends IWindowManager.Stub
for (int i=mRotationWatchers.size()-1; i>=0; i--) {
try {
- mRotationWatchers.get(i).onRotationChanged(rotation);
+ mRotationWatchers.get(i).watcher.onRotationChanged(rotation);
} catch (RemoteException e) {
}
}
@@ -6024,10 +6032,10 @@ public class WindowManagerService extends IWindowManager.Stub
public void binderDied() {
synchronized (mWindowMap) {
for (int i=0; i<mRotationWatchers.size(); i++) {
- if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
- IRotationWatcher removed = mRotationWatchers.remove(i);
+ if (watcherBinder == mRotationWatchers.get(i).watcher.asBinder()) {
+ RotationWatcher removed = mRotationWatchers.remove(i);
if (removed != null) {
- removed.asBinder().unlinkToDeath(this, 0);
+ removed.watcher.asBinder().unlinkToDeath(this, 0);
}
i--;
}
@@ -6039,7 +6047,7 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
try {
watcher.asBinder().linkToDeath(dr, 0);
- mRotationWatchers.add(watcher);
+ mRotationWatchers.add(new RotationWatcher(watcher, dr));
} catch (RemoteException e) {
// Client died, no cleanup needed.
}
@@ -6053,9 +6061,13 @@ public class WindowManagerService extends IWindowManager.Stub
final IBinder watcherBinder = watcher.asBinder();
synchronized (mWindowMap) {
for (int i=0; i<mRotationWatchers.size(); i++) {
- if (watcherBinder == mRotationWatchers.get(i).asBinder()) {
- mRotationWatchers.remove(i);
- i--;
+ RotationWatcher rotationWatcher = mRotationWatchers.get(i);
+ if (watcherBinder == rotationWatcher.watcher.asBinder()) {
+ RotationWatcher removed = mRotationWatchers.remove(i);
+ if (removed != null) {
+ removed.watcher.asBinder().unlinkToDeath(removed.dr, 0);
+ i--;
+ }
}
}
}
@@ -8269,10 +8281,9 @@ public class WindowManagerService extends IWindowManager.Stub
// windows, since that means "perform layout as normal,
// just don't display").
if (!gone || !win.mHaveFrame || win.mLayoutNeeded
- || win.isConfigChanged() && (win.mAttrs.type == TYPE_KEYGUARD ||
- (win.mAppToken != null && (win.mAppToken.configChanges &
- (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION))
- != 0))
+ || ((win.isConfigChanged() || win.setInsetsChanged()) &&
+ (win.mAttrs.type == TYPE_KEYGUARD ||
+ win.mAppToken != null && win.mAppToken.layoutConfigChanges))
|| win.mAttrs.type == TYPE_UNIVERSE_BACKGROUND) {
if (!win.mLayoutAttached) {
if (initial) {
@@ -8706,12 +8717,7 @@ public class WindowManagerService extends IWindowManager.Stub
private void updateResizingWindows(final WindowState w) {
final WindowStateAnimator winAnimator = w.mWinAnimator;
if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
- w.mOverscanInsetsChanged |=
- !w.mLastOverscanInsets.equals(w.mOverscanInsets);
- w.mContentInsetsChanged |=
- !w.mLastContentInsets.equals(w.mContentInsets);
- w.mVisibleInsetsChanged |=
- !w.mLastVisibleInsets.equals(w.mVisibleInsets);
+ w.setInsetsChanged();
boolean configChanged = w.isConfigChanged();
if (DEBUG_CONFIGURATION && configChanged) {
Slog.v(TAG, "Win " + w + " config changed: "
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 2d08792..4d53cea 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -701,6 +701,13 @@ final class WindowState implements WindowManagerPolicy.WindowState {
return mAppToken != null ? mAppToken.appToken : null;
}
+ boolean setInsetsChanged() {
+ mOverscanInsetsChanged |= !mLastOverscanInsets.equals(mOverscanInsets);
+ mContentInsetsChanged |= !mLastContentInsets.equals(mContentInsets);
+ mVisibleInsetsChanged |= !mLastVisibleInsets.equals(mVisibleInsets);
+ return mOverscanInsetsChanged || mContentInsetsChanged || mVisibleInsetsChanged;
+ }
+
public int getDisplayId() {
return mDisplayContent.getDisplayId();
}