summaryrefslogtreecommitdiffstats
path: root/services/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com')
-rw-r--r--services/java/com/android/server/AppWidgetService.java2
-rw-r--r--services/java/com/android/server/BackupManagerService.java181
-rw-r--r--services/java/com/android/server/ConnectivityService.java98
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java90
-rw-r--r--services/java/com/android/server/IntentResolver.java23
-rw-r--r--services/java/com/android/server/LoadAverageService.java4
-rw-r--r--services/java/com/android/server/LocationManagerService.java77
-rw-r--r--services/java/com/android/server/MountService.java32
-rw-r--r--services/java/com/android/server/NetworkManagementService.java315
-rw-r--r--services/java/com/android/server/NetworkTimeUpdateService.java67
-rw-r--r--services/java/com/android/server/SystemBackupAgent.java2
-rw-r--r--services/java/com/android/server/SystemServer.java9
-rw-r--r--services/java/com/android/server/ThrottleService.java40
-rw-r--r--services/java/com/android/server/WifiService.java9
-rw-r--r--services/java/com/android/server/WifiWatchdogService.java1450
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java108
-rw-r--r--services/java/com/android/server/accessibility/TouchExplorer.java34
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java273
-rw-r--r--services/java/com/android/server/am/ActivityStack.java1
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java13
-rw-r--r--services/java/com/android/server/am/BroadcastFilter.java4
-rw-r--r--services/java/com/android/server/am/PendingIntentRecord.java10
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java19
-rw-r--r--services/java/com/android/server/connectivity/Vpn.java496
-rwxr-xr-xservices/java/com/android/server/location/GpsLocationProvider.java59
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java253
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java51
-rw-r--r--services/java/com/android/server/pm/Installer.java7
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java559
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java309
-rw-r--r--services/java/com/android/server/usb/UsbHostManager.java5
-rw-r--r--services/java/com/android/server/usb/UsbSettingsManager.java33
-rw-r--r--services/java/com/android/server/wm/InputManager.java12
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java11
34 files changed, 2072 insertions, 2584 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index 158c778..0b15221 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -1072,7 +1072,7 @@ class AppWidgetService extends IAppWidgetService.Stub
throw new IllegalArgumentException("packageName and uid don't match packageName="
+ packageName);
}
- if (callingUid != packageUid && Process.supportsProcesses()) {
+ if (callingUid != packageUid) {
throw new IllegalArgumentException("packageName and uid don't match packageName="
+ packageName);
}
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 3aa1239..786f2fa 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -23,6 +23,7 @@ import android.app.IActivityManager;
import android.app.IApplicationThread;
import android.app.IBackupAgent;
import android.app.PendingIntent;
+import android.app.backup.BackupAgent;
import android.app.backup.BackupDataOutput;
import android.app.backup.FullBackup;
import android.app.backup.RestoreSet;
@@ -64,6 +65,7 @@ import android.os.SystemClock;
import android.os.WorkSource;
import android.provider.Settings;
import android.util.EventLog;
+import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -222,6 +224,7 @@ class BackupManagerService extends IBackupManager.Stub {
public PackageInfo pkgInfo;
public int pmToken; // in post-install restore, the PM's token for this transaction
public boolean needFullBackup;
+ public String[] filterSet;
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
@@ -231,6 +234,7 @@ class BackupManagerService extends IBackupManager.Stub {
pkgInfo = _pkg;
pmToken = _pmToken;
needFullBackup = _needFullBackup;
+ filterSet = null;
}
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
@@ -241,6 +245,18 @@ class BackupManagerService extends IBackupManager.Stub {
pkgInfo = null;
pmToken = 0;
needFullBackup = _needFullBackup;
+ filterSet = null;
+ }
+
+ RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
+ String[] _filterSet, boolean _needFullBackup) {
+ transport = _transport;
+ observer = _obs;
+ token = _token;
+ pkgInfo = null;
+ pmToken = 0;
+ needFullBackup = _needFullBackup;
+ filterSet = _filterSet;
}
}
@@ -402,7 +418,7 @@ class BackupManagerService extends IBackupManager.Stub {
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
(new PerformRestoreTask(params.transport, params.observer,
params.token, params.pkgInfo, params.pmToken,
- params.needFullBackup)).run();
+ params.needFullBackup, params.filterSet)).run();
break;
}
@@ -1587,8 +1603,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Initiate the target's backup pass
prepareOperationTimeout(token, TIMEOUT_BACKUP_INTERVAL);
- agent.doBackup(savedState, backupData, newState, false,
- token, mBackupManagerBinder);
+ agent.doBackup(savedState, backupData, newState, token, mBackupManagerBinder);
boolean success = waitUntilOperationComplete(token);
if (!success) {
@@ -1764,30 +1779,31 @@ class BackupManagerService extends IBackupManager.Stub {
if (agent != null) {
try {
ApplicationInfo app = pkg.applicationInfo;
- boolean sendApk = mIncludeApks
+ final boolean sendApk = mIncludeApks
&& ((app.flags & ApplicationInfo.FLAG_FORWARD_LOCK) == 0)
&& ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
(app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
sendOnBackupPackage(pkg.packageName);
- {
- BackupDataOutput output = new BackupDataOutput(
- mOutputFile.getFileDescriptor());
+ BackupDataOutput output = new BackupDataOutput(
+ mOutputFile.getFileDescriptor());
- if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
- writeAppManifest(pkg, mManifestFile, sendApk);
- FullBackup.backupToTar(pkg.packageName, null, null,
- mFilesDir.getAbsolutePath(),
- mManifestFile.getAbsolutePath(),
- output);
+ if (DEBUG) Slog.d(TAG, "Writing manifest for " + pkg.packageName);
+ writeAppManifest(pkg, mManifestFile, sendApk);
+ FullBackup.backupToTar(pkg.packageName, null, null,
+ mFilesDir.getAbsolutePath(),
+ mManifestFile.getAbsolutePath(),
+ output);
+
+ if (sendApk) {
+ writeApkToBackup(pkg, output);
}
- if (DEBUG) Slog.d(TAG, "Calling doBackup()");
+ if (DEBUG) Slog.d(TAG, "Calling doFullBackup()");
final int token = generateToken();
prepareOperationTimeout(token, TIMEOUT_FULL_BACKUP_INTERVAL);
- agent.doBackup(null, mOutputFile, null, sendApk,
- token, mBackupManagerBinder);
+ agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on package " + pkg.packageName);
} else {
@@ -1802,6 +1818,29 @@ class BackupManagerService extends IBackupManager.Stub {
tearDown(pkg);
}
+ private void writeApkToBackup(PackageInfo pkg, BackupDataOutput output) {
+ // Forward-locked apps, system-bundled .apks, etc are filtered out before we get here
+ final String appSourceDir = pkg.applicationInfo.sourceDir;
+ final String apkDir = new File(appSourceDir).getParent();
+ FullBackup.backupToTar(pkg.packageName, FullBackup.APK_TREE_TOKEN, null,
+ apkDir, appSourceDir, output);
+
+ // Save associated .obb content if it exists and we did save the apk
+ // check for .obb and save those too
+ final File obbDir = Environment.getExternalStorageAppObbDirectory(pkg.packageName);
+ if (obbDir != null) {
+ if (DEBUG) Log.i(TAG, "obb dir: " + obbDir.getAbsolutePath());
+ File[] obbFiles = obbDir.listFiles();
+ if (obbFiles != null) {
+ final String obbDirName = obbDir.getAbsolutePath();
+ for (File obb : obbFiles) {
+ FullBackup.backupToTar(pkg.packageName, FullBackup.OBB_TREE_TOKEN, null,
+ obbDirName, obb.getAbsolutePath(), output);
+ }
+ }
+ }
+ }
+
private void backupSharedStorage() throws RemoteException {
PackageInfo pkg = null;
try {
@@ -1813,7 +1852,7 @@ class BackupManagerService extends IBackupManager.Stub {
final int token = generateToken();
prepareOperationTimeout(token, TIMEOUT_SHARED_BACKUP_INTERVAL);
- agent.doBackup(null, mOutputFile, null, false, token, mBackupManagerBinder);
+ agent.doFullBackup(mOutputFile, token, mBackupManagerBinder);
if (!waitUntilOperationComplete(token)) {
Slog.e(TAG, "Full backup failed on shared storage");
} else {
@@ -1933,7 +1972,7 @@ class BackupManagerService extends IBackupManager.Stub {
static class FileMetadata {
String packageName; // name of the owning app
String installerPackageName; // name of the market-type app that installed the owner
- int type; // e.g. FullBackup.TYPE_DIRECTORY
+ int type; // e.g. BackupAgent.TYPE_DIRECTORY
String domain; // e.g. FullBackup.DATABASE_TREE_TOKEN
String path; // subpath within the semantic domain
long mode; // e.g. 0666 (actually int)
@@ -2182,15 +2221,15 @@ class BackupManagerService extends IBackupManager.Stub {
// If we haven't sent any data to this app yet, we probably
// need to clear it first. Check that.
if (!mClearedPackages.contains(pkg)) {
- // apps with their own full backup agents are
+ // apps with their own backup agents are
// responsible for coherently managing a full
// restore.
- if (mTargetApp.fullBackupAgentName == null) {
+ if (mTargetApp.backupAgentName == null) {
if (DEBUG) Slog.d(TAG, "Clearing app data preparatory to full restore");
clearApplicationDataSynchronous(pkg);
} else {
- if (DEBUG) Slog.d(TAG, "full backup agent ("
- + mTargetApp.fullBackupAgentName + ") => no clear");
+ if (DEBUG) Slog.d(TAG, "backup agent ("
+ + mTargetApp.backupAgentName + ") => no clear");
}
mClearedPackages.add(pkg);
} else {
@@ -2686,7 +2725,7 @@ class BackupManagerService extends IBackupManager.Stub {
StringBuilder b = new StringBuilder(128);
// mode string
- b.append((info.type == FullBackup.TYPE_DIRECTORY) ? 'd' : '-');
+ b.append((info.type == BackupAgent.TYPE_DIRECTORY) ? 'd' : '-');
b.append(((info.mode & 0400) != 0) ? 'r' : '-');
b.append(((info.mode & 0200) != 0) ? 'w' : '-');
b.append(((info.mode & 0100) != 0) ? 'x' : '-');
@@ -2746,9 +2785,9 @@ class BackupManagerService extends IBackupManager.Stub {
}
switch (typeChar) {
- case '0': info.type = FullBackup.TYPE_FILE; break;
+ case '0': info.type = BackupAgent.TYPE_FILE; break;
case '5': {
- info.type = FullBackup.TYPE_DIRECTORY;
+ info.type = BackupAgent.TYPE_DIRECTORY;
if (info.size != 0) {
Slog.w(TAG, "Directory entry with nonzero size in header");
info.size = 0;
@@ -2995,6 +3034,7 @@ class BackupManagerService extends IBackupManager.Stub {
private File mStateDir;
private int mPmToken;
private boolean mNeedFullBackup;
+ private HashSet<String> mFilterSet;
class RestoreRequest {
public PackageInfo app;
@@ -3008,7 +3048,7 @@ class BackupManagerService extends IBackupManager.Stub {
PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
long restoreSetToken, PackageInfo targetPackage, int pmToken,
- boolean needFullBackup) {
+ boolean needFullBackup, String[] filterSet) {
mTransport = transport;
mObserver = observer;
mToken = restoreSetToken;
@@ -3016,6 +3056,15 @@ class BackupManagerService extends IBackupManager.Stub {
mPmToken = pmToken;
mNeedFullBackup = needFullBackup;
+ if (filterSet != null) {
+ mFilterSet = new HashSet<String>();
+ for (String pkg : filterSet) {
+ mFilterSet.add(pkg);
+ }
+ } else {
+ mFilterSet = null;
+ }
+
try {
mStateDir = new File(mBaseStateDir, transport.transportDirName());
} catch (RemoteException e) {
@@ -3027,7 +3076,8 @@ class BackupManagerService extends IBackupManager.Stub {
long startRealtime = SystemClock.elapsedRealtime();
if (DEBUG) Slog.v(TAG, "Beginning restore process mTransport=" + mTransport
+ " mObserver=" + mObserver + " mToken=" + Long.toHexString(mToken)
- + " mTargetPackage=" + mTargetPackage + " mPmToken=" + mPmToken);
+ + " mTargetPackage=" + mTargetPackage + " mFilterSet=" + mFilterSet
+ + " mPmToken=" + mPmToken);
PackageManagerBackupAgent pmAgent = null;
int error = -1; // assume error
@@ -3046,6 +3096,22 @@ class BackupManagerService extends IBackupManager.Stub {
List<PackageInfo> agentPackages = allAgentPackages();
if (mTargetPackage == null) {
+ // if there's a filter set, strip out anything that isn't
+ // present before proceeding
+ if (mFilterSet != null) {
+ for (int i = agentPackages.size() - 1; i >= 0; i--) {
+ final PackageInfo pkg = agentPackages.get(i);
+ if (! mFilterSet.contains(pkg.packageName)) {
+ agentPackages.remove(i);
+ }
+ }
+ if (DEBUG) {
+ Slog.i(TAG, "Post-filter package set for restore:");
+ for (PackageInfo p : agentPackages) {
+ Slog.i(TAG, " " + p);
+ }
+ }
+ }
restorePackages.addAll(agentPackages);
} else {
// Just one package to attempt restore of
@@ -4241,6 +4307,67 @@ class BackupManagerService extends IBackupManager.Stub {
return -1;
}
+ public synchronized int restoreSome(long token, IRestoreObserver observer,
+ String[] packages) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP,
+ "performRestore");
+
+ if (DEBUG) {
+ StringBuilder b = new StringBuilder(128);
+ b.append("restoreSome token=");
+ b.append(Long.toHexString(token));
+ b.append(" observer=");
+ b.append(observer.toString());
+ b.append(" packages=");
+ if (packages == null) {
+ b.append("null");
+ } else {
+ b.append('{');
+ boolean first = true;
+ for (String s : packages) {
+ if (!first) {
+ b.append(", ");
+ } else first = false;
+ b.append(s);
+ }
+ b.append('}');
+ }
+ Slog.d(TAG, b.toString());
+ }
+
+ if (mEnded) {
+ throw new IllegalStateException("Restore session already ended");
+ }
+
+ if (mRestoreTransport == null || mRestoreSets == null) {
+ Slog.e(TAG, "Ignoring restoreAll() with no restore set");
+ return -1;
+ }
+
+ if (mPackageName != null) {
+ Slog.e(TAG, "Ignoring restoreAll() on single-package session");
+ 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,
+ packages, true);
+ mBackupHandler.sendMessage(msg);
+ Binder.restoreCallingIdentity(oldId);
+ return 0;
+ }
+ }
+ }
+
+ Slog.w(TAG, "Restore token " + Long.toHexString(token) + " not found");
+ return -1;
+ }
+
public synchronized int restorePackage(String packageName, IRestoreObserver observer) {
if (DEBUG) Slog.v(TAG, "restorePackage pkg=" + packageName + " obs=" + observer);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index e6f443a..41450d2 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -44,7 +44,6 @@ import android.net.NetworkUtils;
import android.net.Proxy;
import android.net.ProxyProperties;
import android.net.RouteInfo;
-import android.net.vpn.VpnManager;
import android.net.wifi.WifiStateTracker;
import android.os.Binder;
import android.os.FileUtils;
@@ -65,6 +64,7 @@ import android.util.EventLog;
import android.util.Slog;
import android.util.SparseIntArray;
+import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.telephony.Phone;
import com.android.server.connectivity.Tethering;
@@ -131,8 +131,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
private List mNetRequestersPids[];
- private WifiWatchdogService mWifiWatchdogService;
-
// priority order of the nettrackers
// (excluding dynamically set mNetworkPreference)
// TODO - move mNetworkTypePreference into this
@@ -278,6 +276,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
RadioAttributes[] mRadioAttributes;
+ // the set of network types that can only be enabled by system/sig apps
+ List mProtectedNetworks;
+
public ConnectivityService(
Context context, INetworkManagementService netd, INetworkPolicyManager policyManager) {
if (DBG) log("ConnectivityService starting up");
@@ -381,6 +382,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
+ mProtectedNetworks = new ArrayList<Integer>();
+ int[] protectedNetworks = context.getResources().getIntArray(
+ com.android.internal.R.array.config_protectedNetworks);
+ for (int p : protectedNetworks) {
+ if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) {
+ mProtectedNetworks.add(p);
+ } else {
+ if (DBG) loge("Ignoring protectedNetwork " + p);
+ }
+ }
+
// high priority first
mPriorityList = new int[mNetworksDefined];
{
@@ -432,10 +444,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
wifiService.checkAndStartWifi();
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
wst.startMonitoring(context, mHandler);
-
- //TODO: as part of WWS refactor, create only when needed
- mWifiWatchdogService = new WifiWatchdogService(context);
-
break;
case ConnectivityManager.TYPE_MOBILE:
mNetTrackers[netType] = new MobileDataStateTracker(netType,
@@ -488,11 +496,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mSettingsObserver.observe(mContext);
loadGlobalProxy();
-
- VpnManager.startVpnService(context);
}
-
/**
* Sets the preferred network.
* @param preference the new preference
@@ -802,6 +807,11 @@ public class ConnectivityService extends IConnectivityManager.Stub {
usedNetworkType = networkType;
}
}
+
+ if (mProtectedNetworks.contains(usedNetworkType)) {
+ enforceConnectivityInternalPermission();
+ }
+
NetworkStateTracker network = mNetTrackers[usedNetworkType];
if (network != null) {
Integer currentPid = new Integer(getCallingPid());
@@ -1012,6 +1022,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
enforceChangePermission();
+ if (mProtectedNetworks.contains(networkType)) {
+ enforceConnectivityInternalPermission();
+ }
+
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
return false;
}
@@ -1129,7 +1143,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
public void setDataDependency(int networkType, boolean met) {
- enforceChangePermission();
+ enforceConnectivityInternalPermission();
+
if (DBG) {
log("setDataDependency(" + networkType + ", " + met + ")");
}
@@ -1587,11 +1602,23 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (linkProperties != null) {
String iface = linkProperties.getInterfaceName();
if (TextUtils.isEmpty(iface) == false) {
- if (DBG) log("resetConnections(" + iface + ")");
- NetworkUtils.resetConnections(iface);
+ if (DBG) {
+ log("resetConnections(" + iface + ", NetworkUtils.RESET_ALL_ADDRESSES)");
+ }
+ NetworkUtils.resetConnections(iface, NetworkUtils.RESET_ALL_ADDRESSES);
}
}
}
+
+ // TODO: Temporary notifying upstread change to Tethering.
+ // @see bug/4455071
+ /** Notify TetheringService if interface name has been changed. */
+ if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(),
+ Phone.REASON_LINK_PROPERTIES_CHANGED)) {
+ if (isTetheringSupported()) {
+ mTethering.handleTetherIfaceChange();
+ }
+ }
}
private void addPrivateDnsRoutes(NetworkStateTracker nt) {
@@ -2017,7 +2044,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
break;
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
info = (NetworkInfo) msg.obj;
- handleConnectivityChange(info.getType(), true);
+ // TODO: Temporary allowing network configuration
+ // change not resetting sockets.
+ // @see bug/4455071
+ handleConnectivityChange(info.getType(), false);
break;
case EVENT_CLEAR_NET_TRANSITION_WAKELOCK:
String causedBy = null;
@@ -2442,8 +2472,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
/**
* Protect a socket from VPN routing rules. This method is used by
- * VpnBuilder and not available in ConnectivityManager. Permission
- * checks are done in Vpn class.
+ * VpnBuilder and not available in ConnectivityManager. Permissions
+ * are checked in Vpn class.
* @hide
*/
@Override
@@ -2453,20 +2483,20 @@ public class ConnectivityService extends IConnectivityManager.Stub {
/**
* Prepare for a VPN application. This method is used by VpnDialogs
- * and not available in ConnectivityManager. Permission checks are
- * done in Vpn class.
+ * and not available in ConnectivityManager. Permissions are checked
+ * in Vpn class.
* @hide
*/
@Override
- public String prepareVpn(String packageName) {
- return mVpn.prepare(packageName);
+ public boolean prepareVpn(String oldPackage, String newPackage) {
+ return mVpn.prepare(oldPackage, newPackage);
}
/**
* Configure a TUN interface and return its file descriptor. Parameters
* are encoded and opaque to this class. This method is used by VpnBuilder
- * and not available in ConnectivityManager. Permission checks are done
- * in Vpn class.
+ * and not available in ConnectivityManager. Permissions are checked in
+ * Vpn class.
* @hide
*/
@Override
@@ -2474,6 +2504,28 @@ public class ConnectivityService extends IConnectivityManager.Stub {
return mVpn.establish(config);
}
+ /**
+ * Start legacy VPN and return an intent to VpnDialogs. This method is
+ * used by VpnSettings and not available in ConnectivityManager.
+ * Permissions are checked in Vpn class.
+ * @hide
+ */
+ @Override
+ public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
+ mVpn.startLegacyVpn(config, racoon, mtpd);
+ }
+
+ /**
+ * Return the information of the ongoing legacy VPN. This method is used
+ * by VpnSettings and not available in ConnectivityManager. Permissions
+ * are checked in Vpn class.
+ * @hide
+ */
+ @Override
+ public LegacyVpnInfo getLegacyVpnInfo() {
+ return mVpn.getLegacyVpnInfo();
+ }
+
private String getDefaultInterface() {
if (ConnectivityManager.isNetworkTypeValid(mActiveDefaultNetwork)) {
NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork];
@@ -2502,7 +2554,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private VpnCallback() {
}
- public synchronized void override(String[] dnsServers) {
+ public synchronized void override(List<String> dnsServers, List<String> searchDomains) {
// TODO: override DNS servers and http proxy.
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 8037d7a..2d55433 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -137,6 +137,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private static final String NOT_A_SUBTYPE_ID_STR = String.valueOf(NOT_A_SUBTYPE_ID);
private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
private static final String SUBTYPE_MODE_VOICE = "voice";
+ private static final String TAG_TRY_SUPPRESSING_IME_SWITCHER = "TrySuppressingImeSwitcher";
final Context mContext;
final Resources mRes;
@@ -1057,25 +1058,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
synchronized (mMethodMap) {
List<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked();
final int N = imis.size();
- int count = 0;
+ if (N > 2) return true;
+ if (N < 1) return false;
+ int nonAuxCount = 0;
+ int auxCount = 0;
+ InputMethodSubtype nonAuxSubtype = null;
+ InputMethodSubtype auxSubtype = null;
for(int i = 0; i < N; ++i) {
final InputMethodInfo imi = imis.get(i);
final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeListLocked(
imi, true);
final int subtypeCount = subtypes.size();
if (subtypeCount == 0) {
- ++count;
+ ++nonAuxCount;
} else {
for (int j = 0; j < subtypeCount; ++j) {
- if (!subtypes.get(j).isAuxiliary()) {
- ++count;
+ final InputMethodSubtype subtype = subtypes.get(j);
+ if (!subtype.isAuxiliary()) {
+ ++nonAuxCount;
+ nonAuxSubtype = subtype;
+ } else {
+ ++auxCount;
+ auxSubtype = subtype;
}
}
}
- if (count > 1) return true;
}
+ if (nonAuxCount > 1 || auxCount > 1) {
+ return true;
+ } else if (nonAuxCount == 1 && auxCount == 1) {
+ if (nonAuxSubtype != null && auxSubtype != null
+ && nonAuxSubtype.getLocale().equals(auxSubtype.getLocale())
+ && nonAuxSubtype.containsExtraValueKey(TAG_TRY_SUPPRESSING_IME_SWITCHER)) {
+ return false;
+ }
+ return true;
+ }
+ return false;
}
- return false;
}
@Override
@@ -1603,8 +1623,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (lastImi == null) return null;
try {
final int lastSubtypeHash = Integer.valueOf(lastIme.second);
- return lastImi.getSubtypeAt(getSubtypeIdFromHashCode(
- lastImi, lastSubtypeHash));
+ final int lastSubtypeId = getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
+ if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
+ return null;
+ }
+ return lastImi.getSubtypeAt(lastSubtypeId);
} catch (NumberFormatException e) {
return null;
}
@@ -1621,7 +1644,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
if (imi == null) return false;
final int N = subtypes.length;
- mFileManager.addInputMethodSubtypes(mCurMethodId, subtypes);
+ mFileManager.addInputMethodSubtypes(imi, subtypes);
buildInputMethodListLocked(mMethodList, mMethodMap);
return true;
}
@@ -2003,25 +2026,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final CharSequence label = imi.loadLabel(pm);
if (showSubtypes && enabledSubtypeSet.size() > 0) {
final int subtypeCount = imi.getSubtypeCount();
+ if (DEBUG) {
+ Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
+ }
for (int j = 0; j < subtypeCount; ++j) {
- InputMethodSubtype subtype = imi.getSubtypeAt(j);
- if (enabledSubtypeSet.contains(String.valueOf(subtype.hashCode()))
- && !subtype.isAuxiliary()) {
+ final InputMethodSubtype subtype = imi.getSubtypeAt(j);
+ final String subtypeHashCode = String.valueOf(subtype.hashCode());
+ // We show all enabled IMEs and subtypes when an IME is shown.
+ if (enabledSubtypeSet.contains(subtypeHashCode)
+ && (mInputShown || !subtype.isAuxiliary())) {
final CharSequence title;
- int nameResId = subtype.getNameResId();
- String mode = subtype.getMode();
- if (nameResId != 0) {
- title = TextUtils.concat(subtype.getDisplayName(context,
- imi.getPackageName(), imi.getServiceInfo().applicationInfo),
- (TextUtils.isEmpty(label) ? "" : " (" + label + ")"));
- } else {
- CharSequence language = subtype.getLocale();
- // TODO: Use more friendly Title and UI
- title = label + "," + (mode == null ? "" : mode) + ","
- + (language == null ? "" : language);
- }
+ final String mode = subtype.getMode();
+ title = TextUtils.concat(subtype.getDisplayName(context,
+ imi.getPackageName(), imi.getServiceInfo().applicationInfo),
+ (TextUtils.isEmpty(label) ? "" : " (" + label + ")"));
imList.add(new Pair<CharSequence, Pair<InputMethodInfo, Integer>>(
title, new Pair<InputMethodInfo, Integer>(imi, j)));
+ // Removing this subtype from enabledSubtypeSet because we no longer
+ // need to add an entry of this subtype to imList to avoid duplicated
+ // entries.
+ enabledSubtypeSet.remove(subtypeHashCode);
}
}
} else {
@@ -2318,7 +2342,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
- ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
+ final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
applicableModeAndSubtypesMap.values());
if (!containsKeyboardSubtype) {
InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
@@ -2996,17 +3020,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
public void addInputMethodSubtypes(
- String imiId, InputMethodSubtype[] additionalSubtypes) {
+ InputMethodInfo imi, InputMethodSubtype[] additionalSubtypes) {
synchronized (mMethodMap) {
+ final HashSet<InputMethodSubtype> existingSubtypes =
+ new HashSet<InputMethodSubtype>();
+ for (int i = 0; i < imi.getSubtypeCount(); ++i) {
+ existingSubtypes.add(imi.getSubtypeAt(i));
+ }
+
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
final int N = additionalSubtypes.length;
for (int i = 0; i < N; ++i) {
final InputMethodSubtype subtype = additionalSubtypes[i];
- if (!subtypes.contains(subtype)) {
+ if (!subtypes.contains(subtype) && !existingSubtypes.contains(subtype)) {
subtypes.add(subtype);
}
}
- mSubtypesMap.put(imiId, subtypes);
+ mSubtypesMap.put(imi.getId(), subtypes);
writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
mMethodMap);
}
@@ -3113,8 +3143,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE);
final String imeSubtypeExtraValue =
parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
- final boolean isAuxiliary =
- Boolean.valueOf(parser.getAttributeValue(null, ATTR_IS_AUXILIARY));
+ final boolean isAuxiliary = "1".equals(String.valueOf(
+ parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
final InputMethodSubtype subtype =
new InputMethodSubtype(label, icon, imeSubtypeLocale,
imeSubtypeMode, imeSubtypeExtraValue, isAuxiliary);
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index 1d3e3ac..b3d7220 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -41,7 +41,7 @@ import android.content.IntentFilter;
/**
* {@hide}
*/
-public class IntentResolver<F extends IntentFilter, R extends Object> {
+public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
final private static String TAG = "IntentResolver";
final private static boolean DEBUG = false;
final private static boolean localLOGV = DEBUG || false;
@@ -333,14 +333,19 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
return false;
}
- protected String packageForFilter(F filter) {
- return null;
- }
+ /**
+ * Return the package that owns this filter. This must be implemented to
+ * provide correct filtering of Intents that have specified a package name
+ * they are to be delivered to.
+ */
+ protected abstract String packageForFilter(F filter);
+ @SuppressWarnings("unchecked")
protected R newResult(F filter, int match) {
return (R)filter;
}
+ @SuppressWarnings("unchecked")
protected void sortResults(List<R> results) {
Collections.sort(results, mResolvePrioritySorter);
}
@@ -502,6 +507,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
String resolvedType, String scheme, List<F> src, List<R> dest) {
final String action = intent.getAction();
final Uri data = intent.getData();
+ final String packageName = intent.getPackage();
final boolean excludingStopped = intent.isExcludingStopped();
@@ -520,6 +526,14 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
continue;
}
+ // Is delivery being limited to filters owned by a particular package?
+ if (packageName != null && !packageName.equals(packageForFilter(filter))) {
+ if (debug) {
+ Slog.v(TAG, " Filter is not from package " + packageName + "; skipping");
+ }
+ continue;
+ }
+
// Do we already have this one?
if (!allowFilterResult(filter, dest)) {
if (debug) {
@@ -561,6 +575,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
}
// Sorts a List of IntentFilter objects into descending priority order.
+ @SuppressWarnings("rawtypes")
private static final Comparator mResolvePrioritySorter = new Comparator() {
public int compare(Object o1, Object o2) {
final int q1 = ((IntentFilter) o1).getPriority();
diff --git a/services/java/com/android/server/LoadAverageService.java b/services/java/com/android/server/LoadAverageService.java
index b6baadb..da9fc99 100644
--- a/services/java/com/android/server/LoadAverageService.java
+++ b/services/java/com/android/server/LoadAverageService.java
@@ -278,14 +278,14 @@ public class LoadAverageService extends Service {
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
- WindowManagerImpl wm = (WindowManagerImpl)getSystemService(WINDOW_SERVICE);
+ WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
wm.addView(mView, params);
}
@Override
public void onDestroy() {
super.onDestroy();
- ((WindowManagerImpl)getSystemService(WINDOW_SERVICE)).removeView(mView);
+ ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView);
mView = null;
}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 656ec4d..56afe7f 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -195,6 +195,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
final Object mKey;
final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
int mPendingBroadcasts;
+ String requiredPermissions;
Receiver(ILocationListener listener) {
mListener = listener;
@@ -284,7 +285,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler);
+ mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
+ requiredPermissions);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -319,7 +321,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler);
+ mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
+ requiredPermissions);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -358,7 +361,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler);
+ mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
+ requiredPermissions);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -572,22 +576,30 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return Settings.Secure.isLocationProviderEnabled(resolver, provider);
}
- private void checkPermissionsSafe(String provider) {
- if ((LocationManager.GPS_PROVIDER.equals(provider)
- || LocationManager.PASSIVE_PROVIDER.equals(provider))
- && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)) {
- throw new SecurityException("Provider " + provider
- + " requires ACCESS_FINE_LOCATION permission");
+ private String checkPermissionsSafe(String provider, String lastPermission) {
+ if (LocationManager.GPS_PROVIDER.equals(provider)
+ || LocationManager.PASSIVE_PROVIDER.equals(provider)) {
+ if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Provider " + provider
+ + " requires ACCESS_FINE_LOCATION permission");
+ }
+ return ACCESS_FINE_LOCATION;
}
- if (LocationManager.NETWORK_PROVIDER.equals(provider)
- && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)
- && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)) {
- throw new SecurityException("Provider " + provider
- + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
+
+ // Assume any other provider requires the coarse or fine permission.
+ if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) {
+ return ACCESS_FINE_LOCATION.equals(lastPermission)
+ ? lastPermission : ACCESS_COARSE_LOCATION;
}
+ if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) {
+ return ACCESS_FINE_LOCATION;
+ }
+
+ throw new SecurityException("Provider " + provider
+ + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
}
private boolean isAllowedProviderSafe(String provider) {
@@ -1099,8 +1111,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
+ void validatePendingIntent(PendingIntent intent) {
+ if (intent.isTargetedToPackage()) {
+ return;
+ }
+ Slog.i(TAG, "Given Intent does not require a specific package: "
+ + intent);
+ // XXX we should really throw a security exception, if the caller's
+ // targetSdkVersion is high enough.
+ //throw new SecurityException("Given Intent does not require a specific package: "
+ // + intent);
+ }
+
public void requestLocationUpdatesPI(String provider, Criteria criteria,
long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
+ validatePendingIntent(intent);
if (criteria != null) {
// FIXME - should we consider using multiple providers simultaneously
// rather than only the best one?
@@ -1132,7 +1157,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
throw new IllegalArgumentException("provider=" + provider);
}
- checkPermissionsSafe(provider);
+ receiver.requiredPermissions = checkPermissionsSafe(provider,
+ receiver.requiredPermissions);
// so wakelock calls will succeed
final int callingUid = Binder.getCallingUid();
@@ -1300,7 +1326,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
// first check for permission to the provider
- checkPermissionsSafe(provider);
+ checkPermissionsSafe(provider, null);
// and check for ACCESS_LOCATION_EXTRA_COMMANDS
if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
!= PackageManager.PERMISSION_GRANTED)) {
@@ -1432,7 +1458,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcasts()
// is called before decrementPendingBroadcasts()
- intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
+ intent.send(mContext, 0, enteredIntent, this, mLocationHandler,
+ ACCESS_FINE_LOCATION);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcasts();
@@ -1457,7 +1484,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcasts()
// is called before decrementPendingBroadcasts()
- intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
+ intent.send(mContext, 0, exitedIntent, this, mLocationHandler,
+ ACCESS_FINE_LOCATION);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcasts();
@@ -1526,6 +1554,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public void addProximityAlert(double latitude, double longitude,
float radius, long expiration, PendingIntent intent) {
+ validatePendingIntent(intent);
try {
synchronized (mLock) {
addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
@@ -1626,7 +1655,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return null;
}
- checkPermissionsSafe(provider);
+ checkPermissionsSafe(provider, null);
Bundle b = new Bundle();
b.putBoolean("network", p.requiresNetwork());
@@ -1668,7 +1697,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
private boolean _isProviderEnabledLocked(String provider) {
- checkPermissionsSafe(provider);
+ checkPermissionsSafe(provider, null);
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
@@ -1694,7 +1723,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
private Location _getLastKnownLocationLocked(String provider) {
- checkPermissionsSafe(provider);
+ checkPermissionsSafe(provider, null);
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d3244ec..2e54c99 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1075,18 +1075,22 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
com.android.internal.R.styleable.Storage_mtpReserve, 0);
boolean allowMassStorage = a.getBoolean(
com.android.internal.R.styleable.Storage_allowMassStorage, false);
+ // resource parser does not support longs, so XML value is in megabytes
+ long maxFileSize = a.getInt(
+ com.android.internal.R.styleable.Storage_maxFileSize, 0) * 1024L * 1024L;
Slog.d(TAG, "got storage path: " + path + " description: " + description +
" primary: " + primary + " removable: " + removable +
" emulated: " + emulated + " mtpReserve: " + mtpReserve +
- " allowMassStorage: " + allowMassStorage);
+ " allowMassStorage: " + allowMassStorage +
+ " maxFileSize: " + maxFileSize);
if (path == null || description == null) {
Slog.e(TAG, "path or description is null in readStorageList");
} else {
String pathString = path.toString();
StorageVolume volume = new StorageVolume(pathString,
description.toString(), removable, emulated,
- mtpReserve, allowMassStorage);
+ mtpReserve, allowMassStorage, maxFileSize);
if (primary) {
if (mPrimaryVolume == null) {
mPrimaryVolume = volume;
@@ -1626,6 +1630,30 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
}
}
+ public String getSecureContainerFilesystemPath(String id) {
+ validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ waitForReady();
+ warnOnNotMounted();
+
+ try {
+ ArrayList<String> rsp = mConnector.doCommand(String.format("asec fspath %s", id));
+ String []tok = rsp.get(0).split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code != VoldResponseCode.AsecPathResult) {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ return tok[1];
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageNotFound) {
+ Slog.i(TAG, String.format("Container '%s' not found", id));
+ return null;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ }
+
public void finishMediaUpdate() {
mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 2b01c5e..da1bf83 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -16,10 +16,11 @@
package com.android.server;
+import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
-import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
+import static android.provider.Settings.Secure.NETSTATS_ENABLED;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -35,8 +36,14 @@ import android.os.Binder;
import android.os.INetworkManagementService;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseBooleanArray;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+import com.google.android.collect.Sets;
import java.io.BufferedReader;
import java.io.DataInputStream;
@@ -47,7 +54,10 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
@@ -65,9 +75,18 @@ class NetworkManagementService extends INetworkManagementService.Stub {
private static final int ADD = 1;
private static final int REMOVE = 2;
+ /** Path to {@code /proc/uid_stat}. */
@Deprecated
- private static final File STATS_UIDSTAT = new File("/proc/uid_stat");
- private static final File STATS_NETFILTER = new File("/proc/net/xt_qtaguid/stats");
+ private final File mProcStatsUidstat;
+ /** Path to {@code /proc/net/xt_qtaguid/stats}. */
+ private final File mProcStatsNetfilter;
+
+ /** {@link #mProcStatsNetfilter} headers. */
+ private static final String KEY_IFACE = "iface";
+ private static final String KEY_TAG_HEX = "acct_tag_hex";
+ private static final String KEY_UID = "uid_tag_int";
+ private static final String KEY_RX = "rx_bytes";
+ private static final String KEY_TX = "tx_bytes";
class NetdResponseCode {
public static final int InterfaceListResult = 110;
@@ -102,15 +121,25 @@ class NetworkManagementService extends INetworkManagementService.Stub {
private ArrayList<INetworkManagementEventObserver> mObservers;
+ /** Set of interfaces with active quotas. */
+ private HashSet<String> mInterfaceQuota = Sets.newHashSet();
+ /** Set of UIDs with active reject rules. */
+ private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
+
+ private boolean mBandwidthControlEnabled;
+
/**
* Constructs a new NetworkManagementService instance
*
* @param context Binder context for this service
*/
- private NetworkManagementService(Context context) {
+ private NetworkManagementService(Context context, File procRoot) {
mContext = context;
mObservers = new ArrayList<INetworkManagementEventObserver>();
+ mProcStatsUidstat = new File(procRoot, "uid_stat");
+ mProcStatsNetfilter = new File(procRoot, "net/xt_qtaguid/stats");
+
if ("simulator".equals(SystemProperties.get("ro.product.device"))) {
return;
}
@@ -121,7 +150,8 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
public static NetworkManagementService create(Context context) throws InterruptedException {
- NetworkManagementService service = new NetworkManagementService(context);
+ NetworkManagementService service = new NetworkManagementService(
+ context, new File("/proc/"));
if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
service.mThread.start();
if (DBG) Slog.d(TAG, "Awaiting socket connection");
@@ -130,6 +160,35 @@ class NetworkManagementService extends INetworkManagementService.Stub {
return service;
}
+ // @VisibleForTesting
+ public static NetworkManagementService createForTest(Context context, File procRoot) {
+ // TODO: eventually connect with mock netd
+ return new NetworkManagementService(context, procRoot);
+ }
+
+ public void systemReady() {
+
+ // only enable bandwidth control when support exists, and requested by
+ // system setting.
+ // TODO: eventually migrate to be always enabled
+ final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
+ final boolean shouldEnable =
+ Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 0) != 0;
+
+ mBandwidthControlEnabled = false;
+ if (hasKernelSupport && shouldEnable) {
+ Slog.d(TAG, "enabling bandwidth control");
+ try {
+ mConnector.doCommand("bandwidth enable");
+ mBandwidthControlEnabled = true;
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "problem enabling bandwidth controls", e);
+ }
+ } else {
+ Slog.d(TAG, "not enabling bandwidth control");
+ }
+ }
+
public void registerObserver(INetworkManagementEventObserver obs) {
Slog.d(TAG, "Registering observer");
mObservers.add(obs);
@@ -141,12 +200,26 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
/**
- * Notify our observers of an interface link status change
+ * Notify our observers of an interface status change
+ */
+ private void notifyInterfaceStatusChanged(String iface, boolean up) {
+ for (INetworkManagementEventObserver obs : mObservers) {
+ try {
+ obs.interfaceStatusChanged(iface, up);
+ } catch (Exception ex) {
+ Slog.w(TAG, "Observer notifier failed", ex);
+ }
+ }
+ }
+
+ /**
+ * Notify our observers of an interface link state change
+ * (typically, an Ethernet cable has been plugged-in or unplugged).
*/
- private void notifyInterfaceLinkStatusChanged(String iface, boolean link) {
+ private void notifyInterfaceLinkStateChanged(String iface, boolean up) {
for (INetworkManagementEventObserver obs : mObservers) {
try {
- obs.interfaceLinkStatusChanged(iface, link);
+ obs.interfaceLinkStateChanged(iface, up);
} catch (Exception ex) {
Slog.w(TAG, "Observer notifier failed", ex);
}
@@ -207,6 +280,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
* Format: "NNN Iface added <name>"
* "NNN Iface removed <name>"
* "NNN Iface changed <name> <up/down>"
+ * "NNN Iface linkstatus <name> <up/down>"
*/
if (cooked.length < 4 || !cooked[1].equals("Iface")) {
throw new IllegalStateException(
@@ -219,7 +293,10 @@ class NetworkManagementService extends INetworkManagementService.Stub {
notifyInterfaceRemoved(cooked[3]);
return true;
} else if (cooked[2].equals("changed") && cooked.length == 5) {
- notifyInterfaceLinkStatusChanged(cooked[3], cooked[4].equals("up"));
+ notifyInterfaceStatusChanged(cooked[3], cooked[4].equals("up"));
+ return true;
+ } else if (cooked[2].equals("linkstate") && cooked.length == 5) {
+ notifyInterfaceLinkStateChanged(cooked[3], cooked[4].equals("up"));
return true;
}
throw new IllegalStateException(
@@ -870,7 +947,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- if (STATS_NETFILTER.exists()) {
+ if (mBandwidthControlEnabled) {
return getNetworkStatsDetailNetfilter(UID_ALL);
} else {
return getNetworkStatsDetailUidstat(UID_ALL);
@@ -878,13 +955,103 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
@Override
+ public void setInterfaceQuota(String iface, long quota) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ synchronized (mInterfaceQuota) {
+ if (mInterfaceQuota.contains(iface)) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth setiquota ").append(iface).append(" ").append(quota);
+
+ try {
+ // TODO: add support for quota shared across interfaces
+ mConnector.doCommand(command.toString());
+ mInterfaceQuota.add(iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
+ @Override
+ public void removeInterfaceQuota(String iface) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ synchronized (mInterfaceQuota) {
+ if (!mInterfaceQuota.contains(iface)) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth removeiquota ").append(iface);
+
+ try {
+ // TODO: add support for quota shared across interfaces
+ mConnector.doCommand(command.toString());
+ mInterfaceQuota.remove(iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
+ @Override
+ public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ synchronized (mUidRejectOnQuota) {
+ final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
+ if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth");
+ if (rejectOnQuotaInterfaces) {
+ command.append(" addnaughtyapps");
+ } else {
+ command.append(" removenaughtyapps");
+ }
+ command.append(" ").append(uid);
+
+ try {
+ mConnector.doCommand(command.toString());
+ if (rejectOnQuotaInterfaces) {
+ mUidRejectOnQuota.put(uid, true);
+ } else {
+ mUidRejectOnQuota.delete(uid);
+ }
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
public NetworkStats getNetworkStatsUidDetail(int uid) {
if (Binder.getCallingUid() != uid) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
}
- if (STATS_NETFILTER.exists()) {
+ if (mBandwidthControlEnabled) {
return getNetworkStatsDetailNetfilter(uid);
} else {
return getNetworkStatsDetailUidstat(uid);
@@ -896,35 +1063,36 @@ class NetworkManagementService extends INetworkManagementService.Stub {
*/
private NetworkStats getNetworkStatsDetailNetfilter(int limitUid) {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24);
+ final ArrayList<String> keys = Lists.newArrayList();
+ final ArrayList<String> values = Lists.newArrayList();
+ final HashMap<String, String> parsed = Maps.newHashMap();
BufferedReader reader = null;
try {
- reader = new BufferedReader(new FileReader(STATS_NETFILTER));
-
- // assumes format from kernel:
- // idx iface acct_tag_hex uid_tag_int rx_bytes tx_bytes
+ reader = new BufferedReader(new FileReader(mProcStatsNetfilter));
- // skip first line, which is legend
+ // parse first line as header
String line = reader.readLine();
- while ((line = reader.readLine()) != null) {
- final StringTokenizer t = new StringTokenizer(line);
+ splitLine(line, keys);
- final String idx = t.nextToken();
- final String iface = t.nextToken();
+ // parse remaining lines
+ while ((line = reader.readLine()) != null) {
+ splitLine(line, values);
+ parseLine(keys, values, parsed);
try {
- // TODO: kernel currently emits tag in upper half of long;
- // eventually switch to directly using int.
- final int tag = (int) (Long.parseLong(t.nextToken().substring(2), 16) >> 32);
- final int uid = Integer.parseInt(t.nextToken());
- final long rx = Long.parseLong(t.nextToken());
- final long tx = Long.parseLong(t.nextToken());
+ final String iface = parsed.get(KEY_IFACE);
+ final int tag = NetworkManagementSocketTagger.kernelToTag(
+ parsed.get(KEY_TAG_HEX));
+ final int uid = Integer.parseInt(parsed.get(KEY_UID));
+ final long rx = Long.parseLong(parsed.get(KEY_RX));
+ final long tx = Long.parseLong(parsed.get(KEY_TX));
if (limitUid == UID_ALL || limitUid == uid) {
stats.addEntry(iface, uid, tag, rx, tx);
}
} catch (NumberFormatException e) {
- Slog.w(TAG, "problem parsing stats for idx " + idx + ": " + e);
+ Slog.w(TAG, "problem parsing stats row '" + line + "': " + e);
}
}
} catch (IOException e) {
@@ -946,7 +1114,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
private NetworkStats getNetworkStatsDetailUidstat(int limitUid) {
final String[] knownUids;
if (limitUid == UID_ALL) {
- knownUids = STATS_UIDSTAT.list();
+ knownUids = mProcStatsUidstat.list();
} else {
knownUids = new String[] { String.valueOf(limitUid) };
}
@@ -955,7 +1123,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
SystemClock.elapsedRealtime(), knownUids.length);
for (String uid : knownUids) {
final int uidInt = Integer.parseInt(uid);
- final File uidPath = new File(STATS_UIDSTAT, uid);
+ final File uidPath = new File(mProcStatsUidstat, uid);
final long rx = readSingleLongFromFile(new File(uidPath, "tcp_rcv"));
final long tx = readSingleLongFromFile(new File(uidPath, "tcp_snd"));
stats.addEntry(IFACE_ALL, uidInt, TAG_NONE, rx, tx);
@@ -1023,10 +1191,30 @@ class NetworkManagementService extends INetworkManagementService.Stub {
return getInterfaceThrottle(iface, false);
}
- @Override
- public void setBandwidthControlEnabled(boolean enabled) {
- mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- mConnector.doCommand(String.format("bandwidth %s", (enabled ? "enable" : "disable")));
+ /**
+ * Split given line into {@link ArrayList}.
+ */
+ private static void splitLine(String line, ArrayList<String> outSplit) {
+ outSplit.clear();
+
+ final StringTokenizer t = new StringTokenizer(line);
+ while (t.hasMoreTokens()) {
+ outSplit.add(t.nextToken());
+ }
+ }
+
+ /**
+ * Zip the two given {@link ArrayList} as key and value pairs into
+ * {@link HashMap}.
+ */
+ private static void parseLine(
+ ArrayList<String> keys, ArrayList<String> values, HashMap<String, String> outParsed) {
+ outParsed.clear();
+
+ final int size = Math.min(keys.size(), values.size());
+ for (int i = 0; i < size; i++) {
+ outParsed.put(keys.get(i), values.get(i));
+ }
}
/**
@@ -1043,4 +1231,65 @@ class NetworkManagementService extends INetworkManagementService.Stub {
return -1;
}
}
+
+ public void setDefaultInterfaceForDns(String iface) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ try {
+ String cmd = "resolver setdefaultif " + iface;
+
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Error communicating with native daemon to set default interface", e);
+ }
+ }
+
+ public void setDnsServersForInterface(String iface, String[] servers)
+ throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_NETWORK_STATE,
+ "NetworkManagementService");
+ try {
+ String cmd = "resolver setifdns " + iface;
+ for (String s : servers) {
+ if (s != null && !"0.0.0.0".equals(s) &&
+ !"::".equals(s) && !"0:0:0:0:0:0:0:0".equals(s)) {
+ cmd += " " + InetAddress.getByName(s).getHostAddress();
+ }
+ }
+
+ mConnector.doCommand(cmd);
+ } catch (UnknownHostException e) {
+ throw new IllegalStateException("failed to resolve dns address.", e);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Error communicating with native deamon to set dns for interface", e);
+ }
+ }
+
+ public void flushDefaultDnsCache() throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ try {
+ String cmd = "resolver flushdefaultif";
+
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Error communicating with native deamon to flush default interface", e);
+ }
+ }
+
+ public void flushInterfaceDnsCache(String iface) throws IllegalStateException {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+ try {
+ String cmd = "resolver flushif " + iface;
+
+ mConnector.doCommand(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException(
+ "Error communicating with native deamon to flush interface " + iface, e);
+ }
+ }
}
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index 15f22c0..f7fe39e 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -16,8 +16,6 @@
package com.android.server;
-import com.android.internal.telephony.TelephonyIntents;
-
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
@@ -28,7 +26,6 @@ import android.content.IntentFilter;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.SntpClient;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
@@ -36,12 +33,10 @@ import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
-import android.util.Slog;
+import android.util.NtpTrustedTime;
+import android.util.TrustedTime;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.Properties;
+import com.android.internal.telephony.TelephonyIntents;
/**
* Monitors the network time and updates the system time if it is out of sync
@@ -68,14 +63,11 @@ public class NetworkTimeUpdateService {
private static final long POLLING_INTERVAL_SHORTER_MS = 60 * 1000L; // 60 seconds
/** Number of times to try again */
private static final int TRY_AGAIN_TIMES_MAX = 3;
- /** How long to wait for the NTP server to respond. */
- private static final int MAX_NTP_FETCH_WAIT_MS = 20 * 1000;
/** If the time difference is greater than this threshold, then update the time. */
private static final int TIME_ERROR_THRESHOLD_MS = 5 * 1000;
private static final String ACTION_POLL =
"com.android.server.NetworkTimeUpdateService.action.POLL";
- private static final String PROPERTIES_FILE = "/etc/gps.conf";
private static int POLL_REQUEST = 0;
private static final long NOT_SET = -1;
@@ -84,14 +76,14 @@ public class NetworkTimeUpdateService {
private long mNitzZoneSetTime = NOT_SET;
private Context mContext;
+ private TrustedTime mTime;
+
// NTP lookup is done on this thread and handler
private Handler mHandler;
private HandlerThread mThread;
private AlarmManager mAlarmManager;
private PendingIntent mPendingPollIntent;
private SettingsObserver mSettingsObserver;
- // Address of the NTP server
- private String mNtpServer;
// The last time that we successfully fetched the NTP time.
private long mLastNtpFetchTime = NOT_SET;
// Keeps track of how many quick attempts were made to fetch NTP time.
@@ -101,6 +93,7 @@ public class NetworkTimeUpdateService {
public NetworkTimeUpdateService(Context context) {
mContext = context;
+ mTime = NtpTrustedTime.getInstance(context);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent pollIntent = new Intent(ACTION_POLL, null);
mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0);
@@ -108,12 +101,6 @@ public class NetworkTimeUpdateService {
/** Initialize the receivers and initiate the first NTP request */
public void systemReady() {
- mNtpServer = getNtpServerAddress();
- if (mNtpServer == null) {
- Slog.e(TAG, "NTP server address not found, not syncing to NTP time");
- return;
- }
-
registerForTelephonyIntents();
registerForAlarms();
registerForConnectivityIntents();
@@ -128,27 +115,6 @@ public class NetworkTimeUpdateService {
mSettingsObserver.observe(mContext);
}
- private String getNtpServerAddress() {
- String serverAddress = null;
- FileInputStream stream = null;
- try {
- Properties properties = new Properties();
- File file = new File(PROPERTIES_FILE);
- stream = new FileInputStream(file);
- properties.load(stream);
- serverAddress = properties.getProperty("NTP_SERVER", null);
- } catch (IOException e) {
- Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (Exception e) {}
- }
- }
- return serverAddress;
- }
-
private void registerForTelephonyIntents() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TelephonyIntents.ACTION_NETWORK_SET_TIME);
@@ -189,9 +155,15 @@ public class NetworkTimeUpdateService {
if (mLastNtpFetchTime == NOT_SET || refTime >= mLastNtpFetchTime + POLLING_INTERVAL_MS
|| event == EVENT_AUTO_TIME_CHANGED) {
if (DBG) Log.d(TAG, "Before Ntp fetch");
- long ntp = getNtpTime();
- if (DBG) Log.d(TAG, "Ntp = " + ntp);
- if (ntp > 0) {
+
+ // force refresh NTP cache when outdated
+ if (mTime.getCacheAge() >= POLLING_INTERVAL_MS) {
+ mTime.forceRefresh();
+ }
+
+ // only update when NTP time is fresh
+ if (mTime.getCacheAge() < POLLING_INTERVAL_MS) {
+ final long ntp = mTime.currentTimeMillis();
mTryAgainCounter = 0;
mLastNtpFetchTime = SystemClock.elapsedRealtime();
if (Math.abs(ntp - currentTime) > TIME_ERROR_THRESHOLD_MS) {
@@ -232,15 +204,6 @@ public class NetworkTimeUpdateService {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent);
}
- private long getNtpTime() {
- SntpClient client = new SntpClient();
- if (client.requestTime(mNtpServer, MAX_NTP_FETCH_WAIT_MS)) {
- return client.getNtpTime();
- } else {
- return 0;
- }
- }
-
/**
* Checks if the user prefers to automatically set the time.
*/
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index 08c6699..950f3b6 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -138,7 +138,7 @@ public class SystemBackupAgent extends BackupAgentHelper {
if (outFile == null) {
Slog.w(TAG, "Skipping unrecognized system file: [ " + domain + " : " + path + " ]");
}
- FullBackup.restoreToFile(data, size, type, mode, mtime, outFile, true);
+ FullBackup.restoreFile(data, size, type, mode, mtime, outFile);
if (restoredWallpaper) {
WallpaperManagerService wallpaper =
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index a23bacf..8c7e279 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -209,9 +209,11 @@ class ServerThread extends Thread {
bluetoothA2dp);
bluetooth.initAfterA2dpRegistration();
+ int airplaneModeOn = Settings.System.getInt(mContentResolver,
+ Settings.System.AIRPLANE_MODE_ON, 0);
int bluetoothOn = Settings.Secure.getInt(mContentResolver,
Settings.Secure.BLUETOOTH_ON, 0);
- if (bluetoothOn > 0) {
+ if (airplaneModeOn == 0 && bluetoothOn != 0) {
bluetooth.enable();
}
}
@@ -281,7 +283,8 @@ class ServerThread extends Thread {
try {
Slog.i(TAG, "NetworkPolicy Service");
networkPolicy = new NetworkPolicyManagerService(
- context, ActivityManagerService.self(), power, networkStats);
+ context, ActivityManagerService.self(), power,
+ networkStats, networkManagement);
ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting NetworkPolicy Service", e);
@@ -520,6 +523,7 @@ class ServerThread extends Thread {
// These are needed to propagate to the runnable below.
final Context contextF = context;
final BatteryService batteryF = battery;
+ final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
final NetworkPolicyManagerService networkPolicyF = networkPolicy;
final ConnectivityService connectivityF = connectivity;
@@ -547,6 +551,7 @@ class ServerThread extends Thread {
startSystemUi(contextF);
if (batteryF != null) batteryF.systemReady();
+ if (networkManagementF != null) networkManagementF.systemReady();
if (networkStatsF != null) networkStatsF.systemReady();
if (networkPolicyF != null) networkPolicyF.systemReady();
if (connectivityF != null) connectivityF.systemReady();
diff --git a/services/java/com/android/server/ThrottleService.java b/services/java/com/android/server/ThrottleService.java
index 7266d7d..24d4dd3 100644
--- a/services/java/com/android/server/ThrottleService.java
+++ b/services/java/com/android/server/ThrottleService.java
@@ -16,9 +16,6 @@
package com.android.server;
-import com.android.internal.R;
-import com.android.internal.telephony.TelephonyProperties;
-
import android.app.AlarmManager;
import android.app.Notification;
import android.app.NotificationManager;
@@ -54,6 +51,9 @@ import android.util.NtpTrustedTime;
import android.util.Slog;
import android.util.TrustedTime;
+import com.android.internal.R;
+import com.android.internal.telephony.TelephonyProperties;
+
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileDescriptor;
@@ -63,7 +63,6 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.GregorianCalendar;
-import java.util.Properties;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -87,7 +86,6 @@ public class ThrottleService extends IThrottleManager.Stub {
private static final long TESTING_THRESHOLD = 1 * 1024 * 1024;
private static final long MAX_NTP_CACHE_AGE = 24 * 60 * 60 * 1000;
- private static final long MAX_NTP_FETCH_WAIT = 20 * 1000;
private long mMaxNtpCacheAge = MAX_NTP_CACHE_AGE;
@@ -127,8 +125,6 @@ public class ThrottleService extends IThrottleManager.Stub {
private static final int THROTTLE_INDEX_UNINITIALIZED = -1;
private static final int THROTTLE_INDEX_UNTHROTTLED = 0;
- private static final String PROPERTIES_FILE = "/etc/gps.conf";
-
private Intent mPollStickyBroadcast;
private TrustedTime mTime;
@@ -139,8 +135,7 @@ public class ThrottleService extends IThrottleManager.Stub {
}
public ThrottleService(Context context) {
- // TODO: move to using cached NtpTrustedTime
- this(context, getNetworkManagementService(), new NtpTrustedTime(),
+ this(context, getNetworkManagementService(), NtpTrustedTime.getInstance(context),
context.getResources().getString(R.string.config_datause_iface));
}
@@ -179,14 +174,17 @@ public class ThrottleService extends IThrottleManager.Stub {
mIface = iface;
}
- public void interfaceLinkStatusChanged(String iface, boolean link) {
- if (link) {
+ public void interfaceStatusChanged(String iface, boolean up) {
+ if (up) {
if (TextUtils.equals(iface, mIface)) {
mHandler.obtainMessage(mMsg).sendToTarget();
}
}
}
+ public void interfaceLinkStateChanged(String iface, boolean up) {
+ }
+
public void interfaceAdded(String iface) {
// TODO - an interface added in the UP state should also trigger a StatusChanged
// notification..
@@ -338,26 +336,6 @@ public class ThrottleService extends IThrottleManager.Stub {
}
}, new IntentFilter(ACTION_RESET));
- FileInputStream stream = null;
- try {
- Properties properties = new Properties();
- File file = new File(PROPERTIES_FILE);
- stream = new FileInputStream(file);
- properties.load(stream);
- final String ntpServer = properties.getProperty("NTP_SERVER", null);
- if (mTime instanceof NtpTrustedTime) {
- ((NtpTrustedTime) mTime).setNtpServer(ntpServer, MAX_NTP_FETCH_WAIT);
- }
- } catch (IOException e) {
- Slog.e(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (Exception e) {}
- }
- }
-
// use a new thread as we don't want to stall the system for file writes
mThread = new HandlerThread(TAG);
mThread.start();
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index cb55451..5f0922e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -36,6 +36,7 @@ import android.net.wifi.WifiManager;
import android.net.wifi.WifiStateMachine;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiWatchdogService;
import android.net.wifi.WpsConfiguration;
import android.net.wifi.WpsResult;
import android.net.ConnectivityManager;
@@ -342,6 +343,7 @@ public class WifiService extends IWifiManager.Stub {
* Protected by mWifiStateTracker lock.
*/
private final WorkSource mTmpWorkSource = new WorkSource();
+ private WifiWatchdogService mWifiWatchdogService;
WifiService(Context context) {
mContext = context;
@@ -431,6 +433,9 @@ public class WifiService extends IWifiManager.Stub {
Slog.i(TAG, "WifiService starting up with Wi-Fi " +
(wifiEnabled ? "enabled" : "disabled"));
setWifiEnabled(wifiEnabled);
+
+ //TODO: as part of WWS refactor, create only when needed
+ mWifiWatchdogService = new WifiWatchdogService(mContext);
}
private boolean testAndClearWifiSavedState() {
@@ -1155,6 +1160,10 @@ public class WifiService extends IWifiManager.Stub {
pw.println();
pw.println("Locks held:");
mLocks.dump(pw);
+
+ pw.println();
+ pw.println("WifiWatchdogService dump");
+ mWifiWatchdogService.dump(pw);
}
private class WifiLock extends DeathRecipient {
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
deleted file mode 100644
index 56bfbe0..0000000
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ /dev/null
@@ -1,1450 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.ConnectivityManager;
-import android.net.LinkProperties;
-import android.net.NetworkInfo;
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiInfo;
-import android.net.wifi.WifiManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings;
-import android.text.TextUtils;
-import android.util.Slog;
-
-import java.io.BufferedInputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.net.DatagramPacket;
-import java.net.DatagramSocket;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.SocketException;
-import java.net.SocketTimeoutException;
-import java.net.UnknownHostException;
-import java.net.URL;
-import java.util.Collection;
-import java.util.List;
-import java.util.Random;
-import java.util.Scanner;
-
-/**
- * {@link WifiWatchdogService} monitors the initial connection to a Wi-Fi
- * network with multiple access points. After the framework successfully
- * connects to an access point, the watchdog verifies whether the DNS server is
- * reachable. If not, the watchdog blacklists the current access point, leading
- * to a connection on another access point within the same network.
- * <p>
- * The watchdog has a few safeguards:
- * <ul>
- * <li>Only monitor networks with multiple access points
- * <li>Only check at most {@link #getMaxApChecks()} different access points
- * within the network before giving up
- * <p>
- * The watchdog checks for connectivity on an access point by ICMP pinging the
- * DNS. There are settings that allow disabling the watchdog, or tweaking the
- * acceptable packet loss (and other various parameters).
- * <p>
- * The core logic of the watchdog is done on the main watchdog thread. Wi-Fi
- * callbacks can come in on other threads, so we must queue messages to the main
- * watchdog thread's handler. Most (if not all) state is only written to from
- * the main thread.
- *
- * {@hide}
- */
-public class WifiWatchdogService {
- private static final String TAG = "WifiWatchdogService";
- private static final boolean V = false;
- private static final boolean D = true;
-
- private Context mContext;
- private ContentResolver mContentResolver;
- private WifiManager mWifiManager;
- private ConnectivityManager mConnectivityManager;
-
- /**
- * The main watchdog thread.
- */
- private WifiWatchdogThread mThread;
- /**
- * The handler for the main watchdog thread.
- */
- private WifiWatchdogHandler mHandler;
-
- private ContentObserver mContentObserver;
-
- /**
- * The current watchdog state. Only written from the main thread!
- */
- private WatchdogState mState = WatchdogState.IDLE;
- /**
- * The SSID of the network that the watchdog is currently monitoring. Only
- * touched in the main thread!
- */
- private String mSsid;
- /**
- * The number of access points in the current network ({@link #mSsid}) that
- * have been checked. Only touched in the main thread, using getter/setter methods.
- */
- private int mBssidCheckCount;
- /** Whether the current AP check should be canceled. */
- private boolean mShouldCancel;
-
- WifiWatchdogService(Context context) {
- mContext = context;
- mContentResolver = context.getContentResolver();
- mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
- createThread();
-
- // The content observer to listen needs a handler, which createThread creates
- registerForSettingsChanges();
- if (isWatchdogEnabled()) {
- registerForWifiBroadcasts();
- }
-
- if (V) {
- myLogV("WifiWatchdogService: Created");
- }
- }
-
- /**
- * Observes the watchdog on/off setting, and takes action when changed.
- */
- private void registerForSettingsChanges() {
- ContentResolver contentResolver = mContext.getContentResolver();
- contentResolver.registerContentObserver(
- Settings.Secure.getUriFor(Settings.Secure.WIFI_WATCHDOG_ON), false,
- mContentObserver = new ContentObserver(mHandler) {
- @Override
- public void onChange(boolean selfChange) {
- if (isWatchdogEnabled()) {
- registerForWifiBroadcasts();
- } else {
- unregisterForWifiBroadcasts();
- if (mHandler != null) {
- mHandler.disableWatchdog();
- }
- }
- }
- });
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ON
- */
- private boolean isWatchdogEnabled() {
- return Settings.Secure.getInt(mContentResolver, Settings.Secure.WIFI_WATCHDOG_ON, 1) == 1;
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_AP_COUNT
- */
- private int getApCount() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_AP_COUNT, 2);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT
- */
- private int getInitialIgnoredPingCount() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT , 2);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_COUNT
- */
- private int getPingCount() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_PING_COUNT, 4);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_TIMEOUT_MS
- */
- private int getPingTimeoutMs() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_PING_TIMEOUT_MS, 500);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_PING_DELAY_MS
- */
- private int getPingDelayMs() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_PING_DELAY_MS, 250);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED
- */
- private Boolean isWalledGardenTestEnabled() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_TEST_ENABLED, 1) == 1;
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_URL
- */
- private String getWalledGardenUrl() {
- String url = Settings.Secure.getString(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_URL);
- if (TextUtils.isEmpty(url)) return "http://www.google.com/";
- return url;
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WALLED_GARDEN_PATTERN
- */
- private String getWalledGardenPattern() {
- String pattern = Settings.Secure.getString(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_WALLED_GARDEN_PATTERN);
- if (TextUtils.isEmpty(pattern)) return "<title>.*Google.*</title>";
- return pattern;
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE
- */
- private int getAcceptablePacketLossPercentage() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_ACCEPTABLE_PACKET_LOSS_PERCENTAGE, 25);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS
- */
- private int getMaxApChecks() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_MAX_AP_CHECKS, 7);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED
- */
- private boolean isBackgroundCheckEnabled() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_ENABLED, 1) == 1;
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS
- */
- private int getBackgroundCheckDelayMs() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_DELAY_MS, 60000);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS
- */
- private int getBackgroundCheckTimeoutMs() {
- return Settings.Secure.getInt(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_BACKGROUND_CHECK_TIMEOUT_MS, 1000);
- }
-
- /**
- * @see android.provider.Settings.Secure#WIFI_WATCHDOG_WATCH_LIST
- * @return the comma-separated list of SSIDs
- */
- private String getWatchList() {
- return Settings.Secure.getString(mContentResolver,
- Settings.Secure.WIFI_WATCHDOG_WATCH_LIST);
- }
-
- /**
- * Registers to receive the necessary Wi-Fi broadcasts.
- */
- private void registerForWifiBroadcasts() {
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- mContext.registerReceiver(mReceiver, intentFilter);
- }
-
- /**
- * Unregisters from receiving the Wi-Fi broadcasts.
- */
- private void unregisterForWifiBroadcasts() {
- mContext.unregisterReceiver(mReceiver);
- }
-
- /**
- * Creates the main watchdog thread, including waiting for the handler to be
- * created.
- */
- private void createThread() {
- mThread = new WifiWatchdogThread();
- mThread.start();
- waitForHandlerCreation();
- }
-
- /**
- * Unregister broadcasts and quit the watchdog thread
- */
- //TODO: Change back to running WWS when needed
-// private void quit() {
-// unregisterForWifiBroadcasts();
-// mContext.getContentResolver().unregisterContentObserver(mContentObserver);
-// mHandler.removeAllActions();
-// mHandler.getLooper().quit();
-// }
-
- /**
- * Waits for the main watchdog thread to create the handler.
- */
- private void waitForHandlerCreation() {
- synchronized(this) {
- while (mHandler == null) {
- try {
- // Wait for the handler to be set by the other thread
- wait();
- } catch (InterruptedException e) {
- Slog.e(TAG, "Interrupted while waiting on handler.");
- }
- }
- }
- }
-
- // Utility methods
-
- /**
- * Logs with the current thread.
- */
- private static void myLogV(String message) {
- Slog.v(TAG, "(" + Thread.currentThread().getName() + ") " + message);
- }
-
- private static void myLogD(String message) {
- Slog.d(TAG, "(" + Thread.currentThread().getName() + ") " + message);
- }
-
- /**
- * Gets the first DNS of the current AP.
- *
- * @return The first DNS of the current AP.
- */
- private InetAddress getDns() {
- if (mConnectivityManager == null) {
- mConnectivityManager = (ConnectivityManager)mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- }
-
- LinkProperties linkProperties = mConnectivityManager.getLinkProperties(
- ConnectivityManager.TYPE_WIFI);
- if (linkProperties == null) return null;
-
- Collection<InetAddress> dnses = linkProperties.getDnses();
- if (dnses == null || dnses.size() == 0) return null;
-
- return dnses.iterator().next();
- }
-
- /**
- * Checks whether the DNS can be reached using multiple attempts according
- * to the current setting values.
- *
- * @return Whether the DNS is reachable
- */
- private boolean checkDnsConnectivity() {
- InetAddress dns = getDns();
- if (dns == null) {
- if (V) {
- myLogV("checkDnsConnectivity: Invalid DNS, returning false");
- }
- return false;
- }
-
- if (V) {
- myLogV("checkDnsConnectivity: Checking " + dns.getHostAddress() + " for connectivity");
- }
-
- int numInitialIgnoredPings = getInitialIgnoredPingCount();
- int numPings = getPingCount();
- int pingDelay = getPingDelayMs();
- int acceptableLoss = getAcceptablePacketLossPercentage();
-
- /** See {@link Secure#WIFI_WATCHDOG_INITIAL_IGNORED_PING_COUNT} */
- int ignoredPingCounter = 0;
- int pingCounter = 0;
- int successCounter = 0;
-
- // No connectivity check needed
- if (numPings == 0) {
- return true;
- }
-
- // Do the initial pings that we ignore
- for (; ignoredPingCounter < numInitialIgnoredPings; ignoredPingCounter++) {
- if (shouldCancel()) return false;
-
- boolean dnsAlive = DnsPinger.isDnsReachable(dns, getPingTimeoutMs());
- if (dnsAlive) {
- /*
- * Successful "ignored" pings are *not* ignored (they count in the total number
- * of pings), but failures are really ignored.
- */
-
- // TODO: This is confusing logic and should be rewitten
- // Here, successful 'ignored' pings are interpreted as a success in the below loop
- pingCounter++;
- successCounter++;
- }
-
- if (V) {
- Slog.v(TAG, (dnsAlive ? " +" : " Ignored: -"));
- }
-
- if (shouldCancel()) return false;
-
- try {
- Thread.sleep(pingDelay);
- } catch (InterruptedException e) {
- Slog.w(TAG, "Interrupted while pausing between pings", e);
- }
- }
-
- // Do the pings that we use to measure packet loss
- for (; pingCounter < numPings; pingCounter++) {
- if (shouldCancel()) return false;
-
- if (DnsPinger.isDnsReachable(dns, getPingTimeoutMs())) {
- successCounter++;
- if (V) {
- Slog.v(TAG, " +");
- }
- } else {
- if (V) {
- Slog.v(TAG, " -");
- }
- }
-
- if (shouldCancel()) return false;
-
- try {
- Thread.sleep(pingDelay);
- } catch (InterruptedException e) {
- Slog.w(TAG, "Interrupted while pausing between pings", e);
- }
- }
-
- //TODO: Integer division might cause problems down the road...
- int packetLossPercentage = 100 * (numPings - successCounter) / numPings;
- if (D) {
- Slog.d(TAG, packetLossPercentage
- + "% packet loss (acceptable is " + acceptableLoss + "%)");
- }
-
- return !shouldCancel() && (packetLossPercentage <= acceptableLoss);
- }
-
- private boolean backgroundCheckDnsConnectivity() {
- InetAddress dns = getDns();
-
- if (dns == null) {
- if (V) {
- myLogV("backgroundCheckDnsConnectivity: DNS is empty, returning false");
- }
- return false;
- }
-
- if (V) {
- myLogV("backgroundCheckDnsConnectivity: Background checking " +
- dns.getHostAddress() + " for connectivity");
- }
-
- return DnsPinger.isDnsReachable(dns, getBackgroundCheckTimeoutMs());
- }
-
- /**
- * Signals the current action to cancel.
- */
- private void cancelCurrentAction() {
- mShouldCancel = true;
- }
-
- /**
- * Helper to check whether to cancel.
- *
- * @return Whether to cancel processing the action.
- */
- private boolean shouldCancel() {
- if (V && mShouldCancel) {
- myLogV("shouldCancel: Cancelling");
- }
-
- return mShouldCancel;
- }
-
- // Wi-Fi initiated callbacks (could be executed in another thread)
-
- /**
- * Called when connected to an AP (this can be the next AP in line, or
- * it can be a completely different network).
- *
- * @param ssid The SSID of the access point.
- * @param bssid The BSSID of the access point.
- */
- private void onConnected(String ssid, String bssid) {
- if (V) {
- myLogV("onConnected: SSID: " + ssid + ", BSSID: " + bssid);
- }
-
- /*
- * The current action being processed by the main watchdog thread is now
- * stale, so cancel it.
- */
- cancelCurrentAction();
-
- if ((mSsid == null) || !mSsid.equals(ssid)) {
- /*
- * This is a different network than what the main watchdog thread is
- * processing, dispatch the network change message on the main thread.
- */
- mHandler.dispatchNetworkChanged(ssid);
- }
-
- if (requiresWatchdog(ssid, bssid)) {
- if (D) {
- myLogD(ssid + " (" + bssid + ") requires the watchdog");
- }
-
- // This access point requires a watchdog, so queue the check on the main thread
- mHandler.checkAp(new AccessPoint(ssid, bssid));
-
- } else {
- if (D) {
- myLogD(ssid + " (" + bssid + ") does not require the watchdog");
- }
-
- // This access point does not require a watchdog, so queue idle on the main thread
- mHandler.idle();
- }
- if (isWalledGardenTestEnabled()) mHandler.checkWalledGarden(ssid);
- }
-
- /**
- * Called when Wi-Fi is enabled.
- */
- private void onEnabled() {
- cancelCurrentAction();
- // Queue a hard-reset of the state on the main thread
- mHandler.reset();
- }
-
- /**
- * Called when disconnected (or some other event similar to being disconnected).
- */
- private void onDisconnected() {
- if (V) {
- myLogV("onDisconnected");
- }
-
- /*
- * Disconnected from an access point, the action being processed by the
- * watchdog thread is now stale, so cancel it.
- */
- cancelCurrentAction();
- // Dispatch the disconnected to the main watchdog thread
- mHandler.dispatchDisconnected();
- // Queue the action to go idle
- mHandler.idle();
- }
-
- /**
- * Checks whether an access point requires watchdog monitoring.
- *
- * @param ssid The SSID of the access point.
- * @param bssid The BSSID of the access point.
- * @return Whether the access point/network should be monitored by the
- * watchdog.
- */
- private boolean requiresWatchdog(String ssid, String bssid) {
- if (V) {
- myLogV("requiresWatchdog: SSID: " + ssid + ", BSSID: " + bssid);
- }
-
- WifiInfo info = null;
- if (ssid == null) {
- /*
- * This is called from a Wi-Fi callback, so assume the WifiInfo does
- * not have stale data.
- */
- info = mWifiManager.getConnectionInfo();
- ssid = info.getSSID();
- if (ssid == null) {
- // It's still null, give up
- if (V) {
- Slog.v(TAG, " Invalid SSID, returning false");
- }
- return false;
- }
- }
-
- if (TextUtils.isEmpty(bssid)) {
- // Similar as above
- if (info == null) {
- info = mWifiManager.getConnectionInfo();
- }
- bssid = info.getBSSID();
- if (TextUtils.isEmpty(bssid)) {
- // It's still null, give up
- if (V) {
- Slog.v(TAG, " Invalid BSSID, returning false");
- }
- return false;
- }
- }
-
- if (!isOnWatchList(ssid)) {
- if (V) {
- Slog.v(TAG, " SSID not on watch list, returning false");
- }
- return false;
- }
-
- // The watchdog only monitors networks with multiple APs
- if (!hasRequiredNumberOfAps(ssid)) {
- return false;
- }
-
- return true;
- }
-
- private boolean isOnWatchList(String ssid) {
- String watchList;
-
- if (ssid == null || (watchList = getWatchList()) == null) {
- return false;
- }
-
- String[] list = watchList.split(" *, *");
-
- for (String name : list) {
- if (ssid.equals(name)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Checks if the current scan results have multiple access points with an SSID.
- *
- * @param ssid The SSID to check.
- * @return Whether the SSID has multiple access points.
- */
- private boolean hasRequiredNumberOfAps(String ssid) {
- List<ScanResult> results = mWifiManager.getScanResults();
- if (results == null) {
- if (V) {
- myLogV("hasRequiredNumberOfAps: Got null scan results, returning false");
- }
- return false;
- }
-
- int numApsRequired = getApCount();
- int numApsFound = 0;
- int resultsSize = results.size();
- for (int i = 0; i < resultsSize; i++) {
- ScanResult result = results.get(i);
- if (result == null) continue;
- if (result.SSID == null) continue;
-
- if (result.SSID.equals(ssid)) {
- numApsFound++;
-
- if (numApsFound >= numApsRequired) {
- if (V) {
- myLogV("hasRequiredNumberOfAps: SSID: " + ssid + ", returning true");
- }
- return true;
- }
- }
- }
-
- if (V) {
- myLogV("hasRequiredNumberOfAps: SSID: " + ssid + ", returning false");
- }
- return false;
- }
-
- // Watchdog logic (assume all of these methods will be in our main thread)
-
- /**
- * Handles a Wi-Fi network change (for example, from networkA to networkB).
- */
- private void handleNetworkChanged(String ssid) {
- // Set the SSID being monitored to the new SSID
- mSsid = ssid;
- // Set various state to that when being idle
- setIdleState(true);
- }
-
- /**
- * Handles checking whether an AP is a "good" AP. If not, it will be blacklisted.
- *
- * @param ap The access point to check.
- */
- private void handleCheckAp(AccessPoint ap) {
- // Reset the cancel state since this is the entry point of this action
- mShouldCancel = false;
-
- if (V) {
- myLogV("handleCheckAp: AccessPoint: " + ap);
- }
-
- // Make sure we are not sleeping
- if (mState == WatchdogState.SLEEP) {
- if (V) {
- Slog.v(TAG, " Sleeping (in " + mSsid + "), so returning");
- }
- return;
- }
-
- mState = WatchdogState.CHECKING_AP;
-
- /*
- * Checks to make sure we haven't exceeded the max number of checks
- * we're allowed per network
- */
- incrementBssidCheckCount();
- if (getBssidCheckCount() > getMaxApChecks()) {
- if (V) {
- Slog.v(TAG, " Passed the max attempts (" + getMaxApChecks()
- + "), going to sleep for " + mSsid);
- }
- mHandler.sleep(mSsid);
- return;
- }
-
- // Do the check
- boolean isApAlive = checkDnsConnectivity();
-
- if (V) {
- Slog.v(TAG, " Is it alive: " + isApAlive);
- }
-
- // Take action based on results
- if (isApAlive) {
- handleApAlive(ap);
- } else {
- handleApUnresponsive(ap);
- }
- }
-
- /**
- * Handles the case when an access point is alive.
- *
- * @param ap The access point.
- */
- private void handleApAlive(AccessPoint ap) {
- // Check whether we are stale and should cancel
- if (shouldCancel()) return;
- // We're satisfied with this AP, so go idle
- setIdleState(false);
-
- if (D) {
- myLogD("AP is alive: " + ap.toString());
- }
-
- // Queue the next action to be a background check
- mHandler.backgroundCheckAp(ap);
- }
-
- /**
- * Handles an unresponsive AP by blacklisting it.
- *
- * @param ap The access point.
- */
- private void handleApUnresponsive(AccessPoint ap) {
- // Check whether we are stale and should cancel
- if (shouldCancel()) return;
- // This AP is "bad", switch to another
- mState = WatchdogState.SWITCHING_AP;
-
- if (D) {
- myLogD("AP is dead: " + ap.toString());
- }
-
- // Black list this "bad" AP, this will cause an attempt to connect to another
- blacklistAp(ap.bssid);
- // Initiate an association to an alternate AP
- mWifiManager.reassociate();
- }
-
- private void blacklistAp(String bssid) {
- if (TextUtils.isEmpty(bssid)) {
- return;
- }
-
- // Before taking action, make sure we should not cancel our processing
- if (shouldCancel()) return;
-
- mWifiManager.addToBlacklist(bssid);
-
- if (D) {
- myLogD("Blacklisting " + bssid);
- }
- }
-
- /**
- * Handles a single background check. If it fails, it should trigger a
- * normal check. If it succeeds, it should queue another background check.
- *
- * @param ap The access point to do a background check for. If this is no
- * longer the current AP, it is okay to return without any
- * processing.
- */
- private void handleBackgroundCheckAp(AccessPoint ap) {
- // Reset the cancel state since this is the entry point of this action
- mShouldCancel = false;
-
- if (V) {
- myLogV("handleBackgroundCheckAp: AccessPoint: " + ap);
- }
-
- // Make sure we are not sleeping
- if (mState == WatchdogState.SLEEP) {
- if (V) {
- Slog.v(TAG, " handleBackgroundCheckAp: Sleeping (in " + mSsid + "), so returning");
- }
- return;
- }
-
- // Make sure the AP we're supposed to be background checking is still the active one
- WifiInfo info = mWifiManager.getConnectionInfo();
- if (info.getSSID() == null || !info.getSSID().equals(ap.ssid)) {
- if (V) {
- myLogV("handleBackgroundCheckAp: We are no longer connected to "
- + ap + ", and instead are on " + info);
- }
- return;
- }
-
- if (info.getBSSID() == null || !info.getBSSID().equals(ap.bssid)) {
- if (V) {
- myLogV("handleBackgroundCheckAp: We are no longer connected to "
- + ap + ", and instead are on " + info);
- }
- return;
- }
-
- // Do the check
- boolean isApAlive = backgroundCheckDnsConnectivity();
-
- if (V && !isApAlive) {
- Slog.v(TAG, " handleBackgroundCheckAp: Is it alive: " + isApAlive);
- }
-
- if (shouldCancel()) {
- return;
- }
-
- // Take action based on results
- if (isApAlive) {
- // Queue another background check
- mHandler.backgroundCheckAp(ap);
-
- } else {
- if (D) {
- myLogD("Background check failed for " + ap.toString());
- }
-
- // Queue a normal check, so it can take proper action
- mHandler.checkAp(ap);
- }
- }
-
- /**
- * Handles going to sleep for this network. Going to sleep means we will not
- * monitor this network anymore.
- *
- * @param ssid The network that will not be monitored anymore.
- */
- private void handleSleep(String ssid) {
- // Make sure the network we're trying to sleep in is still the current network
- if (ssid != null && ssid.equals(mSsid)) {
- mState = WatchdogState.SLEEP;
-
- if (D) {
- myLogD("Going to sleep for " + ssid);
- }
-
- /*
- * Before deciding to go to sleep, we may have checked a few APs
- * (and blacklisted them). Clear the blacklist so the AP with best
- * signal is chosen.
- */
- mWifiManager.clearBlacklist();
-
- if (V) {
- myLogV("handleSleep: Set state to SLEEP and cleared blacklist");
- }
- }
- }
-
- /**
- * Handles an access point disconnection.
- */
- private void handleDisconnected() {
- /*
- * We purposefully do not change mSsid to null. This is to handle
- * disconnected followed by connected better (even if there is some
- * duration in between). For example, if the watchdog went to sleep in a
- * network, and then the phone goes to sleep, when the phone wakes up we
- * still want to be in the sleeping state. When the phone went to sleep,
- * we would have gotten a disconnected event which would then set mSsid
- * = null. This is bad, since the following connect would cause us to do
- * the "network is good?" check all over again. */
-
- /*
- * Set the state as if we were idle (don't come out of sleep, only
- * hard reset and network changed should do that.
- */
- setIdleState(false);
- }
-
- /**
- * Handles going idle. Idle means we are satisfied with the current state of
- * things, but if a new connection occurs we'll re-evaluate.
- */
- private void handleIdle() {
- // Reset the cancel state since this is the entry point for this action
- mShouldCancel = false;
-
- if (V) {
- myLogV("handleSwitchToIdle");
- }
-
- // If we're sleeping, don't do anything
- if (mState == WatchdogState.SLEEP) {
- Slog.v(TAG, " Sleeping (in " + mSsid + "), so returning");
- return;
- }
-
- // Set the idle state
- setIdleState(false);
-
- if (V) {
- Slog.v(TAG, " Set state to IDLE");
- }
- }
-
- /**
- * Sets the state as if we are going idle.
- */
- private void setIdleState(boolean forceIdleState) {
- // Setting idle state does not kick us out of sleep unless the forceIdleState is set
- if (forceIdleState || (mState != WatchdogState.SLEEP)) {
- mState = WatchdogState.IDLE;
- }
- resetBssidCheckCount();
- }
-
- /**
- * Handles a hard reset. A hard reset is rarely used, but when used it
- * should revert anything done by the watchdog monitoring.
- */
- private void handleReset() {
- mWifiManager.clearBlacklist();
- setIdleState(true);
- }
-
- // Inner classes
-
- /**
- * Possible states for the watchdog to be in.
- */
- private static enum WatchdogState {
- /** The watchdog is currently idle, but it is still responsive to future AP checks in this network. */
- IDLE,
- /** The watchdog is sleeping, so it will not try any AP checks for the network. */
- SLEEP,
- /** The watchdog is currently checking an AP for connectivity. */
- CHECKING_AP,
- /** The watchdog is switching to another AP in the network. */
- SWITCHING_AP
- }
-
- private int getBssidCheckCount() {
- return mBssidCheckCount;
- }
-
- private void incrementBssidCheckCount() {
- mBssidCheckCount++;
- }
-
- private void resetBssidCheckCount() {
- this.mBssidCheckCount = 0;
- }
-
- /**
- * The main thread for the watchdog monitoring. This will be turned into a
- * {@link Looper} thread.
- */
- private class WifiWatchdogThread extends Thread {
- WifiWatchdogThread() {
- super("WifiWatchdogThread");
- }
-
- @Override
- public void run() {
- // Set this thread up so the handler will work on it
- Looper.prepare();
-
- synchronized(WifiWatchdogService.this) {
- mHandler = new WifiWatchdogHandler();
-
- // Notify that the handler has been created
- WifiWatchdogService.this.notify();
- }
-
- // Listen for messages to the handler
- Looper.loop();
- }
- }
-
- /**
- * The main thread's handler. There are 'actions', and just general
- * 'messages'. There should only ever be one 'action' in the queue (aside
- * from the one being processed, if any). There may be multiple messages in
- * the queue. So, actions are replaced by more recent actions, where as
- * messages will be executed for sure. Messages end up being used to just
- * change some state, and not really take any action.
- * <p>
- * There is little logic inside this class, instead methods of the form
- * "handle___" are called in the main {@link WifiWatchdogService}.
- */
- private class WifiWatchdogHandler extends Handler {
- /** Check whether the AP is "good". The object will be an {@link AccessPoint}. */
- static final int ACTION_CHECK_AP = 1;
- /** Go into the idle state. */
- static final int ACTION_IDLE = 2;
- /**
- * Performs a periodic background check whether the AP is still "good".
- * The object will be an {@link AccessPoint}.
- */
- static final int ACTION_BACKGROUND_CHECK_AP = 3;
- /** Check whether the connection is a walled garden */
- static final int ACTION_CHECK_WALLED_GARDEN = 4;
-
- /**
- * Go to sleep for the current network. We are conservative with making
- * this a message rather than action. We want to make sure our main
- * thread sees this message, but if it were an action it could be
- * removed from the queue and replaced by another action. The main
- * thread will ensure when it sees the message that the state is still
- * valid for going to sleep.
- * <p>
- * For an explanation of sleep, see {@link android.provider.Settings.Secure#WIFI_WATCHDOG_MAX_AP_CHECKS}.
- */
- static final int MESSAGE_SLEEP = 101;
- /** Disables the watchdog. */
- static final int MESSAGE_DISABLE_WATCHDOG = 102;
- /** The network has changed. */
- static final int MESSAGE_NETWORK_CHANGED = 103;
- /** The current access point has disconnected. */
- static final int MESSAGE_DISCONNECTED = 104;
- /** Performs a hard-reset on the watchdog state. */
- static final int MESSAGE_RESET = 105;
-
- /* Walled garden detection */
- private String mLastSsid;
- private long mLastTime;
- private final long MIN_WALLED_GARDEN_TEST_INTERVAL = 15 * 60 * 1000; //15 minutes
-
- void checkWalledGarden(String ssid) {
- sendMessage(obtainMessage(ACTION_CHECK_WALLED_GARDEN, ssid));
- }
-
- void checkAp(AccessPoint ap) {
- removeAllActions();
- sendMessage(obtainMessage(ACTION_CHECK_AP, ap));
- }
-
- void backgroundCheckAp(AccessPoint ap) {
- if (!isBackgroundCheckEnabled()) return;
-
- removeAllActions();
- sendMessageDelayed(obtainMessage(ACTION_BACKGROUND_CHECK_AP, ap),
- getBackgroundCheckDelayMs());
- }
-
- void idle() {
- removeAllActions();
- sendMessage(obtainMessage(ACTION_IDLE));
- }
-
- void sleep(String ssid) {
- removeAllActions();
- sendMessage(obtainMessage(MESSAGE_SLEEP, ssid));
- }
-
- void disableWatchdog() {
- removeAllActions();
- sendMessage(obtainMessage(MESSAGE_DISABLE_WATCHDOG));
- }
-
- void dispatchNetworkChanged(String ssid) {
- removeAllActions();
- sendMessage(obtainMessage(MESSAGE_NETWORK_CHANGED, ssid));
- }
-
- void dispatchDisconnected() {
- removeAllActions();
- sendMessage(obtainMessage(MESSAGE_DISCONNECTED));
- }
-
- void reset() {
- removeAllActions();
- sendMessage(obtainMessage(MESSAGE_RESET));
- }
-
- private void removeAllActions() {
- removeMessages(ACTION_CHECK_AP);
- removeMessages(ACTION_IDLE);
- removeMessages(ACTION_BACKGROUND_CHECK_AP);
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (V) {
- myLogV("handleMessage: " + msg.what);
- }
- switch (msg.what) {
- case MESSAGE_NETWORK_CHANGED:
- handleNetworkChanged((String) msg.obj);
- break;
- case ACTION_CHECK_AP:
- handleCheckAp((AccessPoint) msg.obj);
- break;
- case ACTION_BACKGROUND_CHECK_AP:
- handleBackgroundCheckAp((AccessPoint) msg.obj);
- break;
- case ACTION_CHECK_WALLED_GARDEN:
- handleWalledGardenCheck((String) msg.obj);
- break;
- case MESSAGE_SLEEP:
- handleSleep((String) msg.obj);
- break;
- case ACTION_IDLE:
- handleIdle();
- break;
- case MESSAGE_DISABLE_WATCHDOG:
- handleIdle();
- break;
- case MESSAGE_DISCONNECTED:
- handleDisconnected();
- break;
- case MESSAGE_RESET:
- handleReset();
- break;
- }
- }
-
- /**
- * DNS based detection techniques do not work at all hotspots. The one sure way to check
- * a walled garden is to see if a URL fetch on a known address fetches the data we
- * expect
- */
- private boolean isWalledGardenConnection() {
- InputStream in = null;
- HttpURLConnection urlConnection = null;
- try {
- URL url = new URL(getWalledGardenUrl());
- urlConnection = (HttpURLConnection) url.openConnection();
- in = new BufferedInputStream(urlConnection.getInputStream());
- Scanner scanner = new Scanner(in);
- if (scanner.findInLine(getWalledGardenPattern()) != null) {
- return false;
- } else {
- return true;
- }
- } catch (IOException e) {
- return false;
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- }
- }
- if (urlConnection != null) urlConnection.disconnect();
- }
- }
-
- private void handleWalledGardenCheck(String ssid) {
- long currentTime = System.currentTimeMillis();
- //Avoid a walled garden test on the same network if one was already done
- //within MIN_WALLED_GARDEN_TEST_INTERVAL. This will handle scenarios where
- //there are frequent network disconnections
- if (ssid.equals(mLastSsid) &&
- (currentTime - mLastTime) < MIN_WALLED_GARDEN_TEST_INTERVAL) {
- return;
- }
-
- mLastTime = currentTime;
- mLastSsid = ssid;
-
- if (isWalledGardenConnection()) {
- Uri uri = Uri.parse("http://www.google.com");
- Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
- Intent.FLAG_ACTIVITY_NEW_TASK);
- mContext.startActivity(intent);
- }
- }
- }
-
- /**
- * Receives Wi-Fi broadcasts.
- * <p>
- * There is little logic in this class, instead methods of the form "on___"
- * are called in the {@link WifiWatchdogService}.
- */
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final String action = intent.getAction();
- if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- handleNetworkStateChanged(
- (NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO));
- } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
- handleWifiStateChanged(intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
- WifiManager.WIFI_STATE_UNKNOWN));
- }
- }
-
- private void handleNetworkStateChanged(NetworkInfo info) {
- if (V) {
- myLogV("Receiver.handleNetworkStateChanged: NetworkInfo: "
- + info);
- }
-
- switch (info.getState()) {
- case CONNECTED:
- WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
- if (wifiInfo.getSSID() == null || wifiInfo.getBSSID() == null) {
- if (V) {
- myLogV("handleNetworkStateChanged: Got connected event but SSID or BSSID are null. SSID: "
- + wifiInfo.getSSID()
- + ", BSSID: "
- + wifiInfo.getBSSID() + ", ignoring event");
- }
- return;
- }
- onConnected(wifiInfo.getSSID(), wifiInfo.getBSSID());
- break;
-
- case DISCONNECTED:
- onDisconnected();
- break;
- }
- }
-
- private void handleWifiStateChanged(int wifiState) {
- if (wifiState == WifiManager.WIFI_STATE_DISABLED) {
- onDisconnected();
- } else if (wifiState == WifiManager.WIFI_STATE_ENABLED) {
- onEnabled();
- }
- }
- };
-
- /**
- * Describes an access point by its SSID and BSSID.
- *
- */
- private static class AccessPoint {
- String ssid;
- String bssid;
-
- /**
- * @param ssid cannot be null
- * @param bssid cannot be null
- */
- AccessPoint(String ssid, String bssid) {
- if (ssid == null || bssid == null) {
- Slog.e(TAG, String.format("(%s) INVALID ACCESSPOINT: (%s, %s)",
- Thread.currentThread().getName(),ssid,bssid));
- }
- this.ssid = ssid;
- this.bssid = bssid;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof AccessPoint)) return false;
- AccessPoint otherAp = (AccessPoint) o;
-
- // Either we both have a null, or our SSIDs and BSSIDs are equal
- return ssid.equals(otherAp.ssid) && bssid.equals(otherAp.bssid);
- }
-
- @Override
- public int hashCode() {
- return ssid.hashCode() + bssid.hashCode();
- }
-
- @Override
- public String toString() {
- return ssid + " (" + bssid + ")";
- }
- }
-
- /**
- * Performs a simple DNS "ping" by sending a "server status" query packet to
- * the DNS server. As long as the server replies, we consider it a success.
- * <p>
- * We do not use a simple hostname lookup because that could be cached and
- * the API may not differentiate between a time out and a failure lookup
- * (which we really care about).
- */
- private static class DnsPinger {
-
- /** Number of bytes for the query */
- private static final int DNS_QUERY_BASE_SIZE = 33;
-
- /** The DNS port */
- private static final int DNS_PORT = 53;
-
- /** Used to generate IDs */
- private static Random sRandom = new Random();
-
- static boolean isDnsReachable(InetAddress dnsAddress, int timeout) {
- DatagramSocket socket = null;
- try {
- socket = new DatagramSocket();
-
- // Set some socket properties
- socket.setSoTimeout(timeout);
-
- byte[] buf = new byte[DNS_QUERY_BASE_SIZE];
- fillQuery(buf);
-
- // Send the DNS query
-
- DatagramPacket packet = new DatagramPacket(buf,
- buf.length, dnsAddress, DNS_PORT);
- socket.send(packet);
-
- // Wait for reply (blocks for the above timeout)
- DatagramPacket replyPacket = new DatagramPacket(buf, buf.length);
- socket.receive(replyPacket);
-
- // If a timeout occurred, an exception would have been thrown. We got a reply!
- return true;
-
- } catch (SocketException e) {
- if (V) {
- Slog.v(TAG, "DnsPinger.isReachable received SocketException", e);
- }
- return false;
-
- } catch (UnknownHostException e) {
- if (V) {
- Slog.v(TAG, "DnsPinger.isReachable is unable to resolve the DNS host", e);
- }
- return false;
-
- } catch (SocketTimeoutException e) {
- return false;
-
- } catch (IOException e) {
- if (V) {
- Slog.v(TAG, "DnsPinger.isReachable got an IOException", e);
- }
- return false;
-
- } catch (Exception e) {
- if (V) {
- Slog.d(TAG, "DnsPinger.isReachable got an unknown exception", e);
- }
- return false;
- } finally {
- if (socket != null) {
- socket.close();
- }
- }
- }
-
- private static void fillQuery(byte[] buf) {
-
- /*
- * See RFC2929 (though the bit tables in there are misleading for
- * us. For example, the recursion desired bit is the 0th bit for us,
- * but looking there it would appear as the 7th bit of the byte
- */
-
- // Make sure it's all zeroed out
- for (int i = 0; i < buf.length; i++) buf[i] = 0;
-
- // Form a query for www.android.com
-
- // [0-1] bytes are an ID, generate random ID for this query
- buf[0] = (byte) sRandom.nextInt(256);
- buf[1] = (byte) sRandom.nextInt(256);
-
- // [2-3] bytes are for flags.
- buf[2] = 1; // Recursion desired
-
- // [4-5] bytes are for the query count
- buf[5] = 1; // One query
-
- // [6-7] [8-9] [10-11] are all counts of other fields we don't use
-
- // [12-15] for www
- writeString(buf, 12, "www");
-
- // [16-23] for android
- writeString(buf, 16, "android");
-
- // [24-27] for com
- writeString(buf, 24, "com");
-
- // [29-30] bytes are for QTYPE, set to 1
- buf[30] = 1;
-
- // [31-32] bytes are for QCLASS, set to 1
- buf[32] = 1;
- }
-
- private static void writeString(byte[] buf, int startPos, String string) {
- int pos = startPos;
-
- // Write the length first
- buf[pos++] = (byte) string.length();
- for (int i = 0; i < string.length(); i++) {
- buf[pos++] = (byte) string.charAt(i);
- }
- }
- }
-}
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index f6dd43a..80cdf6b 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -436,7 +436,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
public IAccessibilityServiceConnection registerEventListener(IEventListener listener) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
FUNCTION_REGISTER_EVENT_LISTENER);
- ComponentName componentName = new ComponentName("foo.bar", "FakeAccessibilityService");
+ ComponentName componentName = new ComponentName("foo.bar",
+ "AutomationAccessibilityService");
synchronized (mLock) {
Service oldService = mComponentNameToServiceMap.get(componentName);
if (oldService != null) {
@@ -550,6 +551,26 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private void notifyEventListenerLocked(Service service, int eventType) {
IEventListener listener = service.mServiceInterface;
AccessibilityEvent event = service.mPendingEvents.get(eventType);
+
+ // Check for null here because there is a concurrent scenario in which this
+ // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked
+ // which posts a message for dispatching an event. 2) The message is pulled
+ // from the queue by the handler on the service thread and the latter is
+ // just about to acquire the lock and call this method. 3) Now another binder
+ // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked
+ // so the service thread waits for the lock; 4) The binder thread replaces
+ // the event with a more recent one (assume the same event type) and posts a
+ // dispatch request releasing the lock. 5) Now the main thread is unblocked and
+ // dispatches the event which is removed from the pending ones. 6) And ... now
+ // the service thread handles the last message posted by the last binder call
+ // but the event is already dispatched and hence looking it up in the pending
+ // ones yields null. This check is much simpler that keeping count for each
+ // event type of each service to catch such a scenario since only one message
+ // is processed at a time.
+ if (event == null) {
+ return;
+ }
+
service.mPendingEvents.remove(eventType);
try {
if (mSecurityPolicy.canRetrieveWindowContent(service)) {
@@ -809,7 +830,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
boolean mCanRetrieveScreenContent;
- boolean mIsFake;
+ boolean mIsAutomation;
final Callback mCallback = new Callback();
@@ -822,12 +843,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
new SparseArray<AccessibilityEvent>();
public Service(ComponentName componentName,
- AccessibilityServiceInfo accessibilityServiceInfo, boolean isFake) {
+ AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
mId = sIdCounter++;
mComponentName = componentName;
mAccessibilityServiceInfo = accessibilityServiceInfo;
- mIsFake = isFake;
- if (!isFake) {
+ mIsAutomation = isAutomation;
+ if (!isAutomation) {
mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
mIntent = new Intent().setComponent(mComponentName);
mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
@@ -861,7 +882,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* @return True if binding is successful.
*/
public boolean bind() {
- if (!mIsFake && mService == null) {
+ if (!mIsAutomation && mService == null) {
return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE);
}
return false;
@@ -878,7 +899,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
synchronized (mLock) {
tryRemoveServiceLocked(this);
}
- if (!mIsFake) {
+ if (!mIsAutomation) {
mContext.unbindService(this);
}
mService = null;
@@ -918,16 +939,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
IAccessibilityInteractionConnection connection = null;
synchronized (mLock) {
final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this);
- if (permissionGranted) {
+ if (!permissionGranted) {
+ return null;
+ } else {
connection = getConnectionToRetrievalAllowingWindowLocked();
+ if (connection == null) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to a retrieve "
+ + "allowing window.");
+ }
+ return null;
+ }
}
}
- if (connection == null) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "No interaction connection to a retrieve allowing window.");
- }
- return null;
- }
final long identityToken = Binder.clearCallingIdentity();
try {
final int interactionId = mInteractionIdCounter.getAndIncrement();
@@ -962,16 +986,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
synchronized (mLock) {
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
- if (permissionGranted) {
+ if (!permissionGranted) {
+ return null;
+ } else {
connection = getConnectionToRetrievalAllowingWindowLocked();
+ if (connection == null) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to focused window.");
+ }
+ return null;
+ }
}
}
- if (connection == null) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "No interaction connection to focused window.");
- }
- return null;
- }
final long identityToken = Binder.clearCallingIdentity();
try {
final int interactionId = mInteractionIdCounter.getAndIncrement();
@@ -1005,17 +1031,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
synchronized (mLock) {
final boolean permissionGranted =
mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId);
- if (permissionGranted) {
+ if (!permissionGranted) {
+ return null;
+ } else {
connection = mWindowIdToInteractionConnectionMap.get(accessibilityWindowId);
+ if (connection == null) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to window: "
+ + accessibilityWindowId);
+ }
+ return null;
+ }
}
}
- if (connection == null) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "No interaction connection to window: "
- + accessibilityWindowId);
- }
- return null;
- }
final long identityToken = Binder.clearCallingIdentity();
try {
final int interactionId = mInteractionIdCounter.getAndIncrement();
@@ -1046,17 +1074,19 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
synchronized (mLock) {
final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this,
accessibilityWindowId, action);
- if (permissionGranted) {
+ if (!permissionGranted) {
+ return false;
+ } else {
connection = mWindowIdToInteractionConnectionMap.get(accessibilityWindowId);
+ if (connection == null) {
+ if (DEBUG) {
+ Slog.e(LOG_TAG, "No interaction connection to window: "
+ + accessibilityWindowId);
+ }
+ return false;
+ }
}
}
- if (connection == null) {
- if (DEBUG) {
- Slog.e(LOG_TAG, "No interaction connection to window: "
- + accessibilityWindowId);
- }
- return false;
- }
final long identityToken = Binder.clearCallingIdentity();
try {
final int interactionId = mInteractionIdCounter.getAndIncrement();
@@ -1131,7 +1161,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
| AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
| AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
| AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_SELECTED
- | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
+ | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
+ | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
+ | AccessibilityEvent.TYPE_VIEW_SCROLLED;
private int mRetrievalAlowingWindowId;
diff --git a/services/java/com/android/server/accessibility/TouchExplorer.java b/services/java/com/android/server/accessibility/TouchExplorer.java
index aab189a..1af7015 100644
--- a/services/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/java/com/android/server/accessibility/TouchExplorer.java
@@ -26,7 +26,6 @@ import android.content.Context;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Slog;
-import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.WindowManagerPolicy;
@@ -73,15 +72,6 @@ public class TouchExplorer implements Explorer {
private static final int STATE_DRAGGING = 0x00000002;
private static final int STATE_DELEGATING = 0x00000004;
- // Human readable symbolic names for the states of the explorer.
- private static final SparseArray<String> sStateSymbolicNames = new SparseArray<String>();
- static {
- SparseArray<String> symbolicNames = sStateSymbolicNames;
- symbolicNames.append(STATE_TOUCH_EXPLORING, "STATE_TOUCH_EXPLORING");
- symbolicNames.append(STATE_DRAGGING, "STATE_DRAGING");
- symbolicNames.append(STATE_DELEGATING, "STATE_DELEGATING");
- }
-
// Invalid pointer ID.
private static final int INVALID_POINTER_ID = -1;
@@ -189,7 +179,7 @@ public class TouchExplorer implements Explorer {
if (DEBUG) {
Slog.d(LOG_TAG_RECEIVED, "Received event: " + event + ", policyFlags=0x"
+ Integer.toHexString(policyFlags));
- Slog.d(LOG_TAG_STATE, sStateSymbolicNames.get(mCurrentState));
+ Slog.d(LOG_TAG_STATE, getStateSymbolicName(mCurrentState));
}
// Keep track of the pointers's state.
@@ -708,8 +698,7 @@ public class TouchExplorer implements Explorer {
private void sendActionDownAndUp(MotionEvent prototype, int policyFlags) {
final PointerProperties[] pointerProperties = mTempPointerProperties;
final PointerCoords[] pointerCoords = mTempPointerCoords;
- final int pointerId = mPointerTracker.getLastReceivedUpPointerId();
- final int pointerIndex = prototype.findPointerIndex(pointerId);
+ final int pointerIndex = prototype.getActionIndex();
// Send down.
prototype.getPointerProperties(pointerIndex, pointerProperties[0]);
@@ -884,6 +873,25 @@ public class TouchExplorer implements Explorer {
}
/**
+ * Gets the symbolic name of a state.
+ *
+ * @param state A state.
+ * @return The state symbolic name.
+ */
+ private static String getStateSymbolicName(int state) {
+ switch (state) {
+ case STATE_TOUCH_EXPLORING:
+ return "STATE_TOUCH_EXPLORING";
+ case STATE_DRAGGING:
+ return "STATE_DRAGGING";
+ case STATE_DELEGATING:
+ return "STATE_DELEGATING";
+ default:
+ throw new IllegalArgumentException("Unknown state: " + state);
+ }
+ }
+
+ /**
* Helper class for tracking pointers and more specifically which of
* them are currently down, which are active, and which are delivered
* to the view hierarchy. The enclosing {@link TouchExplorer} uses the
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4ec71c1..d5e8730 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -502,15 +502,6 @@ public final class ActivityManagerService extends ActivityManagerNative
= new ArrayList<ProcessRecord>();
/**
- * List of records for processes that we have started and are waiting
- * for them to call back. This is really only needed when running in
- * single processes mode, in which case we do not have a unique pid for
- * each process.
- */
- final ArrayList<ProcessRecord> mStartingProcesses
- = new ArrayList<ProcessRecord>();
-
- /**
* List of persistent applications that are in the process
* of being started.
*/
@@ -622,6 +613,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
return true;
}
+
+ @Override
+ protected String packageForFilter(BroadcastFilter filter) {
+ return filter.packageName;
+ }
};
/**
@@ -1825,6 +1821,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// We already have the app running, or are waiting for it to
// come up (we have a pid but not yet its thread), so keep it.
if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
+ // If this is a new package in the process, add the package to the list
+ app.addPackage(info.packageName);
return app;
} else {
// An application record is attached to a previous process,
@@ -1946,11 +1944,15 @@ public final class ActivityManagerService extends ActivityManagerNative
if ("1".equals(SystemProperties.get("debug.checkjni"))) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
+ if ("1".equals(SystemProperties.get("debug.jni.logging"))) {
+ debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
+ }
if ("1".equals(SystemProperties.get("debug.assert"))) {
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
int pid = Process.start("android.app.ActivityThread",
- app.processName, uid, uid, gids, debugFlags, null);
+ app.processName, uid, uid, gids, debugFlags,
+ app.info.targetSdkVersion, null);
BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
synchronized (bs) {
if (bs.isOnBattery()) {
@@ -1990,12 +1992,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
buf.append("}");
Slog.i(TAG, buf.toString());
- if (pid == 0 || pid == MY_PID) {
- // Processes are being emulated with threads.
- app.pid = MY_PID;
- app.removed = false;
- mStartingProcesses.add(app);
- } else if (pid > 0) {
+ if (pid > 0) {
app.pid = pid;
app.removed = false;
synchronized (mPidsSelfLocked) {
@@ -2278,7 +2275,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- return pir.sendInner(0, fillInIntent, resolvedType,
+ return pir.sendInner(0, fillInIntent, resolvedType, null,
null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
}
@@ -3595,9 +3592,6 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
- } else if (mStartingProcesses.size() > 0) {
- app = mStartingProcesses.remove(0);
- app.setPid(pid);
} else {
app = null;
}
@@ -4031,8 +4025,7 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized(this) {
int callingUid = Binder.getCallingUid();
try {
- if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
- Process.supportsProcesses()) {
+ if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
int uid = AppGlobals.getPackageManager()
.getPackageUid(packageName);
if (uid != Binder.getCallingUid()) {
@@ -4162,6 +4155,27 @@ public final class ActivityManagerService extends ActivityManagerNative
return null;
}
+ public boolean isIntentSenderTargetedToPackage(IIntentSender pendingResult) {
+ if (!(pendingResult instanceof PendingIntentRecord)) {
+ return false;
+ }
+ try {
+ PendingIntentRecord res = (PendingIntentRecord)pendingResult;
+ if (res.key.allIntents == null) {
+ return false;
+ }
+ for (int i=0; i<res.key.allIntents.length; i++) {
+ Intent intent = res.key.allIntents[i];
+ if (intent.getPackage() != null && intent.getComponent() != null) {
+ return false;
+ }
+ }
+ return true;
+ } catch (ClassCastException e) {
+ }
+ return false;
+ }
+
public void setProcessLimit(int max) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
"setProcessLimit()");
@@ -4270,8 +4284,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
// Root, system server and our own process get to do everything.
- if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
- !Process.supportsProcesses()) {
+ if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID) {
return PackageManager.PERMISSION_GRANTED;
}
// If there is a uid that owns whatever is being accessed, it has
@@ -4415,7 +4428,7 @@ public final class ActivityManagerService extends ActivityManagerNative
private final boolean checkUriPermissionLocked(Uri uri, int uid,
int modeFlags) {
// Root gets to do everything.
- if (uid == 0 || !Process.supportsProcesses()) {
+ if (uid == 0) {
return true;
}
HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
@@ -5143,7 +5156,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private void removeTaskProcessesLocked(ActivityRecord root) {
+ private void cleanUpRemovedTaskLocked(ActivityRecord root, boolean killProcesses) {
TaskRecord tr = root.task;
Intent baseIntent = new Intent(
tr.intent != null ? tr.intent : tr.affinityIntent);
@@ -5166,6 +5179,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ServiceRecord sr = services.get(i);
if (sr.startRequested) {
if ((sr.serviceInfo.flags&ServiceInfo.FLAG_STOP_WITH_TASK) != 0) {
+ Slog.i(TAG, "Stopping service " + sr.shortName + ": remove task");
stopServiceLocked(sr);
} else {
sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
@@ -5177,26 +5191,28 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- // Find any running processes associated with this app.
- ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
- SparseArray<ProcessRecord> appProcs
- = mProcessNames.getMap().get(component.getPackageName());
- if (appProcs != null) {
- for (int i=0; i<appProcs.size(); i++) {
- procs.add(appProcs.valueAt(i));
- }
- }
-
- // Kill the running processes.
- for (int i=0; i<procs.size(); i++) {
- ProcessRecord pr = procs.get(i);
- if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + pr + ": remove task");
- EventLog.writeEvent(EventLogTags.AM_KILL, pr.pid,
- pr.processName, pr.setAdj, "remove task");
- Process.killProcessQuiet(pr.pid);
- } else {
- pr.waitingToKill = "remove task";
+ if (killProcesses) {
+ // Find any running processes associated with this app.
+ ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
+ SparseArray<ProcessRecord> appProcs
+ = mProcessNames.getMap().get(component.getPackageName());
+ if (appProcs != null) {
+ for (int i=0; i<appProcs.size(); i++) {
+ procs.add(appProcs.valueAt(i));
+ }
+ }
+
+ // Kill the running processes.
+ for (int i=0; i<procs.size(); i++) {
+ ProcessRecord pr = procs.get(i);
+ if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ Slog.i(TAG, "Killing " + pr.toShortString() + ": remove task");
+ EventLog.writeEvent(EventLogTags.AM_KILL, pr.pid,
+ pr.processName, pr.setAdj, "remove task");
+ Process.killProcessQuiet(pr.pid);
+ } else {
+ pr.waitingToKill = "remove task";
+ }
}
}
}
@@ -5210,11 +5226,8 @@ public final class ActivityManagerService extends ActivityManagerNative
ActivityRecord r = mMainStack.removeTaskActivitiesLocked(taskId, -1);
if (r != null) {
mRecentTasks.remove(r.task);
-
- if ((flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0) {
- removeTaskProcessesLocked(r);
- }
-
+ cleanUpRemovedTaskLocked(r,
+ (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0);
return true;
}
} finally {
@@ -5496,8 +5509,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// CONTENT PROVIDERS
// =========================================================
- private final List generateApplicationProvidersLocked(ProcessRecord app) {
- List providers = null;
+ private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
+ List<ProviderInfo> providers = null;
try {
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.info.uid,
@@ -5935,7 +5948,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
public static final void installSystemProviders() {
- List providers;
+ List<ProviderInfo> providers;
synchronized (mSelf) {
ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
providers = mSelf.generateApplicationProvidersLocked(app);
@@ -6553,13 +6566,6 @@ public final class ActivityManagerService extends ActivityManagerNative
}
public void systemReady(final Runnable goingCallback) {
- // In the simulator, startRunning will never have been called, which
- // normally sets a few crucial variables. Do it here instead.
- if (!Process.supportsProcesses()) {
- mStartRunning = true;
- mTopAction = Intent.ACTION_MAIN;
- }
-
synchronized(this) {
if (mSystemReady) {
if (goingCallback != null) goingCallback.run();
@@ -7923,14 +7929,6 @@ public final class ActivityManagerService extends ActivityManagerNative
"Starting Norm", "Restarting PERS");
}
- if (mStartingProcesses.size() > 0) {
- if (needSep) pw.println(" ");
- needSep = true;
- pw.println(" Processes that are starting:");
- dumpProcessList(pw, this, mStartingProcesses, " ",
- "Starting Norm", "Starting PERS");
- }
-
if (mRemovedProcesses.size() > 0) {
if (needSep) pw.println(" ");
needSep = true;
@@ -9895,6 +9893,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
if (app != null && app.thread != null) {
try {
+ app.addPackage(r.appInfo.packageName);
realStartServiceLocked(r, app);
return true;
} catch (RemoteException e) {
@@ -10945,7 +10944,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mBroadcastsScheduled = true;
}
- public Intent registerReceiver(IApplicationThread caller,
+ public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission) {
synchronized(this) {
ProcessRecord callerApp = null;
@@ -10957,6 +10956,13 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
+ if (callerApp.info.uid != Process.SYSTEM_UID &&
+ !callerApp.pkgList.contains(callerPackage)) {
+ throw new SecurityException("Given caller package " + callerPackage
+ + " is not running in process " + callerApp);
+ }
+ } else {
+ callerPackage = null;
}
List allSticky = null;
@@ -11001,7 +11007,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
- BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
+ BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadast");
@@ -12155,6 +12161,7 @@ public final class ActivityManagerService extends ActivityManagerNative
info.activityInfo.applicationInfo.uid);
if (app != null && app.thread != null) {
try {
+ app.addPackage(info.activityInfo.packageName);
processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
@@ -13087,74 +13094,72 @@ public final class ActivityManagerService extends ActivityManagerNative
int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
- if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
- if (app.curRawAdj != app.setRawAdj) {
- if (app.curRawAdj > FOREGROUND_APP_ADJ
- && app.setRawAdj <= FOREGROUND_APP_ADJ) {
- // If this app is transitioning from foreground to
- // non-foreground, have it do a gc.
- scheduleAppGcLocked(app);
- } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
- && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
- // Likewise do a gc when an app is moving in to the
- // background (such as a service stopping).
- scheduleAppGcLocked(app);
- }
-
- if (wasKeeping && !app.keeping) {
- // This app is no longer something we want to keep. Note
- // its current wake lock time to later know to kill it if
- // it is not behaving well.
- BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
- synchronized (stats) {
- app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
- app.pid, SystemClock.elapsedRealtime());
- }
- app.lastCpuTime = app.curCpuTime;
+ if (app.curRawAdj != app.setRawAdj) {
+ if (app.curRawAdj > FOREGROUND_APP_ADJ
+ && app.setRawAdj <= FOREGROUND_APP_ADJ) {
+ // If this app is transitioning from foreground to
+ // non-foreground, have it do a gc.
+ scheduleAppGcLocked(app);
+ } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
+ && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
+ // Likewise do a gc when an app is moving in to the
+ // background (such as a service stopping).
+ scheduleAppGcLocked(app);
+ }
+
+ if (wasKeeping && !app.keeping) {
+ // This app is no longer something we want to keep. Note
+ // its current wake lock time to later know to kill it if
+ // it is not behaving well.
+ BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ synchronized (stats) {
+ app.lastWakeTime = stats.getProcessWakeTime(app.info.uid,
+ app.pid, SystemClock.elapsedRealtime());
}
+ app.lastCpuTime = app.curCpuTime;
+ }
- app.setRawAdj = app.curRawAdj;
+ app.setRawAdj = app.curRawAdj;
+ }
+ if (adj != app.setAdj) {
+ if (Process.setOomAdj(app.pid, adj)) {
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
+ TAG, "Set app " + app.processName +
+ " oom adj to " + adj);
+ app.setAdj = adj;
+ } else {
+ success = false;
}
- if (adj != app.setAdj) {
- if (Process.setOomAdj(app.pid, adj)) {
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
- TAG, "Set app " + app.processName +
- " oom adj to " + adj);
- app.setAdj = adj;
- } else {
- success = false;
+ }
+ if (app.setSchedGroup != app.curSchedGroup) {
+ app.setSchedGroup = app.curSchedGroup;
+ if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
+ "Setting process group of " + app.processName
+ + " to " + app.curSchedGroup);
+ if (app.waitingToKill != null &&
+ app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ Slog.i(TAG, "Killing " + app.toShortString() + ": " + app.waitingToKill);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, app.waitingToKill);
+ Process.killProcessQuiet(app.pid);
+ } else {
+ if (true) {
+ long oldId = Binder.clearCallingIdentity();
+ try {
+ Process.setProcessGroup(app.pid, app.curSchedGroup);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed setting process group of " + app.pid
+ + " to " + app.curSchedGroup);
+ e.printStackTrace();
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
}
- }
- if (app.setSchedGroup != app.curSchedGroup) {
- app.setSchedGroup = app.curSchedGroup;
- if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
- "Setting process group of " + app.processName
- + " to " + app.curSchedGroup);
- if (app.waitingToKill != null &&
- app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
- Slog.i(TAG, "Killing " + app + ": " + app.waitingToKill);
- EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
- app.processName, app.setAdj, app.waitingToKill);
- Process.killProcessQuiet(app.pid);
- } else {
- if (true) {
- long oldId = Binder.clearCallingIdentity();
+ if (false) {
+ if (app.thread != null) {
try {
- Process.setProcessGroup(app.pid, app.curSchedGroup);
- } catch (Exception e) {
- Slog.w(TAG, "Failed setting process group of " + app.pid
- + " to " + app.curSchedGroup);
- e.printStackTrace();
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
- if (false) {
- if (app.thread != null) {
- try {
- app.thread.setSchedulingGroup(app.curSchedGroup);
- } catch (RemoteException e) {
- }
+ app.thread.setSchedulingGroup(app.curSchedGroup);
+ } catch (RemoteException e) {
}
}
}
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b94ee58..b1da69f 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -652,6 +652,7 @@ final class ActivityStack {
if (app != null && app.thread != null) {
try {
+ app.addPackage(r.info.packageName);
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index b4fdc9f..293702d 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -446,6 +446,15 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
Binder.getCallingPid(), Binder.getCallingUid(), null);
}
+ private void dumpHelp(PrintWriter pw) {
+ pw.println("Battery stats (batteryinfo) dump options:");
+ pw.println(" [--checkin] [--reset] [--write] [-h]");
+ pw.println(" --checkin: format output for a checkin report.");
+ pw.println(" --reset: reset the stats, clearing all current data.");
+ pw.println(" --write: force write current collected stats to disk.");
+ pw.println(" -h: print this help text.");
+ }
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
boolean isCheckin = false;
@@ -466,8 +475,12 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
pw.println("Battery stats written.");
noOutput = true;
}
+ } else if ("-h".equals(arg)) {
+ dumpHelp(pw);
+ return;
} else {
pw.println("Unknown option: " + arg);
+ dumpHelp(pw);
}
}
}
diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java
index 2e784d3..b49bc22 100644
--- a/services/java/com/android/server/am/BroadcastFilter.java
+++ b/services/java/com/android/server/am/BroadcastFilter.java
@@ -25,12 +25,14 @@ import java.io.PrintWriter;
class BroadcastFilter extends IntentFilter {
// Back-pointer to the list this filter is in.
final ReceiverList receiverList;
+ final String packageName;
final String requiredPermission;
BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
- String _requiredPermission) {
+ String _packageName, String _requiredPermission) {
super(_filter);
receiverList = _receiverList;
+ packageName = _packageName;
requiredPermission = _requiredPermission;
}
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index ee6e420..8ed0cc1 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -177,13 +177,13 @@ class PendingIntentRecord extends IIntentSender.Stub {
}
public int send(int code, Intent intent, String resolvedType,
- IIntentReceiver finishedReceiver) {
+ IIntentReceiver finishedReceiver, String requiredPermission) {
return sendInner(code, intent, resolvedType, finishedReceiver,
- null, null, 0, 0, 0);
+ requiredPermission, null, null, 0, 0, 0);
}
int sendInner(int code, Intent intent, String resolvedType,
- IIntentReceiver finishedReceiver,
+ IIntentReceiver finishedReceiver, String requiredPermission,
IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues) {
synchronized(owner) {
@@ -246,8 +246,8 @@ class PendingIntentRecord extends IIntentSender.Stub {
// that the broadcast be delivered synchronously
owner.broadcastIntentInPackage(key.packageName, uid,
finalIntent, resolvedType,
- finishedReceiver, code, null, null, null,
- (finishedReceiver != null), false);
+ finishedReceiver, code, null, null,
+ requiredPermission, (finishedReceiver != null), false);
sendFinish = false;
} catch (RuntimeException e) {
Slog.w(ActivityManagerService.TAG,
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 911cac2..6bb7949 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -189,8 +189,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
mDnsServers[1] = DNS_DEFAULT_SERVER2;
}
- public void interfaceLinkStatusChanged(String iface, boolean link) {
- if (DEBUG) Log.d(TAG, "interfaceLinkStatusChanged " + iface + ", " + link);
+ public void interfaceStatusChanged(String iface, boolean up) {
+ if (DEBUG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
boolean found = false;
boolean usb = false;
if (isWifi(iface)) {
@@ -205,7 +205,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
synchronized (mIfaces) {
TetherInterfaceSM sm = mIfaces.get(iface);
- if (link) {
+ if (up) {
if (sm == null) {
sm = new TetherInterfaceSM(iface, mLooper, usb);
mIfaces.put(iface, sm);
@@ -220,6 +220,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
+ public void interfaceLinkStateChanged(String iface, boolean up) {
+ if (DEBUG) Log.d(TAG, "interfaceLinkStateChanged " + iface + ", " + up);
+ interfaceStatusChanged(iface, up);
+ }
+
private boolean isUsb(String iface) {
for (String regex : mTetherableUsbRegexs) {
if (iface.matches(regex)) return true;
@@ -689,6 +694,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
return retVal;
}
+ //TODO: Temporary handling upstream change triggered without
+ // CONNECTIVITY_ACTION. Only to accomodate interface
+ // switch during HO.
+ // @see bug/4455071
+ public void handleTetherIfaceChange() {
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_UPSTREAM_CHANGED);
+ }
+
class TetherInterfaceSM extends StateMachine {
// notification from the master SM that it's not in tether mode
static final int CMD_TETHER_MODE_DEAD = 1;
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index 47813f8..c185012 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -27,15 +27,24 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.net.INetworkManagementEventObserver;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.SystemProperties;
import android.util.Log;
import com.android.internal.R;
+import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.server.ConnectivityService.VpnCallback;
+import java.io.OutputStream;
+import java.nio.charset.Charsets;
+import java.util.Arrays;
+
/**
* @hide
*/
@@ -47,9 +56,9 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
private final Context mContext;
private final VpnCallback mCallback;
- private String mPackageName;
- private String mInterfaceName;
- private String mDnsPropertyPrefix;
+ private String mPackage = VpnConfig.LEGACY_VPN;
+ private String mInterface;
+ private LegacyVpnRunner mLegacyVpnRunner;
public Vpn(Context context, VpnCallback callback) {
mContext = context;
@@ -57,74 +66,98 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
/**
- * Prepare for a VPN application.
+ * Protect a socket from routing changes by binding it to the given
+ * interface. The socket IS closed by this method.
+ *
+ * @param socket The socket to be bound.
+ * @param name The name of the interface.
+ */
+ public void protect(ParcelFileDescriptor socket, String interfaze) {
+ try {
+ mContext.enforceCallingPermission(VPN, "protect");
+ jniProtect(socket.getFd(), interfaze);
+ } finally {
+ try {
+ socket.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Prepare for a VPN application. This method is designed to solve
+ * race conditions. It first compares the current prepared package
+ * with {@code oldPackage}. If they are the same, the prepared
+ * package is revoked and replaced with {@code newPackage}. If
+ * {@code oldPackage} is {@code null}, the comparison is omitted.
+ * If {@code newPackage} is the same package or {@code null}, the
+ * revocation is omitted. This method returns {@code true} if the
+ * operation is succeeded.
+ *
+ * Legacy VPN is handled specially since it is not a real package.
+ * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and
+ * it can be revoked by itself.
*
- * @param packageName The package name of the new VPN application.
- * @return The name of the current prepared package.
+ * @param oldPackage The package name of the old VPN application.
+ * @param newPackage The package name of the new VPN application.
+ * @return true if the operation is succeeded.
*/
- public synchronized String prepare(String packageName) {
- // Return the current prepared package if the new one is null.
- if (packageName == null) {
- return mPackageName;
+ public synchronized boolean prepare(String oldPackage, String newPackage) {
+ // Return false if the package does not match.
+ if (oldPackage != null && !oldPackage.equals(mPackage)) {
+ return false;
}
- // Check the permission of the caller.
- PackageManager pm = mContext.getPackageManager();
- VpnConfig.enforceCallingPackage(pm.getNameForUid(Binder.getCallingUid()));
+ // Return true if we do not need to revoke.
+ if (newPackage == null ||
+ (newPackage.equals(mPackage) && !newPackage.equals(VpnConfig.LEGACY_VPN))) {
+ return true;
+ }
+
+ // Only system user can revoke a package.
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Unauthorized Caller");
+ }
// Check the permission of the given package.
- if (packageName.isEmpty()) {
- packageName = null;
- } else if (pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException(packageName + " does not have " + VPN);
+ PackageManager pm = mContext.getPackageManager();
+ if (!newPackage.equals(VpnConfig.LEGACY_VPN) &&
+ pm.checkPermission(VPN, newPackage) != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(newPackage + " does not have " + VPN);
}
// Reset the interface and hide the notification.
- if (mInterfaceName != null) {
- nativeReset(mInterfaceName);
+ if (mInterface != null) {
+ jniReset(mInterface);
mCallback.restore();
hideNotification();
- mInterfaceName = null;
+ mInterface = null;
}
- // Notify the package being revoked.
- if (mPackageName != null) {
+ // Send out the broadcast or stop LegacyVpnRunner.
+ if (!mPackage.equals(VpnConfig.LEGACY_VPN)) {
Intent intent = new Intent(VpnConfig.ACTION_VPN_REVOKED);
- intent.setPackage(mPackageName);
+ intent.setPackage(mPackage);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcast(intent);
+ } else if (mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.exit();
+ mLegacyVpnRunner = null;
}
- Log.i(TAG, "Switched from " + mPackageName + " to " + packageName);
- mPackageName = packageName;
- return mPackageName;
- }
-
- /**
- * Protect a socket from routing changes by binding it to the given
- * interface. The socket IS closed by this method.
- *
- * @param socket The socket to be bound.
- * @param name The name of the interface.
- */
- public void protect(ParcelFileDescriptor socket, String name) {
- try {
- mContext.enforceCallingPermission(VPN, "protect");
- nativeProtect(socket.getFd(), name);
- } finally {
- try {
- socket.close();
- } catch (Exception e) {
- // ignore
- }
- }
+ Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
+ mPackage = newPackage;
+ return true;
}
/**
- * Configure a TUN interface and return its file descriptor.
+ * Establish a VPN network and return the file descriptor of the VPN
+ * interface. This methods returns {@code null} if the application is
+ * revoked or not prepared.
*
- * @param configuration The parameters to configure the interface.
- * @return The file descriptor of the interface.
+ * @param config The parameters to configure the network.
+ * @return The file descriptor of the VPN interface.
*/
public synchronized ParcelFileDescriptor establish(VpnConfig config) {
// Check the permission of the caller.
@@ -134,7 +167,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
PackageManager pm = mContext.getPackageManager();
ApplicationInfo app = null;
try {
- app = pm.getApplicationInfo(mPackageName, 0);
+ app = pm.getApplicationInfo(mPackage, 0);
} catch (Exception e) {
return null;
}
@@ -142,85 +175,91 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
return null;
}
- // Create and configure the interface.
- ParcelFileDescriptor descriptor = ParcelFileDescriptor.adoptFd(
- nativeEstablish(config.mtu, config.addresses, config.routes));
+ // Load the label.
+ String label = app.loadLabel(pm).toString();
+
+ // Load the icon and convert it into a bitmap.
+ Drawable icon = app.loadIcon(pm);
+ Bitmap bitmap = null;
+ if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) {
+ int width = mContext.getResources().getDimensionPixelSize(
+ android.R.dimen.notification_large_icon_width);
+ int height = mContext.getResources().getDimensionPixelSize(
+ android.R.dimen.notification_large_icon_height);
+ icon.setBounds(0, 0, width, height);
+ bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ icon.draw(new Canvas(bitmap));
+ }
- // Replace the interface and abort if it fails.
+ // Configure the interface. Abort if any of these steps fails.
+ ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(
+ jniConfigure(config.mtu, config.addresses, config.routes));
try {
- String interfaceName = nativeGetName(descriptor.getFd());
-
- if (mInterfaceName != null && !mInterfaceName.equals(interfaceName)) {
- nativeReset(mInterfaceName);
+ String interfaze = jniGetName(tun.getFd());
+ if (mInterface != null && !mInterface.equals(interfaze)) {
+ jniReset(mInterface);
}
- mInterfaceName = interfaceName;
+ mInterface = interfaze;
} catch (RuntimeException e) {
try {
- descriptor.close();
+ tun.close();
} catch (Exception ex) {
// ignore
}
throw e;
}
- String dnsServers = (config.dnsServers == null) ? "" : config.dnsServers.trim();
- mCallback.override(dnsServers.isEmpty() ? null : dnsServers.split(" "));
+ // Override DNS servers and search domains.
+ mCallback.override(config.dnsServers, config.searchDomains);
+
+ // Fill more values.
+ config.packagz = mPackage;
+ config.interfaze = mInterface;
- config.packageName = mPackageName;
- config.interfaceName = mInterfaceName;
- showNotification(pm, app, config);
- return descriptor;
+ // Show the notification!
+ showNotification(config, label, bitmap);
+ return tun;
}
// INetworkManagementEventObserver.Stub
- public void interfaceLinkStatusChanged(String name, boolean up) {
+ public void interfaceStatusChanged(String interfaze, boolean up) {
}
// INetworkManagementEventObserver.Stub
- public void interfaceAdded(String name) {
+ public void interfaceLinkStateChanged(String interfaze, boolean up) {
}
// INetworkManagementEventObserver.Stub
- public synchronized void interfaceRemoved(String name) {
- if (name.equals(mInterfaceName) && nativeCheck(name) == 0) {
- hideNotification();
- mInterfaceName = null;
+ public void interfaceAdded(String interfaze) {
+ }
+
+ // INetworkManagementEventObserver.Stub
+ public synchronized void interfaceRemoved(String interfaze) {
+ if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
mCallback.restore();
+ hideNotification();
+ mInterface = null;
}
}
- private void showNotification(PackageManager pm, ApplicationInfo app, VpnConfig config) {
+ private void showNotification(VpnConfig config, String label, Bitmap icon) {
NotificationManager nm = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (nm != null) {
- // Load the icon and convert it into a bitmap.
- Drawable icon = app.loadIcon(pm);
- Bitmap bitmap = null;
- if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) {
- int width = mContext.getResources().getDimensionPixelSize(
- android.R.dimen.notification_large_icon_width);
- int height = mContext.getResources().getDimensionPixelSize(
- android.R.dimen.notification_large_icon_height);
- icon.setBounds(0, 0, width, height);
- bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- icon.draw(new Canvas(bitmap));
- }
+ String title = (label == null) ? mContext.getString(R.string.vpn_title) :
+ mContext.getString(R.string.vpn_title_long, label);
+ String text = (config.session == null) ? mContext.getString(R.string.vpn_text) :
+ mContext.getString(R.string.vpn_text_long, config.session);
+ config.startTime = SystemClock.elapsedRealtime();
- // Load the label.
- String label = app.loadLabel(pm).toString();
-
- // Build the notification.
- String text = (config.sessionName == null) ? mContext.getString(R.string.vpn_text) :
- mContext.getString(R.string.vpn_text_long, config.sessionName);
long identity = Binder.clearCallingIdentity();
Notification notification = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.vpn_connected)
- .setLargeIcon(bitmap)
- .setTicker(mContext.getString(R.string.vpn_ticker, label))
- .setContentTitle(mContext.getString(R.string.vpn_title, label))
+ .setLargeIcon(icon)
+ .setContentTitle(title)
.setContentText(text)
- .setContentIntent(VpnConfig.getIntentForNotification(mContext, config))
+ .setContentIntent(VpnConfig.getIntentForStatusPanel(mContext, config))
.setDefaults(Notification.DEFAULT_ALL)
.setOngoing(true)
.getNotification();
@@ -240,9 +279,264 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
}
- private native int nativeEstablish(int mtu, String addresses, String routes);
- private native String nativeGetName(int fd);
- private native void nativeReset(String name);
- private native int nativeCheck(String name);
- private native void nativeProtect(int fd, String name);
+ private native int jniConfigure(int mtu, String addresses, String routes);
+ private native String jniGetName(int tun);
+ private native void jniReset(String interfaze);
+ private native int jniCheck(String interfaze);
+ private native void jniProtect(int socket, String interfaze);
+
+ /**
+ * Start legacy VPN. This method stops the daemons and restart them
+ * if arguments are not null. Heavy things are offloaded to another
+ * thread, so callers will not be blocked for a long time.
+ *
+ * @param config The parameters to configure the network.
+ * @param raoocn The arguments to be passed to racoon.
+ * @param mtpd The arguments to be passed to mtpd.
+ */
+ public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
+ // Prepare for the new request. This also checks the caller.
+ prepare(null, VpnConfig.LEGACY_VPN);
+
+ // Start a new LegacyVpnRunner and we are done!
+ mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
+ mLegacyVpnRunner.start();
+ }
+
+ /**
+ * Return the information of the current ongoing legacy VPN.
+ */
+ public synchronized LegacyVpnInfo getLegacyVpnInfo() {
+ // Only system user can call this method.
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Unauthorized Caller");
+ }
+ return (mLegacyVpnRunner == null) ? null : mLegacyVpnRunner.getInfo();
+ }
+
+ /**
+ * Bringing up a VPN connection takes time, and that is all this thread
+ * does. Here we have plenty of time. The only thing we need to take
+ * care of is responding to interruptions as soon as possible. Otherwise
+ * requests will be piled up. This can be done in a Handler as a state
+ * machine, but it is much easier to read in the current form.
+ */
+ private class LegacyVpnRunner extends Thread {
+ private static final String TAG = "LegacyVpnRunner";
+ private static final String NONE = "--";
+
+ private final VpnConfig mConfig;
+ private final String[] mDaemons;
+ private final String[][] mArguments;
+ private final LegacyVpnInfo mInfo;
+
+ private long mTimer = -1;
+
+ public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
+ super(TAG);
+ mConfig = config;
+ mDaemons = new String[] {"racoon", "mtpd"};
+ mArguments = new String[][] {racoon, mtpd};
+ mInfo = new LegacyVpnInfo();
+
+ // Legacy VPN is not a real package, so we use it to carry the key.
+ mInfo.key = mConfig.packagz;
+ mConfig.packagz = VpnConfig.LEGACY_VPN;
+ }
+
+ public void exit() {
+ // We assume that everything is reset after the daemons die.
+ for (String daemon : mDaemons) {
+ SystemProperties.set("ctl.stop", daemon);
+ }
+ interrupt();
+ }
+
+ public LegacyVpnInfo getInfo() {
+ // Update the info when VPN is disconnected.
+ if (mInfo.state == LegacyVpnInfo.STATE_CONNECTED && mInterface == null) {
+ mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED;
+ mInfo.intent = null;
+ }
+ return mInfo;
+ }
+
+ @Override
+ public void run() {
+ // Wait for the previous thread since it has been interrupted.
+ Log.v(TAG, "Waiting");
+ synchronized (TAG) {
+ Log.v(TAG, "Executing");
+ execute();
+ }
+ }
+
+ private void checkpoint(boolean yield) throws InterruptedException {
+ long now = SystemClock.elapsedRealtime();
+ if (mTimer == -1) {
+ mTimer = now;
+ Thread.sleep(1);
+ } else if (now - mTimer <= 30000) {
+ Thread.sleep(yield ? 200 : 1);
+ } else {
+ mInfo.state = LegacyVpnInfo.STATE_TIMEOUT;
+ throw new IllegalStateException("time is up");
+ }
+ }
+
+ private void execute() {
+ // Catch all exceptions so we can clean up few things.
+ try {
+ // Initialize the timer.
+ checkpoint(false);
+ mInfo.state = LegacyVpnInfo.STATE_INITIALIZING;
+
+ // First stop the daemons.
+ for (String daemon : mDaemons) {
+ SystemProperties.set("ctl.stop", daemon);
+ }
+
+ // Wait for the daemons to stop.
+ for (String daemon : mDaemons) {
+ String key = "init.svc." + daemon;
+ while (!"stopped".equals(SystemProperties.get(key))) {
+ checkpoint(true);
+ }
+ }
+
+ // Reset the properties.
+ SystemProperties.set("vpn.dns", NONE);
+ SystemProperties.set("vpn.via", NONE);
+ while (!NONE.equals(SystemProperties.get("vpn.dns")) ||
+ !NONE.equals(SystemProperties.get("vpn.via"))) {
+ checkpoint(true);
+ }
+
+ // Check if we need to restart any of the daemons.
+ boolean restart = false;
+ for (String[] arguments : mArguments) {
+ restart = restart || (arguments != null);
+ }
+ if (!restart) {
+ mInfo.state = LegacyVpnInfo.STATE_DISCONNECTED;
+ return;
+ }
+ mInfo.state = LegacyVpnInfo.STATE_CONNECTING;
+
+ // Start the daemon with arguments.
+ for (int i = 0; i < mDaemons.length; ++i) {
+ String[] arguments = mArguments[i];
+ if (arguments == null) {
+ continue;
+ }
+
+ // Start the daemon.
+ String daemon = mDaemons[i];
+ SystemProperties.set("ctl.start", daemon);
+
+ // Wait for the daemon to start.
+ String key = "init.svc." + daemon;
+ while (!"running".equals(SystemProperties.get(key))) {
+ checkpoint(true);
+ }
+
+ // Create the control socket.
+ LocalSocket socket = new LocalSocket();
+ LocalSocketAddress address = new LocalSocketAddress(
+ daemon, LocalSocketAddress.Namespace.RESERVED);
+
+ // Wait for the socket to connect.
+ while (true) {
+ try {
+ socket.connect(address);
+ break;
+ } catch (Exception e) {
+ // ignore
+ }
+ checkpoint(true);
+ }
+ socket.setSoTimeout(500);
+
+ // Send over the arguments.
+ OutputStream out = socket.getOutputStream();
+ for (String argument : arguments) {
+ byte[] bytes = argument.getBytes(Charsets.UTF_8);
+ if (bytes.length >= 0xFFFF) {
+ throw new IllegalArgumentException("argument is too large");
+ }
+ out.write(bytes.length >> 8);
+ out.write(bytes.length);
+ out.write(bytes);
+ checkpoint(false);
+ }
+
+ // Send End-Of-Arguments.
+ out.write(0xFF);
+ out.write(0xFF);
+ out.flush();
+ socket.close();
+ }
+
+ // Now here is the beast from the old days. We check few
+ // properties to figure out the current status. Ideally we
+ // can read things back from the sockets and get rid of the
+ // properties, but we have no time...
+ while (NONE.equals(SystemProperties.get("vpn.dns")) ||
+ NONE.equals(SystemProperties.get("vpn.via"))) {
+
+ // Check if a running daemon is dead.
+ for (int i = 0; i < mDaemons.length; ++i) {
+ String daemon = mDaemons[i];
+ if (mArguments[i] != null && !"running".equals(
+ SystemProperties.get("init.svc." + daemon))) {
+ throw new IllegalStateException(daemon + " is dead");
+ }
+ }
+ checkpoint(true);
+ }
+
+ // Now we are connected. Get the interface.
+ mConfig.interfaze = SystemProperties.get("vpn.via");
+
+ // Get the DNS servers if they are not set in config.
+ if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
+ String dnsServers = SystemProperties.get("vpn.dns").trim();
+ if (!dnsServers.isEmpty()) {
+ mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
+ }
+ }
+
+ // TODO: support search domains from ISAKMP mode config.
+
+ // The final step must be synchronized.
+ synchronized (Vpn.this) {
+ // Check if the thread is interrupted while we are waiting.
+ checkpoint(false);
+
+ // Check if the interface is gone while we are waiting.
+ if (jniCheck(mConfig.interfaze) == 0) {
+ throw new IllegalStateException(mConfig.interfaze + " is gone");
+ }
+
+ // Now INetworkManagementEventObserver is watching our back.
+ mInterface = mConfig.interfaze;
+ mCallback.override(mConfig.dnsServers, mConfig.searchDomains);
+ showNotification(mConfig, null, null);
+
+ Log.i(TAG, "Connected!");
+ mInfo.state = LegacyVpnInfo.STATE_CONNECTED;
+ mInfo.intent = VpnConfig.getIntentForStatusPanel(mContext, null);
+ }
+ } catch (Exception e) {
+ Log.i(TAG, "Aborting", e);
+ exit();
+ } finally {
+ // Do not leave an unstable state.
+ if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING ||
+ mInfo.state == LegacyVpnInfo.STATE_CONNECTING) {
+ mInfo.state = LegacyVpnInfo.STATE_FAILED;
+ }
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 67e73f5..c813d37 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -32,7 +32,6 @@ import android.location.LocationManager;
import android.location.LocationProvider;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
-import android.net.SntpClient;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -51,6 +50,7 @@ import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
+import android.util.NtpTrustedTime;
import android.util.SparseIntArray;
import com.android.internal.app.IBatteryStats;
@@ -61,7 +61,7 @@ import com.android.internal.telephony.Phone;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
-import java.io.StringBufferInputStream;
+import java.io.StringReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map.Entry;
@@ -132,7 +132,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
private static final int GPS_CAPABILITY_MSB = 0x0000002;
private static final int GPS_CAPABILITY_MSA = 0x0000004;
private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
-
+ private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
// these need to match AGpsType enum in gps.h
private static final int AGPS_TYPE_SUPL = 1;
@@ -200,6 +200,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
private boolean mInjectNtpTimePending = true;
private boolean mDownloadXtraDataPending = true;
+ // set to true if the GPS engine does not do on-demand NTP time requests
+ private boolean mPeriodicTimeInjection;
+
// true if GPS is navigating
private boolean mNavigating;
@@ -232,13 +235,13 @@ public class GpsLocationProvider implements LocationProviderInterface {
// properties loaded from PROPERTIES_FILE
private Properties mProperties;
- private String mNtpServer;
private String mSuplServerHost;
private int mSuplServerPort;
private String mC2KServerHost;
private int mC2KServerPort;
private final Context mContext;
+ private final NtpTrustedTime mNtpTime;
private final ILocationManager mLocationManager;
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
private Bundle mLocationExtras = new Bundle();
@@ -283,10 +286,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
// current setting - 5 minutes
private static final long RETRY_INTERVAL = 5*60*1000;
- // to avoid injecting bad NTP time, we reject any time fixes that differ from system time
- // by more than 5 minutes.
- private static final long MAX_NTP_SYSTEM_TIME_OFFSET = 5*60*1000;
-
private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
if (listener == null) {
@@ -375,6 +374,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
public GpsLocationProvider(Context context, ILocationManager locationManager) {
mContext = context;
+ mNtpTime = NtpTrustedTime.getInstance(context);
mLocationManager = locationManager;
mNIHandler = new GpsNetInitiatedHandler(context);
@@ -415,7 +415,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
FileInputStream stream = new FileInputStream(file);
mProperties.load(stream);
stream.close();
- mNtpServer = mProperties.getProperty("NTP_SERVER", null);
mSuplServerHost = mProperties.getProperty("SUPL_HOST");
String portString = mProperties.getProperty("SUPL_PORT");
@@ -527,13 +526,18 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
mInjectNtpTimePending = false;
- SntpClient client = new SntpClient();
long delay;
- if (client.requestTime(mNtpServer, 10000)) {
- long time = client.getNtpTime();
- long timeReference = client.getNtpTimeReference();
- int certainty = (int)(client.getRoundTripTime()/2);
+ // force refresh NTP cache when outdated
+ if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
+ mNtpTime.forceRefresh();
+ }
+
+ // only update when NTP time is fresh
+ if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
+ long time = mNtpTime.getCachedNtpTime();
+ long timeReference = mNtpTime.getCachedNtpTimeReference();
+ long certainty = mNtpTime.getCacheCertainty();
long now = System.currentTimeMillis();
Log.d(TAG, "NTP server returned: "
@@ -542,17 +546,19 @@ public class GpsLocationProvider implements LocationProviderInterface {
+ " certainty: " + certainty
+ " system time offset: " + (time - now));
- native_inject_time(time, timeReference, certainty);
+ native_inject_time(time, timeReference, (int) certainty);
delay = NTP_INTERVAL;
} else {
if (DEBUG) Log.d(TAG, "requestTime failed");
delay = RETRY_INTERVAL;
}
- // send delayed message for next NTP injection
- // since this is delayed and not urgent we do not hold a wake lock here
- mHandler.removeMessages(INJECT_NTP_TIME);
- mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+ if (mPeriodicTimeInjection) {
+ // send delayed message for next NTP injection
+ // since this is delayed and not urgent we do not hold a wake lock here
+ mHandler.removeMessages(INJECT_NTP_TIME);
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+ }
}
private void handleDownloadXtraData() {
@@ -1305,6 +1311,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
*/
private void setEngineCapabilities(int capabilities) {
mEngineCapabilities = capabilities;
+
+ if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) {
+ mPeriodicTimeInjection = true;
+ requestUtcTime();
+ }
}
/**
@@ -1385,7 +1396,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
Properties extraProp = new Properties();
try {
- extraProp.load(new StringBufferInputStream(extras));
+ extraProp.load(new StringReader(extras));
}
catch (IOException e)
{
@@ -1438,6 +1449,14 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
/**
+ * Called from native code to request utc time info
+ */
+
+ private void requestUtcTime() {
+ sendMessage(INJECT_NTP_TIME, 0, null);
+ }
+
+ /**
* Called from native code to request reference location info
*/
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 584cd03..d23d0f4 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -25,6 +25,7 @@ import static android.Manifest.permission.READ_PHONE_STATE;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.*;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -57,6 +58,8 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
@@ -71,7 +74,9 @@ import android.net.NetworkTemplate;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.INetworkManagementService;
import android.os.IPowerManager;
+import android.os.Message;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.telephony.TelephonyManager;
@@ -108,6 +113,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import libcore.io.IoUtils;
@@ -148,10 +154,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS;
+ private static final int MSG_RULES_CHANGED = 0x1;
+ private static final int MSG_METERED_IFACES_CHANGED = 0x2;
+
private final Context mContext;
private final IActivityManager mActivityManager;
private final IPowerManager mPowerManager;
private final INetworkStatsService mNetworkStats;
+ private final INetworkManagementService mNetworkManagement;
private final TrustedTime mTime;
private IConnectivityManager mConnManager;
@@ -160,6 +170,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final Object mRulesLock = new Object();
private boolean mScreenOn;
+ private boolean mBackgroundData;
/** Current policy for network templates. */
private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
@@ -188,11 +199,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
+ // TODO: watch for package added broadcast to catch new UIDs.
+
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- IPowerManager powerManager, INetworkStatsService networkStats) {
- // TODO: move to using cached NtpTrustedTime
- this(context, activityManager, powerManager, networkStats, new NtpTrustedTime(),
- getSystemDir());
+ IPowerManager powerManager, INetworkStatsService networkStats,
+ INetworkManagementService networkManagement) {
+ this(context, activityManager, powerManager, networkStats, networkManagement,
+ NtpTrustedTime.getInstance(context), getSystemDir());
}
private static File getSystemDir() {
@@ -200,17 +213,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- IPowerManager powerManager, INetworkStatsService networkStats, TrustedTime time,
- File systemDir) {
+ IPowerManager powerManager, INetworkStatsService networkStats,
+ INetworkManagementService networkManagement,
+ TrustedTime time, File systemDir) {
mContext = checkNotNull(context, "missing context");
mActivityManager = checkNotNull(activityManager, "missing activityManager");
mPowerManager = checkNotNull(powerManager, "missing powerManager");
mNetworkStats = checkNotNull(networkStats, "missing networkStats");
+ mNetworkManagement = checkNotNull(networkManagement, "missing networkManagement");
mTime = checkNotNull(time, "missing TrustedTime");
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
+ mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback);
mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml"));
}
@@ -231,6 +246,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
updateScreenOn();
+ updateBackgroundData(true);
try {
mActivityManager.registerProcessObserver(mProcessObserver);
@@ -256,11 +272,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
- // listen for warning polling events; currently dispatched by
+ // listen for stats update events
final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
mContext.registerReceiver(
mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
+ // listen for changes to background data flag
+ final IntentFilter bgFilter = new IntentFilter(ACTION_BACKGROUND_DATA_SETTING_CHANGED);
+ mContext.registerReceiver(mBgReceiver, bgFilter, CONNECTIVITY_INTERNAL, mHandler);
+
}
private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -269,9 +289,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// only someone like AMS should only be calling us
mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
- // skip when UID couldn't have any policy
- if (!isUidValidForPolicy(mContext, uid)) return;
-
synchronized (mRulesLock) {
// because a uid can have multiple pids running inside, we need to
// remember all pid states and summarize foreground at uid level.
@@ -292,9 +309,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// only someone like AMS should only be calling us
mContext.enforceCallingOrSelfPermission(MANAGE_APP_TOKENS, TAG);
- // skip when UID couldn't have any policy
- if (!isUidValidForPolicy(mContext, uid)) return;
-
synchronized (mRulesLock) {
// clear records and recompute, when they exist
final SparseBooleanArray pidForeground = mUidPidForeground.get(uid);
@@ -349,6 +363,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
};
/**
+ * Receiver that watches for
+ * {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}.
+ */
+ private BroadcastReceiver mBgReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // on background handler thread, and verified CONNECTIVITY_INTERNAL
+ // permission above.
+
+ synchronized (mRulesLock) {
+ updateBackgroundData(false);
+ }
+ }
+ };
+
+ /**
* Check {@link NetworkPolicy} against current {@link INetworkStatsService}
* to show visible notifications as needed.
*/
@@ -561,7 +591,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
: System.currentTimeMillis();
- mMeteredIfaces.clear();
+ final HashSet<String> newMeteredIfaces = Sets.newHashSet();
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
@@ -591,28 +621,30 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
// remaining "quota" is based on usage in current cycle
final long quota = Math.max(0, policy.limitBytes - total);
- //kernelSetIfacesQuota(ifaces, quota);
+
+ if (ifaces.length > 1) {
+ // TODO: switch to shared quota once NMS supports
+ Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
+ }
for (String iface : ifaces) {
- mMeteredIfaces.add(iface);
+ removeInterfaceQuota(iface);
+ setInterfaceQuota(iface, quota);
+ newMeteredIfaces.add(iface);
}
}
}
- // dispatch changed rule to existing listeners
- // TODO: dispatch outside of holding lock
- final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
- final int length = mListeners.beginBroadcast();
- for (int i = 0; i < length; i++) {
- final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onMeteredIfacesChanged(meteredIfaces);
- } catch (RemoteException e) {
- }
+ // remove quota on any trailing interfaces
+ for (String iface : mMeteredIfaces) {
+ if (!newMeteredIfaces.contains(iface)) {
+ removeInterfaceQuota(iface);
}
}
- mListeners.finishBroadcast();
+ mMeteredIfaces = newMeteredIfaces;
+
+ final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
+ mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
}
/**
@@ -804,32 +836,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mListeners.register(listener);
- synchronized (mRulesLock) {
- // dispatch any existing rules to new listeners
- // TODO: dispatch outside of holding lock
- final int size = mUidRules.size();
- for (int i = 0; i < size; i++) {
- final int uid = mUidRules.keyAt(i);
- final int uidRules = mUidRules.valueAt(i);
- if (uidRules != RULE_ALLOW_ALL) {
- try {
- listener.onUidRulesChanged(uid, uidRules);
- } catch (RemoteException e) {
- }
- }
- }
-
- // dispatch any metered ifaces to new listeners
- // TODO: dispatch outside of holding lock
- if (mMeteredIfaces.size() > 0) {
- final String[] meteredIfaces = mMeteredIfaces.toArray(
- new String[mMeteredIfaces.size()]);
- try {
- listener.onMeteredIfacesChanged(meteredIfaces);
- } catch (RemoteException e) {
- }
- }
- }
+ // TODO: consider dispatching existing rules to new listeners
}
@Override
@@ -963,6 +970,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void updateBackgroundData(boolean systemReady) {
+ synchronized (mRulesLock) {
+ try {
+ mBackgroundData = mConnManager.getBackgroundDataSetting();
+ } catch (RemoteException e) {
+ }
+ if (systemReady && mBackgroundData) {
+ // typical behavior of background enabled during systemReady;
+ // no need to clear rules for all UIDs.
+ } else {
+ updateRulesForBackgroundDataLocked();
+ }
+ }
+ }
+
/**
* Update rules that might be changed by {@link #mScreenOn} value.
*/
@@ -977,9 +999,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- private void updateRulesForUidLocked(int uid) {
- if (!isUidValidForPolicy(mContext, uid)) return;
+ /**
+ * Update rules that might be changed by {@link #mBackgroundData} value.
+ */
+ private void updateRulesForBackgroundDataLocked() {
+ // update rules for all installed applications
+ final PackageManager pm = mContext.getPackageManager();
+ final List<ApplicationInfo> apps = pm.getInstalledApplications(0);
+ for (ApplicationInfo app : apps) {
+ updateRulesForUidLocked(app.uid);
+ }
+ // and catch system UIDs
+ // TODO: keep in sync with android_filesystem_config.h
+ for (int uid = 1000; uid <= 1025; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 2000; uid <= 2002; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 3000; uid <= 3007; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 9998; uid <= 9999; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ }
+
+ private void updateRulesForUidLocked(int uid) {
final int uidPolicy = getUidPolicy(uid);
final boolean uidForeground = isUidForeground(uid);
@@ -989,28 +1036,96 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// uid in background, and policy says to block metered data
uidRules = RULE_REJECT_METERED;
}
+ if (!uidForeground && !mBackgroundData) {
+ // uid in background, and global background disabled
+ uidRules = RULE_REJECT_METERED;
+ }
// TODO: only dispatch when rules actually change
- // record rule locally to dispatch to new listeners
- mUidRules.put(uid, uidRules);
+ if (uidRules == RULE_ALLOW_ALL) {
+ mUidRules.delete(uid);
+ } else {
+ mUidRules.put(uid, uidRules);
+ }
final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
- //kernelSetUidRejectPaid(uid, rejectPaid);
+ setUidNetworkRules(uid, rejectMetered);
// dispatch changed rule to existing listeners
- // TODO: dispatch outside of holding lock
- final int length = mListeners.beginBroadcast();
- for (int i = 0; i < length; i++) {
- final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
- if (listener != null) {
- try {
- listener.onUidRulesChanged(uid, uidRules);
- } catch (RemoteException e) {
+ mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
+ }
+
+ private Handler.Callback mHandlerCallback = new Handler.Callback() {
+ /** {@inheritDoc} */
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_RULES_CHANGED: {
+ final int uid = msg.arg1;
+ final int uidRules = msg.arg2;
+ final int length = mListeners.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ if (listener != null) {
+ try {
+ listener.onUidRulesChanged(uid, uidRules);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mListeners.finishBroadcast();
+ return true;
+ }
+ case MSG_METERED_IFACES_CHANGED: {
+ final String[] meteredIfaces = (String[]) msg.obj;
+ final int length = mListeners.beginBroadcast();
+ for (int i = 0; i < length; i++) {
+ final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
+ if (listener != null) {
+ try {
+ listener.onMeteredIfacesChanged(meteredIfaces);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ mListeners.finishBroadcast();
+ return true;
+ }
+ default: {
+ return false;
}
}
}
- mListeners.finishBroadcast();
+ };
+
+ private void setInterfaceQuota(String iface, long quota) {
+ try {
+ mNetworkManagement.setInterfaceQuota(iface, quota);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem setting interface quota", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem setting interface quota", e);
+ }
+ }
+
+ private void removeInterfaceQuota(String iface) {
+ try {
+ mNetworkManagement.removeInterfaceQuota(iface);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem removing interface quota", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem removing interface quota", e);
+ }
+ }
+
+ private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ try {
+ mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem setting uid rules", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem setting uid rules", e);
+ }
}
private String getActiveSubscriberId() {
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 524dd40..b6834f6 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -27,7 +27,6 @@ import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
-import static android.provider.Settings.Secure.NETSTATS_ENABLED;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION;
import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY;
import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD;
@@ -71,7 +70,6 @@ import android.util.Slog;
import android.util.TrustedTime;
import com.android.internal.os.AtomicFile;
-import com.android.server.NativeDaemonConnectorException;
import com.google.android.collect.Maps;
import com.google.android.collect.Sets;
@@ -124,8 +122,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
private PendingIntent mPollIntent;
// TODO: listen for kernel push events through netd instead of polling
- // TODO: watch for UID uninstall, and transfer stats into single bucket
-
// TODO: trim empty history objects entirely
private static final long KB_IN_BYTES = 1024;
@@ -136,7 +132,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
* Settings that can be changed externally.
*/
public interface NetworkStatsSettings {
- public boolean getEnabled();
public long getPollInterval();
public long getPersistThreshold();
public long getNetworkBucketDuration();
@@ -178,9 +173,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
public NetworkStatsService(
Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) {
- // TODO: move to using cached NtpTrustedTime
- this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir(),
- new DefaultNetworkStatsSettings(context));
+ this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context),
+ getSystemDir(), new DefaultNetworkStatsSettings(context));
}
private static File getSystemDir() {
@@ -209,20 +203,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
public void systemReady() {
- if (mSettings.getEnabled()) {
- try {
- // enable low-level bandwidth stats and control
- // TODO: consider shipping with this enabled by default
- mNetworkManager.setBandwidthControlEnabled(true);
- } catch (RemoteException e) {
- Slog.e(TAG, "problem talking to netd while enabling bandwidth controls", e);
- } catch (NativeDaemonConnectorException ndce) {
- Slog.e(TAG, "problem enabling bandwidth controls", ndce);
- }
- } else {
- Slog.w(TAG, "detailed network stats disabled");
- }
-
synchronized (mStatsLock) {
// read historical network stats from disk, since policy service
// might need them right away. we delay loading detailed UID stats
@@ -391,6 +371,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
+ @Override
+ public void forceUpdate() {
+ mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+
+ synchronized (mStatsLock) {
+ performPollLocked(true, false);
+ }
+ }
+
/**
* Receiver that watches for {@link IConnectivityManager} to claim network
* interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
@@ -506,8 +495,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
try {
networkSnapshot = mNetworkManager.getNetworkStatsSummary();
uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null;
+ } catch (IllegalStateException e) {
+ Slog.w(TAG, "problem reading network stats: " + e);
+ return;
} catch (RemoteException e) {
- Slog.w(TAG, "problem reading network stats");
+ Slog.w(TAG, "problem reading network stats: " + e);
return;
}
@@ -904,6 +896,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
argSet.add(arg);
}
+ final boolean fullHistory = argSet.contains("full");
+
synchronized (mStatsLock) {
// TODO: remove this testing code, since it corrupts stats
if (argSet.contains("generate")) {
@@ -929,7 +923,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
final NetworkStatsHistory history = mNetworkStats.get(ident);
pw.print(" ident="); pw.println(ident.toString());
- history.dump(" ", pw);
+ history.dump(" ", pw, fullHistory);
}
if (argSet.contains("detail")) {
@@ -949,7 +943,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final NetworkStatsHistory history = uidStats.valueAt(i);
pw.print(" UID="); pw.print(uid);
pw.print(" tag="); pw.println(tag);
- history.dump(" ", pw);
+ history.dump(" ", pw, fullHistory);
}
}
}
@@ -1057,13 +1051,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return Settings.Secure.getLong(mResolver, name, def);
}
- public boolean getEnabled() {
- if (!new File("/proc/net/xt_qtaguid/ctrl").exists()) {
- Slog.w(TAG, "kernel does not support bandwidth control");
- return false;
- }
- return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 1) != 0;
- }
public long getPollInterval() {
return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS);
}
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index d10aa97..11ccd60 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -307,7 +307,7 @@ class Installer {
}
public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
- PackageStats pStats) {
+ String asecPath, PackageStats pStats) {
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
builder.append(pkgName);
@@ -315,17 +315,20 @@ class Installer {
builder.append(apkPath);
builder.append(' ');
builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
+ builder.append(' ');
+ builder.append(asecPath != null ? asecPath : "!");
String s = transaction(builder.toString());
String res[] = s.split(" ");
- if ((res == null) || (res.length != 4)) {
+ if ((res == null) || (res.length != 5)) {
return -1;
}
try {
pStats.codeSize = Long.parseLong(res[1]);
pStats.dataSize = Long.parseLong(res[2]);
pStats.cacheSize = Long.parseLong(res[3]);
+ pStats.externalCodeSize = Long.parseLong(res[4]);
return Integer.parseInt(res[0]);
} catch (NumberFormatException e) {
return -1;
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 5a9dae9..d6a15e6 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -75,6 +75,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileObserver;
import android.os.FileUtils;
+import android.os.FileUtils.FileStatus;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -156,7 +157,6 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
- private static final int KEYCHAIN_UID = Process.KEYCHAIN_UID;
static final int FIRST_APPLICATION_UID =
Process.FIRST_APPLICATION_UID;
static final int MAX_APPLICATION_UIDS = 1000;
@@ -760,10 +760,6 @@ public class PackageManagerService extends IPackageManager.Stub {
MULTIPLE_APPLICATION_UIDS
? NFC_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLPw("android.uid.keychain",
- MULTIPLE_APPLICATION_UIDS
- ? KEYCHAIN_UID : FIRST_APPLICATION_UID,
- ApplicationInfo.FLAG_SYSTEM);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -782,16 +778,7 @@ public class PackageManagerService extends IPackageManager.Stub {
mSeparateProcesses = null;
}
- Installer installer = new Installer();
- // Little hacky thing to check if installd is here, to determine
- // whether we are running on the simulator and thus need to take
- // care of building the /data file structure ourself.
- // (apparently the sim now has a working installer)
- if (installer.ping() && Process.supportsProcesses()) {
- mInstaller = installer;
- } else {
- mInstaller = null;
- }
+ mInstaller = new Installer();
WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
@@ -810,17 +797,6 @@ public class PackageManagerService extends IPackageManager.Stub {
mUserManager = new UserManager(mInstaller, mUserAppDataDir);
- if (mInstaller == null) {
- // Make sure these dirs exist, when we are running in
- // the simulator.
- // Make a wide-open directory for random misc stuff.
- File miscDir = new File(dataDir, "misc");
- miscDir.mkdirs();
- mAppDataDir.mkdirs();
- mUserAppDataDir.mkdirs();
- mDrmAppPrivateInstallDir.mkdirs();
- }
-
readPermissions();
mRestoredSettings = mSettings.readLPw();
@@ -842,104 +818,102 @@ public class PackageManagerService extends IPackageManager.Stub {
mFrameworkDir = new File(Environment.getRootDirectory(), "framework");
mDalvikCacheDir = new File(dataDir, "dalvik-cache");
- if (mInstaller != null) {
- boolean didDexOpt = false;
-
- /**
- * Out of paranoia, ensure that everything in the boot class
- * path has been dexed.
- */
- String bootClassPath = System.getProperty("java.boot.class.path");
- if (bootClassPath != null) {
- String[] paths = splitString(bootClassPath, ':');
- for (int i=0; i<paths.length; i++) {
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
- libFiles.add(paths[i]);
- mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Boot class path not found: " + paths[i]);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading boot class path: " + paths[i], e);
+ boolean didDexOpt = false;
+
+ /**
+ * Out of paranoia, ensure that everything in the boot class
+ * path has been dexed.
+ */
+ String bootClassPath = System.getProperty("java.boot.class.path");
+ if (bootClassPath != null) {
+ String[] paths = splitString(bootClassPath, ':');
+ for (int i=0; i<paths.length; i++) {
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {
+ libFiles.add(paths[i]);
+ mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);
+ didDexOpt = true;
}
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Boot class path not found: " + paths[i]);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading boot class path: " + paths[i], e);
}
- } else {
- Slog.w(TAG, "No BOOTCLASSPATH found!");
}
+ } else {
+ Slog.w(TAG, "No BOOTCLASSPATH found!");
+ }
- /**
- * Also ensure all external libraries have had dexopt run on them.
- */
- if (mSharedLibraries.size() > 0) {
- Iterator<String> libs = mSharedLibraries.values().iterator();
- while (libs.hasNext()) {
- String lib = libs.next();
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
- libFiles.add(lib);
- mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Library not found: " + lib);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading library: " + lib, e);
+ /**
+ * Also ensure all external libraries have had dexopt run on them.
+ */
+ if (mSharedLibraries.size() > 0) {
+ Iterator<String> libs = mSharedLibraries.values().iterator();
+ while (libs.hasNext()) {
+ String lib = libs.next();
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(lib)) {
+ libFiles.add(lib);
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, true);
+ didDexOpt = true;
}
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Library not found: " + lib);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading library: " + lib, e);
}
}
+ }
- // Gross hack for now: we know this file doesn't contain any
- // code, so don't dexopt it to avoid the resulting log spew.
- libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
-
- /**
- * And there are a number of commands implemented in Java, which
- * we currently need to do the dexopt on so that they can be
- * run from a non-root shell.
- */
- String[] frameworkFiles = mFrameworkDir.list();
- if (frameworkFiles != null) {
- for (int i=0; i<frameworkFiles.length; i++) {
- File libPath = new File(mFrameworkDir, frameworkFiles[i]);
- String path = libPath.getPath();
- // Skip the file if we alrady did it.
- if (libFiles.contains(path)) {
- continue;
- }
- // Skip the file if it is not a type we want to dexopt.
- if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
- continue;
- }
- try {
- if (dalvik.system.DexFile.isDexOptNeeded(path)) {
- mInstaller.dexopt(path, Process.SYSTEM_UID, true);
- didDexOpt = true;
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "Jar not found: " + path);
- } catch (IOException e) {
- Slog.w(TAG, "Exception reading jar: " + path, e);
+ // Gross hack for now: we know this file doesn't contain any
+ // code, so don't dexopt it to avoid the resulting log spew.
+ libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
+
+ /**
+ * And there are a number of commands implemented in Java, which
+ * we currently need to do the dexopt on so that they can be
+ * run from a non-root shell.
+ */
+ String[] frameworkFiles = mFrameworkDir.list();
+ if (frameworkFiles != null) {
+ for (int i=0; i<frameworkFiles.length; i++) {
+ File libPath = new File(mFrameworkDir, frameworkFiles[i]);
+ String path = libPath.getPath();
+ // Skip the file if we alrady did it.
+ if (libFiles.contains(path)) {
+ continue;
+ }
+ // Skip the file if it is not a type we want to dexopt.
+ if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
+ continue;
+ }
+ try {
+ if (dalvik.system.DexFile.isDexOptNeeded(path)) {
+ mInstaller.dexopt(path, Process.SYSTEM_UID, true);
+ didDexOpt = true;
}
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "Jar not found: " + path);
+ } catch (IOException e) {
+ Slog.w(TAG, "Exception reading jar: " + path, e);
}
}
+ }
- if (didDexOpt) {
- // If we had to do a dexopt of one of the previous
- // things, then something on the system has changed.
- // Consider this significant, and wipe away all other
- // existing dexopt files to ensure we don't leave any
- // dangling around.
- String[] files = mDalvikCacheDir.list();
- if (files != null) {
- for (int i=0; i<files.length; i++) {
- String fn = files[i];
- if (fn.startsWith("data@app@")
- || fn.startsWith("data@app-private@")) {
- Slog.i(TAG, "Pruning dalvik file: " + fn);
- (new File(mDalvikCacheDir, fn)).delete();
- }
+ if (didDexOpt) {
+ // If we had to do a dexopt of one of the previous
+ // things, then something on the system has changed.
+ // Consider this significant, and wipe away all other
+ // existing dexopt files to ensure we don't leave any
+ // dangling around.
+ String[] files = mDalvikCacheDir.list();
+ if (files != null) {
+ for (int i=0; i<files.length; i++) {
+ String fn = files[i];
+ if (fn.startsWith("data@app@")
+ || fn.startsWith("data@app-private@")) {
+ Slog.i(TAG, "Pruning dalvik file: " + fn);
+ (new File(mDalvikCacheDir, fn)).delete();
}
}
}
@@ -969,11 +943,9 @@ public class PackageManagerService extends IPackageManager.Stub {
scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);
- if (mInstaller != null) {
- if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
- mInstaller.moveFiles();
- }
-
+ if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
+ mInstaller.moveFiles();
+
// Prune any system packages that no longer exist.
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
@@ -985,19 +957,12 @@ public class PackageManagerService extends IPackageManager.Stub {
String msg = "System package " + ps.name
+ " no longer exists; wiping its data";
reportSettingsProblem(Log.WARN, msg);
- if (mInstaller != null) {
- mInstaller.remove(ps.name, 0);
- mUserManager.removePackageForAllUsers(ps.name);
- }
+ mInstaller.remove(ps.name, 0);
+ mUserManager.removePackageForAllUsers(ps.name);
}
}
mAppInstallDir = new File(dataDir, "app");
- if (mInstaller == null) {
- // Make sure these dirs exist, when we are running in
- // the simulator.
- mAppInstallDir.mkdirs(); // scanDirLI() assumes this dir exists
- }
//look for any incomplete package installations
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
//clean up list
@@ -1071,19 +1036,12 @@ public class PackageManagerService extends IPackageManager.Stub {
void cleanupInstallFailedPackage(PackageSetting ps) {
Slog.i(TAG, "Cleaning up incompletely installed app: " + ps.name);
- if (mInstaller != null) {
- int retCode = mInstaller.remove(ps.name, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data directory for package: "
- + ps.name + ", retcode=" + retCode);
- } else {
- mUserManager.removePackageForAllUsers(ps.name);
- }
+ int retCode = mInstaller.remove(ps.name, 0);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove app data directory for package: "
+ + ps.name + ", retcode=" + retCode);
} else {
- //for emulator
- PackageParser.Package pkg = mPackages.get(ps.name);
- File dataDir = new File(pkg.applicationInfo.dataDir);
- dataDir.delete();
+ mUserManager.removePackageForAllUsers(ps.name);
}
if (ps.codePath != null) {
if (!ps.codePath.delete()) {
@@ -1566,12 +1524,10 @@ public class PackageManagerService extends IPackageManager.Stub {
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- if (mInstaller != null) {
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
- }
- } //end if mInstaller
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
+ }
if (observer != null) {
try {
observer.onRemoveCompleted(null, (retCode >= 0));
@@ -1591,11 +1547,9 @@ public class PackageManagerService extends IPackageManager.Stub {
public void run() {
mHandler.removeCallbacks(this);
int retCode = -1;
- if (mInstaller != null) {
- retCode = mInstaller.freeCache(freeStorageSize);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't clear application caches");
- }
+ retCode = mInstaller.freeCache(freeStorageSize);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't clear application caches");
}
if(pi != null) {
try {
@@ -2854,7 +2808,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) {
boolean performed = false;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0 && mInstaller != null) {
+ if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
String path = pkg.mScanPath;
int ret = 0;
try {
@@ -3239,42 +3193,39 @@ public class PackageManagerService extends IPackageManager.Stub {
mOutPermissions[1] = 0;
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
- // If we have mismatched owners for the data path, we have a
- // problem (unless we're running in the simulator.)
- if (mOutPermissions[1] != pkg.applicationInfo.uid && Process.supportsProcesses()) {
+ // If we have mismatched owners for the data path, we have a problem.
+ if (mOutPermissions[1] != pkg.applicationInfo.uid) {
boolean recovered = false;
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
// If this is a system app, we can at least delete its
// current data so the application will still work.
- if (mInstaller != null) {
- int ret = mInstaller.remove(pkgName, 0);
- if (ret >= 0) {
- // TODO: Kill the processes first
- // Remove the data directories for all users
- mUserManager.removePackageForAllUsers(pkgName);
- // Old data gone!
- String msg = "System package " + pkg.packageName
- + " has changed from uid: "
- + mOutPermissions[1] + " to "
- + pkg.applicationInfo.uid + "; old data erased";
+ int ret = mInstaller.remove(pkgName, 0);
+ if (ret >= 0) {
+ // TODO: Kill the processes first
+ // Remove the data directories for all users
+ mUserManager.removePackageForAllUsers(pkgName);
+ // Old data gone!
+ String msg = "System package " + pkg.packageName
+ + " has changed from uid: "
+ + mOutPermissions[1] + " to "
+ + pkg.applicationInfo.uid + "; old data erased";
+ reportSettingsProblem(Log.WARN, msg);
+ recovered = true;
+
+ // And now re-install the app.
+ ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
+ pkg.applicationInfo.uid);
+ if (ret == -1) {
+ // Ack should not happen!
+ msg = "System package " + pkg.packageName
+ + " could not have data directory re-created after delete.";
reportSettingsProblem(Log.WARN, msg);
- recovered = true;
-
- // And now re-install the app.
- ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
- if (ret == -1) {
- // Ack should not happen!
- msg = "System package " + pkg.packageName
- + " could not have data directory re-created after delete.";
- reportSettingsProblem(Log.WARN, msg);
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
- }
- // Create data directories for all users
- mUserManager.installPackageForAllUsers(pkgName,
- pkg.applicationInfo.uid);
+ mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return null;
}
+ // Create data directories for all users
+ mUserManager.installPackageForAllUsers(pkgName,
+ pkg.applicationInfo.uid);
}
if (!recovered) {
mHasSystemUidErrors = true;
@@ -3307,25 +3258,16 @@ public class PackageManagerService extends IPackageManager.Stub {
Log.v(TAG, "Want this data dir: " + dataPath);
}
//invoke installer to do the actual installation
- if (mInstaller != null) {
- int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
- pkg.applicationInfo.uid);
- if (ret < 0) {
- // Error from installer
- mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- return null;
- }
- // Create data directories for all users
- mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
- } else {
- dataPath.mkdirs();
- if (dataPath.exists()) {
- FileUtils.setPermissions(
- dataPath.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
- pkg.applicationInfo.uid, pkg.applicationInfo.uid);
- }
+ int ret = mInstaller.install(pkgName, pkg.applicationInfo.uid,
+ pkg.applicationInfo.uid);
+ if (ret < 0) {
+ // Error from installer
+ mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ return null;
}
+ // Create data directories for all users
+ mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid);
+
if (dataPath.exists()) {
pkg.applicationInfo.dataDir = dataPath.getPath();
} else {
@@ -3356,65 +3298,62 @@ public class PackageManagerService extends IPackageManager.Stub {
pkgSetting.uidError = uidError;
}
- // If we're running in the simulator, we don't need to unpack anything.
- if (mInstaller != null) {
- String path = scanFile.getPath();
- /* Note: We don't want to unpack the native binaries for
- * system applications, unless they have been updated
- * (the binaries are already under /system/lib).
- * Also, don't unpack libs for apps on the external card
- * since they should have their libraries in the ASEC
- * container already.
- *
- * In other words, we're going to unpack the binaries
- * only for non-system apps and system app upgrades.
- */
- if (pkg.applicationInfo.nativeLibraryDir != null) {
- try {
- final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
- final String dataPathString = dataPath.getCanonicalFile().getPath();
+ String path = scanFile.getPath();
+ /* Note: We don't want to unpack the native binaries for
+ * system applications, unless they have been updated
+ * (the binaries are already under /system/lib).
+ * Also, don't unpack libs for apps on the external card
+ * since they should have their libraries in the ASEC
+ * container already.
+ *
+ * In other words, we're going to unpack the binaries
+ * only for non-system apps and system app upgrades.
+ */
+ if (pkg.applicationInfo.nativeLibraryDir != null) {
+ try {
+ final File nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+ final String dataPathString = dataPath.getCanonicalFile().getPath();
- if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
- /*
- * Upgrading from a previous version of the OS sometimes
- * leaves native libraries in the /data/data/<app>/lib
- * directory for system apps even when they shouldn't be.
- * Recent changes in the JNI library search path
- * necessitates we remove those to match previous behavior.
- */
- if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) {
- Log.i(TAG, "removed obsolete native libraries for system package "
- + path);
- }
- } else if (nativeLibraryDir.getCanonicalFile().getParent()
- .equals(dataPathString)) {
- /*
- * If this is an internal application or our
- * nativeLibraryPath points to our data directory, unpack
- * the libraries. The native library path pointing to the
- * data directory for an application in an ASEC container
- * can happen for older apps that existed before an OTA to
- * Gingerbread.
- */
- Slog.i(TAG, "Unpacking native libraries for " + path);
- mInstaller.unlinkNativeLibraryDirectory(dataPathString);
- NativeLibraryHelper.copyNativeBinariesLI(scanFile, nativeLibraryDir);
- } else {
- Slog.i(TAG, "Linking native library dir for " + path);
- mInstaller.linkNativeLibraryDirectory(dataPathString,
- pkg.applicationInfo.nativeLibraryDir);
+ if (isSystemApp(pkg) && !isUpdatedSystemApp(pkg)) {
+ /*
+ * Upgrading from a previous version of the OS sometimes
+ * leaves native libraries in the /data/data/<app>/lib
+ * directory for system apps even when they shouldn't be.
+ * Recent changes in the JNI library search path
+ * necessitates we remove those to match previous behavior.
+ */
+ if (NativeLibraryHelper.removeNativeBinariesFromDirLI(nativeLibraryDir)) {
+ Log.i(TAG, "removed obsolete native libraries for system package "
+ + path);
}
- } catch (IOException ioe) {
- Log.e(TAG, "Unable to get canonical file " + ioe.toString());
+ } else if (nativeLibraryDir.getCanonicalFile().getParent()
+ .equals(dataPathString)) {
+ /*
+ * If this is an internal application or our
+ * nativeLibraryPath points to our data directory, unpack
+ * the libraries. The native library path pointing to the
+ * data directory for an application in an ASEC container
+ * can happen for older apps that existed before an OTA to
+ * Gingerbread.
+ */
+ Slog.i(TAG, "Unpacking native libraries for " + path);
+ mInstaller.unlinkNativeLibraryDirectory(dataPathString);
+ NativeLibraryHelper.copyNativeBinariesLI(scanFile, nativeLibraryDir);
+ } else {
+ Slog.i(TAG, "Linking native library dir for " + path);
+ mInstaller.linkNativeLibraryDirectory(dataPathString,
+ pkg.applicationInfo.nativeLibraryDir);
}
+ } catch (IOException ioe) {
+ Log.e(TAG, "Unable to get canonical file " + ioe.toString());
}
- pkg.mScanPath = path;
+ }
+ pkg.mScanPath = path;
- if ((scanMode&SCAN_NO_DEX) == 0) {
- if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
- mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
- return null;
- }
+ if ((scanMode&SCAN_NO_DEX) == 0) {
+ if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) {
+ mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT;
+ return null;
}
}
@@ -4887,8 +4826,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private final IPackageStatsObserver mObserver;
- public MeasureParams(PackageStats stats, boolean success,
- IPackageStatsObserver observer) {
+ public MeasureParams(PackageStats stats, boolean success, IPackageStatsObserver observer) {
mObserver = observer;
mStats = stats;
mSuccess = success;
@@ -5439,7 +5377,7 @@ public class PackageManagerService extends IPackageManager.Stub {
void cleanUpResourcesLI() {
String sourceDir = getCodePath();
- if (cleanUp() && mInstaller != null) {
+ if (cleanUp()) {
int retCode = mInstaller.rmdex(sourceDir);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
@@ -5480,6 +5418,17 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ /**
+ * Extract the MountService "container ID" from the full code path of an
+ * .apk.
+ */
+ static String cidFromCodePath(String fullCodePath) {
+ int eidx = fullCodePath.lastIndexOf("/");
+ String subStr1 = fullCodePath.substring(0, eidx);
+ int sidx = subStr1.lastIndexOf("/");
+ return subStr1.substring(sidx+1, eidx);
+ }
+
class SdInstallArgs extends InstallArgs {
static final String RES_FILE_NAME = "pkg.apk";
@@ -5656,14 +5605,12 @@ public class PackageManagerService extends IPackageManager.Stub {
void cleanUpResourcesLI() {
String sourceFile = getCodePath();
// Remove dex file
- if (mInstaller != null) {
- int retCode = mInstaller.rmdex(sourceFile);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove dex file for package: "
- + " at location "
- + sourceFile.toString() + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- }
+ int retCode = mInstaller.rmdex(sourceFile);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove dex file for package: "
+ + " at location "
+ + sourceFile.toString() + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
}
cleanUp();
}
@@ -6071,9 +6018,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
if((res.returnCode = setPermissionsLI(newPackage))
!= PackageManager.INSTALL_SUCCEEDED) {
- if (mInstaller != null) {
- mInstaller.rmdex(newPackage.mScanPath);
- }
+ mInstaller.rmdex(newPackage.mScanPath);
return;
} else {
Log.d(TAG, "New package installed in " + newPackage.mPath);
@@ -6201,15 +6146,8 @@ public class PackageManagerService extends IPackageManager.Stub {
} finally {
//TODO clean up the extracted public files
}
- if (mInstaller != null) {
- retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
- newPackage.applicationInfo.uid);
- } else {
- final int filePermissions =
- FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP;
- retCode = FileUtils.setPermissions(newPackage.mPath, filePermissions, -1,
- newPackage.applicationInfo.uid);
- }
+ retCode = mInstaller.setForwardLockPerm(getApkName(newPackage.mPath),
+ newPackage.applicationInfo.uid);
} else {
// The permissions on the resource file was set when it was copied for
// non forward locked apps and apps on sdcard
@@ -6472,25 +6410,14 @@ public class PackageManagerService extends IPackageManager.Stub {
deletedPs = mSettings.mPackages.get(packageName);
}
if ((flags&PackageManager.DONT_DELETE_DATA) == 0) {
- if (mInstaller != null) {
- int retCode = mInstaller.remove(packageName, 0);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
- + packageName + ", retcode=" + retCode);
- // we don't consider this to be a failure of the core package deletion
- } else {
- // TODO: Kill the processes first
- mUserManager.removePackageForAllUsers(packageName);
- }
+ int retCode = mInstaller.remove(packageName, 0);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove app data or cache directory for package: "
+ + packageName + ", retcode=" + retCode);
+ // we don't consider this to be a failure of the core package deletion
} else {
- // for simulator
- File dataDir;
- // reader
- synchronized (mPackages) {
- PackageParser.Package pkg = mPackages.get(packageName);
- dataDir = new File(pkg.applicationInfo.dataDir);
- }
- dataDir.delete();
+ // TODO: Kill the processes first
+ mUserManager.removePackageForAllUsers(packageName);
}
schedulePackageCleaning(packageName);
}
@@ -6739,13 +6666,11 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
}
- if (mInstaller != null) {
- int retCode = mInstaller.clearUserData(packageName, 0); // TODO - correct userId
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: "
- + packageName);
- return false;
- }
+ int retCode = mInstaller.clearUserData(packageName, 0); // TODO - correct userId
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove cache files for package: "
+ + packageName);
+ return false;
}
return true;
}
@@ -6791,13 +6716,11 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- if (mInstaller != null) {
- int retCode = mInstaller.deleteCacheFiles(packageName);
- if (retCode < 0) {
- Slog.w(TAG, "Couldn't remove cache files for package: "
- + packageName);
- return false;
- }
+ int retCode = mInstaller.deleteCacheFiles(packageName);
+ if (retCode < 0) {
+ Slog.w(TAG, "Couldn't remove cache files for package: "
+ + packageName);
+ return false;
}
return true;
}
@@ -6831,6 +6754,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
PackageParser.Package p;
boolean dataOnly = false;
+ String asecPath = null;
synchronized (mPackages) {
p = mPackages.get(packageName);
if(p == null) {
@@ -6842,6 +6766,12 @@ public class PackageManagerService extends IPackageManager.Stub {
}
p = ps.pkg;
}
+ if (p != null && isExternal(p)) {
+ String secureContainerId = cidFromCodePath(p.applicationInfo.sourceDir);
+ if (secureContainerId != null) {
+ asecPath = PackageHelper.getSdFilesystem(secureContainerId);
+ }
+ }
}
String publicSrcDir = null;
if(!dataOnly) {
@@ -6850,16 +6780,15 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
- }
- if (mInstaller != null) {
- int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir, pStats);
- if (res < 0) {
- return false;
- } else {
- return true;
+ if (isForwardLocked(p)) {
+ publicSrcDir = applicationInfo.publicSourceDir;
}
}
+ int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
+ asecPath, pStats);
+ if (res < 0) {
+ return false;
+ }
return true;
}
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 918f1b6..1ab570a 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -45,7 +45,6 @@ import android.os.storage.StorageVolume;
import android.os.SystemProperties;
import android.os.UEventObserver;
import android.provider.Settings;
-import android.util.Log;
import android.util.Slog;
import java.io.File;
@@ -62,7 +61,7 @@ import java.util.List;
public class UsbDeviceManager {
private static final String TAG = UsbDeviceManager.class.getSimpleName();
- private static final boolean LOG = false;
+ private static final boolean DEBUG = false;
private static final String USB_STATE_MATCH =
"DEVPATH=/devices/virtual/android_usb/android0";
@@ -73,7 +72,9 @@ public class UsbDeviceManager {
private static final String STATE_PATH =
"/sys/class/android_usb/android0/state";
private static final String MASS_STORAGE_FILE_PATH =
- "/sys/class/android_usb/f_mass_storage/lun/file";
+ "/sys/class/android_usb/android0/f_mass_storage/lun/file";
+ private static final String RNDIS_ETH_ADDR_PATH =
+ "/sys/class/android_usb/android0/f_rndis/ethaddr";
private static final int MSG_UPDATE_STATE = 0;
private static final int MSG_ENABLE_ADB = 1;
@@ -93,18 +94,9 @@ public class UsbDeviceManager {
private final UsbSettingsManager mSettingsManager;
private NotificationManager mNotificationManager;
private final boolean mHasUsbAccessory;
-
- // for USB connected notification
- private boolean mUsbNotificationShown;
private boolean mUseUsbNotification;
- private Notification mUsbNotification;
-
- // for adb connected notification
- private boolean mAdbNotificationShown;
- private Notification mAdbNotification;
private boolean mAdbEnabled;
-
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
super(null);
@@ -117,115 +109,20 @@ public class UsbDeviceManager {
}
}
- private void updateUsbNotification(boolean connected) {
- if (mNotificationManager == null || !mUseUsbNotification) return;
- if (connected) {
- if (!mUsbNotificationShown) {
- Resources r = mContext.getResources();
- CharSequence title = r.getText(
- com.android.internal.R.string.usb_preferences_notification_title);
- CharSequence message = r.getText(
- com.android.internal.R.string.usb_preferece_notification_message);
-
- if (mUsbNotification == null) {
- mUsbNotification = new Notification();
- mUsbNotification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
- mUsbNotification.when = 0;
- mUsbNotification.flags = Notification.FLAG_ONGOING_EVENT;
- mUsbNotification.tickerText = title;
- mUsbNotification.defaults = 0; // please be quiet
- mUsbNotification.sound = null;
- mUsbNotification.vibrate = null;
- }
-
- Intent intent = new Intent();
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- intent.setClassName("com.android.systemui",
- "com.android.systemui.usb.UsbPreferenceActivity");
- PendingIntent pi = PendingIntent.getActivity(mContext, 0,
- intent, 0);
-
- mUsbNotification.setLatestEventInfo(mContext, title, message, pi);
-
- mUsbNotificationShown = true;
- mNotificationManager.notify(
- com.android.internal.R.string.usb_preferences_notification_title,
- mUsbNotification);
- }
-
- } else if (mUsbNotificationShown) {
- mUsbNotificationShown = false;
- mNotificationManager.cancel(
- com.android.internal.R.string.usb_preferences_notification_title);
- }
- }
-
- private void updateAdbNotification(boolean adbEnabled) {
- if (mNotificationManager == null) return;
- if (adbEnabled) {
- if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
-
- if (!mAdbNotificationShown) {
- Resources r = mContext.getResources();
- CharSequence title = r.getText(
- com.android.internal.R.string.adb_active_notification_title);
- CharSequence message = r.getText(
- com.android.internal.R.string.adb_active_notification_message);
-
- if (mAdbNotification == null) {
- mAdbNotification = new Notification();
- mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;
- mAdbNotification.when = 0;
- mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
- mAdbNotification.tickerText = title;
- mAdbNotification.defaults = 0; // please be quiet
- mAdbNotification.sound = null;
- mAdbNotification.vibrate = null;
- }
-
- Intent intent = new Intent(
- Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- // Note: we are hard-coding the component because this is
- // an important security UI that we don't want anyone
- // intercepting.
- intent.setComponent(new ComponentName("com.android.settings",
- "com.android.settings.DevelopmentSettings"));
- PendingIntent pi = PendingIntent.getActivity(mContext, 0,
- intent, 0);
-
- mAdbNotification.setLatestEventInfo(mContext, title, message, pi);
-
- mAdbNotificationShown = true;
- mNotificationManager.notify(
- com.android.internal.R.string.adb_active_notification_title,
- mAdbNotification);
- }
- } else if (mAdbNotificationShown) {
- mAdbNotificationShown = false;
- mNotificationManager.cancel(
- com.android.internal.R.string.adb_active_notification_title);
- }
- }
-
/*
* Listens for uevent messages from the kernel to monitor the USB state
*/
private final UEventObserver mUEventObserver = new UEventObserver() {
@Override
public void onUEvent(UEventObserver.UEvent event) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Slog.v(TAG, "USB UEVENT: " + event.toString());
- }
+ if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
String state = event.get("USB_STATE");
String accessory = event.get("ACCESSORY");
if (state != null) {
mHandler.updateState(state);
} else if ("START".equals(accessory)) {
- Slog.d(TAG, "got accessory start");
+ if (DEBUG) Slog.d(TAG, "got accessory start");
setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);
}
}
@@ -237,6 +134,7 @@ public class UsbDeviceManager {
mSettingsManager = settingsManager;
PackageManager pm = mContext.getPackageManager();
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
+ initRndisAddress();
// create a thread for our Handler
HandlerThread thread = new HandlerThread("UsbDeviceManager",
@@ -271,6 +169,29 @@ public class UsbDeviceManager {
mHandler.sendEmptyMessage(MSG_SYSTEM_READY);
}
+ private static void initRndisAddress() {
+ // configure RNDIS ethernet address based on our serial number using the same algorithm
+ // we had been previously using in kernel board files
+ final int ETH_ALEN = 6;
+ int address[] = new int[ETH_ALEN];
+ // first byte is 0x02 to signify a locally administered address
+ address[0] = 0x02;
+
+ String serial = SystemProperties.get("ro.serialno", "1234567890ABCDEF");
+ int serialLength = serial.length();
+ // XOR the USB serial across the remaining 5 bytes
+ for (int i = 0; i < serialLength; i++) {
+ address[i % (ETH_ALEN - 1) + 1] ^= (int)serial.charAt(i);
+ }
+ String addrString = String.format("%02X:%02X:%02X:%02X:%02X:%02X",
+ address[0], address[1], address[2], address[3], address[4], address[5]);
+ try {
+ FileUtils.stringToFile(RNDIS_ETH_ADDR_PATH, addrString);
+ } catch (IOException e) {
+ Slog.e(TAG, "failed to write to " + RNDIS_ETH_ADDR_PATH);
+ }
+ }
+
private static String addFunction(String functions, String function) {
if (!containsFunction(functions, function)) {
if (functions.length() > 0) {
@@ -319,16 +240,32 @@ public class UsbDeviceManager {
private String mDefaultFunctions;
private UsbAccessory mCurrentAccessory;
private boolean mDeferAccessoryAttached;
+ private int mUsbNotificationId;
+ private boolean mAdbNotificationShown;
+
+ private static final int NOTIFICATION_NONE = 0;
+ private static final int NOTIFICATION_MTP = 1;
+ private static final int NOTIFICATION_PTP = 2;
+ private static final int NOTIFICATION_INSTALLER = 3;
+ private static final int NOTIFICATION_ADB = 4;
public UsbHandler() {
- // Read initial USB state
try {
+ // sanity check the sys.usb.config system property
+ // this may be necessary if we crashed while switching USB configurations
+ String config = SystemProperties.get("sys.usb.config", "none");
+ if (config.equals("none")) {
+ String persistConfig = SystemProperties.get("persist.sys.usb.config", "none");
+ Slog.w(TAG, "resetting config to persistent property: " + persistConfig);
+ SystemProperties.set("sys.usb.config", persistConfig);
+ }
+
+ // Read initial USB state
mCurrentFunctions = FileUtils.readTextFile(
new File(FUNCTIONS_PATH), 0, null).trim();
mDefaultFunctions = mCurrentFunctions;
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
-
mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
// Upgrade step for previous versions that used persist.service.adb.enable
@@ -414,12 +351,12 @@ public class UsbDeviceManager {
} catch (InterruptedException e) {
}
}
- Log.e(TAG, "waitForState(" + state + ") FAILED");
+ Slog.e(TAG, "waitForState(" + state + ") FAILED");
return false;
}
private boolean setUsbConfig(String config) {
- Log.d(TAG, "setUsbConfig(" + config + ")");
+ if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
// set the new configuration
SystemProperties.set("sys.usb.config", config);
return waitForState(config);
@@ -428,7 +365,7 @@ public class UsbDeviceManager {
private void doSetCurrentFunctions(String functions) {
if (!mCurrentFunctions.equals(functions)) {
if (!setUsbConfig("none") || !setUsbConfig(functions)) {
- Log.e(TAG, "Failed to switch USB configuration to " + functions);
+ Slog.e(TAG, "Failed to switch USB configuration to " + functions);
// revert to previous configuration if we fail
setUsbConfig(mCurrentFunctions);
} else {
@@ -438,6 +375,7 @@ public class UsbDeviceManager {
}
private void setAdbEnabled(boolean enable) {
+ if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable != mAdbEnabled) {
mAdbEnabled = enable;
String functions;
@@ -449,7 +387,7 @@ public class UsbDeviceManager {
functions = removeFunction(mDefaultFunctions, UsbManager.USB_FUNCTION_ADB);
}
setCurrentFunction(functions, true);
- updateAdbNotification(mAdbEnabled && mConnected);
+ updateAdbNotification();
}
}
@@ -469,7 +407,7 @@ public class UsbDeviceManager {
String[] strings = nativeGetAccessoryStrings();
if (strings != null) {
mCurrentAccessory = new UsbAccessory(strings);
- Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
+ Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
// defer accessoryAttached if system is not ready
if (mSystemReady) {
mSettingsManager.accessoryAttached(mCurrentAccessory);
@@ -477,12 +415,12 @@ public class UsbDeviceManager {
mDeferAccessoryAttached = true;
}
} else {
- Log.e(TAG, "nativeGetAccessoryStrings failed");
+ Slog.e(TAG, "nativeGetAccessoryStrings failed");
}
} else if (!mConnected) {
// make sure accessory mode is off
// and restore default functions
- Log.d(TAG, "exited USB accessory mode");
+ Slog.d(TAG, "exited USB accessory mode");
setEnabledFunctions(mDefaultFunctions);
if (mCurrentAccessory != null) {
@@ -517,8 +455,8 @@ public class UsbDeviceManager {
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
- updateUsbNotification(mConnected);
- updateAdbNotification(mAdbEnabled && mConnected);
+ updateUsbNotification();
+ updateAdbNotification();
if (containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
@@ -562,8 +500,8 @@ public class UsbDeviceManager {
}
break;
case MSG_SYSTEM_READY:
- updateUsbNotification(mConnected);
- updateAdbNotification(mAdbEnabled && mConnected);
+ updateUsbNotification();
+ updateAdbNotification();
updateUsbState();
if (mCurrentAccessory != null && mDeferAccessoryAttached) {
mSettingsManager.accessoryAttached(mCurrentAccessory);
@@ -576,6 +514,106 @@ public class UsbDeviceManager {
return mCurrentAccessory;
}
+ private void updateUsbNotification() {
+ if (mNotificationManager == null || !mUseUsbNotification) return;
+ if (mConnected) {
+ Resources r = mContext.getResources();
+ CharSequence title = null;
+ int id = NOTIFICATION_NONE;
+ if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
+ title = r.getText(
+ com.android.internal.R.string.usb_mtp_notification_title);
+ id = NOTIFICATION_MTP;
+ } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
+ title = r.getText(
+ com.android.internal.R.string.usb_ptp_notification_title);
+ id = NOTIFICATION_PTP;
+ } else if (containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_MASS_STORAGE)) {
+ title = r.getText(
+ com.android.internal.R.string.usb_cd_installer_notification_title);
+ id = NOTIFICATION_INSTALLER;
+ } else {
+ Slog.e(TAG, "No known USB function in updateUsbNotification");
+ }
+ if (id != mUsbNotificationId) {
+ // clear notification if title needs changing
+ if (mUsbNotificationId != NOTIFICATION_NONE) {
+ mNotificationManager.cancel(mUsbNotificationId);
+ mUsbNotificationId = NOTIFICATION_NONE;
+ }
+ }
+ if (mUsbNotificationId == NOTIFICATION_NONE) {
+ CharSequence message = r.getText(
+ com.android.internal.R.string.usb_notification_message);
+
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
+ notification.when = 0;
+ notification.flags = Notification.FLAG_ONGOING_EVENT;
+ notification.tickerText = title;
+ notification.defaults = 0; // please be quiet
+ notification.sound = null;
+ notification.vibrate = null;
+
+ Intent intent = new Intent(
+ Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ intent.setComponent(new ComponentName("com.android.settings",
+ "com.android.settings.UsbSettings"));
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0,
+ intent, 0);
+ notification.setLatestEventInfo(mContext, title, message, pi);
+ mNotificationManager.notify(id, notification);
+ mUsbNotificationId = id;
+ }
+
+ } else if (mUsbNotificationId != NOTIFICATION_NONE) {
+ mNotificationManager.cancel(mUsbNotificationId);
+ mUsbNotificationId = NOTIFICATION_NONE;
+ }
+ }
+
+ private void updateAdbNotification() {
+ if (mNotificationManager == null) return;
+ if (mAdbEnabled && mConnected) {
+ if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
+
+ if (!mAdbNotificationShown) {
+ Resources r = mContext.getResources();
+ CharSequence title = r.getText(
+ com.android.internal.R.string.adb_active_notification_title);
+ CharSequence message = r.getText(
+ com.android.internal.R.string.adb_active_notification_message);
+
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_sys_adb;
+ notification.when = 0;
+ notification.flags = Notification.FLAG_ONGOING_EVENT;
+ notification.tickerText = title;
+ notification.defaults = 0; // please be quiet
+ notification.sound = null;
+ notification.vibrate = null;
+
+ Intent intent = new Intent(
+ Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ intent.setComponent(new ComponentName("com.android.settings",
+ "com.android.settings.DevelopmentSettings"));
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0,
+ intent, 0);
+ notification.setLatestEventInfo(mContext, title, message, pi);
+ mAdbNotificationShown = true;
+ mNotificationManager.notify(NOTIFICATION_ADB, notification);
+ }
+ } else if (mAdbNotificationShown) {
+ mAdbNotificationShown = false;
+ mNotificationManager.cancel(NOTIFICATION_ADB);
+ }
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw) {
pw.println(" USB Device State:");
pw.println(" Current Functions: " + mCurrentFunctions);
@@ -592,22 +630,23 @@ public class UsbDeviceManager {
}
/* opens the currently attached USB accessory */
- public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
- UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
- if (currentAccessory == null) {
- throw new IllegalArgumentException("no accessory attached");
- }
- if (!currentAccessory.equals(accessory)) {
- String error = accessory.toString()
- + " does not match current accessory "
- + currentAccessory;
- throw new IllegalArgumentException(error);
- }
- mSettingsManager.checkPermission(accessory);
- return nativeOpenAccessory();
+ public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+ UsbAccessory currentAccessory = mHandler.getCurrentAccessory();
+ if (currentAccessory == null) {
+ throw new IllegalArgumentException("no accessory attached");
+ }
+ if (!currentAccessory.equals(accessory)) {
+ String error = accessory.toString()
+ + " does not match current accessory "
+ + currentAccessory;
+ throw new IllegalArgumentException(error);
}
+ mSettingsManager.checkPermission(accessory);
+ return nativeOpenAccessory();
+ }
public void setCurrentFunction(String function, boolean makeDefault) {
+ if (DEBUG) Slog.d(TAG, "setCurrentFunction(" + function + ") default: " + makeDefault);
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault);
}
diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/java/com/android/server/usb/UsbHostManager.java
index 923b049..0a0ff59 100644
--- a/services/java/com/android/server/usb/UsbHostManager.java
+++ b/services/java/com/android/server/usb/UsbHostManager.java
@@ -37,7 +37,6 @@ import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.os.UEventObserver;
import android.provider.Settings;
-import android.util.Log;
import android.util.Slog;
import java.io.File;
@@ -112,7 +111,7 @@ public class UsbHostManager {
synchronized (mLock) {
if (mDevices.get(deviceName) != null) {
- Log.w(TAG, "device already on mDevices list: " + deviceName);
+ Slog.w(TAG, "device already on mDevices list: " + deviceName);
return;
}
@@ -148,7 +147,7 @@ public class UsbHostManager {
} catch (Exception e) {
// beware of index out of bound exceptions, which might happen if
// a device does not set bNumEndpoints correctly
- Log.e(TAG, "error parsing USB descriptors", e);
+ Slog.e(TAG, "error parsing USB descriptors", e);
return;
}
diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/java/com/android/server/usb/UsbSettingsManager.java
index 9113677..0baafbb 100644
--- a/services/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbSettingsManager.java
@@ -35,7 +35,7 @@ import android.hardware.usb.UsbManager;
import android.os.Binder;
import android.os.FileUtils;
import android.os.Process;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.Xml;
@@ -62,6 +62,7 @@ import java.util.List;
class UsbSettingsManager {
private static final String TAG = "UsbSettingsManager";
+ private static final boolean DEBUG = false;
private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml");
private final Context mContext;
@@ -410,9 +411,9 @@ class UsbSettingsManager {
}
}
} catch (FileNotFoundException e) {
- Log.w(TAG, "settings file not found");
+ if (DEBUG) Slog.d(TAG, "settings file not found");
} catch (Exception e) {
- Log.e(TAG, "error reading settings file, deleting to start fresh", e);
+ Slog.e(TAG, "error reading settings file, deleting to start fresh", e);
sSettingsFile.delete();
} finally {
if (stream != null) {
@@ -428,7 +429,7 @@ class UsbSettingsManager {
FileOutputStream fos = null;
try {
FileOutputStream fstr = new FileOutputStream(sSettingsFile);
- Log.d(TAG, "writing settings to " + fstr);
+ if (DEBUG) Slog.d(TAG, "writing settings to " + fstr);
BufferedOutputStream str = new BufferedOutputStream(fstr);
FastXmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, "utf-8");
@@ -457,7 +458,7 @@ class UsbSettingsManager {
FileUtils.sync(fstr);
str.close();
} catch (Exception e) {
- Log.e(TAG, "error writing settings file, deleting to start fresh", e);
+ Slog.e(TAG, "error writing settings file, deleting to start fresh", e);
sSettingsFile.delete();
}
}
@@ -472,7 +473,7 @@ class UsbSettingsManager {
try {
parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
if (parser == null) {
- Log.w(TAG, "no meta-data for " + info);
+ Slog.w(TAG, "no meta-data for " + info);
return false;
}
@@ -494,7 +495,7 @@ class UsbSettingsManager {
XmlUtils.nextElement(parser);
}
} catch (Exception e) {
- Log.w(TAG, "Unable to load component info " + info.toString(), e);
+ Slog.w(TAG, "Unable to load component info " + info.toString(), e);
} finally {
if (parser != null) parser.close();
}
@@ -553,7 +554,7 @@ class UsbSettingsManager {
Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
- Log.d(TAG, "usbDeviceRemoved, sending " + intent);
+ if (DEBUG) Slog.d(TAG, "usbDeviceRemoved, sending " + intent);
mContext.sendBroadcast(intent);
}
@@ -604,7 +605,7 @@ class UsbSettingsManager {
try {
mContext.startActivity(dialogIntent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "unable to start UsbAccessoryUriActivity");
+ Slog.e(TAG, "unable to start UsbAccessoryUriActivity");
}
}
}
@@ -652,7 +653,7 @@ class UsbSettingsManager {
defaultRI.activityInfo.name));
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "startActivity failed", e);
+ Slog.e(TAG, "startActivity failed", e);
}
} else {
Intent resolverIntent = new Intent();
@@ -679,7 +680,7 @@ class UsbSettingsManager {
try {
mContext.startActivity(resolverIntent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "unable to start activity " + resolverIntent);
+ Slog.e(TAG, "unable to start activity " + resolverIntent);
}
}
}
@@ -733,7 +734,7 @@ class UsbSettingsManager {
XmlUtils.nextElement(parser);
}
} catch (Exception e) {
- Log.w(TAG, "Unable to load component info " + aInfo.toString(), e);
+ Slog.w(TAG, "Unable to load component info " + aInfo.toString(), e);
} finally {
if (parser != null) parser.close();
}
@@ -751,7 +752,7 @@ class UsbSettingsManager {
info = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
- Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+ Slog.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
return;
}
@@ -831,7 +832,7 @@ class UsbSettingsManager {
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "unable to start UsbPermissionActivity");
+ Slog.e(TAG, "unable to start UsbPermissionActivity");
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -847,7 +848,7 @@ class UsbSettingsManager {
try {
pi.send(mContext, 0, intent);
} catch (PendingIntent.CanceledException e) {
- Log.w(TAG, "requestPermission PendingIntent was cancelled");
+ if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
}
return;
}
@@ -867,7 +868,7 @@ class UsbSettingsManager {
try {
pi.send(mContext, 0, intent);
} catch (PendingIntent.CanceledException e) {
- Log.w(TAG, "requestPermission PendingIntent was cancelled");
+ if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
}
return;
}
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index ee69311..65007f9 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -551,18 +551,6 @@ public class InputManager {
android.Manifest.permission.INJECT_EVENTS, injectorPid, injectorUid)
== PackageManager.PERMISSION_GRANTED;
}
-
- @SuppressWarnings("unused")
- public boolean filterTouchEvents() {
- return mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_filterTouchEvents);
- }
-
- @SuppressWarnings("unused")
- public boolean filterJumpyTouchEvents() {
- return mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_filterJumpyTouchEvents);
- }
@SuppressWarnings("unused")
public int getVirtualKeyQuietTimeMillis() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 3bf309b..be21ac0 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -231,7 +231,7 @@ public class WindowManagerService extends IWindowManager.Stub
// Maximum number of milliseconds to wait for input devices to be enumerated before
// proceding with safe mode detection.
private static final int INPUT_DEVICES_READY_FOR_SAFE_MODE_DETECTION_TIMEOUT_MILLIS = 1000;
-
+
// Default input dispatching timeout in nanoseconds.
static final long DEFAULT_INPUT_DISPATCHING_TIMEOUT_NANOS = 5000 * 1000000L;
@@ -4886,8 +4886,13 @@ public class WindowManagerService extends IWindowManager.Stub
int fw = frame.width();
int fh = frame.height();
- // First try reducing to fit in x dimension.
- scale = width/(float)fw;
+ // Constrain thumbnail to smaller of screen width or height. Assumes aspect
+ // of thumbnail is the same as the screen (in landscape) or square.
+ if (dw <= dh) {
+ scale = width / (float) fw; // portrait
+ } else {
+ scale = height / (float) fh; // landscape
+ }
// The screen shot will contain the entire screen.
dw = (int)(dw*scale);