uevent 学习总结

近期在调试一个usb 设备的插拔事件上报功能发现上层未能收到插拔事件。
核心代码就两行kobject_uevent(&dev->kobj, KOBJ_CHANGE);
private static final String USB_STATE_IGNOR = “DEVPATH=/devices/platform/usb_xhci”;
mUEventObserver = new UsbUEventObserver();
mUEventObserver.startObserving(USB_STATE_MATCH);
+mUEventObserver.startObserving(USB_STATE_IGNOR);
mUEventObserver.startObserving(ACCESSORY_START_MATCH);

但其中涉及到的代码块跨底层到上层
kernel 到hardware 到jni 到framework manager
其中底层核心代码为
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
device_error 函数是参照device_add 作的修改,目的是在usb 识别失败时调用,同时通过uevent change 事件 告诉android 系统 有事件发生。
上层要做的就是监听当前事件上报的文件节点。如果不知道具体节点可以监听其上一级节点。
但device_error 函数是有问题的,当前为了特殊功能才加的。

#ifdef CONFIG_BICV_USB_AUTHENTICATE
int device_error(struct device *dev)
{
struct device *parent = NULL;
struct kobject *kobj;
//struct class_interface *class_intf;
int error = -EINVAL;
struct kobject *glue_dir = NULL;

dev = get_device(dev);
#if 0
if (!dev)
	goto done;
#endif
if (!dev->p) {
	error = device_private_init(dev);
    #if 0
	if (error)
		goto done;
    #endif
}

/*
 * for statically allocated devices, which should all be converted
 * some day, we need to initialize the name. We prevent reading back
 * the name, and force the use of dev_name()
 */
if (dev->init_name) {
	dev_set_name(dev, "%s", dev->init_name);
	dev->init_name = NULL;
}

/* subsystems can specify simple device enumeration */
if (!dev_name(dev) && dev->bus && dev->bus->dev_name)
	dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id);

if (!dev_name(dev)) {
	error = -EINVAL;
	//goto name_error;
}

printk("device: '%s': %s\n", dev_name(dev), __func__);

parent = get_device(dev->parent);
kobj = get_device_parent(dev, parent);
if (IS_ERR(kobj)) {
	error = PTR_ERR(kobj);
	//goto parent_error;
}
if (kobj)
	dev->kobj.parent = kobj;

/* use parent numa_node */
if (parent && (dev_to_node(dev) == NUMA_NO_NODE))
	set_dev_node(dev, dev_to_node(parent));

/* first, register with generic layer. */
/* we require the name to be set before, and pass NULL */
printk("device: '%s': %s 01\n", dev_name(dev), __func__);
error = kobject_add(&dev->kobj, dev->kobj.parent, NULL);
printk("device: '%s': %s 02\n", dev_name(dev), __func__);
if (error) {
	glue_dir = get_glue_dir(dev);
	//goto Error;
}

/* notify platform of device entry */
if (platform_notify)
	platform_notify(dev);

kobject_uevent(&dev->kobj, KOBJ_CHANGE);
printk("device: '%s': %s 03\n", dev_name(dev), __func__);
//kobject_uevent(&dev->kobj, KOBJ_MAX);
//kobject_del(&dev->kobj);
//put_device(dev);
return error;

#if 0
error = device_create_file(dev, &dev_attr_uevent);
if (error)
goto attrError;

error = device_add_class_symlinks(dev);
if (error)
	goto SymlinkError;
error = device_add_attrs(dev);
if (error)
	goto AttrsError;
error = bus_add_device(dev);
if (error)
	goto BusError;
error = dpm_sysfs_add(dev);
if (error)
	goto DPMError;
device_pm_add(dev);

if (MAJOR(dev->devt)) {
	error = device_create_file(dev, &dev_attr_dev);
	if (error)
		goto DevAttrError;

	error = device_create_sys_dev_entry(dev);
	if (error)
		goto SysEntryError;

	devtmpfs_create_node(dev);
}

/* Notify clients of device addition.  This call must come
 * after dpm_sysfs_add() and before kobject_uevent().
 */
if (dev->bus)
	blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
				     BUS_NOTIFY_ADD_DEVICE, dev);

kobject_uevent(&dev->kobj, KOBJ_ADD);
bus_probe_device(dev);
if (parent)
	klist_add_tail(&dev->p->knode_parent,
		       &parent->p->klist_children);

if (dev->class) {
	mutex_lock(&dev->class->p->mutex);
	/* tie the class to the device */
	klist_add_tail(&dev->knode_class,
		       &dev->class->p->klist_devices);

	/* notify any interfaces that the device is here */
	list_for_each_entry(class_intf,
			    &dev->class->p->interfaces, node)
		if (class_intf->add_dev)
			class_intf->add_dev(dev, class_intf);
	mutex_unlock(&dev->class->p->mutex);
}

done:
put_device(dev);
return error;
SysEntryError:
if (MAJOR(dev->devt))
device_remove_file(dev, &dev_attr_dev);
DevAttrError:
device_pm_remove(dev);
dpm_sysfs_remove(dev);
DPMError:
bus_remove_device(dev);
BusError:
device_remove_attrs(dev);
AttrsError:
device_remove_class_symlinks(dev);
SymlinkError:
device_remove_file(dev, &dev_attr_uevent);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
glue_dir = get_glue_dir(dev);
kobject_del(&dev->kobj);
Error:
cleanup_glue_dir(dev, glue_dir);
parent_error:
put_device(parent);
name_error:
kfree(dev->p);
dev->p = NULL;
goto done;
#endif

}
EXPORT_SYMBOL_GPL(device_error);
#endif

/*

  • Copyright © 2008 The Android Open Source Project
  • Licensed under the Apache License, Version 2.0 (the “License”);
  • you may not use this file except in compliance with the License.
  • You may obtain a copy of the License at
  •  http://www.apache.org/licenses/LICENSE-2.0
    
  • Unless required by applicable law or agreed to in writing, software
  • distributed under the License is distributed on an “AS IS” BASIS,
  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  • See the License for the specific language governing permissions and
  • limitations under the License.
    */

package android.os;

import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;

import java.util.ArrayList;
import java.util.HashMap;

/**

  • UEventObserver is an abstract class that receives UEvents from the kernel.

  • Subclass UEventObserver, implementing onUEvent(UEvent event), then call

  • startObserving() with a match string. The UEvent thread will then call your

  • onUEvent() method when a UEvent occurs that contains your match string.

  • 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 UEventObserver {
    private static final String TAG = “UEventObserver”;
    private static final boolean DEBUG = true;//false;

    private static UEventThread sThread;

    private static native void nativeSetup();
    private static native String nativeWaitForNextEvent();
    private static native void nativeAddMatch(String match);
    private static native void nativeRemoveMatch(String match);

    @UnsupportedAppUsage
    public UEventObserver() {
    }

    @Override
    protected void finalize() throws Throwable {
    try {
    stopObserving();
    } finally {
    super.finalize();
    }
    }

    private static UEventThread getThread() {
    synchronized (UEventObserver.class) {
    if (sThread == null) {
    sThread = new UEventThread();
    sThread.start();
    }
    return sThread;
    }
    }

    private static UEventThread peekThread() {
    synchronized (UEventObserver.class) {
    return sThread;
    }
    }

    /**

    • Begin observation of UEvents.

    • This method will cause the UEvent thread to start if this is the first

    • invocation of startObserving in this process.

    • Once called, the UEvent thread will call onUEvent() when an incoming

    • UEvent matches the specified string.

    • This method can be called multiple times to register multiple matches.

    • Only one call to stopObserving is required even with multiple registered

    • matches.

    • @param match A substring of the UEvent to match. Try to be as specific

    • as possible to avoid incurring unintended additional cost from processing

    • irrelevant messages. Netlink messages can be moderately high bandwidth and

    • are expensive to parse. For example, some devices may send one netlink message

    • for each vsync period.
      */
      @UnsupportedAppUsage
      public final void startObserving(String match) {
      if (match == null || match.isEmpty()) {
      throw new IllegalArgumentException(“match substring must be non-empty”);
      }

      final UEventThread t = getThread();
      t.addObserver(match, this);
      }

    /**

    • End observation of UEvents.

    • This process’s UEvent thread will never call onUEvent() on this
    • UEventObserver after this call. Repeated calls have no effect.
      */
      @UnsupportedAppUsage
      public final void stopObserving() {
      final UEventThread t = peekThread();
      if (t != null) {
      t.removeObserver(this);
      }
      }

    /**

    • Subclasses of UEventObserver should override this method to handle
    • UEvents.
      */
      @UnsupportedAppUsage
      public abstract void onUEvent(UEvent event);

    /**

    • Representation of a UEvent.
      */
      public static final class UEvent {
      // collection of key=value pairs parsed from the uevent message
      private final HashMap<String,String> mMap = new HashMap<String,String>();

      public UEvent(String message) {
      int offset = 0;
      int length = message.length();

       while (offset < length) {
           int equals = message.indexOf('=', offset);
           int at = message.indexOf('\0', offset);
           if (at < 0) break;
      
           if (equals > offset && equals < at) {
               // key is before the equals sign, and value is after
               mMap.put(message.substring(offset, equals),
                       message.substring(equals + 1, at));
           }
      
           offset = at + 1;
       }
      

      }

      @UnsupportedAppUsage
      public String get(String key) {
      return mMap.get(key);
      }

      @UnsupportedAppUsage
      public String get(String key, String defaultValue) {
      String result = mMap.get(key);
      return (result == null ? defaultValue : result);
      }

      public String toString() {
      return mMap.toString();
      }
      }

    private static final class UEventThread extends Thread {
    /** Many to many mapping of string match to observer.
    * Multimap would be better, but not available in android, so use
    * an ArrayList where even elements are the String match and odd
    * elements the corresponding UEventObserver observer */
    private final ArrayList mKeysAndObservers = new ArrayList();

     private final ArrayList<UEventObserver> mTempObserversToSignal =
             new ArrayList<UEventObserver>();
    
     public UEventThread() {
         super("UEventObserver");
     }
    
     @Override
     public void run() {
         nativeSetup();
    
         while (true) {
             String message = nativeWaitForNextEvent();
             if (message != null) {
                 if (DEBUG) {
                     Log.d(TAG, message);
                 }
     			Log.d(TAG, "UEventObserver begin");
                 sendEvent(message);
             }
         }
     }
    
     private void sendEvent(String message) {
         synchronized (mKeysAndObservers) {
             final int N = mKeysAndObservers.size();
             for (int i = 0; i < N; i += 2) {
                 final String key = (String)mKeysAndObservers.get(i);
                 if (message.contains(key)) {
                     final UEventObserver observer =
                             (UEventObserver)mKeysAndObservers.get(i + 1);
                     mTempObserversToSignal.add(observer);
                 }
             }
         }
    
         if (!mTempObserversToSignal.isEmpty()) {
             final UEvent event = new UEvent(message);
             final int N = mTempObserversToSignal.size();
             for (int i = 0; i < N; i++) {
                 final UEventObserver observer = mTempObserversToSignal.get(i);
                 observer.onUEvent(event);
             }
             mTempObserversToSignal.clear();
         }
     }
    
     public void addObserver(String match, UEventObserver observer) {
         synchronized (mKeysAndObservers) {
             mKeysAndObservers.add(match);
             mKeysAndObservers.add(observer);
             nativeAddMatch(match);
         }
     }
    
     /** Removes every key/value pair where value=observer from mObservers */
     public void removeObserver(UEventObserver observer) {
         synchronized (mKeysAndObservers) {
             for (int i = 0; i < mKeysAndObservers.size(); ) {
                 if (mKeysAndObservers.get(i + 1) == observer) {
                     mKeysAndObservers.remove(i + 1);
                     final String match = (String)mKeysAndObservers.remove(i);
                     nativeRemoveMatch(match);
                 } else {
                     i += 2;
                 }
             }
         }
     }
    

    }
    }

private static native void nativeSetup();
private static native String nativeWaitForNextEvent();
private static native void nativeAddMatch(String match);
private static native void nativeRemoveMatch(String match);

/*

  • Copyright © 2008 The Android Open Source Project
  • Licensed under the Apache License, Version 2.0 (the “License”);
  • you may not use this file except in compliance with the License.
  • You may obtain a copy of the License at
  •  http://www.apache.org/licenses/LICENSE-2.0
    
  • Unless required by applicable law or agreed to in writing, software
  • distributed under the License is distributed on an “AS IS” BASIS,
  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  • See the License for the specific language governing permissions and
  • limitations under the License.
    */

#define LOG_TAG “UEventObserver”
#define LOG_NDEBUG 1

#include “utils/Log.h”

#include “hardware_legacy/uevent.h”
#include “jni.h”
#include <nativehelper/JNIHelp.h>
#include “core_jni_helpers.h”

#include <utils/Mutex.h>
#include <utils/Vector.h>
#include <utils/String8.h>
#include <nativehelper/ScopedUtfChars.h>

namespace android {

static Mutex gMatchesMutex;
static Vector gMatches;

static void nativeSetup(JNIEnv *env, jclass clazz) {
if (!uevent_init()) {
jniThrowException(env, “java/lang/RuntimeException”,
“Unable to open socket for UEventObserver”);
}
}

static bool isMatch(const char* buffer, size_t length) {
AutoMutex _l(gMatchesMutex);

for (size_t i = 0; i < gMatches.size(); i++) {
    const String8& match = gMatches.itemAt(i);

    // Consider all zero-delimited fields of the buffer.
    const char* field = buffer;
    const char* end = buffer + length + 1;
    do {
        if (strstr(field, match.string())) {
            ALOGV("Matched uevent message with pattern: %s", match.string());
            return true;
        }
        field += strlen(field) + 1;
    } while (field != end);
}
return false;

}

static jstring nativeWaitForNextEvent(JNIEnv *env, jclass clazz) {
char buffer[1024];

for (;;) {
    int length = uevent_next_event(buffer, sizeof(buffer) - 1);
    if (length <= 0) {
        return NULL;
    }
    buffer[length] = '\0';

    ALOGV("Received uevent message: %s", buffer);

    if (isMatch(buffer, length)) {
        // Assume the message is ASCII.
        jchar message[length];
        for (int i = 0; i < length; i++) {
            message[i] = buffer[i];
        }
        return env->NewString(message, length);
    }
}

}

static void nativeAddMatch(JNIEnv* env, jclass clazz, jstring matchStr) {
ScopedUtfChars match(env, matchStr);

AutoMutex _l(gMatchesMutex);
gMatches.add(String8(match.c_str()));

}

static void nativeRemoveMatch(JNIEnv* env, jclass clazz, jstring matchStr) {
ScopedUtfChars match(env, matchStr);

AutoMutex _l(gMatchesMutex);
for (size_t i = 0; i < gMatches.size(); i++) {
    if (gMatches.itemAt(i) == match.c_str()) {
        gMatches.removeAt(i);
        break; // only remove first occurrence
    }
}

}

static const JNINativeMethod gMethods[] = {
{ “nativeSetup”, “()V”,
(void *)nativeSetup },
{ “nativeWaitForNextEvent”, “()Ljava/lang/String;”,
(void *)nativeWaitForNextEvent },
{ “nativeAddMatch”, “(Ljava/lang/String;)V”,
(void *)nativeAddMatch },
{ “nativeRemoveMatch”, “(Ljava/lang/String;)V”,
(void *)nativeRemoveMatch },
};

int register_android_os_UEventObserver(JNIEnv *env)
{
FindClassOrDie(env, “android/os/UEventObserver”);

return RegisterMethodsOrDie(env, "android/os/UEventObserver", gMethods, NELEM(gMethods));

}

} // namespace android

#include “hardware_legacy/uevent.h”
hardware/libhardware_legacy/uevent.c

/*

  • Copyright © 2008 The Android Open Source Project
  • Licensed under the Apache License, Version 2.0 (the “License”);
  • you may not use this file except in compliance with the License.
  • You may obtain a copy of the License at
  •  http://www.apache.org/licenses/LICENSE-2.0
    
  • Unless required by applicable law or agreed to in writing, software
  • distributed under the License is distributed on an “AS IS” BASIS,
  • WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  • See the License for the specific language governing permissions and
  • limitations under the License.
    */

#include <hardware_legacy/uevent.h>

#include <malloc.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <pthread.h>

#include <sys/socket.h>
#include <sys/un.h>
#include <sys/queue.h>
#include <linux/netlink.h>

LIST_HEAD(uevent_handler_head, uevent_handler) uevent_handler_list;
pthread_mutex_t uevent_handler_list_lock = PTHREAD_MUTEX_INITIALIZER;

struct uevent_handler {
void (*handler)(void *data, const char *msg, int msg_len);
void *handler_data;
LIST_ENTRY(uevent_handler) list;
};

static int fd = -1;

/* Returns 0 on failure, 1 on success /
int uevent_init()
{
struct sockaddr_nl addr;
int sz = 64
1024;
int s;

memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = getpid();
addr.nl_groups = 0xffffffff;

s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if(s < 0)
    return 0;

setsockopt(s, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));

if(bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
    close(s);
    return 0;
}

fd = s;
return (fd > 0);

}

int uevent_get_fd()
{
return fd;
}

int uevent_next_event(char* buffer, int buffer_length)
{
while (1) {
struct pollfd fds;
int nr;

    fds.fd = fd;
    fds.events = POLLIN;
    fds.revents = 0;
    nr = poll(&fds, 1, -1);
 
    if(nr > 0 && (fds.revents & POLLIN)) {
        int count = recv(fd, buffer, buffer_length, 0);
        if (count > 0) {
            struct uevent_handler *h;
            pthread_mutex_lock(&uevent_handler_list_lock);
            LIST_FOREACH(h, &uevent_handler_list, list)
                h->handler(h->handler_data, buffer, buffer_length);
            pthread_mutex_unlock(&uevent_handler_list_lock);

            return count;
        } 
    }
}

// won't get here
return 0;

}

int uevent_add_native_handler(void (*handler)(void *data, const char *msg, int msg_len),
void *handler_data)
{
struct uevent_handler *h;

h = malloc(sizeof(struct uevent_handler));
if (h == NULL)
    return -1;
h->handler = handler;
h->handler_data = handler_data;

pthread_mutex_lock(&uevent_handler_list_lock);
LIST_INSERT_HEAD(&uevent_handler_list, h, list);
pthread_mutex_unlock(&uevent_handler_list_lock);

return 0;

}

int uevent_remove_native_handler(void (*handler)(void *data, const char *msg, int msg_len))
{
struct uevent_handler *h;
int err = -1;

pthread_mutex_lock(&uevent_handler_list_lock);
LIST_FOREACH(h, &uevent_handler_list, list) {
    if (h->handler == handler) {
        LIST_REMOVE(h, list);
        err = 0;
        break;
   }
}
pthread_mutex_unlock(&uevent_handler_list_lock);

return err;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值