Loading services/core/java/com/android/server/ExtconUEventObserver.java +41 −5 Original line number Diff line number Diff line Loading @@ -22,8 +22,11 @@ import android.util.Slog; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.regex.Pattern; /** * A specialized UEventObserver that receives UEvents from the kernel for devices in the {@code Loading @@ -40,13 +43,14 @@ import java.util.Map; * time in that process. Once started the UEvent thread will not stop (although it can stop * notifying UEventObserver's via stopObserving()). * * <p> * * @hide */ public abstract class ExtconUEventObserver extends UEventObserver { private static final String TAG = "ExtconUEventObserver"; private static final boolean LOG = false; private static final String SELINUX_POLICIES_NEED_TO_BE_CHANGED = "This probably mean the selinux policies need to be changed."; private final Map<String, ExtconInfo> mExtconInfos = new ArrayMap<>(); @Override Loading @@ -70,15 +74,47 @@ public abstract class ExtconUEventObserver extends UEventObserver { /** Starts observing {@link ExtconInfo#getDevicePath()}. */ public void startObserving(ExtconInfo extconInfo) { mExtconInfos.put(extconInfo.getDevicePath(), extconInfo); if (LOG) Slog.v(TAG, "Observing " + extconInfo.getDevicePath()); startObserving("DEVPATH=" + extconInfo.getDevicePath()); String devicePath = extconInfo.getDevicePath(); if (devicePath == null) { Slog.wtf(TAG, "Unable to start observing " + extconInfo.getName() + " because the device path is null. " + SELINUX_POLICIES_NEED_TO_BE_CHANGED); } else { mExtconInfos.put(devicePath, extconInfo); if (LOG) Slog.v(TAG, "Observing " + devicePath); startObserving("DEVPATH=" + devicePath); } } /** An External Connection to watch. */ public static final class ExtconInfo { private static final String TAG = "ExtconInfo"; /** Returns a new list of all external connections whose name matches {@code regex}. */ public static List<ExtconInfo> getExtconInfos(@Nullable String regex) { Pattern p = regex == null ? null : Pattern.compile(regex); File file = new File("/sys/class/extcon"); File[] files = file.listFiles(); if (files == null) { Slog.wtf(TAG, file + " exists " + file.exists() + " isDir " + file.isDirectory() + " but listFiles returns null. " + SELINUX_POLICIES_NEED_TO_BE_CHANGED); return new ArrayList<>(0); // Always return a new list. } else { ArrayList list = new ArrayList(files.length); for (File f : files) { String name = f.getName(); if (p == null || p.matcher(name).matches()) { ExtconInfo uei = new ExtconInfo(name); list.add(uei); if (LOG) Slog.d(TAG, name + " matches " + regex); } else { if (LOG) Slog.d(TAG, name + " does not match " + regex); } } return list; } } private final String mName; public ExtconInfo(String name) { Loading services/core/java/com/android/server/WiredAccessoryManager.java +125 −30 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.UEventObserver; import android.util.Pair; import android.util.Slog; import android.media.AudioManager; import android.util.Log; Loading @@ -31,6 +32,7 @@ import android.view.InputDevice; import com.android.internal.R; import com.android.server.input.InputManagerService; import com.android.server.input.InputManagerService.WiredAccessoryCallbacks; import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT; import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT; import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT; Loading @@ -41,6 +43,7 @@ import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT_BIT import java.io.File; import java.io.FileReader; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; Loading @@ -52,7 +55,7 @@ import java.util.Locale; */ final class WiredAccessoryManager implements WiredAccessoryCallbacks { private static final String TAG = WiredAccessoryManager.class.getSimpleName(); private static final boolean LOG = true; private static final boolean LOG = false; private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET_NO_MIC = (1 << 1); Loading Loading @@ -82,6 +85,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { private int mSwitchValues; private final WiredAccessoryObserver mObserver; private final WiredAccessoryExtconObserver mExtconObserver; private final InputManagerService mInputManager; private final boolean mUseDevInputEventForAudioJack; Loading @@ -96,16 +100,19 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); mExtconObserver = new WiredAccessoryExtconObserver(); mObserver = new WiredAccessoryObserver(); } private void onSystemReady() { if (mUseDevInputEventForAudioJack) { int switchValues = 0; if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { switchValues |= SW_HEADPHONE_INSERT_BIT; } if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) { if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) { switchValues |= SW_MICROPHONE_INSERT_BIT; } if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_LINEOUT_INSERT) == 1) { Loading @@ -115,14 +122,25 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT); } if (ExtconUEventObserver.extconExists()) { if (mUseDevInputEventForAudioJack) { Log.w(TAG, "Both input event and extcon are used for audio jack," + " please just choose one."); } mExtconObserver.init(); } else { mObserver.init(); } } @Override public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) { if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos if (LOG) { Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos + " bits=" + switchCodeToString(switchValues, switchMask) + " mask=" + Integer.toHexString(switchMask)); } synchronized (mLock) { int headset; Loading Loading @@ -186,10 +204,12 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT); boolean h2wStateChange = true; boolean usbStateChange = true; if (LOG) Slog.v(TAG, "newName=" + newName if (LOG) { Slog.v(TAG, "newName=" + newName + " newState=" + newState + " headsetState=" + headsetState + " prev headsetState=" + mHeadsetState); } if (mHeadsetState == headsetState) { Log.e(TAG, "No state change."); Loading Loading @@ -438,7 +458,9 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { mStateNbits = stateNbits; } public String getDevName() { return mDevName; } public String getDevName() { return mDevName; } public String getDevPath() { return String.format(Locale.US, "/devices/virtual/switch/%s", mDevName); Loading @@ -463,4 +485,77 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { } } } private class WiredAccessoryExtconObserver extends ExtconStateObserver<Pair<Integer, Integer>> { private final List<ExtconInfo> mExtconInfos; WiredAccessoryExtconObserver() { mExtconInfos = ExtconInfo.getExtconInfos(".*audio.*"); } private void init() { for (ExtconInfo extconInfo : mExtconInfos) { Pair<Integer, Integer> state = null; try { state = parseStateFromFile(extconInfo); } catch (FileNotFoundException e) { Slog.w(TAG, extconInfo.getStatePath() + " not found while attempting to determine initial state", e); } catch (IOException e) { Slog.e( TAG, "Error reading " + extconInfo.getStatePath() + " while attempting to determine initial state", e); } if (state != null) { updateState(extconInfo, extconInfo.getName(), state); } if (LOG) Slog.d(TAG, "observing " + extconInfo.getName()); startObserving(extconInfo); } } @Override public Pair<Integer, Integer> parseState(ExtconInfo extconInfo, String status) { if (LOG) Slog.v(TAG, "status " + status); int []maskAndState = {0,0}; // extcon event state changes from kernel4.9 // new state will be like STATE=MICROPHONE=1\nHEADPHONE=0 updateBit(maskAndState, BIT_HEADSET_NO_MIC, status, "HEADPHONE") ; updateBit(maskAndState, BIT_HEADSET, status,"MICROPHONE") ; updateBit(maskAndState, BIT_HDMI_AUDIO, status,"HDMI") ; updateBit(maskAndState, BIT_LINEOUT, status,"LINE-OUT") ; if (LOG) Slog.v(TAG, "mask " + maskAndState[0] + " state " + maskAndState[1]); return Pair.create(maskAndState[0],maskAndState[1]); } @Override public void updateState(ExtconInfo extconInfo, String name, Pair<Integer, Integer> maskAndState) { synchronized (mLock) { int mask = maskAndState.first; int state = maskAndState.second; updateLocked(name, mHeadsetState | (mask & state) & ~(mask & ~state)); return; } } } /** * Updates the mask bit at {@code position} to 1 and the state bit at {@code position} to true * if {@code name=1} or false if {}@code name=0} is contained in {@code state}. */ private static void updateBit(int[] maskAndState, int position, String state, String name) { maskAndState[0] |= position; if (state.contains(name + "=1")) { maskAndState[0] |= position; maskAndState[1] |= position; } else if (state.contains(name + "=0")) { maskAndState[0] |= position; maskAndState[1] &= ~position; } } } Loading
services/core/java/com/android/server/ExtconUEventObserver.java +41 −5 Original line number Diff line number Diff line Loading @@ -22,8 +22,11 @@ import android.util.Slog; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.regex.Pattern; /** * A specialized UEventObserver that receives UEvents from the kernel for devices in the {@code Loading @@ -40,13 +43,14 @@ import java.util.Map; * time in that process. Once started the UEvent thread will not stop (although it can stop * notifying UEventObserver's via stopObserving()). * * <p> * * @hide */ public abstract class ExtconUEventObserver extends UEventObserver { private static final String TAG = "ExtconUEventObserver"; private static final boolean LOG = false; private static final String SELINUX_POLICIES_NEED_TO_BE_CHANGED = "This probably mean the selinux policies need to be changed."; private final Map<String, ExtconInfo> mExtconInfos = new ArrayMap<>(); @Override Loading @@ -70,15 +74,47 @@ public abstract class ExtconUEventObserver extends UEventObserver { /** Starts observing {@link ExtconInfo#getDevicePath()}. */ public void startObserving(ExtconInfo extconInfo) { mExtconInfos.put(extconInfo.getDevicePath(), extconInfo); if (LOG) Slog.v(TAG, "Observing " + extconInfo.getDevicePath()); startObserving("DEVPATH=" + extconInfo.getDevicePath()); String devicePath = extconInfo.getDevicePath(); if (devicePath == null) { Slog.wtf(TAG, "Unable to start observing " + extconInfo.getName() + " because the device path is null. " + SELINUX_POLICIES_NEED_TO_BE_CHANGED); } else { mExtconInfos.put(devicePath, extconInfo); if (LOG) Slog.v(TAG, "Observing " + devicePath); startObserving("DEVPATH=" + devicePath); } } /** An External Connection to watch. */ public static final class ExtconInfo { private static final String TAG = "ExtconInfo"; /** Returns a new list of all external connections whose name matches {@code regex}. */ public static List<ExtconInfo> getExtconInfos(@Nullable String regex) { Pattern p = regex == null ? null : Pattern.compile(regex); File file = new File("/sys/class/extcon"); File[] files = file.listFiles(); if (files == null) { Slog.wtf(TAG, file + " exists " + file.exists() + " isDir " + file.isDirectory() + " but listFiles returns null. " + SELINUX_POLICIES_NEED_TO_BE_CHANGED); return new ArrayList<>(0); // Always return a new list. } else { ArrayList list = new ArrayList(files.length); for (File f : files) { String name = f.getName(); if (p == null || p.matcher(name).matches()) { ExtconInfo uei = new ExtconInfo(name); list.add(uei); if (LOG) Slog.d(TAG, name + " matches " + regex); } else { if (LOG) Slog.d(TAG, name + " does not match " + regex); } } return list; } } private final String mName; public ExtconInfo(String name) { Loading
services/core/java/com/android/server/WiredAccessoryManager.java +125 −30 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.PowerManager.WakeLock; import android.os.UEventObserver; import android.util.Pair; import android.util.Slog; import android.media.AudioManager; import android.util.Log; Loading @@ -31,6 +32,7 @@ import android.view.InputDevice; import com.android.internal.R; import com.android.server.input.InputManagerService; import com.android.server.input.InputManagerService.WiredAccessoryCallbacks; import static com.android.server.input.InputManagerService.SW_HEADPHONE_INSERT; import static com.android.server.input.InputManagerService.SW_MICROPHONE_INSERT; import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT; Loading @@ -41,6 +43,7 @@ import static com.android.server.input.InputManagerService.SW_LINEOUT_INSERT_BIT import java.io.File; import java.io.FileReader; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Locale; Loading @@ -52,7 +55,7 @@ import java.util.Locale; */ final class WiredAccessoryManager implements WiredAccessoryCallbacks { private static final String TAG = WiredAccessoryManager.class.getSimpleName(); private static final boolean LOG = true; private static final boolean LOG = false; private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET_NO_MIC = (1 << 1); Loading Loading @@ -82,6 +85,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { private int mSwitchValues; private final WiredAccessoryObserver mObserver; private final WiredAccessoryExtconObserver mExtconObserver; private final InputManagerService mInputManager; private final boolean mUseDevInputEventForAudioJack; Loading @@ -96,16 +100,19 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { mUseDevInputEventForAudioJack = context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); mExtconObserver = new WiredAccessoryExtconObserver(); mObserver = new WiredAccessoryObserver(); } private void onSystemReady() { if (mUseDevInputEventForAudioJack) { int switchValues = 0; if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { switchValues |= SW_HEADPHONE_INSERT_BIT; } if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) { if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_MICROPHONE_INSERT) == 1) { switchValues |= SW_MICROPHONE_INSERT_BIT; } if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_LINEOUT_INSERT) == 1) { Loading @@ -115,14 +122,25 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { SW_HEADPHONE_INSERT_BIT | SW_MICROPHONE_INSERT_BIT | SW_LINEOUT_INSERT_BIT); } if (ExtconUEventObserver.extconExists()) { if (mUseDevInputEventForAudioJack) { Log.w(TAG, "Both input event and extcon are used for audio jack," + " please just choose one."); } mExtconObserver.init(); } else { mObserver.init(); } } @Override public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask) { if (LOG) Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos if (LOG) { Slog.v(TAG, "notifyWiredAccessoryChanged: when=" + whenNanos + " bits=" + switchCodeToString(switchValues, switchMask) + " mask=" + Integer.toHexString(switchMask)); } synchronized (mLock) { int headset; Loading Loading @@ -186,10 +204,12 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC | BIT_LINEOUT); boolean h2wStateChange = true; boolean usbStateChange = true; if (LOG) Slog.v(TAG, "newName=" + newName if (LOG) { Slog.v(TAG, "newName=" + newName + " newState=" + newState + " headsetState=" + headsetState + " prev headsetState=" + mHeadsetState); } if (mHeadsetState == headsetState) { Log.e(TAG, "No state change."); Loading Loading @@ -438,7 +458,9 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { mStateNbits = stateNbits; } public String getDevName() { return mDevName; } public String getDevName() { return mDevName; } public String getDevPath() { return String.format(Locale.US, "/devices/virtual/switch/%s", mDevName); Loading @@ -463,4 +485,77 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { } } } private class WiredAccessoryExtconObserver extends ExtconStateObserver<Pair<Integer, Integer>> { private final List<ExtconInfo> mExtconInfos; WiredAccessoryExtconObserver() { mExtconInfos = ExtconInfo.getExtconInfos(".*audio.*"); } private void init() { for (ExtconInfo extconInfo : mExtconInfos) { Pair<Integer, Integer> state = null; try { state = parseStateFromFile(extconInfo); } catch (FileNotFoundException e) { Slog.w(TAG, extconInfo.getStatePath() + " not found while attempting to determine initial state", e); } catch (IOException e) { Slog.e( TAG, "Error reading " + extconInfo.getStatePath() + " while attempting to determine initial state", e); } if (state != null) { updateState(extconInfo, extconInfo.getName(), state); } if (LOG) Slog.d(TAG, "observing " + extconInfo.getName()); startObserving(extconInfo); } } @Override public Pair<Integer, Integer> parseState(ExtconInfo extconInfo, String status) { if (LOG) Slog.v(TAG, "status " + status); int []maskAndState = {0,0}; // extcon event state changes from kernel4.9 // new state will be like STATE=MICROPHONE=1\nHEADPHONE=0 updateBit(maskAndState, BIT_HEADSET_NO_MIC, status, "HEADPHONE") ; updateBit(maskAndState, BIT_HEADSET, status,"MICROPHONE") ; updateBit(maskAndState, BIT_HDMI_AUDIO, status,"HDMI") ; updateBit(maskAndState, BIT_LINEOUT, status,"LINE-OUT") ; if (LOG) Slog.v(TAG, "mask " + maskAndState[0] + " state " + maskAndState[1]); return Pair.create(maskAndState[0],maskAndState[1]); } @Override public void updateState(ExtconInfo extconInfo, String name, Pair<Integer, Integer> maskAndState) { synchronized (mLock) { int mask = maskAndState.first; int state = maskAndState.second; updateLocked(name, mHeadsetState | (mask & state) & ~(mask & ~state)); return; } } } /** * Updates the mask bit at {@code position} to 1 and the state bit at {@code position} to true * if {@code name=1} or false if {}@code name=0} is contained in {@code state}. */ private static void updateBit(int[] maskAndState, int position, String state, String name) { maskAndState[0] |= position; if (state.contains(name + "=1")) { maskAndState[0] |= position; maskAndState[1] |= position; } else if (state.contains(name + "=0")) { maskAndState[0] |= position; maskAndState[1] &= ~position; } } }