diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/java/com/android/server/ConnectivityService.java | 231 | ||||
-rwxr-xr-x | services/java/com/android/server/NotificationManagerService.java | 14 | ||||
-rw-r--r-- | services/java/com/android/server/SystemServer.java | 12 | ||||
-rw-r--r-- | services/java/com/android/server/UsbObserver.java | 207 | ||||
-rwxr-xr-x | services/java/com/android/server/am/ActivityManagerService.java | 5 | ||||
-rw-r--r-- | services/java/com/android/server/connectivity/Tethering.java | 39 | ||||
-rwxr-xr-x | services/java/com/android/server/location/GpsLocationProvider.java | 2 | ||||
-rw-r--r-- | services/java/com/android/server/usb/UsbDeviceSettingsManager.java | 671 | ||||
-rw-r--r-- | services/java/com/android/server/usb/UsbService.java | 475 | ||||
-rw-r--r-- | services/jni/Android.mk | 1 | ||||
-rw-r--r-- | services/jni/com_android_server_UsbService.cpp | 141 | ||||
-rw-r--r-- | services/jni/onload.cpp | 2 | ||||
-rw-r--r-- | services/surfaceflinger/LayerBase.cpp | 12 | ||||
-rw-r--r-- | services/surfaceflinger/LayerBase.h | 2 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 47 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 1 |
16 files changed, 1454 insertions, 408 deletions
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 8560d16..4145854 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -18,10 +18,13 @@ package com.android.server; import android.app.Notification; import android.app.NotificationManager; -import android.content.ContentResolver; import android.content.Context; +import android.content.ContentResolver; +import android.content.ContextWrapper; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; import android.net.ConnectivityManager; import android.net.IConnectivityManager; import android.net.MobileDataStateTracker; @@ -29,6 +32,7 @@ import android.net.NetworkInfo; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.wifi.WifiStateTracker; +import android.net.wimax.WimaxManagerConstants; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -41,19 +45,23 @@ import android.provider.Settings; import android.text.TextUtils; import android.util.EventLog; import android.util.Slog; - import com.android.internal.telephony.Phone; - import com.android.server.connectivity.Tethering; - +import dalvik.system.DexClassLoader; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.GregorianCalendar; import java.util.List; import java.net.InetAddress; import java.net.UnknownHostException; + + /** * @hide */ @@ -103,7 +111,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean mTestMode; private static ConnectivityService sServiceInstance; - private static final int ENABLED = 1; private static final int DISABLED = 0; @@ -381,6 +388,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[netType].teardown(); } break; + case ConnectivityManager.TYPE_WIMAX: + NetworkStateTracker nst = makeWimaxStateTracker(); + if (nst != null) { + nst.startMonitoring(); + } + mNetTrackers[netType] = nst; + break; default: Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " + mNetAttributes[netType].mRadio); @@ -400,6 +414,94 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + private NetworkStateTracker makeWimaxStateTracker() { + //Initialize Wimax + DexClassLoader wimaxClassLoader; + Class wimaxStateTrackerClass = null; + Class wimaxServiceClass = null; + Class wimaxManagerClass; + String wimaxJarLocation; + String wimaxLibLocation; + String wimaxManagerClassName; + String wimaxServiceClassName; + String wimaxStateTrackerClassName; + + NetworkStateTracker wimaxStateTracker = null; + + boolean isWimaxEnabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_wimaxEnabled); + + if (isWimaxEnabled) { + try { + wimaxJarLocation = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxServiceJarLocation); + wimaxLibLocation = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxNativeLibLocation); + wimaxManagerClassName = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxManagerClassname); + wimaxServiceClassName = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxServiceClassname); + wimaxStateTrackerClassName = mContext.getResources().getString( + com.android.internal.R.string.config_wimaxStateTrackerClassname); + + wimaxClassLoader = new DexClassLoader(wimaxJarLocation, + new ContextWrapper(mContext).getCacheDir().getAbsolutePath(), + wimaxLibLocation,ClassLoader.getSystemClassLoader()); + + try { + wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName); + wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName); + wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName); + } catch (ClassNotFoundException ex) { + ex.printStackTrace(); + return null; + } + } catch(Resources.NotFoundException ex) { + Slog.e(TAG, "Wimax Resources does not exist!!! "); + return null; + } + + try { + Slog.v(TAG, "Starting Wimax Service... "); + + Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor + (new Class[] {Context.class,Handler.class}); + wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,mHandler); + + Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor + (new Class[] {Context.class,wimaxStateTrackerClass}); + wmxSrvConst.setAccessible(true); + IBinder svcInvoker = (IBinder) wmxSrvConst.newInstance(mContext,wimaxStateTracker); + wmxSrvConst.setAccessible(false); + + ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker); + + } catch(ClassCastException ex) { + ex.printStackTrace(); + return null; + } catch (NoSuchMethodException ex) { + ex.printStackTrace(); + return null; + } catch (InstantiationException ex) { + ex.printStackTrace(); + return null; + } catch(IllegalAccessException ex) { + ex.printStackTrace(); + return null; + } catch(InvocationTargetException ex) { + ex.printStackTrace(); + return null; + } catch(Exception ex) { + ex.printStackTrace(); + return null; + } + } else { + Slog.e(TAG, "Wimax is not enabled or not added to the network attributes!!! "); + return null; + } + + return wimaxStateTracker; + } /** * Sets the preferred network. @@ -492,18 +594,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ public NetworkInfo getActiveNetworkInfo() { enforceAccessPermission(); - for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { - if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) { - continue; - } - NetworkStateTracker t = mNetTrackers[type]; - NetworkInfo info = t.getNetworkInfo(); - if (info.isConnected()) { - if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG, - "connected default network is not " + - "mActiveDefaultNetwork!"); - return info; - } + if (mActiveDefaultNetwork != -1) { + return mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); } return null; } @@ -1018,18 +1110,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { info.getExtraInfo()); } - NetworkStateTracker newNet = null; if (mNetAttributes[prevNetType].isDefault()) { - newNet = tryFailover(prevNetType); - if (newNet != null) { - NetworkInfo switchTo = newNet.getNetworkInfo(); - if (!switchTo.isConnected()) { - // if the other net is connected they've already reset this and perhaps even gotten - // a positive report we don't want to overwrite, but if not we need to clear this now - // to turn our cellular sig strength white - mDefaultInetConditionPublished = 0; - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } + tryFailover(prevNetType); + if (mActiveDefaultNetwork != -1) { + NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { mDefaultInetConditionPublished = 0; // we're not connected anymore @@ -1045,86 +1129,41 @@ public class ConnectivityService extends IConnectivityManager.Stub { * If the failover network is already connected, then immediately send * out a followup broadcast indicating successful failover */ - if (newNet != null && newNet.getNetworkInfo().isConnected()) { - sendConnectedBroadcast(newNet.getNetworkInfo()); + if (mActiveDefaultNetwork != -1) { + sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); } } - // returns null if no failover available - private NetworkStateTracker tryFailover(int prevNetType) { + private void tryFailover(int prevNetType) { /* * If this is a default network, check if other defaults are available * or active */ - NetworkStateTracker newNet = null; if (mNetAttributes[prevNetType].isDefault()) { if (mActiveDefaultNetwork == prevNetType) { mActiveDefaultNetwork = -1; } - int newType = -1; - int newPriority = -1; boolean noMobileData = !getMobileDataEnabled(); for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { if (checkType == prevNetType) continue; if (mNetAttributes[checkType] == null) continue; + if (mNetAttributes[checkType].isDefault() == false) continue; if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE && noMobileData) { Slog.e(TAG, "not failing over to mobile type " + checkType + " because Mobile Data Disabled"); continue; } - if (mNetAttributes[checkType].isDefault()) { - /* TODO - if we have multiple nets we could use - * we may want to put more thought into which we choose - */ - if (checkType == mNetworkPreference) { - newType = checkType; - break; - } - if (mNetAttributes[checkType].mPriority > newPriority) { - newType = checkType; - newPriority = mNetAttributes[newType].mPriority; - } - } - } - - if (newType != -1) { - newNet = mNetTrackers[newType]; - /** - * See if the other network is available to fail over to. - * If is not available, we enable it anyway, so that it - * will be able to connect when it does become available, - * but we report a total loss of connectivity rather than - * report that we are attempting to fail over. - */ - if (newNet.isAvailable()) { - NetworkInfo switchTo = newNet.getNetworkInfo(); - switchTo.setFailover(true); - if (!switchTo.isConnectedOrConnecting() || - newNet.isTeardownRequested()) { - newNet.reconnect(); - } - if (DBG) { - if (switchTo.isConnected()) { - Slog.v(TAG, "Switching to already connected " + - switchTo.getTypeName()); - } else { - Slog.v(TAG, "Attempting to switch to " + - switchTo.getTypeName()); - } - } - } else { - newNet.reconnect(); - newNet = null; // not officially avail.. try anyway, but - // report no failover + NetworkStateTracker checkTracker = mNetTrackers[checkType]; + NetworkInfo checkInfo = checkTracker.getNetworkInfo(); + if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) { + checkInfo.setFailover(true); + checkTracker.reconnect(); } - } else { - Slog.e(TAG, "Network failover failing."); + if (DBG) Slog.d(TAG, "Attempting to switch to " + checkInfo.getTypeName()); } } - - return newNet; } private void sendConnectedBroadcast(NetworkInfo info) { @@ -1187,17 +1226,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { info.setFailover(false); } - NetworkStateTracker newNet = null; if (mNetAttributes[info.getType()].isDefault()) { - newNet = tryFailover(info.getType()); - if (newNet != null) { - NetworkInfo switchTo = newNet.getNetworkInfo(); - if (!switchTo.isConnected()) { - // if the other net is connected they've already reset this and perhaps - // even gotten a positive report we don't want to overwrite, but if not - // we need to clear this now to turn our cellular sig strength white - mDefaultInetConditionPublished = 0; - } + tryFailover(info.getType()); + if (mActiveDefaultNetwork != -1) { + NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { mDefaultInetConditionPublished = 0; @@ -1211,8 +1243,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { * If the failover network is already connected, then immediately send * out a followup broadcast indicating successful failover */ - if (newNet != null && newNet.getNetworkInfo().isConnected()) { - sendConnectedBroadcast(newNet.getNetworkInfo()); + if (mActiveDefaultNetwork != -1) { + sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); } } @@ -1327,6 +1359,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mNetAttributes[netType].isDefault()) { mNetTrackers[netType].addDefaultRoute(); } else { + // many radios add a default route even when we don't want one. + // remove the default interface unless we need it for our active network + if (mActiveDefaultNetwork != -1) { + String defaultIface = mNetTrackers[mActiveDefaultNetwork].getInterfaceName(); + if (defaultIface != null && + !defaultIface.equals(mNetTrackers[netType].getInterfaceName())) { + mNetTrackers[netType].removeDefaultRoute(); + } + } mNetTrackers[netType].addPrivateDnsRoutes(); } } else { diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 4da5eb2..540389e 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -38,7 +38,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.database.ContentObserver; -import android.hardware.Usb; +import android.hardware.usb.UsbManager; import android.media.AudioManager; import android.net.Uri; import android.os.BatteryManager; @@ -352,14 +352,12 @@ public class NotificationManagerService extends INotificationManager.Stub mBatteryFull = batteryFull; updateLights(); } - } else if (action.equals(Usb.ACTION_USB_STATE)) { + } else if (action.equals(UsbManager.ACTION_USB_STATE)) { Bundle extras = intent.getExtras(); - boolean usbConnected = extras.getBoolean(Usb.USB_CONNECTED); - boolean adbEnabled = (Usb.USB_FUNCTION_ENABLED.equals( - extras.getString(Usb.USB_FUNCTION_ADB))); + boolean usbConnected = extras.getBoolean(UsbManager.USB_CONNECTED); + boolean adbEnabled = (UsbManager.USB_FUNCTION_ENABLED.equals( + extras.getString(UsbManager.USB_FUNCTION_ADB))); updateAdbNotification(usbConnected && adbEnabled); - } else if (action.equals(Usb.ACTION_USB_DISCONNECTED)) { - updateAdbNotification(false); } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART)) @@ -475,7 +473,7 @@ public class NotificationManagerService extends INotificationManager.Stub // register for battery changed notifications IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); - filter.addAction(Usb.ACTION_USB_STATE); + filter.addAction(UsbManager.ACTION_USB_STATE); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index df69b76..0f03f75 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -17,6 +17,7 @@ package com.android.server; import com.android.server.am.ActivityManagerService; +import com.android.server.usb.UsbService; import com.android.internal.app.ShutdownThread; import com.android.internal.os.BinderInternal; import com.android.internal.os.SamplingProfilerIntegration; @@ -122,7 +123,7 @@ class ServerThread extends Thread { BluetoothA2dpService bluetoothA2dp = null; HeadsetObserver headset = null; DockObserver dock = null; - UsbObserver usb = null; + UsbService usb = null; UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; ThrottleService throttle = null; @@ -397,11 +398,12 @@ class ServerThread extends Thread { } try { - Slog.i(TAG, "USB Observer"); + Slog.i(TAG, "USB Service"); // Listen for USB changes - usb = new UsbObserver(context); + usb = new UsbService(context); + ServiceManager.addService(Context.USB_SERVICE, usb); } catch (Throwable e) { - Slog.e(TAG, "Failure starting UsbObserver", e); + Slog.e(TAG, "Failure starting UsbService", e); } try { @@ -493,7 +495,7 @@ class ServerThread extends Thread { final BatteryService batteryF = battery; final ConnectivityService connectivityF = connectivity; final DockObserver dockF = dock; - final UsbObserver usbF = usb; + final UsbService usbF = usb; final ThrottleService throttleF = throttle; final UiModeManagerService uiModeF = uiMode; final AppWidgetService appWidgetF = appWidget; diff --git a/services/java/com/android/server/UsbObserver.java b/services/java/com/android/server/UsbObserver.java deleted file mode 100644 index d08fe9b..0000000 --- a/services/java/com/android/server/UsbObserver.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.hardware.Usb; -import android.net.Uri; -import android.os.Handler; -import android.os.Message; -import android.os.UEventObserver; -import android.provider.Settings; -import android.util.Log; -import android.util.Slog; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.util.ArrayList; - -/** - * <p>UsbObserver monitors for changes to USB state. - */ -class UsbObserver extends UEventObserver { - private static final String TAG = UsbObserver.class.getSimpleName(); - private static final boolean LOG = false; - - private static final String USB_CONFIGURATION_MATCH = "DEVPATH=/devices/virtual/switch/usb_configuration"; - private static final String USB_FUNCTIONS_MATCH = "DEVPATH=/devices/virtual/usb_composite/"; - private static final String USB_CONFIGURATION_PATH = "/sys/class/switch/usb_configuration/state"; - private static final String USB_COMPOSITE_CLASS_PATH = "/sys/class/usb_composite"; - - private static final int MSG_UPDATE = 0; - - private int mUsbConfig = 0; - private int mPreviousUsbConfig = 0; - - // lists of enabled and disabled USB functions - private final ArrayList<String> mEnabledFunctions = new ArrayList<String>(); - private final ArrayList<String> mDisabledFunctions = new ArrayList<String>(); - - private boolean mSystemReady; - - private final Context mContext; - - private PowerManagerService mPowerManager; - - public UsbObserver(Context context) { - mContext = context; - init(); // set initial status - - startObserving(USB_CONFIGURATION_MATCH); - startObserving(USB_FUNCTIONS_MATCH); - } - - @Override - public void onUEvent(UEventObserver.UEvent event) { - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Slog.v(TAG, "USB UEVENT: " + event.toString()); - } - - synchronized (this) { - String switchState = event.get("SWITCH_STATE"); - if (switchState != null) { - try { - int newConfig = Integer.parseInt(switchState); - if (newConfig != mUsbConfig) { - mPreviousUsbConfig = mUsbConfig; - mUsbConfig = newConfig; - // trigger an Intent broadcast - if (mSystemReady) { - update(); - } - } - } catch (NumberFormatException e) { - Slog.e(TAG, "Could not parse switch state from event " + event); - } - } else { - String function = event.get("FUNCTION"); - String enabledStr = event.get("ENABLED"); - if (function != null && enabledStr != null) { - // Note: we do not broadcast a change when a function is enabled or disabled. - // We just record the state change for the next broadcast. - boolean enabled = "1".equals(enabledStr); - if (enabled) { - if (!mEnabledFunctions.contains(function)) { - mEnabledFunctions.add(function); - } - mDisabledFunctions.remove(function); - } else { - if (!mDisabledFunctions.contains(function)) { - mDisabledFunctions.add(function); - } - mEnabledFunctions.remove(function); - } - } - } - } - } - private final void init() { - char[] buffer = new char[1024]; - - try { - FileReader file = new FileReader(USB_CONFIGURATION_PATH); - int len = file.read(buffer, 0, 1024); - mPreviousUsbConfig = mUsbConfig = Integer.valueOf((new String(buffer, 0, len)).trim()); - - } catch (FileNotFoundException e) { - Slog.w(TAG, "This kernel does not have USB configuration switch support"); - } catch (Exception e) { - Slog.e(TAG, "" , e); - } - - try { - File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); - for (int i = 0; i < files.length; i++) { - File file = new File(files[i], "enable"); - FileReader reader = new FileReader(file); - int len = reader.read(buffer, 0, 1024); - int value = Integer.valueOf((new String(buffer, 0, len)).trim()); - String functionName = files[i].getName(); - if (value == 1) { - mEnabledFunctions.add(functionName); - } else { - mDisabledFunctions.add(functionName); - } - } - } catch (FileNotFoundException e) { - Slog.w(TAG, "This kernel does not have USB composite class support"); - } catch (Exception e) { - Slog.e(TAG, "" , e); - } - } - - void systemReady() { - synchronized (this) { - update(); - mSystemReady = true; - } - } - - private final void update() { - mHandler.sendEmptyMessage(MSG_UPDATE); - } - - private final Handler mHandler = new Handler() { - private void addEnabledFunctions(Intent intent) { - // include state of all USB functions in our extras - for (int i = 0; i < mEnabledFunctions.size(); i++) { - intent.putExtra(mEnabledFunctions.get(i), Usb.USB_FUNCTION_ENABLED); - } - for (int i = 0; i < mDisabledFunctions.size(); i++) { - intent.putExtra(mDisabledFunctions.get(i), Usb.USB_FUNCTION_DISABLED); - } - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_UPDATE: - synchronized (this) { - final ContentResolver cr = mContext.getContentResolver(); - - if (Settings.Secure.getInt(cr, - Settings.Secure.DEVICE_PROVISIONED, 0) == 0) { - Slog.i(TAG, "Device not provisioned, skipping USB broadcast"); - return; - } - // Send an Intent containing connected/disconnected state - // and the enabled/disabled state of all USB functions - Intent intent; - boolean usbConnected = (mUsbConfig != 0); - if (usbConnected) { - intent = new Intent(Usb.ACTION_USB_CONNECTED); - addEnabledFunctions(intent); - } else { - intent = new Intent(Usb.ACTION_USB_DISCONNECTED); - } - mContext.sendBroadcast(intent); - - // send a sticky broadcast for clients interested in both connect and disconnect - intent = new Intent(Usb.ACTION_USB_STATE); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - intent.putExtra(Usb.USB_CONNECTED, usbConnected); - addEnabledFunctions(intent); - mContext.sendStickyBroadcast(intent); - } - break; - } - } - }; -} diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 0e38e10..883fdda 100755 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -6694,8 +6694,9 @@ public final class ActivityManagerService extends ActivityManagerNative addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo); - if (Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.WTF_IS_FATAL, 0) != 0) { + if (r != null && r.pid != Process.myPid() && + Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.WTF_IS_FATAL, 0) != 0) { crashApplication(r, crashInfo); return true; } else { diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java index a73a4ce..1ec9b51 100644 --- a/services/java/com/android/server/connectivity/Tethering.java +++ b/services/java/com/android/server/connectivity/Tethering.java @@ -26,7 +26,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; -import android.hardware.Usb; +import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.InterfaceConfiguration; import android.net.IConnectivityManager; @@ -111,14 +111,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub { private boolean mUsbMassStorageOff; // track the status of USB Mass Storage private boolean mUsbConnected; // track the status of USB connection - // mUsbHandler message - static final int USB_STATE_CHANGE = 1; - static final int USB_DISCONNECTED = 0; - static final int USB_CONNECTED = 1; - - // Time to delay before processing USB disconnect events - static final long USB_DISCONNECT_DELAY = 1000; - public Tethering(Context context, Looper looper) { mContext = context; mLooper = looper; @@ -143,7 +135,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub { mStateReceiver = new StateReceiver(); IntentFilter filter = new IntentFilter(); - filter.addAction(Usb.ACTION_USB_STATE); + filter.addAction(UsbManager.ACTION_USB_STATE); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(Intent.ACTION_BOOT_COMPLETED); mContext.registerReceiver(mStateReceiver, filter); @@ -429,25 +421,12 @@ public class Tethering extends INetworkManagementEventObserver.Stub { } } - private Handler mUsbHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - mUsbConnected = (msg.arg1 == USB_CONNECTED); - updateUsbStatus(); - } - }; - private class StateReceiver extends BroadcastReceiver { public void onReceive(Context content, Intent intent) { String action = intent.getAction(); - if (action.equals(Usb.ACTION_USB_STATE)) { - // process connect events immediately, but delay handling disconnects - // to debounce USB configuration changes - boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED); - Message msg = Message.obtain(mUsbHandler, USB_STATE_CHANGE, - (connected ? USB_CONNECTED : USB_DISCONNECTED), 0); - mUsbHandler.removeMessages(USB_STATE_CHANGE); - mUsbHandler.sendMessageDelayed(msg, connected ? 0 : USB_DISCONNECT_DELAY); + if (action.equals(UsbManager.ACTION_USB_STATE)) { + mUsbConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED); + updateUsbStatus(); } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) { mUsbMassStorageOff = false; updateUsbStatus(); @@ -1194,18 +1173,18 @@ public class Tethering extends INetworkManagementEventObserver.Stub { for (String iface : ifaces) { for (String regex : mUpstreamIfaceRegexs) { if (iface.matches(regex)) { - // verify it is up! + // verify it is active InterfaceConfiguration ifcg = null; try { ifcg = service.getInterfaceConfig(iface); + if (ifcg.isActive()) { + return iface; + } } catch (Exception e) { Log.e(TAG, "Error getting iface config :" + e); // ignore - try next continue; } - if (ifcg.interfaceFlags.contains("up")) { - return iface; - } } } } diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java index 3561862..63ce0bd 100755 --- a/services/java/com/android/server/location/GpsLocationProvider.java +++ b/services/java/com/android/server/location/GpsLocationProvider.java @@ -203,7 +203,7 @@ public class GpsLocationProvider implements LocationProviderInterface { // flags to trigger NTP or XTRA data download when network becomes available // initialized to true so we do NTP and XTRA when the network comes up after booting private boolean mInjectNtpTimePending = true; - private boolean mDownloadXtraDataPending = false; + private boolean mDownloadXtraDataPending = true; // true if GPS is navigating private boolean mNavigating; diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java new file mode 100644 index 0000000..616bdca --- /dev/null +++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java @@ -0,0 +1,671 @@ +/* + * Copyright (C) 2011 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.usb; + +import android.app.PendingIntent; +import android.content.ActivityNotFoundException; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.ResolveInfo; +import android.content.res.XmlResourceParser; +import android.hardware.usb.UsbAccessory; +import android.hardware.usb.UsbManager; +import android.os.Binder; +import android.os.FileUtils; +import android.os.Process; +import android.util.Log; +import android.util.SparseBooleanArray; +import android.util.Xml; + +import com.android.internal.content.PackageMonitor; +import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.XmlUtils; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +class UsbDeviceSettingsManager { + + private static final String TAG = "UsbDeviceSettingsManager"; + private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml"); + + private final Context mContext; + private final PackageManager mPackageManager; + + // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory + private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap = + new HashMap<UsbAccessory, SparseBooleanArray>(); + // Maps AccessoryFilter to user preferred application package + private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap = + new HashMap<AccessoryFilter, String>(); + + private final Object mLock = new Object(); + + // This class is used to describe a USB accessory. + // When used in HashMaps all values must be specified, + // but wildcards can be used for any of the fields in + // the package meta-data. + private static class AccessoryFilter { + // USB accessory manufacturer (or null for unspecified) + public final String mManufacturer; + // USB accessory model (or null for unspecified) + public final String mModel; + // USB accessory version (or null for unspecified) + public final String mVersion; + + public AccessoryFilter(String manufacturer, String model, String version) { + mManufacturer = manufacturer; + mModel = model; + mVersion = version; + } + + public AccessoryFilter(UsbAccessory accessory) { + mManufacturer = accessory.getManufacturer(); + mModel = accessory.getModel(); + mVersion = accessory.getVersion(); + } + + public static AccessoryFilter read(XmlPullParser parser) + throws XmlPullParserException, IOException { + String manufacturer = null; + String model = null; + String version = null; + + int count = parser.getAttributeCount(); + for (int i = 0; i < count; i++) { + String name = parser.getAttributeName(i); + String value = parser.getAttributeValue(i); + + if ("manufacturer".equals(name)) { + manufacturer = value; + } else if ("model".equals(name)) { + model = value; + } else if ("version".equals(name)) { + version = value; + } + } + return new AccessoryFilter(manufacturer, model, version); + } + + public void write(XmlSerializer serializer)throws IOException { + serializer.startTag(null, "usb-accessory"); + if (mManufacturer != null) { + serializer.attribute(null, "manufacturer", mManufacturer); + } + if (mModel != null) { + serializer.attribute(null, "model", mModel); + } + if (mVersion != null) { + serializer.attribute(null, "version", mVersion); + } + serializer.endTag(null, "usb-accessory"); + } + + public boolean matches(UsbAccessory acc) { + if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false; + if (mModel != null && !acc.getModel().equals(mModel)) return false; + if (mVersion != null && !acc.getVersion().equals(mVersion)) return false; + return true; + } + + public boolean matches(AccessoryFilter f) { + if (mManufacturer != null && !f.mManufacturer.equals(mManufacturer)) return false; + if (mModel != null && !f.mModel.equals(mModel)) return false; + if (mVersion != null && !f.mVersion.equals(mVersion)) return false; + return true; + } + + @Override + public boolean equals(Object obj) { + // can't compare if we have wildcard strings + if (mManufacturer == null || mModel == null || mVersion == null) { + return false; + } + if (obj instanceof AccessoryFilter) { + AccessoryFilter filter = (AccessoryFilter)obj; + return (mManufacturer.equals(filter.mManufacturer) && + mModel.equals(filter.mModel) && + mVersion.equals(filter.mVersion)); + } + if (obj instanceof UsbAccessory) { + UsbAccessory accessory = (UsbAccessory)obj; + return (mManufacturer.equals(accessory.getManufacturer()) && + mModel.equals(accessory.getModel()) && + mVersion.equals(accessory.getVersion())); + } + return false; + } + + @Override + public int hashCode() { + return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^ + (mModel == null ? 0 : mModel.hashCode()) ^ + (mVersion == null ? 0 : mVersion.hashCode())); + } + + @Override + public String toString() { + return "AccessoryFilter[mManufacturer=\"" + mManufacturer + + "\", mModel=\"" + mModel + + "\", mVersion=\"" + mVersion + "\"]"; + } + } + + private class MyPackageMonitor extends PackageMonitor { + + public void onPackageAdded(String packageName, int uid) { + handlePackageUpdate(packageName); + } + + public void onPackageChanged(String packageName, int uid, String[] components) { + handlePackageUpdate(packageName); + } + + public void onPackageRemoved(String packageName, int uid) { + clearDefaults(packageName); + } + } + MyPackageMonitor mPackageMonitor = new MyPackageMonitor(); + + public UsbDeviceSettingsManager(Context context) { + mContext = context; + mPackageManager = context.getPackageManager(); + synchronized (mLock) { + readSettingsLocked(); + } + mPackageMonitor.register(context, true); + } + + private void readPreference(XmlPullParser parser) + throws XmlPullParserException, IOException { + String packageName = null; + int count = parser.getAttributeCount(); + for (int i = 0; i < count; i++) { + if ("package".equals(parser.getAttributeName(i))) { + packageName = parser.getAttributeValue(i); + break; + } + } + XmlUtils.nextElement(parser); + if ("usb-accessory".equals(parser.getName())) { + AccessoryFilter filter = AccessoryFilter.read(parser); + mAccessoryPreferenceMap.put(filter, packageName); + } + XmlUtils.nextElement(parser); + } + + private void readSettingsLocked() { + FileInputStream stream = null; + try { + stream = new FileInputStream(sSettingsFile); + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(stream, null); + + XmlUtils.nextElement(parser); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if ("preference".equals(tagName)) { + readPreference(parser); + } else { + XmlUtils.nextElement(parser); + } + } + } catch (FileNotFoundException e) { + Log.w(TAG, "settings file not found"); + } catch (Exception e) { + Log.e(TAG, "error reading settings file, deleting to start fresh", e); + sSettingsFile.delete(); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + } + } + } + } + + private void writeSettingsLocked() { + FileOutputStream fos = null; + try { + FileOutputStream fstr = new FileOutputStream(sSettingsFile); + Log.d(TAG, "writing settings to " + fstr); + BufferedOutputStream str = new BufferedOutputStream(fstr); + FastXmlSerializer serializer = new FastXmlSerializer(); + serializer.setOutput(str, "utf-8"); + serializer.startDocument(null, true); + serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); + serializer.startTag(null, "settings"); + + for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) { + serializer.startTag(null, "preference"); + serializer.attribute(null, "package", mAccessoryPreferenceMap.get(filter)); + filter.write(serializer); + serializer.endTag(null, "preference"); + } + + serializer.endTag(null, "settings"); + serializer.endDocument(); + + str.flush(); + FileUtils.sync(fstr); + str.close(); + } catch (Exception e) { + Log.e(TAG, "error writing settings file, deleting to start fresh", e); + sSettingsFile.delete(); + } + } + + // Checks to see if a package matches an accessory. + private boolean packageMatchesLocked(ResolveInfo info, String metaDataName, + UsbAccessory accessory) { + ActivityInfo ai = info.activityInfo; + + XmlResourceParser parser = null; + try { + parser = ai.loadXmlMetaData(mPackageManager, metaDataName); + if (parser == null) { + Log.w(TAG, "no meta-data for " + info); + return false; + } + + XmlUtils.nextElement(parser); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if (accessory != null && "usb-accessory".equals(tagName)) { + AccessoryFilter filter = AccessoryFilter.read(parser); + if (filter.matches(accessory)) { + return true; + } + } + XmlUtils.nextElement(parser); + } + } catch (Exception e) { + Log.w(TAG, "Unable to load component info " + info.toString(), e); + } finally { + if (parser != null) parser.close(); + } + return false; + } + + private final ArrayList<ResolveInfo> getAccessoryMatchesLocked( + UsbAccessory accessory, Intent intent) { + ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>(); + List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent, + PackageManager.GET_META_DATA); + int count = resolveInfos.size(); + for (int i = 0; i < count; i++) { + ResolveInfo resolveInfo = resolveInfos.get(i); + if (packageMatchesLocked(resolveInfo, intent.getAction(), accessory)) { + matches.add(resolveInfo); + } + } + return matches; + } + + public void accessoryAttached(UsbAccessory accessory) { + Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED); + intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + ArrayList<ResolveInfo> matches; + String defaultPackage; + synchronized (mLock) { + matches = getAccessoryMatchesLocked(accessory, intent); + // Launch our default activity directly, if we have one. + // Otherwise we will start the UsbResolverActivity to allow the user to choose. + defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory)); + } + + resolveActivity(intent, matches, defaultPackage, accessory); + } + + public void accessoryDetached(UsbAccessory accessory) { + // clear temporary permissions for the accessory + mAccessoryPermissionMap.remove(accessory); + + Intent intent = new Intent( + UsbManager.ACTION_USB_ACCESSORY_DETACHED); + intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + mContext.sendBroadcast(intent); + } + + private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches, + String defaultPackage, UsbAccessory accessory) { + int count = matches.size(); + + // don't show the resolver activity if there are no choices available + if (count == 0) { + if (accessory != null) { + String uri = accessory.getUri(); + if (uri != null && uri.length() > 0) { + // display URI to user + // start UsbResolverActivity so user can choose an activity + Intent dialogIntent = new Intent(); + dialogIntent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbAccessoryUriActivity"); + dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + dialogIntent.putExtra("uri", uri); + try { + mContext.startActivity(dialogIntent); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "unable to start UsbAccessoryUriActivity"); + } + } + } + + // do nothing + return; + } + + ResolveInfo defaultRI = null; + if (count == 1 && defaultPackage == null) { + // Check to see if our single choice is on the system partition. + // If so, treat it as our default without calling UsbResolverActivity + ResolveInfo rInfo = matches.get(0); + if (rInfo.activityInfo != null && + rInfo.activityInfo.applicationInfo != null && + (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + defaultRI = rInfo; + } + } + + if (defaultRI == null && defaultPackage != null) { + // look for default activity + for (int i = 0; i < count; i++) { + ResolveInfo rInfo = matches.get(i); + if (rInfo.activityInfo != null && + defaultPackage.equals(rInfo.activityInfo.packageName)) { + defaultRI = rInfo; + break; + } + } + } + + if (defaultRI != null) { + // grant permission for default activity + grantAccessoryPermission(accessory, defaultRI.activityInfo.applicationInfo.uid); + + // start default activity directly + try { + intent.setComponent( + new ComponentName(defaultRI.activityInfo.packageName, + defaultRI.activityInfo.name)); + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "startActivity failed", e); + } + } else { + Intent resolverIntent = new Intent(); + resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + if (count == 1) { + // start UsbConfirmActivity if there is only one choice + resolverIntent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbConfirmActivity"); + resolverIntent.putExtra("rinfo", matches.get(0)); + resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + } else { + // start UsbResolverActivity so user can choose an activity + resolverIntent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbResolverActivity"); + resolverIntent.putParcelableArrayListExtra("rlist", matches); + resolverIntent.putExtra(Intent.EXTRA_INTENT, intent); + } + try { + mContext.startActivity(resolverIntent); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "unable to start activity " + resolverIntent); + } + } + } + + private boolean clearCompatibleMatchesLocked(String packageName, AccessoryFilter filter) { + boolean changed = false; + for (AccessoryFilter test : mAccessoryPreferenceMap.keySet()) { + if (filter.matches(test)) { + mAccessoryPreferenceMap.remove(test); + changed = true; + } + } + return changed; + } + + private boolean handlePackageUpdateLocked(String packageName, ActivityInfo aInfo, + String metaDataName) { + XmlResourceParser parser = null; + boolean changed = false; + + try { + parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName); + if (parser == null) return false; + + XmlUtils.nextElement(parser); + while (parser.getEventType() != XmlPullParser.END_DOCUMENT) { + String tagName = parser.getName(); + if ("usb-accessory".equals(tagName)) { + AccessoryFilter filter = AccessoryFilter.read(parser); + if (clearCompatibleMatchesLocked(packageName, filter)) { + changed = true; + } + } + XmlUtils.nextElement(parser); + } + } catch (Exception e) { + Log.w(TAG, "Unable to load component info " + aInfo.toString(), e); + } finally { + if (parser != null) parser.close(); + } + return changed; + } + + // Check to see if the package supports any USB devices or accessories. + // If so, clear any non-matching preferences for matching devices/accessories. + private void handlePackageUpdate(String packageName) { + synchronized (mLock) { + PackageInfo info; + boolean changed = false; + + try { + info = mPackageManager.getPackageInfo(packageName, + PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA); + } catch (NameNotFoundException e) { + Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e); + return; + } + + ActivityInfo[] activities = info.activities; + if (activities == null) return; + for (int i = 0; i < activities.length; i++) { + // check for meta-data, both for devices and accessories + if (handlePackageUpdateLocked(packageName, activities[i], + UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) { + changed = true; + } + } + + if (changed) { + writeSettingsLocked(); + } + } + } + + public boolean hasPermission(UsbAccessory accessory) { + synchronized (mLock) { + SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); + if (uidList == null) { + return false; + } + return uidList.get(Binder.getCallingUid()); + } + } + + public void checkPermission(UsbAccessory accessory) { + if (!hasPermission(accessory)) { + throw new SecurityException("User has not given permission to accessory " + accessory); + } + } + + private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) { + int uid = Binder.getCallingUid(); + + // compare uid with packageName to foil apps pretending to be someone else + try { + ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0); + if (aInfo.uid != uid) { + throw new IllegalArgumentException("package " + packageName + + " does not match caller's uid " + uid); + } + } catch (PackageManager.NameNotFoundException e) { + throw new IllegalArgumentException("package " + packageName + " not found"); + } + + long identity = Binder.clearCallingIdentity(); + intent.setClassName("com.android.systemui", + "com.android.systemui.usb.UsbPermissionActivity"); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(Intent.EXTRA_INTENT, pi); + intent.putExtra("package", packageName); + intent.putExtra("uid", uid); + try { + mContext.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "unable to start UsbPermissionActivity"); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) { + Intent intent = new Intent(); + + // respond immediately if permission has already been granted + if (hasPermission(accessory)) { + intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true); + try { + pi.send(mContext, 0, intent); + } catch (PendingIntent.CanceledException e) { + Log.w(TAG, "requestPermission PendingIntent was cancelled"); + } + return; + } + + intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory); + requestPermissionDialog(intent, packageName, pi); + } + + public void setAccessoryPackage(UsbAccessory accessory, String packageName) { + AccessoryFilter filter = new AccessoryFilter(accessory); + boolean changed = false; + synchronized (mLock) { + if (packageName == null) { + changed = (mAccessoryPreferenceMap.remove(filter) != null); + } else { + changed = !packageName.equals(mAccessoryPreferenceMap.get(filter)); + if (changed) { + mAccessoryPreferenceMap.put(filter, packageName); + } + } + if (changed) { + writeSettingsLocked(); + } + } + } + + public void grantAccessoryPermission(UsbAccessory accessory, int uid) { + synchronized (mLock) { + SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); + if (uidList == null) { + uidList = new SparseBooleanArray(1); + mAccessoryPermissionMap.put(accessory, uidList); + } + uidList.put(uid, true); + } + } + + public boolean hasDefaults(String packageName) { + synchronized (mLock) { + return mAccessoryPreferenceMap.values().contains(packageName); + } + } + + public void clearDefaults(String packageName) { + synchronized (mLock) { + if (clearPackageDefaultsLocked(packageName)) { + writeSettingsLocked(); + } + } + } + + private boolean clearPackageDefaultsLocked(String packageName) { + boolean cleared = false; + synchronized (mLock) { + if (mAccessoryPreferenceMap.containsValue(packageName)) { + // make a copy of the key set to avoid ConcurrentModificationException + Object[] keys = mAccessoryPreferenceMap.keySet().toArray(); + for (int i = 0; i < keys.length; i++) { + Object key = keys[i]; + if (packageName.equals(mAccessoryPreferenceMap.get(key))) { + mAccessoryPreferenceMap.remove(key); + cleared = true; + } + } + } + return cleared; + } + } + + public void dump(FileDescriptor fd, PrintWriter pw) { + synchronized (mLock) { + pw.println(" Accessory permissions:"); + for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) { + pw.print(" " + accessory + ": "); + SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory); + int count = uidList.size(); + for (int i = 0; i < count; i++) { + pw.print(Integer.toString(uidList.keyAt(i)) + " "); + } + pw.println(""); + } + pw.println(" Accessory preferences:"); + for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) { + pw.println(" " + filter + ": " + mAccessoryPreferenceMap.get(filter)); + } + } + } +} diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java new file mode 100644 index 0000000..f366e10 --- /dev/null +++ b/services/java/com/android/server/usb/UsbService.java @@ -0,0 +1,475 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.usb; + +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.hardware.usb.IUsbManager; +import android.hardware.usb.UsbAccessory; +import android.hardware.usb.UsbManager; +import android.net.Uri; +import android.os.Binder; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +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; +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * UsbService monitors for changes to USB state. + * This includes code for both USB host support (where the android device is the host) + * as well as USB device support (android device is connected to a USB host). + * Accessory mode is a special case of USB device mode, where the android device is + * connected to a USB host that supports the android accessory protocol. + */ +public class UsbService extends IUsbManager.Stub { + private static final String TAG = UsbService.class.getSimpleName(); + private static final boolean LOG = false; + + private static final String USB_CONNECTED_MATCH = + "DEVPATH=/devices/virtual/switch/usb_connected"; + private static final String USB_CONFIGURATION_MATCH = + "DEVPATH=/devices/virtual/switch/usb_configuration"; + private static final String USB_FUNCTIONS_MATCH = + "DEVPATH=/devices/virtual/usb_composite/"; + private static final String USB_CONNECTED_PATH = + "/sys/class/switch/usb_connected/state"; + private static final String USB_CONFIGURATION_PATH = + "/sys/class/switch/usb_configuration/state"; + private static final String USB_COMPOSITE_CLASS_PATH = + "/sys/class/usb_composite"; + + private static final int MSG_UPDATE_STATE = 0; + private static final int MSG_FUNCTION_ENABLED = 1; + private static final int MSG_FUNCTION_DISABLED = 2; + + // Delay for debouncing USB disconnects. + // We often get rapid connect/disconnect events when enabling USB functions, + // which need debouncing. + private static final int UPDATE_DELAY = 1000; + + // current connected and configuration state + private int mConnected; + private int mConfiguration; + + // last broadcasted connected and configuration state + private int mLastConnected = -1; + private int mLastConfiguration = -1; + + // lists of enabled and disabled USB functions (for USB device mode) + private final ArrayList<String> mEnabledFunctions = new ArrayList<String>(); + private final ArrayList<String> mDisabledFunctions = new ArrayList<String>(); + + private boolean mSystemReady; + + private UsbAccessory mCurrentAccessory; + // USB functions that are enabled by default, to restore after exiting accessory mode + private final ArrayList<String> mDefaultFunctions = new ArrayList<String>(); + + private final Context mContext; + private final Object mLock = new Object(); + private final UsbDeviceSettingsManager mDeviceManager; + private final boolean mHasUsbAccessory; + + private final void readCurrentAccessoryLocked() { + if (mHasUsbAccessory) { + String[] strings = nativeGetAccessoryStrings(); + if (strings != null) { + mCurrentAccessory = new UsbAccessory(strings); + Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory); + if (mSystemReady) { + mDeviceManager.accessoryAttached(mCurrentAccessory); + } + } else { + Log.e(TAG, "nativeGetAccessoryStrings failed"); + } + } + } + + /* + * Handles USB function enable/disable events (device mode) + */ + private final void functionEnabledLocked(String function, boolean enabled) { + if (enabled) { + if (!mEnabledFunctions.contains(function)) { + mEnabledFunctions.add(function); + } + mDisabledFunctions.remove(function); + + if (UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) { + readCurrentAccessoryLocked(); + } + } else { + if (!mDisabledFunctions.contains(function)) { + mDisabledFunctions.add(function); + } + mEnabledFunctions.remove(function); + } + } + + /* + * Listens for uevent messages from the kernel to monitor the USB state (device mode) + */ + 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()); + } + + synchronized (mLock) { + String name = event.get("SWITCH_NAME"); + String state = event.get("SWITCH_STATE"); + if (name != null && state != null) { + try { + int intState = Integer.parseInt(state); + if ("usb_connected".equals(name)) { + mConnected = intState; + // trigger an Intent broadcast + if (mSystemReady) { + // debounce disconnects to avoid problems bringing up USB tethering + update(mConnected == 0); + } + } else if ("usb_configuration".equals(name)) { + mConfiguration = intState; + // trigger an Intent broadcast + if (mSystemReady) { + update(mConnected == 0); + } + } + } catch (NumberFormatException e) { + Slog.e(TAG, "Could not parse switch state from event " + event); + } + } else { + String function = event.get("FUNCTION"); + String enabledStr = event.get("ENABLED"); + if (function != null && enabledStr != null) { + // Note: we do not broadcast a change when a function is enabled or disabled. + // We just record the state change for the next broadcast. + int what = ("1".equals(enabledStr) ? + MSG_FUNCTION_ENABLED : MSG_FUNCTION_DISABLED); + Message msg = Message.obtain(mHandler, what); + msg.obj = function; + mHandler.sendMessage(msg); + } + } + } + } + }; + + private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() { + public void onReceive(Context context, Intent intent) { + // handle accessories attached at boot time + synchronized (mLock) { + if (mCurrentAccessory != null) { + mDeviceManager.accessoryAttached(mCurrentAccessory); + } + } + } + }; + + public UsbService(Context context) { + mContext = context; + mDeviceManager = new UsbDeviceSettingsManager(context); + PackageManager pm = mContext.getPackageManager(); + mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY); + + synchronized (mLock) { + init(); // set initial status + + // Watch for USB configuration changes + if (mConfiguration >= 0) { + mUEventObserver.startObserving(USB_CONNECTED_MATCH); + mUEventObserver.startObserving(USB_CONFIGURATION_MATCH); + mUEventObserver.startObserving(USB_FUNCTIONS_MATCH); + } + } + } + + private final void init() { + char[] buffer = new char[1024]; + boolean inAccessoryMode = false; + + // Read initial USB state (device mode) + mConfiguration = -1; + try { + FileReader file = new FileReader(USB_CONNECTED_PATH); + int len = file.read(buffer, 0, 1024); + file.close(); + mConnected = Integer.valueOf((new String(buffer, 0, len)).trim()); + + file = new FileReader(USB_CONFIGURATION_PATH); + len = file.read(buffer, 0, 1024); + file.close(); + mConfiguration = Integer.valueOf((new String(buffer, 0, len)).trim()); + + } catch (FileNotFoundException e) { + Slog.i(TAG, "This kernel does not have USB configuration switch support"); + } catch (Exception e) { + Slog.e(TAG, "" , e); + } + if (mConfiguration < 0) { + // This may happen in the emulator or devices without USB device mode support + return; + } + + // Read initial list of enabled and disabled functions (device mode) + try { + File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles(); + for (int i = 0; i < files.length; i++) { + File file = new File(files[i], "enable"); + FileReader reader = new FileReader(file); + int len = reader.read(buffer, 0, 1024); + reader.close(); + int value = Integer.valueOf((new String(buffer, 0, len)).trim()); + String functionName = files[i].getName(); + if (value == 1) { + mEnabledFunctions.add(functionName); + if (UsbManager.USB_FUNCTION_ACCESSORY.equals(functionName)) { + // The USB accessory driver is on by default, but it might have been + // enabled before the USB service has initialized. + inAccessoryMode = true; + } else if (!UsbManager.USB_FUNCTION_ADB.equals(functionName)) { + // adb is enabled/disabled automatically by the adbd daemon, + // so don't treat it as a default function. + mDefaultFunctions.add(functionName); + } + } else { + mDisabledFunctions.add(functionName); + } + } + } catch (FileNotFoundException e) { + Slog.w(TAG, "This kernel does not have USB composite class support"); + } catch (Exception e) { + Slog.e(TAG, "" , e); + } + + // handle the case where an accessory switched the driver to accessory mode + // before the framework finished booting + if (inAccessoryMode) { + readCurrentAccessoryLocked(); + + // FIXME - if we booted in accessory mode, then we have no way to figure out + // which functions are enabled by default. + // For now, assume that MTP or mass storage are the only possibilities + if (mDisabledFunctions.contains(UsbManager.USB_FUNCTION_MTP)) { + mDefaultFunctions.add(UsbManager.USB_FUNCTION_MTP); + } else if (mDisabledFunctions.contains(UsbManager.USB_FUNCTION_MASS_STORAGE)) { + mDefaultFunctions.add(UsbManager.USB_FUNCTION_MASS_STORAGE); + } + } + } + + public void systemReady() { + synchronized (mLock) { + update(false); + if (mCurrentAccessory != null) { + Log.d(TAG, "accessoryAttached at systemReady"); + // its still too early to handle accessories, so add a BOOT_COMPLETED receiver + // to handle this later. + mContext.registerReceiver(mBootCompletedReceiver, + new IntentFilter(Intent.ACTION_BOOT_COMPLETED)); + } + mSystemReady = true; + } + } + + /* + * Sends a message to update the USB connected and configured state (device mode). + * If delayed is true, then we add a small delay in sending the message to debounce + * the USB connection when enabling USB tethering. + */ + private final void update(boolean delayed) { + mHandler.removeMessages(MSG_UPDATE_STATE); + mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATE, delayed ? UPDATE_DELAY : 0); + } + + /* returns the currently attached USB accessory (device mode) */ + public UsbAccessory getCurrentAccessory() { + return mCurrentAccessory; + } + + /* opens the currently attached USB accessory (device mode) */ + public ParcelFileDescriptor openAccessory(UsbAccessory accessory) { + synchronized (mLock) { + if (mCurrentAccessory == null) { + throw new IllegalArgumentException("no accessory attached"); + } + if (!mCurrentAccessory.equals(accessory)) { + Log.e(TAG, accessory.toString() + " does not match current accessory " + + mCurrentAccessory); + throw new IllegalArgumentException("accessory not attached"); + } + mDeviceManager.checkPermission(mCurrentAccessory); + return nativeOpenAccessory(); + } + } + + public void setAccessoryPackage(UsbAccessory accessory, String packageName) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + mDeviceManager.setAccessoryPackage(accessory, packageName); + } + + public boolean hasAccessoryPermission(UsbAccessory accessory) { + return mDeviceManager.hasPermission(accessory); + } + + public void requestAccessoryPermission(UsbAccessory accessory, String packageName, + PendingIntent pi) { + mDeviceManager.requestPermission(accessory, packageName, pi); + } + + public void grantAccessoryPermission(UsbAccessory accessory, int uid) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + mDeviceManager.grantAccessoryPermission(accessory, uid); + } + + public boolean hasDefaults(String packageName) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + return mDeviceManager.hasDefaults(packageName); + } + + public void clearDefaults(String packageName) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null); + mDeviceManager.clearDefaults(packageName); + } + + /* + * This handler is for deferred handling of events related to device mode and accessories. + */ + private final Handler mHandler = new Handler() { + private void addEnabledFunctionsLocked(Intent intent) { + // include state of all USB functions in our extras + for (int i = 0; i < mEnabledFunctions.size(); i++) { + intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED); + } + for (int i = 0; i < mDisabledFunctions.size(); i++) { + intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED); + } + } + + @Override + public void handleMessage(Message msg) { + synchronized (mLock) { + switch (msg.what) { + case MSG_UPDATE_STATE: + if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) { + if (mConnected == 0) { + // make sure accessory mode is off, and restore default functions + if (mCurrentAccessory != null && UsbManager.setFunctionEnabled( + UsbManager.USB_FUNCTION_ACCESSORY, false)) { + Log.d(TAG, "exited USB accessory mode"); + + int count = mDefaultFunctions.size(); + for (int i = 0; i < count; i++) { + String function = mDefaultFunctions.get(i); + if (!UsbManager.setFunctionEnabled(function, true)) { + Log.e(TAG, "could not reenable function " + function); + } + } + + mDeviceManager.accessoryDetached(mCurrentAccessory); + mCurrentAccessory = null; + } + } + + final ContentResolver cr = mContext.getContentResolver(); + if (Settings.Secure.getInt(cr, + Settings.Secure.DEVICE_PROVISIONED, 0) == 0) { + Slog.i(TAG, "Device not provisioned, skipping USB broadcast"); + return; + } + + mLastConnected = mConnected; + mLastConfiguration = mConfiguration; + + // send a sticky broadcast containing current USB state + Intent intent = new Intent(UsbManager.ACTION_USB_STATE); + intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); + intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0); + intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration); + addEnabledFunctionsLocked(intent); + mContext.sendStickyBroadcast(intent); + } + break; + case MSG_FUNCTION_ENABLED: + case MSG_FUNCTION_DISABLED: + functionEnabledLocked((String)msg.obj, msg.what == MSG_FUNCTION_ENABLED); + break; + } + } + } + }; + + @Override + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump UsbManager from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + synchronized (mLock) { + pw.println("USB Manager State:"); + + pw.println(" USB Device State:"); + pw.print(" Enabled Functions: "); + for (int i = 0; i < mEnabledFunctions.size(); i++) { + pw.print(mEnabledFunctions.get(i) + " "); + } + pw.println(""); + pw.print(" Disabled Functions: "); + for (int i = 0; i < mDisabledFunctions.size(); i++) { + pw.print(mDisabledFunctions.get(i) + " "); + } + pw.println(""); + pw.print(" Default Functions: "); + for (int i = 0; i < mDefaultFunctions.size(); i++) { + pw.print(mDefaultFunctions.get(i) + " "); + } + pw.println(""); + pw.println(" mConnected: " + mConnected + ", mConfiguration: " + mConfiguration); + pw.println(" mCurrentAccessory: " + mCurrentAccessory); + + mDeviceManager.dump(fd, pw); + } + } + + // accessory support + private native String[] nativeGetAccessoryStrings(); + private native ParcelFileDescriptor nativeOpenAccessory(); +} diff --git a/services/jni/Android.mk b/services/jni/Android.mk index c90879d..de8f158 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES:= \ com_android_server_LightsService.cpp \ com_android_server_PowerManagerService.cpp \ com_android_server_SystemServer.cpp \ + com_android_server_UsbService.cpp \ com_android_server_VibratorService.cpp \ com_android_server_location_GpsLocationProvider.cpp \ onload.cpp diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp new file mode 100644 index 0000000..92c5008 --- /dev/null +++ b/services/jni/com_android_server_UsbService.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "UsbService" +#include "utils/Log.h" + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" +#include "utils/Vector.h" + +#include <stdio.h> +#include <asm/byteorder.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <linux/usb/f_accessory.h> + +#define DRIVER_NAME "/dev/usb_accessory" + +namespace android +{ + +static struct file_descriptor_offsets_t +{ + jclass mClass; + jmethodID mConstructor; + jfieldID mDescriptor; +} gFileDescriptorOffsets; + +static struct parcel_file_descriptor_offsets_t +{ + jclass mClass; + jmethodID mConstructor; +} gParcelFileDescriptorOffsets; + +static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + LOGE("An exception was thrown by callback '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); + } +} + +static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strArray, int index) +{ + char buffer[256]; + + buffer[0] = 0; + int length = ioctl(fd, cmd, buffer); + if (buffer[0]) { + jstring obj = env->NewStringUTF(buffer); + env->SetObjectArrayElement(strArray, index, obj); + env->DeleteLocalRef(obj); + } +} + + +static jobjectArray android_server_UsbService_getAccessoryStrings(JNIEnv *env, jobject thiz) +{ + int fd = open(DRIVER_NAME, O_RDWR); + if (fd < 0) { + LOGE("could not open %s", DRIVER_NAME); + return NULL; + } + jclass stringClass = env->FindClass("java/lang/String"); + jobjectArray strArray = env->NewObjectArray(6, stringClass, NULL); + if (!strArray) goto out; + set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0); + set_accessory_string(env, fd, ACCESSORY_GET_STRING_MODEL, strArray, 1); + set_accessory_string(env, fd, ACCESSORY_GET_STRING_DESCRIPTION, strArray, 2); + set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3); + set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4); + set_accessory_string(env, fd, ACCESSORY_GET_STRING_SERIAL, strArray, 5); + +out: + close(fd); + return strArray; +} + +static jobject android_server_UsbService_openAccessory(JNIEnv *env, jobject thiz) +{ + int fd = open(DRIVER_NAME, O_RDWR); + if (fd < 0) { + LOGE("could not open %s", DRIVER_NAME); + return NULL; + } + jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass, + gFileDescriptorOffsets.mConstructor); + if (fileDescriptor != NULL) { + env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd); + } else { + return NULL; + } + return env->NewObject(gParcelFileDescriptorOffsets.mClass, + gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); +} + +static JNINativeMethod method_table[] = { + { "nativeGetAccessoryStrings", "()[Ljava/lang/String;", + (void*)android_server_UsbService_getAccessoryStrings }, + { "nativeOpenAccessory","()Landroid/os/ParcelFileDescriptor;", + (void*)android_server_UsbService_openAccessory }, +}; + +int register_android_server_UsbService(JNIEnv *env) +{ + jclass clazz = env->FindClass("java/io/FileDescriptor"); + LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor"); + gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V"); + gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I"); + LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL, + "Unable to find descriptor field in java.io.FileDescriptor"); + + clazz = env->FindClass("android/os/ParcelFileDescriptor"); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor"); + gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V"); + LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL, + "Unable to find constructor for android.os.ParcelFileDescriptor"); + + return jniRegisterNativeMethods(env, "com/android/server/usb/UsbService", + method_table, NELEM(method_table)); +} + +}; diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index cd4f0a4..613683b 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -9,6 +9,7 @@ int register_android_server_BatteryService(JNIEnv* env); int register_android_server_InputManager(JNIEnv* env); int register_android_server_LightsService(JNIEnv* env); int register_android_server_PowerManagerService(JNIEnv* env); +int register_android_server_UsbService(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); int register_android_server_location_GpsLocationProvider(JNIEnv* env); @@ -32,6 +33,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_LightsService(env); register_android_server_AlarmManagerService(env); register_android_server_BatteryService(env); + register_android_server_UsbService(env); register_android_server_VibratorService(env); register_android_server_SystemServer(env); register_android_server_location_GpsLocationProvider(env); diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 916d420..21c36e1 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -515,12 +515,6 @@ void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const result.append(buffer); } -void LayerBase::shortDump(String8& result, char* scratch, size_t size) const -{ - LayerBase::dump(result, scratch, size); -} - - // --------------------------------------------------------------------------- int32_t LayerBaseClient::sIdentity = 1; @@ -572,12 +566,6 @@ void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const result.append(buffer); } - -void LayerBaseClient::shortDump(String8& result, char* scratch, size_t size) const -{ - LayerBaseClient::dump(result, scratch, size); -} - // --------------------------------------------------------------------------- LayerBaseClient::Surface::Surface( diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 1470729..afc5ec8 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -206,7 +206,6 @@ public: /** always call base class first */ virtual void dump(String8& result, char* scratch, size_t size) const; - virtual void shortDump(String8& result, char* scratch, size_t size) const; enum { // flags for doTransaction() @@ -326,7 +325,6 @@ public: protected: virtual void dump(String8& result, char* scratch, size_t size) const; - virtual void shortDump(String8& result, char* scratch, size_t size) const; private: mutable Mutex mLock; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 4876946..c08e2c9 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1066,12 +1066,8 @@ status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase) status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase) { - // First add the layer to the purgatory list, which makes sure it won't - // go away, then remove it from the main list (through a transaction). + // remove the layer from the main list (through a transaction). ssize_t err = removeLayer_l(layerBase); - if (err >= 0) { - mLayerPurgatory.add(layerBase); - } layerBase->onRemoved(); @@ -1342,19 +1338,6 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer) * to use the purgatory. */ status_t err = flinger->removeLayer_l(l); - if (err == NAME_NOT_FOUND) { - // The surface wasn't in the current list, which means it was - // removed already, which means it is in the purgatory, - // and need to be removed from there. - // This needs to happen from the main thread since its dtor - // must run from there (b/c of OpenGL ES). Additionally, we - // can't really acquire our internal lock from - // destroySurface() -- see postMessage() below. - ssize_t idx = flinger->mLayerPurgatory.remove(l); - LOGE_IF(idx < 0, - "layer=%p is not in the purgatory list", l.get()); - } - LOGE_IF(err<0 && err != NAME_NOT_FOUND, "error removing layer=%p (%s)", l.get(), strerror(-err)); return true; @@ -1470,13 +1453,8 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) result.append(buffer); } - /* - * Dump the visible layer list - */ const LayerVector& currentLayers = mCurrentState.layersSortedByZ; const size_t count = currentLayers.size(); - snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count); - result.append(buffer); for (size_t i=0 ; i<count ; i++) { const sp<LayerBase>& layer(currentLayers[i]); layer->dump(result, buffer, SIZE); @@ -1486,24 +1464,6 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) layer->visibleRegionScreen.dump(result, "visibleRegionScreen"); } - /* - * Dump the layers in the purgatory - */ - - const size_t purgatorySize = mLayerPurgatory.size(); - snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize); - result.append(buffer); - for (size_t i=0 ; i<purgatorySize ; i++) { - const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i)); - layer->shortDump(result, buffer, SIZE); - } - - /* - * Dump SurfaceFlinger global state - */ - - snprintf(buffer, SIZE, "SurfaceFlinger global state\n"); - result.append(buffer); mWormholeRegion.dump(result, "WormholeRegion"); const DisplayHardware& hw(graphicPlane(0).displayHardware()); snprintf(buffer, SIZE, @@ -1529,9 +1489,6 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) result.append(buffer); } - /* - * Dump gralloc state - */ const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); alloc.dump(result); @@ -2427,7 +2384,7 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const } break; } - if (++name > 31) + if (++name >= SharedBufferStack::NUM_LAYERS_MAX) name = NO_MEMORY; } while(name >= 0); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a023347..df1ca48 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -370,7 +370,6 @@ private: volatile int32_t mTransactionFlags; volatile int32_t mTransactionCount; Condition mTransactionCV; - SortedVector< sp<LayerBase> > mLayerPurgatory; bool mResizeTransationPending; // protected by mStateLock (but we could use another lock) |