diff options
Diffstat (limited to 'services/java')
12 files changed, 933 insertions, 111 deletions
diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/java/com/android/server/CommonTimeManagementService.java new file mode 100644 index 0000000..9a25d2e --- /dev/null +++ b/services/java/com/android/server/CommonTimeManagementService.java @@ -0,0 +1,377 @@ +/* + * Copyright (C) 2012 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 java.io.FileDescriptor; +import java.io.PrintWriter; +import java.net.InetAddress; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.IConnectivityManager; +import android.net.INetworkManagementEventObserver; +import android.net.InterfaceConfiguration; +import android.net.NetworkInfo; +import android.os.Binder; +import android.os.CommonTimeConfig; +import android.os.Handler; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.SystemProperties; +import android.util.Log; + +/** + * @hide + * <p>CommonTimeManagementService manages the configuration of the native Common Time service, + * reconfiguring the native service as appropriate in response to changes in network configuration. + */ +class CommonTimeManagementService extends Binder { + /* + * Constants and globals. + */ + private static final String TAG = CommonTimeManagementService.class.getSimpleName(); + private static final int NATIVE_SERVICE_RECONNECT_TIMEOUT = 5000; + private static final String AUTO_DISABLE_PROP = "ro.common_time.auto_disable"; + private static final String ALLOW_WIFI_PROP = "ro.common_time.allow_wifi"; + private static final String SERVER_PRIO_PROP = "ro.common_time.server_prio"; + private static final String NO_INTERFACE_TIMEOUT_PROP = "ro.common_time.no_iface_timeout"; + private static final boolean AUTO_DISABLE; + private static final boolean ALLOW_WIFI; + private static final byte BASE_SERVER_PRIO; + private static final int NO_INTERFACE_TIMEOUT; + private static final InterfaceScoreRule[] IFACE_SCORE_RULES; + + static { + int tmp; + AUTO_DISABLE = (0 != SystemProperties.getInt(AUTO_DISABLE_PROP, 1)); + ALLOW_WIFI = (0 != SystemProperties.getInt(ALLOW_WIFI_PROP, 0)); + tmp = SystemProperties.getInt(SERVER_PRIO_PROP, 1); + NO_INTERFACE_TIMEOUT = SystemProperties.getInt(NO_INTERFACE_TIMEOUT_PROP, 60000); + + if (tmp < 1) + BASE_SERVER_PRIO = 1; + else + if (tmp > 30) + BASE_SERVER_PRIO = 30; + else + BASE_SERVER_PRIO = (byte)tmp; + + if (ALLOW_WIFI) { + IFACE_SCORE_RULES = new InterfaceScoreRule[] { + new InterfaceScoreRule("wlan", (byte)1), + new InterfaceScoreRule("eth", (byte)2), + }; + } else { + IFACE_SCORE_RULES = new InterfaceScoreRule[] { + new InterfaceScoreRule("eth", (byte)2), + }; + } + }; + + /* + * Internal state + */ + private final Context mContext; + private INetworkManagementService mNetMgr; + private CommonTimeConfig mCTConfig; + private String mCurIface; + private Handler mReconnectHandler = new Handler(); + private Handler mNoInterfaceHandler = new Handler(); + private Object mLock = new Object(); + private boolean mDetectedAtStartup = false; + private byte mEffectivePrio = BASE_SERVER_PRIO; + + /* + * Callback handler implementations. + */ + private INetworkManagementEventObserver mIfaceObserver = + new INetworkManagementEventObserver.Stub() { + + public void interfaceStatusChanged(String iface, boolean up) { + reevaluateServiceState(); + } + public void interfaceLinkStateChanged(String iface, boolean up) { + reevaluateServiceState(); + } + public void interfaceAdded(String iface) { + reevaluateServiceState(); + } + public void interfaceRemoved(String iface) { + reevaluateServiceState(); + } + public void limitReached(String limitName, String iface) { } + }; + + private BroadcastReceiver mConnectivityMangerObserver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + reevaluateServiceState(); + } + }; + + private CommonTimeConfig.OnServerDiedListener mCTServerDiedListener = + new CommonTimeConfig.OnServerDiedListener() { + public void onServerDied() { + scheduleTimeConfigReconnect(); + } + }; + + private Runnable mReconnectRunnable = new Runnable() { + public void run() { connectToTimeConfig(); } + }; + + private Runnable mNoInterfaceRunnable = new Runnable() { + public void run() { handleNoInterfaceTimeout(); } + }; + + /* + * Public interface (constructor, systemReady and dump) + */ + public CommonTimeManagementService(Context context) { + mContext = context; + } + + void systemReady() { + if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) { + Log.i(TAG, "No common time service detected on this platform. " + + "Common time services will be unavailable."); + return; + } + + mDetectedAtStartup = true; + + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNetMgr = INetworkManagementService.Stub.asInterface(b); + + // Network manager is running along-side us, so we should never receiver a remote exception + // while trying to register this observer. + try { + mNetMgr.registerObserver(mIfaceObserver); + } + catch (RemoteException e) { } + + // Register with the connectivity manager for connectivity changed intents. + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + mContext.registerReceiver(mConnectivityMangerObserver, filter); + + // Connect to the common time config service and apply the initial configuration. + connectToTimeConfig(); + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println(String.format( + "Permission Denial: can't dump CommonTimeManagement service from from " + + "pid=%d, uid=%d", Binder.getCallingPid(), Binder.getCallingUid())); + return; + } + + if (!mDetectedAtStartup) { + pw.println("Native Common Time service was not detected at startup. " + + "Service is unavailable"); + return; + } + + synchronized (mLock) { + pw.println("Current Common Time Management Service Config:"); + pw.println(String.format(" Native service : %s", + (null == mCTConfig) ? "reconnecting" + : "alive")); + pw.println(String.format(" Bound interface : %s", + (null == mCurIface ? "unbound" : mCurIface))); + pw.println(String.format(" Allow WiFi : %s", ALLOW_WIFI ? "yes" : "no")); + pw.println(String.format(" Allow Auto Disable : %s", AUTO_DISABLE ? "yes" : "no")); + pw.println(String.format(" Server Priority : %d", mEffectivePrio)); + pw.println(String.format(" No iface timeout : %d", NO_INTERFACE_TIMEOUT)); + } + } + + /* + * Inner helper classes + */ + private static class InterfaceScoreRule { + public final String mPrefix; + public final byte mScore; + public InterfaceScoreRule(String prefix, byte score) { + mPrefix = prefix; + mScore = score; + } + }; + + /* + * Internal implementation + */ + private void cleanupTimeConfig() { + mReconnectHandler.removeCallbacks(mReconnectRunnable); + mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable); + if (null != mCTConfig) { + mCTConfig.release(); + mCTConfig = null; + } + } + + private void connectToTimeConfig() { + // Get access to the common time service configuration interface. If we catch a remote + // exception in the process (service crashed or no running for w/e reason), schedule an + // attempt to reconnect in the future. + cleanupTimeConfig(); + try { + synchronized (mLock) { + mCTConfig = new CommonTimeConfig(); + mCTConfig.setServerDiedListener(mCTServerDiedListener); + mCurIface = mCTConfig.getInterfaceBinding(); + mCTConfig.setAutoDisable(AUTO_DISABLE); + mCTConfig.setMasterElectionPriority(mEffectivePrio); + } + + if (NO_INTERFACE_TIMEOUT >= 0) + mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT); + + reevaluateServiceState(); + } + catch (RemoteException e) { + scheduleTimeConfigReconnect(); + } + } + + private void scheduleTimeConfigReconnect() { + cleanupTimeConfig(); + Log.w(TAG, String.format("Native service died, will reconnect in %d mSec", + NATIVE_SERVICE_RECONNECT_TIMEOUT)); + mReconnectHandler.postDelayed(mReconnectRunnable, + NATIVE_SERVICE_RECONNECT_TIMEOUT); + } + + private void handleNoInterfaceTimeout() { + if (null != mCTConfig) { + Log.i(TAG, "Timeout waiting for interface to come up. " + + "Forcing networkless master mode."); + if (CommonTimeConfig.ERROR_DEAD_OBJECT == mCTConfig.forceNetworklessMasterMode()) + scheduleTimeConfigReconnect(); + } + } + + private void reevaluateServiceState() { + String bindIface = null; + byte bestScore = -1; + try { + // Check to see if this interface is suitable to use for time synchronization. + // + // TODO : This selection algorithm needs to be enhanced for use with mobile devices. In + // particular, the choice of whether to a wireless interface or not should not be an all + // or nothing thing controlled by properties. It would probably be better if the + // platform had some concept of public wireless networks vs. home or friendly wireless + // networks (something a user would configure in settings or when a new interface is + // added). Then this algorithm could pick only wireless interfaces which were flagged + // as friendly, and be dormant when on public wireless networks. + // + // Another issue which needs to be dealt with is the use of driver supplied interface + // name to determine the network type. The fact that the wireless interface on a device + // is named "wlan0" is just a matter of convention; its not a 100% rule. For example, + // there are devices out there where the wireless is name "tiwlan0", not "wlan0". The + // internal network management interfaces in Android have all of the information needed + // to make a proper classification, there is just no way (currently) to fetch an + // interface's type (available from the ConnectionManager) as well as its address + // (available from either the java.net interfaces or from the NetworkManagment service). + // Both can enumerate interfaces, but that is no way to correlate their results (no + // common shared key; although using the interface name in the connection manager would + // be a good start). Until this gets resolved, we resort to substring searching for + // tags like wlan and eth. + // + String ifaceList[] = mNetMgr.listInterfaces(); + if (null != ifaceList) { + for (String iface : ifaceList) { + + byte thisScore = -1; + for (InterfaceScoreRule r : IFACE_SCORE_RULES) { + if (iface.contains(r.mPrefix)) { + thisScore = r.mScore; + break; + } + } + + if (thisScore <= bestScore) + continue; + + InterfaceConfiguration config = mNetMgr.getInterfaceConfig(iface); + if (null == config) + continue; + + if (config.isActive()) { + bindIface = iface; + bestScore = thisScore; + } + } + } + } + catch (RemoteException e) { + // Bad news; we should not be getting remote exceptions from the connectivity manager + // since it is running in SystemServer along side of us. It probably does not matter + // what we do here, but go ahead and unbind the common time service in this case, just + // so we have some defined behavior. + bindIface = null; + } + + boolean doRebind = true; + synchronized (mLock) { + if ((null != bindIface) && (null == mCurIface)) { + Log.e(TAG, String.format("Binding common time service to %s.", bindIface)); + mCurIface = bindIface; + } else + if ((null == bindIface) && (null != mCurIface)) { + Log.e(TAG, "Unbinding common time service."); + mCurIface = null; + } else + if ((null != bindIface) && (null != mCurIface) && !bindIface.equals(mCurIface)) { + Log.e(TAG, String.format("Switching common time service binding from %s to %s.", + mCurIface, bindIface)); + mCurIface = bindIface; + } else { + doRebind = false; + } + } + + if (doRebind && (null != mCTConfig)) { + byte newPrio = (bestScore > 0) + ? (byte)(bestScore * BASE_SERVER_PRIO) + : BASE_SERVER_PRIO; + if (newPrio != mEffectivePrio) { + mEffectivePrio = newPrio; + mCTConfig.setMasterElectionPriority(mEffectivePrio); + } + + int res = mCTConfig.setNetworkBinding(mCurIface); + if (res != CommonTimeConfig.SUCCESS) + scheduleTimeConfigReconnect(); + + else if (NO_INTERFACE_TIMEOUT >= 0) { + mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable); + if (null == mCurIface) + mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT); + } + } + } +} diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java index f7fe39e..02a0872 100644 --- a/services/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/java/com/android/server/NetworkTimeUpdateService.java @@ -55,7 +55,7 @@ public class NetworkTimeUpdateService { private static final int EVENT_AUTO_TIME_CHANGED = 1; private static final int EVENT_POLL_NETWORK_TIME = 2; - private static final int EVENT_WIFI_CONNECTED = 3; + private static final int EVENT_NETWORK_CONNECTED = 3; /** Normal polling frequency */ private static final long POLLING_INTERVAL_MS = 24L * 60 * 60 * 1000; // 24 hrs @@ -239,8 +239,9 @@ public class NetworkTimeUpdateService { if (netInfo != null) { // Verify that it's a WIFI connection if (netInfo.getState() == NetworkInfo.State.CONNECTED && - netInfo.getType() == ConnectivityManager.TYPE_WIFI ) { - mHandler.obtainMessage(EVENT_WIFI_CONNECTED).sendToTarget(); + (netInfo.getType() == ConnectivityManager.TYPE_WIFI || + netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) ) { + mHandler.obtainMessage(EVENT_NETWORK_CONNECTED).sendToTarget(); } } } @@ -259,7 +260,7 @@ public class NetworkTimeUpdateService { switch (msg.what) { case EVENT_AUTO_TIME_CHANGED: case EVENT_POLL_NETWORK_TIME: - case EVENT_WIFI_CONNECTED: + case EVENT_NETWORK_CONNECTED: onPollNetworkTime(msg.what); break; } diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index 2a0d2a0..0538a88 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -50,6 +50,7 @@ import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; +import android.os.SystemProperties; import android.os.WorkSource; import android.provider.Settings.SettingNotFoundException; import android.provider.Settings; @@ -163,6 +164,7 @@ public class PowerManagerService extends IPowerManager.Stub private boolean mDoneBooting = false; private boolean mBootCompleted = false; + private boolean mHeadless = false; private int mStayOnConditions = 0; private final int[] mBroadcastQueue = new int[] { -1, -1, -1 }; private final int[] mBroadcastWhy = new int[3]; @@ -512,6 +514,7 @@ public class PowerManagerService extends IPowerManager.Stub mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS); mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD); mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION); + mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0")); nativeInit(); synchronized (mLocks) { @@ -1877,9 +1880,11 @@ public class PowerManagerService extends IPowerManager.Stub } private void updateNativePowerStateLocked() { - nativeSetPowerState( - (mPowerState & SCREEN_ON_BIT) != 0, - (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT); + if (!mHeadless) { + nativeSetPowerState( + (mPowerState & SCREEN_ON_BIT) != 0, + (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT); + } } private int screenOffFinishedAnimatingLocked(int reason) { @@ -2223,11 +2228,13 @@ public class PowerManagerService extends IPowerManager.Stub mScreenOffHandler.postAtTime(this, now+(1000/60)); } } else { - // It's pretty scary to hold mLocks for this long, and we should - // redesign this, but it works for now. - nativeStartSurfaceFlingerAnimation( - mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR - ? 0 : mAnimationSetting); + if (!mHeadless) { + // It's pretty scary to hold mLocks for this long, and we should + // redesign this, but it works for now. + nativeStartSurfaceFlingerAnimation( + mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR + ? 0 : mAnimationSetting); + } mScreenBrightness.jumpToTargetLocked(); } } diff --git a/services/java/com/android/server/SerialService.java b/services/java/com/android/server/SerialService.java new file mode 100644 index 0000000..5d2b2a0 --- /dev/null +++ b/services/java/com/android/server/SerialService.java @@ -0,0 +1,58 @@ +/* + * 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 an + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.hardware.ISerialManager; +import android.os.ParcelFileDescriptor; + +import java.io.File; +import java.util.ArrayList; + +public class SerialService extends ISerialManager.Stub { + + private final Context mContext; + private final String[] mSerialPorts; + + public SerialService(Context context) { + mContext = context; + mSerialPorts = context.getResources().getStringArray( + com.android.internal.R.array.config_serialPorts); + } + + public String[] getSerialPorts() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null); + + ArrayList<String> ports = new ArrayList<String>(); + for (int i = 0; i < mSerialPorts.length; i++) { + String path = mSerialPorts[i]; + if (new File(path).exists()) { + ports.add(path); + } + } + String[] result = new String[ports.size()]; + ports.toArray(result); + return result; + } + + public ParcelFileDescriptor openSerialPort(String path) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null); + return native_open(path); + } + + private native ParcelFileDescriptor native_open(String path); +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 3ae62ad..25bee92 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -108,6 +108,7 @@ class ServerThread extends Thread { String factoryTestStr = SystemProperties.get("ro.factorytest"); int factoryTest = "".equals(factoryTestStr) ? SystemServer.FACTORY_TEST_OFF : Integer.parseInt(factoryTestStr); + final boolean headless = "1".equals(SystemProperties.get("ro.config.headless", "0")); LightsService lights = null; PowerManagerService power = null; @@ -126,10 +127,12 @@ class ServerThread extends Thread { BluetoothA2dpService bluetoothA2dp = null; DockObserver dock = null; UsbService usb = null; + SerialService serial = null; UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; ThrottleService throttle = null; NetworkTimeUpdateService networkTimeUpdater = null; + CommonTimeManagementService commonTimeMgmtService = null; // Critical services... try { @@ -231,10 +234,13 @@ class ServerThread extends Thread { bluetooth = new BluetoothService(context); ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth); bluetooth.initAfterRegistration(); - bluetoothA2dp = new BluetoothA2dpService(context, bluetooth); - ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE, - bluetoothA2dp); - bluetooth.initAfterA2dpRegistration(); + + if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) { + bluetoothA2dp = new BluetoothA2dpService(context, bluetooth); + ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE, + bluetoothA2dp); + bluetooth.initAfterA2dpRegistration(); + } int airplaneModeOn = Settings.System.getInt(mContentResolver, Settings.System.AIRPLANE_MODE_ON, 0); @@ -397,14 +403,24 @@ class ServerThread extends Thread { } try { - /* - * NotificationManagerService is dependant on MountService, - * (for media / usb notifications) so we must start MountService first. - */ - Slog.i(TAG, "Mount Service"); - ServiceManager.addService("mount", new MountService(context)); + Slog.i(TAG, "UpdateLock Service"); + ServiceManager.addService(Context.UPDATE_LOCK_SERVICE, + new UpdateLockService(context)); } catch (Throwable e) { - reportWtf("starting Mount Service", e); + reportWtf("starting UpdateLockService", e); + } + + if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) { + try { + /* + * NotificationManagerService is dependant on MountService, + * (for media / usb notifications) so we must start MountService first. + */ + Slog.i(TAG, "Mount Service"); + ServiceManager.addService("mount", new MountService(context)); + } catch (Throwable e) { + reportWtf("starting Mount Service", e); + } } try { @@ -456,19 +472,26 @@ class ServerThread extends Thread { reportWtf("starting DropBoxManagerService", e); } - try { - Slog.i(TAG, "Wallpaper Service"); - wallpaper = new WallpaperManagerService(context); - ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); - } catch (Throwable e) { - reportWtf("starting Wallpaper Service", e); + if (context.getResources().getBoolean( + com.android.internal.R.bool.config_enableWallpaperService)) { + try { + Slog.i(TAG, "Wallpaper Service"); + if (!headless) { + wallpaper = new WallpaperManagerService(context); + ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); + } + } catch (Throwable e) { + reportWtf("starting Wallpaper Service", e); + } } - try { - Slog.i(TAG, "Audio Service"); - ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context)); - } catch (Throwable e) { - reportWtf("starting Audio Service", e); + if (!"0".equals(SystemProperties.get("system_init.startaudioservice"))) { + try { + Slog.i(TAG, "Audio Service"); + ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context)); + } catch (Throwable e) { + reportWtf("starting Audio Service", e); + } } try { @@ -497,6 +520,15 @@ class ServerThread extends Thread { } try { + Slog.i(TAG, "Serial Service"); + // Serial port support + serial = new SerialService(context); + ServiceManager.addService(Context.SERIAL_SERVICE, serial); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting SerialService", e); + } + + try { Slog.i(TAG, "UI Mode Manager Service"); // Listen for UI mode changes uiMode = new UiModeManagerService(context); @@ -552,6 +584,14 @@ class ServerThread extends Thread { } catch (Throwable e) { reportWtf("starting NetworkTimeUpdate service", e); } + + try { + Slog.i(TAG, "CommonTimeManagementService"); + commonTimeMgmtService = new CommonTimeManagementService(context); + ServiceManager.addService("commontime_management", commonTimeMgmtService); + } catch (Throwable e) { + reportWtf("starting CommonTimeManagementService service", e); + } } // Before things start rolling, be sure we have decided whether @@ -630,6 +670,7 @@ class ServerThread extends Thread { final LocationManagerService locationF = location; final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; + final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService; final TextServicesManagerService textServiceManagerServiceF = tsms; final StatusBarManagerService statusBarF = statusBar; @@ -642,7 +683,7 @@ class ServerThread extends Thread { public void run() { Slog.i(TAG, "Making services ready"); - startSystemUi(contextF); + if (!headless) startSystemUi(contextF); try { if (batteryF != null) batteryF.systemReady(); } catch (Throwable e) { @@ -729,6 +770,11 @@ class ServerThread extends Thread { reportWtf("making Network Time Service ready", e); } try { + if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemReady(); + } catch (Throwable e) { + reportWtf("making Common time management service ready", e); + } + try { if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady(); } catch (Throwable e) { reportWtf("making Text Services Manager Service ready", e); diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java index c7fbc00..1709001 100644 --- a/services/java/com/android/server/UiModeManagerService.java +++ b/services/java/com/android/server/UiModeManagerService.java @@ -90,6 +90,7 @@ class UiModeManagerService extends IUiModeManager.Stub { private int mNightMode = UiModeManager.MODE_NIGHT_NO; private boolean mCarModeEnabled = false; private boolean mCharging = false; + private final int mDefaultUiModeType; private final boolean mCarModeKeepsScreenOn; private final boolean mDeskModeKeepsScreenOn; @@ -347,6 +348,8 @@ class UiModeManagerService extends IUiModeManager.Stub { mConfiguration.setToDefaults(); + mDefaultUiModeType = context.getResources().getInteger( + com.android.internal.R.integer.config_defaultUiModeType); mCarModeKeepsScreenOn = (context.getResources().getInteger( com.android.internal.R.integer.config_carDockKeepsScreenOn) == 1); mDeskModeKeepsScreenOn = (context.getResources().getInteger( @@ -452,7 +455,7 @@ class UiModeManagerService extends IUiModeManager.Stub { } final void updateConfigurationLocked(boolean sendIt) { - int uiMode = Configuration.UI_MODE_TYPE_NORMAL; + int uiMode = mDefaultUiModeType; if (mCarModeEnabled) { uiMode = Configuration.UI_MODE_TYPE_CAR; } else if (isDeskDockState(mDockState)) { diff --git a/services/java/com/android/server/UpdateLockService.java b/services/java/com/android/server/UpdateLockService.java new file mode 100644 index 0000000..1ffd196 --- /dev/null +++ b/services/java/com/android/server/UpdateLockService.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2012 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.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.IUpdateLock; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.TokenWatcher; +import android.os.UpdateLock; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +public class UpdateLockService extends IUpdateLock.Stub { + static final boolean DEBUG = false; + static final String TAG = "UpdateLockService"; + + // signatureOrSystem required to use update locks + static final String PERMISSION = "android.permission.UPDATE_LOCK"; + + Context mContext; + LockWatcher mLocks; + + class LockWatcher extends TokenWatcher { + LockWatcher(Handler h, String tag) { + super(h, tag); + } + + public void acquired() { + if (DEBUG) { + Slog.d(TAG, "first acquire; broadcasting convenient=false"); + } + sendLockChangedBroadcast(false); + } + public void released() { + if (DEBUG) { + Slog.d(TAG, "last release; broadcasting convenient=true"); + } + sendLockChangedBroadcast(true); + } + } + + UpdateLockService(Context context) { + mContext = context; + mLocks = new LockWatcher(new Handler(), "UpdateLocks"); + + // Consider just-booting to be a reasonable time to allow + // interruptions for update installation etc. + sendLockChangedBroadcast(true); + } + + void sendLockChangedBroadcast(boolean state) { + // Safe early during boot because this broadcast only goes to registered receivers. + long oldIdent = Binder.clearCallingIdentity(); + try { + Intent intent = new Intent(UpdateLock.UPDATE_LOCK_CHANGED) + .putExtra(UpdateLock.NOW_IS_CONVENIENT, state) + .putExtra(UpdateLock.TIMESTAMP, System.currentTimeMillis()) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + mContext.sendStickyBroadcast(intent); + } finally { + Binder.restoreCallingIdentity(oldIdent); + } + } + + @Override + public void acquireUpdateLock(IBinder token, String tag) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "acquire(" + token + ") by " + makeTag(tag)); + } + + mContext.enforceCallingOrSelfPermission(PERMISSION, "acquireUpdateLock"); + mLocks.acquire(token, makeTag(tag)); + } + + @Override + public void releaseUpdateLock(IBinder token) throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "release(" + token + ')'); + } + + mContext.enforceCallingOrSelfPermission(PERMISSION, "releaseUpdateLock"); + mLocks.release(token); + }; + + private String makeTag(String tag) { + return "{tag=" + tag + + " uid=" + Binder.getCallingUid() + + " pid=" + Binder.getCallingPid() + '}'; + } + + @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 update lock service from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + mLocks.dump(pw); + } +} diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java index 6a63eac..a7a46dd 100644 --- a/services/java/com/android/server/WiredAccessoryObserver.java +++ b/services/java/com/android/server/WiredAccessoryObserver.java @@ -30,8 +30,11 @@ import android.util.Slog; import android.media.AudioManager; import android.util.Log; +import java.io.File; import java.io.FileReader; import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; /** * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock. @@ -39,17 +42,6 @@ import java.io.FileNotFoundException; class WiredAccessoryObserver extends UEventObserver { private static final String TAG = WiredAccessoryObserver.class.getSimpleName(); private static final boolean LOG = true; - private static final int MAX_AUDIO_PORTS = 3; /* h2w, USB Audio & hdmi */ - private static final String uEventInfo[][] = { {"DEVPATH=/devices/virtual/switch/h2w", - "/sys/class/switch/h2w/state", - "/sys/class/switch/h2w/name"}, - {"DEVPATH=/devices/virtual/switch/usb_audio", - "/sys/class/switch/usb_audio/state", - "/sys/class/switch/usb_audio/name"}, - {"DEVPATH=/devices/virtual/switch/hdmi", - "/sys/class/switch/hdmi/state", - "/sys/class/switch/hdmi/name"} }; - private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET_NO_MIC = (1 << 1); private static final int BIT_USB_HEADSET_ANLG = (1 << 2); @@ -60,10 +52,89 @@ class WiredAccessoryObserver extends UEventObserver { BIT_HDMI_AUDIO); private static final int HEADSETS_WITH_MIC = BIT_HEADSET; + private static class UEventInfo { + private final String mDevName; + private final int mState1Bits; + private final int mState2Bits; + + public UEventInfo(String devName, int state1Bits, int state2Bits) { + mDevName = devName; + mState1Bits = state1Bits; + mState2Bits = state2Bits; + } + + public String getDevName() { return mDevName; } + + public String getDevPath() { + return String.format("DEVPATH=/devices/virtual/switch/%s", mDevName); + } + + public String getSwitchStatePath() { + return String.format("/sys/class/switch/%s/state", mDevName); + } + + public boolean checkSwitchExists() { + File f = new File(getSwitchStatePath()); + return ((null != f) && f.exists()); + } + + public int computeNewHeadsetState(int headsetState, int switchState) { + int preserveMask = ~(mState1Bits | mState2Bits); + int setBits = ((switchState == 1) ? mState1Bits : + ((switchState == 2) ? mState2Bits : 0)); + + return ((headsetState & preserveMask) | setBits); + } + } + + private static List<UEventInfo> makeObservedUEventList() { + List<UEventInfo> retVal = new ArrayList<UEventInfo>(); + UEventInfo uei; + + // Monitor h2w + uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have wired headset support"); + } + + // Monitor USB + uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have usb audio support"); + } + + // Monitor HDMI + // + // If the kernel has support for the "hdmi_audio" switch, use that. It will be signalled + // only when the HDMI driver has a video mode configured, and the downstream sink indicates + // support for audio in its EDID. + // + // If the kernel does not have an "hdmi_audio" switch, just fall back on the older "hdmi" + // switch instead. + uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have HDMI audio support"); + } + } + + return retVal; + } + + private static List<UEventInfo> uEventInfo = makeObservedUEventList(); + private int mHeadsetState; private int mPrevHeadsetState; private String mHeadsetName; - private int switchState; private final Context mContext; private final WakeLock mWakeLock; // held while there is a pending route change @@ -85,11 +156,12 @@ class WiredAccessoryObserver extends UEventObserver { // one on the board, one on the dock and one on HDMI: // observe three UEVENTs init(); // set initial status - for (int i = 0; i < MAX_AUDIO_PORTS; i++) { - startObserving(uEventInfo[i][0]); + for (int i = 0; i < uEventInfo.size(); ++i) { + UEventInfo uei = uEventInfo.get(i); + startObserving(uei.getDevPath()); } } - } + } @Override public void onUEvent(UEventObserver.UEvent event) { @@ -106,50 +178,47 @@ class WiredAccessoryObserver extends UEventObserver { private synchronized final void updateState(String name, int state) { - if (name.equals("usb_audio")) { - switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|BIT_HDMI_AUDIO)) | - ((state == 1) ? BIT_USB_HEADSET_ANLG : - ((state == 2) ? BIT_USB_HEADSET_DGTL : 0))); - } else if (name.equals("hdmi")) { - switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC| - BIT_USB_HEADSET_DGTL|BIT_USB_HEADSET_ANLG)) | - ((state == 1) ? BIT_HDMI_AUDIO : 0)); - } else { - switchState = ((mHeadsetState & (BIT_HDMI_AUDIO|BIT_USB_HEADSET_ANLG| - BIT_USB_HEADSET_DGTL)) | - ((state == 1) ? BIT_HEADSET : - ((state == 2) ? BIT_HEADSET_NO_MIC : 0))); + // FIXME: When ueventd informs of a change in state for a switch, it does not have to be + // the case that the name reported by /sys/class/switch/<device>/name is the same as + // <device>. For normal users of the linux switch class driver, it will be. But it is + // technically possible to hook the print_name method in the class driver and return a + // different name each and every time the name sysfs entry is queried. + // + // Right now this is not the case for any of the switch implementations used here. I'm not + // certain anyone would ever choose to implement such a dynamic name, or what it would mean + // for the implementation at this level, but if it ever happens, we will need to revisit + // this code. + for (int i = 0; i < uEventInfo.size(); ++i) { + UEventInfo uei = uEventInfo.get(i); + if (name.equals(uei.getDevName())) { + update(name, uei.computeNewHeadsetState(mHeadsetState, state)); + return; + } } - update(name, switchState); } private synchronized final void init() { char[] buffer = new char[1024]; - - String newName = mHeadsetName; - int newState = mHeadsetState; mPrevHeadsetState = mHeadsetState; if (LOG) Slog.v(TAG, "init()"); - for (int i = 0; i < MAX_AUDIO_PORTS; i++) { + for (int i = 0; i < uEventInfo.size(); ++i) { + UEventInfo uei = uEventInfo.get(i); try { - FileReader file = new FileReader(uEventInfo[i][1]); + int curState; + FileReader file = new FileReader(uei.getSwitchStatePath()); int len = file.read(buffer, 0, 1024); file.close(); - newState = Integer.valueOf((new String(buffer, 0, len)).trim()); + curState = Integer.valueOf((new String(buffer, 0, len)).trim()); - file = new FileReader(uEventInfo[i][2]); - len = file.read(buffer, 0, 1024); - file.close(); - newName = new String(buffer, 0, len).trim(); - - if (newState > 0) { - updateState(newName, newState); + if (curState > 0) { + updateState(uei.getDevName(), curState); } } catch (FileNotFoundException e) { - Slog.w(TAG, "This kernel does not have wired headset support"); + Slog.w(TAG, uei.getSwitchStatePath() + + " not found while attempting to determine initial switch state"); } catch (Exception e) { Slog.e(TAG, "" , e); } @@ -191,8 +260,12 @@ class WiredAccessoryObserver extends UEventObserver { mHeadsetState = headsetState; if (headsetState == 0) { - Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); - mContext.sendBroadcast(intent); + if (mContext.getResources().getBoolean( + com.android.internal.R.bool.config_sendAudioBecomingNoisy)) { + Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY); + mContext.sendBroadcast(intent); + } + // It can take hundreds of ms flush the audio pipeline after // apps pause audio playback, but audio route changes are // immediate, so delay the route change by 1000ms. diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index cffb391..7684566 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -104,6 +104,7 @@ import android.os.ServiceManager; import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.UpdateLock; import android.provider.Settings; import android.text.format.Time; import android.util.EventLog; @@ -172,6 +173,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final boolean DEBUG_CONFIGURATION = localLOGV || false; static final boolean DEBUG_POWER = localLOGV || false; static final boolean DEBUG_POWER_QUICK = DEBUG_POWER || false; + static final boolean DEBUG_IMMERSIVE = localLOGV || true; static final boolean VALIDATE_TOKENS = false; static final boolean SHOW_ACTIVITY_START_TIME = true; @@ -262,7 +264,14 @@ public final class ActivityManagerService extends ActivityManagerNative static final String[] EMPTY_STRING_ARRAY = new String[0]; public ActivityStack mMainStack; - + + private final boolean mHeadless; + + // Whether we should show our dialogs (ANR, crash, etc) or just perform their + // default actuion automatically. Important for devices without direct input + // devices. + private boolean mShowDialogs = true; + /** * Description of a request to start a new activity, which has been held * due to app switches being disabled. @@ -805,6 +814,12 @@ public final class ActivityManagerService extends ActivityManagerNative long mLastWriteTime = 0; /** + * Used to retain an update lock when the foreground activity is in + * immersive mode. + */ + final UpdateLock mUpdateLock = new UpdateLock("immersive"); + + /** * Set to true after the system has finished booting. */ boolean mBooted = false; @@ -889,7 +904,7 @@ public final class ActivityManagerService extends ActivityManagerNative return; } AppErrorResult res = (AppErrorResult) data.get("result"); - if (!mSleeping && !mShuttingDown) { + if (mShowDialogs && !mSleeping && !mShuttingDown) { Dialog d = new AppErrorDialog(mContext, res, proc); d.show(); proc.crashDialog = d; @@ -918,11 +933,15 @@ public final class ActivityManagerService extends ActivityManagerNative broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, false, false, MY_PID, Process.SYSTEM_UID); - - Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, - mContext, proc, (ActivityRecord)data.get("activity")); - d.show(); - proc.anrDialog = d; + if (mShowDialogs) { + Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, + mContext, proc, (ActivityRecord) data.get("activity")); + d.show(); + proc.anrDialog = d; + } else { + // Just kill the app if there is no dialog to be shown. + killAppAtUsersRequest(proc, null); + } } ensureBootCompleted(); @@ -940,7 +959,7 @@ public final class ActivityManagerService extends ActivityManagerNative return; } AppErrorResult res = (AppErrorResult) data.get("result"); - if (!mSleeping && !mShuttingDown) { + if (mShowDialogs && !mSleeping && !mShuttingDown) { Dialog d = new StrictModeViolationDialog(mContext, res, proc); d.show(); proc.crashDialog = d; @@ -1060,16 +1079,22 @@ public final class ActivityManagerService extends ActivityManagerNative } } break; case SHOW_UID_ERROR_MSG: { - // XXX This is a temporary dialog, no need to localize. - AlertDialog d = new BaseErrorDialog(mContext); - d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); - d.setCancelable(false); - d.setTitle("System UIDs Inconsistent"); - d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable."); - d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky", - mHandler.obtainMessage(IM_FEELING_LUCKY_MSG)); - mUidAlert = d; - d.show(); + String title = "System UIDs Inconsistent"; + String text = "UIDs on the system are inconsistent, you need to wipe your" + + " data partition or your device will be unstable."; + Log.e(TAG, title + ": " + text); + if (mShowDialogs) { + // XXX This is a temporary dialog, no need to localize. + AlertDialog d = new BaseErrorDialog(mContext); + d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); + d.setCancelable(false); + d.setTitle(title); + d.setMessage(text); + d.setButton(DialogInterface.BUTTON_POSITIVE, "I'm Feeling Lucky", + mHandler.obtainMessage(IM_FEELING_LUCKY_MSG)); + mUidAlert = d; + d.show(); + } } break; case IM_FEELING_LUCKY_MSG: { if (mUidAlert != null) { @@ -1496,6 +1521,7 @@ public final class ActivityManagerService extends ActivityManagerNative mUsageStatsService = new UsageStatsService(new File( systemDir, "usagestats").toString()); + mHeadless = "1".equals(SystemProperties.get("ro.config.headless", "0")); GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); @@ -1696,6 +1722,21 @@ public final class ActivityManagerService extends ActivityManagerNative if (r != null) { mWindowManager.setFocusedApp(r.appToken, true); } + applyUpdateLockStateLocked(r); + } + } + + final void applyUpdateLockStateLocked(ActivityRecord r) { + final boolean nextState = r != null && r.immersive; + if (mUpdateLock.isHeld() != nextState) { + if (DEBUG_IMMERSIVE) { + Slog.d(TAG, "Applying new update lock state '" + nextState + "' for " + r); + } + if (nextState) { + mUpdateLock.acquire(); + } else { + mUpdateLock.release(); + } } } @@ -2034,6 +2075,13 @@ public final class ActivityManagerService extends ActivityManagerNative } boolean startHomeActivityLocked() { + if (mHeadless) { + // Added because none of the other calls to ensureBootCompleted seem to fire + // when running headless. + ensureBootCompleted(); + return false; + } + if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL && mTopAction == null) { // We are running in factory test mode, but unable to find @@ -3929,7 +3977,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid && processName.equals(hr.processName)) { try { - if (mMainStack.realStartActivityLocked(hr, app, true, true)) { + if (mHeadless) { + Slog.e(TAG, "Starting activities not supported on headless device: " + hr); + } else if (mMainStack.realStartActivityLocked(hr, app, true, true)) { didSomething = true; } } catch (Exception e) { @@ -6644,11 +6694,24 @@ public final class ActivityManagerService extends ActivityManagerNative public void setImmersive(IBinder token, boolean immersive) { synchronized(this) { - ActivityRecord r = mMainStack.isInStackLocked(token); + final ActivityRecord r = mMainStack.isInStackLocked(token); if (r == null) { throw new IllegalArgumentException(); } r.immersive = immersive; + + // update associated state if we're frontmost + if (r == mMainStack.topRunningActivityLocked(null)) { + long oldId = Binder.clearCallingIdentity(); + try { + if (DEBUG_IMMERSIVE) { + Slog.d(TAG, "Frontmost changed immersion: "+ r); + } + applyUpdateLockStateLocked(r); + } finally { + Binder.restoreCallingIdentity(oldId); + } + } } } @@ -7208,7 +7271,7 @@ public final class ActivityManagerService extends ActivityManagerNative mMainStack.resumeTopActivityLocked(null); } else { ActivityRecord r = mMainStack.topRunningActivityLocked(null); - if (r.app == app) { + if (r != null && r.app == app) { // If the top running activity is from this crashing // process, then terminate it to avoid getting in a loop. Slog.w(TAG, " Force finishing activity " @@ -13442,6 +13505,9 @@ public final class ActivityManagerService extends ActivityManagerNative */ public boolean updateConfigurationLocked(Configuration values, ActivityRecord starting, boolean persistent, boolean initLocale) { + // do nothing if we are headless + if (mHeadless) return true; + int changes = 0; boolean kept = true; @@ -13470,6 +13536,10 @@ public final class ActivityManagerService extends ActivityManagerNative mConfiguration = newConfig; Slog.i(TAG, "Config changed: " + newConfig); + // TODO: If our config changes, should we auto dismiss any currently + // showing dialogs? + mShowDialogs = shouldShowDialogs(newConfig); + final Configuration configCopy = new Configuration(mConfiguration); AttributeCache ac = AttributeCache.instance(); @@ -13537,6 +13607,19 @@ public final class ActivityManagerService extends ActivityManagerNative return kept; } + + /** + * Decide based on the configuration whether we should shouw the ANR, + * crash, etc dialogs. The idea is that if there is no affordnace to + * press the on-screen buttons, we shouldn't show the dialog. + * + * A thought: SystemUI might also want to get told about this, the Power + * dialog / global actions also might want different behaviors. + */ + private static final boolean shouldShowDialogs(Configuration config) { + return !(config.keyboard == Configuration.KEYBOARD_NOKEYS + && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH); + } /** * Save the locale. You must be inside a synchronized (this) block. diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index 36442a0..b54c519 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -2020,6 +2020,39 @@ final class Settings { return false; } + static final void printFlags(PrintWriter pw, int val, Object[] spec) { + pw.print("[ "); + for (int i=0; i<spec.length; i+=2) { + int mask = (Integer)spec[i]; + if ((val & mask) != 0) { + pw.print(spec[i+1]); + pw.print(" "); + } + } + pw.print("]"); + } + + static final Object[] FLAG_DUMP_SPEC = new Object[] { + ApplicationInfo.FLAG_SYSTEM, "SYSTEM", + ApplicationInfo.FLAG_DEBUGGABLE, "DEBUGGABLE", + ApplicationInfo.FLAG_HAS_CODE, "HAS_CODE", + ApplicationInfo.FLAG_PERSISTENT, "PERSISTENT", + ApplicationInfo.FLAG_FACTORY_TEST, "FACTORY_TEST", + ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING, "ALLOW_TASK_REPARENTING", + ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA, "ALLOW_CLEAR_USER_DATA", + ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, "UPDATED_SYSTEM_APP", + ApplicationInfo.FLAG_TEST_ONLY, "TEST_ONLY", + ApplicationInfo.FLAG_VM_SAFE_MODE, "VM_SAFE_MODE", + ApplicationInfo.FLAG_ALLOW_BACKUP, "ALLOW_BACKUP", + ApplicationInfo.FLAG_KILL_AFTER_RESTORE, "KILL_AFTER_RESTORE", + ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION", + ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE", + ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP", + ApplicationInfo.FLAG_STOPPED, "STOPPED", + ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK", + ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE", + }; + void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) { final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); final Date date = new Date(); @@ -2060,6 +2093,7 @@ final class Settings { pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString); pw.print(" versionCode="); pw.println(ps.versionCode); if (ps.pkg != null) { + pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags, FLAG_DUMP_SPEC); pw.println(); pw.print(" versionName="); pw.println(ps.pkg.mVersionName); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion); @@ -2261,4 +2295,4 @@ final class Settings { pw.println("Settings parse messages:"); pw.print(mReadMessages.toString()); } -}
\ No newline at end of file +} diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index ed83fbe..c2ded8a 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -43,6 +43,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.UEventObserver; import android.provider.Settings; @@ -206,6 +207,9 @@ public class UsbDeviceManager { } private static String addFunction(String functions, String function) { + if ("none".equals(functions)) { + return function; + } if (!containsFunction(functions, function)) { if (functions.length() > 0) { functions += ","; @@ -222,6 +226,9 @@ public class UsbDeviceManager { split[i] = null; } } + if (split.length == 1 && split[0] == null) { + return "none"; + } StringBuilder builder = new StringBuilder(); for (int i = 0; i < split.length; i++) { String s = split[i]; @@ -365,11 +372,7 @@ public class UsbDeviceManager { for (int i = 0; i < 20; i++) { // State transition is done when sys.usb.state is set to the new configuration if (state.equals(SystemProperties.get("sys.usb.state"))) return true; - try { - // try again in 50ms - Thread.sleep(50); - } catch (InterruptedException e) { - } + SystemClock.sleep(50); } Slog.e(TAG, "waitForState(" + state + ") FAILED"); return false; diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 3f72dec..5c295d3 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -250,6 +250,7 @@ public class WindowManagerService extends IWindowManager.Stub private static final String SYSTEM_SECURE = "ro.secure"; private static final String SYSTEM_DEBUGGABLE = "ro.debuggable"; + private static final String SYSTEM_HEADLESS = "ro.config.headless"; /** * Condition waited on by {@link #reenableKeyguard} to know the call to @@ -259,6 +260,8 @@ public class WindowManagerService extends IWindowManager.Stub */ private boolean mKeyguardDisabled = false; + private final boolean mHeadless; + private static final int ALLOW_DISABLE_YES = 1; private static final int ALLOW_DISABLE_NO = 0; private static final int ALLOW_DISABLE_UNKNOWN = -1; // check with DevicePolicyManager @@ -753,6 +756,7 @@ public class WindowManagerService extends IWindowManager.Stub mAllowBootMessages = showBootMsgs; mLimitedAlphaCompositing = context.getResources().getBoolean( com.android.internal.R.bool.config_sf_limitedAlpha); + mHeadless = "1".equals(SystemProperties.get(SYSTEM_HEADLESS, "0")); mPowerManager = pm; mPowerManager.setPolicy(mPolicy); @@ -4839,7 +4843,7 @@ public class WindowManagerService extends IWindowManager.Stub public void performBootTimeout() { synchronized(mWindowMap) { - if (mDisplayEnabled) { + if (mDisplayEnabled || mHeadless) { return; } Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled"); @@ -4870,7 +4874,11 @@ public class WindowManagerService extends IWindowManager.Stub // have been drawn. boolean haveBootMsg = false; boolean haveApp = false; + // if the wallpaper service is disabled on the device, we're never going to have + // wallpaper, don't bother waiting for it boolean haveWallpaper = false; + boolean wallpaperEnabled = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_enableWallpaperService); boolean haveKeyguard = true; final int N = mWindows.size(); for (int i=0; i<N; i++) { @@ -4906,7 +4914,8 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_SCREEN_ON || DEBUG_BOOT) { Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp - + " haveWall=" + haveWallpaper + " haveKeyguard=" + haveKeyguard); + + " haveWall=" + haveWallpaper + " wallEnabled=" + wallpaperEnabled + + " haveKeyguard=" + haveKeyguard); } // If we are turning on the screen to show the boot message, @@ -4918,7 +4927,8 @@ public class WindowManagerService extends IWindowManager.Stub // If we are turning on the screen after the boot is completed // normally, don't do so until we have the application and // wallpaper. - if (mSystemBooted && ((!haveApp && !haveKeyguard) || !haveWallpaper)) { + if (mSystemBooted && ((!haveApp && !haveKeyguard) || + (wallpaperEnabled && !haveWallpaper))) { return; } } @@ -5007,6 +5017,8 @@ public class WindowManagerService extends IWindowManager.Stub // TODO: more accounting of which pid(s) turned it on, keep count, // only allow disables from pids which have count on, etc. public void showStrictModeViolation(boolean on) { + if (mHeadless) return; + int pid = Binder.getCallingPid(); synchronized(mWindowMap) { // Ignoring requests to enable the red border from clients |
