All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.ExtconUEventObserver Maven / Gradle / Ivy

/*
 * Copyright (C) 2018 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.annotation.Nullable;
import android.os.UEventObserver;
import android.util.ArrayMap;
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
 * /sys/class/extcon}. directory
 *
 * 

Subclass ExtconUEventObserver, implementing {@link #onUEvent(ExtconInfo, UEvent)}, then call * startObserving() with a ExtconInfo to observe. The UEvent thread will then call your onUEvent() * method when a UEvent occurs that matches the path of your ExtconInfos. * *

Call stopObserving() to stop receiving UEvents. * *

There is only one UEvent thread per process, even if that process has multiple UEventObserver * subclass instances. The UEvent thread starts when the startObserving() is called for the first * time in that process. Once started the UEvent thread will not stop (although it can stop * notifying UEventObserver's via stopObserving()). * * @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 means the selinux policies need to be changed."; private final Map mExtconInfos = new ArrayMap<>(); @Override public final void onUEvent(UEvent event) { String devPath = event.get("DEVPATH"); ExtconInfo info = mExtconInfos.get(devPath); if (info != null) { onUEvent(info, event); } else { Slog.w(TAG, "No match found for DEVPATH of " + event + " in " + mExtconInfos); } } /** * Subclasses of ExtconUEventObserver should override this method to handle UEvents. * * @param extconInfo that matches the {@code DEVPATH} of {@code event} * @param event the event */ protected abstract void onUEvent(ExtconInfo extconInfo, UEvent event); /** Starts observing {@link ExtconInfo#getDevicePath()}. */ public void startObserving(ExtconInfo extconInfo) { 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 getExtconInfos(@Nullable String regex) { if (!extconExists()) { return new ArrayList<>(0); // Always return a new list. } 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) { mName = name; } /** The name of the external connection */ public String getName() { return mName; } /** * The path to the device for this external connection. * *

NOTE getting this path involves resolving a symlink. * * @return the device path, or null if it not found. */ @Nullable public String getDevicePath() { try { String extconPath = String.format(Locale.US, "/sys/class/extcon/%s", mName); File devPath = new File(extconPath); if (devPath.exists()) { String canonicalPath = devPath.getCanonicalPath(); int start = canonicalPath.indexOf("/devices"); return canonicalPath.substring(start); } return null; } catch (IOException e) { Slog.e(TAG, "Could not get the extcon device path for " + mName, e); return null; } } /** The path to the state file */ public String getStatePath() { return String.format(Locale.US, "/sys/class/extcon/%s/state", mName); } } /** Does the {@code /sys/class/extcon/} directory exist */ public static boolean namedExtconDirExists(String name) { File extconDir = new File("/sys/class/extcon/" + name); return extconDir.exists() && extconDir.isDirectory(); } /** Does the {@code /sys/class/extcon} directory exist */ public static boolean extconExists() { File extconDir = new File("/sys/class/extcon"); return extconDir.exists() && extconDir.isDirectory(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy