Maemo Linux手机平台系列分析:7 Maemo平台开发之LibOSSO

看看GtkWindow如何被生出来的(gtk_window_new()的内部机制).  看看GtkWindow如何被生出来的.用Glib/GObject/Gtk也有很长时间了,没有时间往下刨根,现在刨一刨。 1 定义GtkWindow.. 22 展开它:... 2在gtype.h中定义如下宏:... 2把定义的宏展开:... 3再把GtkBin的定义展开:... 4再展开GtkContainer的定义://不用展开,直接定义的... 5G 阅读详情
 
这部分的内容:
  • LibOSSO介绍
  • 调用LibOSSO去实现D-Bus方法调用
  • 调用LibOSSO实现异步方法调用
  • 设备状态和模式的通知
  • 模拟设备状态的改变
 
LibOSSO介绍
几乎Maemo中所有的程序都要使用LibOSSO 库。主要的原因是:LibOSSO可以保护一些将被杀掉的进程幸免于难,而不被杀掉。当从任务导航栏中启动一个没有注册D-Bus服务的程序时,超过一定时间,这个程序将由桌面环境去杀掉。LibOSSO另外一个方面的功能是版本隔离作用:由于D-Bus仍然在开发升级中,由LibOSSO对D-Bus进行封装,用户程序只要调用LibOSSO的对应接口就行,不必去直接调用D-Bus接口。
除了保护和隔离作用外,LibOSSO还提供了另外一些有用的功能:自动保存和状态保存;处理硬件状态;以及其它重要的事件。还有:对D-Bus的封装可以使得LibOSSO提供非常方便的函数去做RPC(远程调用).
下面我们会重点介绍LibOSSO的RPC:
 
通过LibOSSO库实现D-Bus的方法调用
我们从哪开始呢?记得我们前面曾直接使用libdbus的函数实现了一个RPC, 这里我们依然使用这个例子,只不过,这次我们用LibOSSO的函数去实现一个同样弹出对话框的功能。当然,LibOSSO库中有个函数(osso_system_note_dialog)可以直接去实现这种功能. 我们暂时不用它。我们通过详细的代码看看LibOSSO如何支持RPC的。
头文件:
#include <libosso.h> //必须包含这个头文件
 
 /*... Listing cut for brevity ...*/
//与上面一个例子同样的定义
#define SYSNOTE_NAME "org.freedesktop.Notifications"
#define SYSNOTE_OPATH "/org/freedesktop/Notifications"
#define SYSNOTE_IFACE "org.freedesktop.Notifications"
#define SYSNOTE_NOTE "SystemNoteDialog"
[ 使用LibOSSO库函数需要包含的头文件 ]
使用LibOSSO库,仅仅需要包含一个libosso.h头文件,我们这里同样定义D-Bus service名字,对象路径、接口名字、方法名字;
我们看看LibOSSO的上下文如何创建的以及如何运行的:
int main(int argc, char** argv) {
 
 /* The LibOSSO context that we need to do RPC. */
 osso_context_t* ossoContext = NULL;
 
 g_print("Initializing LibOSSO/n");
 /* The program name for registration is communicated from the
    Makefile via a -D preprocessor directive. Since it doesn't
     contain any dots in it, a prefix of "com.nokia." will be added
     to it internally within osso_initialize(). */
 ossoContext = osso_initialize(ProgName, "1.0", FALSE, NULL);
 if (ossoContext == NULL) {
    g_error("Failed to initialize LibOSSO/n");
 }
 
 g_print("Invoking the method call/n");
 runRPC(ossoContext);
 
 g_print("Shutting down LibOSSO/n");
 /* Deinitialize LibOSSO. The function doesn't return status code so
     we cannot know whether it succeeded or failed. We assume that it
     always succeeds. */
 osso_deinitialize(ossoContext);
 ossoContext = NULL;
 
 g_print("Quitting/n");
 return EXIT_SUCCESS;
}
[LibOSSO 初始化与卸载,见(libosso-example-sync/libosso-rpc-sync.c) ]
LibOSSO上下文,这个数据结构含有通过D-Bus进行通信的必要信息。当准备创建这个上下文时,第一个参数:你需要传入一个程序名字给osso_initialize, 这个名字有两个用途:1,注册给D-Bus; 2, 将来阻止销毁任务杀掉你的进程。如果这个名字没有包含任何点字符,那么,LibOSSO会自动把那个名字加个前缀:com.nokia. 一般情况下,用户是看不到这个名字的,不过,这问题不大。如果你老是使用这种没有前缀的名字的话,可能会和别人的程序名冲突。建议使用全名。
第二个参数:版本号,目前LibOSSO中并没有用,不过你可以加上,以后可能会用的。
倒数第二个参数:如果最后一个参数传入NULL,这个参数不会起到任何作用。最后一个参数:使用LibOSSO自己的GMainLoop还是外面的,如果传入NULL,则直接使用LibOSSO内部的主循环。
释放LibOSSO 上下文会自动关闭链接到D-Bus上面的链接通道,同时释放一些分配的内存。
下面这一段代码演示了如何使用LibOSSO做RPC调用,以及错误处理。
/**
 * Do the RPC call.(实现D-Bus远程调用的示例)
 *
 * Note that this function will block until the method call either
 * succeeds, or fails. If the method call would take a long time to
 * run, this would block the GUI of the program (which we don't have).
 * ()
 * Needs the LibOSSO state to do the launch.
 */
static void runRPC(osso_context_t* ctx) {
 
 /* Message to display. */
 const char* dispMsg = "Hello SystemNote!/nVia LibOSSO/sync.";
 /* Icon type to use. */
 gint iconType = OSSO_GN_ERROR;
 /* Button label text to use, "" means leaving the defaults. */
 const char* labelText = "";
 
 /* Will hold the result from the RPC invocation function. */
 osso_return_t result;
 /* Will hold the result of the method call (or error). */
 osso_rpc_t methodResult = {};
 
 g_print("runRPC called/n");
 
 g_assert(ctx != NULL);
 
 /* Compared to the libdbus functions, LibOSSO provides conveniently
     a function that will do the dispatch and also allows us to pass
     the arguments all with one call. (libOSSO比libdbus更简单)
 
     The arguments for the "SystemNoteDialog" are the same as in
     dbus-example.c (since it is the same service). You might also
     notice that even if LibOSSO provides some convenience, it does
     not completely isolate us from libdbus. We still supply the
     argument types using D-Bus constants. (在传参数方面,LibOSSO并没有完全同D-Bus隔离,还是使用D-Bus的参数规定)
 
     NOTE Do not pass the argument values by pointers as with libdbus,
          instead pass them by value (as below). */
/* (这是个阻塞调用,如果失败的话,可能会花费很长时间才能返回,这取决于D-Bus的超时时间值,D-Bus同步调用的超时时间值一般是25s)*/
 result = osso_rpc_run(ctx,
                        SYSNOTE_NAME,      /* well-known name */
                        SYSNOTE_OPATH,         /* object path */
                        SYSNOTE_IFACE,           /* interface */
                        SYSNOTE_NOTE,          /* method name */
                        &methodResult, /* method return value */
                        /* The arguments for the RPC. The types
                           are unchanged, but instead of passing
                           them via pointers, they're passed by
                           "value" instead. */
                        DBUS_TYPE_STRING, dispMsg,
                        DBUS_TYPE_UINT32, iconType,
                        DBUS_TYPE_STRING, labelText,
                        DBUS_TYPE_INVALID);
 /* Check whether launching the RPC succeeded. */
 if (result != OSSO_OK) {
    g_error("Error launching the RPC (%s)/n",
            ossoErrorStr(result));
    /* We also terminate right away since there's nothing to do. */
 }
 g_print("RPC launched successfully/n");
 
 /* Now decode the return data from the method call.
     NOTE: If there is an error during RPC delivery, the return value
           will be a string. It is not possible to differentiate that
           condition from an RPC call that returns a string.
 
     If a method returns "void", the type-field in the methodResult
     will be set to DBUS_TYPE_INVALID. This is not an error. */
 g_print("Method returns: ");
 printOssoValue(&methodResult); /* 查看方法调用的返回情况 */
 g_print("/n");
 
 g_print("runRPC ending/n");
}
大家一定要注意:函数osso_rpc_run是个同步(阻塞)调用,有两种结果:有个及时的相应;或者超时返回。在实际使用过程中,一定要铭记这是一个阻塞的调用。另外呢:LibOSSO也有一套异步(非阻塞)的RPC函数。
如果你的方法调用返回不止一个值(D-Bus是支持的),不过,LibOSSO 目前并不支持返回所有的(而是返回第一个)。
对于函数返回码的Error code,这里非常直接的。我有篇文章是专门讲如何做Error code, 那篇文章中对于Error code的解析非常好:有巧妙的、有直白的,也有更专业的。
/**
 * Utility to return a pointer to a statically allocated string giving
 * the textural representation of LibOSSO errors. Has no internal
 * state (safe to use from threads).
 *
 * LibOSSO does not come with a function for this, so we define one
 * ourselves.
 */
static const gchar* ossoErrorStr(osso_return_t errCode) {
 
 switch (errCode) {
    case OSSO_OK:
      return "No error (OSSO_OK)";
    case OSSO_ERROR:
      return "Some kind of error occurred (OSSO_ERROR)";
    case OSSO_INVALID:
      return "At least one parameter is invalid (OSSO_INVALID)";
    case OSSO_RPC_ERROR:
      return "Osso RPC method returned an error (OSSO_RPC_ERROR)";
    case OSSO_ERROR_NAME:
      return "(undocumented error) (OSSO_ERROR_NAME)";
    case OSSO_ERROR_NO_STATE:
      return "No state file found to read (OSSO_ERROR_NO_STATE)";
    case OSSO_ERROR_STATE_SIZE:
      return "Size of state file unexpected (OSSO_ERROR_STATE_SIZE)";
    default:
      return "Unknown/Undefined";
 }
}
对于函数返回值的解析,有点复杂,因为返回值是包含在一个结构中的,需要逐个分拣。
/**
 * Utility to print out the type and content of given osso_rpc_t.
 * It also demonstrates the types available when using LibOSSO for
 * the RPC. Most simple types are available, but arrays are not
 * (unfortunately).
 */
static void printOssoValue(const osso_rpc_t* val) {
 
 g_assert(val != NULL);
 
 // 对返回值的类型进行分拣,还是D-Bus的特色,让人用起来不习惯
 switch (val->type) {
    case DBUS_TYPE_BOOLEAN:
      g_print("boolean:%s", (val->value.b == TRUE)?"TRUE":"FALSE");
      break;
    case DBUS_TYPE_DOUBLE:
      g_print("double:%.3f", val->value.d);
      break;
    case DBUS_TYPE_INT32:
      g_print("int32:%d", val->value.i);
      break;
    case DBUS_TYPE_UINT32:
      g_print("uint32:%u", val->value.u);
      break;
    case DBUS_TYPE_STRING:
      g_print("string:'%s'", val->value.s);
      break;
    case DBUS_TYPE_INVALID:
      g_print("invalid/void");
      break;
    default:
      g_print("unknown(type=%d)", val->type);
      break;
 }
}
请注意:libOSSO RPC函数并不支持数组参数,因此你要使用一些简单的参数了L。这可是不好的消息,GArray不能在libOSSO 中使用了?D-Bus可是支持的啊。估计是支持的,有时间试探试探。
把上面的例子编译后运行,我们发现会弹出一个熟悉的对话框。
[sbox-CHINOOK_X86: ~/libosso-example-sync] > run-standalone.sh ./libosso-rpc-sync
Initializing LibOSSO
Invoking the method call
runRPC called
/dev/dsp: No such file or directory
RPC launched successfully
Method returns: uint32:8
runRPC ending
Shutting down LibOSSO
Quitting
和前一个例子的区别就是,多了一个关于音频设备的错误信息。这个信息可能会在RPC返回之前出现,因为runRPC是阻塞调用。
 
我们在前面的代码中用到了一个程序名称:ProgName,我们一般把它定义在makefile文件中,为什么呢?有时候我们需要分别编译i386和ARMEL,如果定义在头文件中,可能需要区分定义,如果放在makefile总定义,由于makefile的开头一般会先区分i386,和ARM。另外一个好处是,我们把ProgName定义在makefile中,可以提高上面代码的复用率。
# define a list of pkg-config packages we want to use
pkg_packages := glib-2.0 libosso
 
# ... Listing cut for brevity ...
 
libosso-rpc-sync: libosso-rpc-sync.c
      $(CC) $(CFLAGS) -DProgName=/"LibOSSOExample/" / #定义在这里好处有两个,1 提高代码重用性,2 方便为不同的archetecture定义
       $< -o $@ $(LDFLAGS)
 
LibOSSO的异步调用
有时候,一个函数需要很长时间才能执行完,或者你不能确定这个函数是否需要很长时间,这些情况下,你应当使用异步调用,而不要使用同步调用。同步和异步最大的区别就是:异步是把同步割成两部分,启动RPC和在回调中处理返回结果。就是说,你RPC什么时候回来,我什么时候处理你的结果,这样就不至于导致D-Bus的超时问题。
为了使用LibOSSO的回调和控制其主循环,我们需要创建一个状态变量,这个状态变量在需要时,会传递给回调。
/**
 * Small application state so that we can pass both LibOSSO context
 * and the mainloop around to the callbacks.
 */
typedef struct {
 /* A mainloop object that will "drive" our example. */
 GMainLoop* mainloop;
  /* The LibOSSO context which we use to do RPC. */
 osso_context_t* ossoContext;
} ApplicationState;
函数osso_rpc_async_run是用来启动异步调用的,并且它立即返回。如果它返回了一个错误,可能是client端的错误,而不是server端得错误,因为RPC的错误没有通过它返回。那么,谁来处理RPC的回应数据呢,回调函数!
/**
 * We launch the RPC call from within a timer callback in order to
 * make sure that a mainloop object will be running when the RPC will
 * return (to avoid a nasty race condition).
 *
 * So, in essence this is a one-shot timer callback.
 *
 * In order to launch the RPC, it will need to get a valid LibOSSO
 * context (which is carried via the userData/application state
 * parameter).
 */
static gboolean launchRPC(gpointer userData) {
 
 ApplicationState* state = (ApplicationState*)userData;
 /* Message to display. */
 const char* dispMsg = "Hello SystemNote!/nVia LibOSSO/async.";
 /* Icon type to use. */
 gint iconType = OSSO_GN_ERROR;
 /* Button label text to use. */
 const char* labelText = "Execute!";
 
 /* Will hold the result from the RPC launch call. */
 osso_return_t result;
 
 g_print("launchRPC called/n");
 
 g_assert(state != NULL);
 
 /*... Listing cut for brevity ...*/
 
 /* The only difference compared to the synchronous version is the
     addition of the callback function parameter, and the user-data
     parameter for data that will be passed to the callback. */
 result = osso_rpc_async_run(state->ossoContext,
                              SYSNOTE_NAME,     /* well-known name */
                              SYSNOTE_OPATH,        /* object path */
                              SYSNOTE_IFACE,          /* interface */
                              SYSNOTE_NOTE,         /* method name */
                              rpcCompletedCallback,    /* 这就是我们注册的回调函数,async cb */
                              state,           /* user-data for cb */
                              /* The arguments for the RPC. */
                              DBUS_TYPE_STRING, dispMsg,
                              DBUS_TYPE_UINT32, iconType,
                              DBUS_TYPE_STRING, labelText,
                              DBUS_TYPE_INVALID);
 /* Check whether launching the RPC succeeded (we don't know the
     result from the RPC itself). */
 if (result != OSSO_OK) {
    g_error("Error launching the RPC (%s)/n",
            ossoErrorStr(result));
    /* We also terminate right away since there's nothing to do. */
 }
 g_print("RPC launched successfully/n");
 
 g_print("launchRPC ending/n");
 
 /* We only want to be called once, so ask the caller to remove this
     callback from the timer launch list by returning FALSE. */
 return FALSE;
}
由一个简单的回调函数来处理RPC的返回,在这个函数中使用osso_rpc_async_run的两个参数:interface 和method,这两个参数非常有用,这样的话,你就可以对多个RPC使用同一个回调函数了,因为这些RPC的interface和method都不同。
这个返回值的数据结构的内存是由LibOSSO分配的,当你的回调函数返回后,这个变量会由LibOSSO释放,因此,你不必手动去处理这个事情(这也是使用回调机制要注意的问题)。
/**
 * Will be called from LibOSSO when the RPC return data is available.
 * Will print out the result, and return. Note that it must not free
 * the value, since it does not own it.
 *
 * The prototype (for reference) must be osso_rpc_async_f().
 *
 * The parameters for the callback are the D-Bus interface and method
 * names (note that object path and well-known name are NOT
 * communicated). The idea is that you can then reuse the same
 * callback to process completions from multiple simple RPC calls.
 */
static void rpcCompletedCallback(const gchar* interface,
                                 const gchar* method,
                                 osso_rpc_t* retVal,
                                 gpointer userData) {
 
 ApplicationState* state = (ApplicationState*)userData;
 
 g_print("rpcCompletedCallback called/n");
 
 g_assert(interface != NULL);
 g_assert(method != NULL);
 g_assert(retVal != NULL);
 g_assert(state != NULL);
 
 g_print(" interface: %s/n", interface);
 g_print(" method: %s/n", method);
 /* NOTE If there is an error in the RPC delivery, the return value
          will be a string. This is unfortunate if your RPC call is
          supposed to return a string as well, since it is not
          possible to differentiate between the two cases.
 
          If a method returns "void", the type-field in the retVal
          will be set to DBUS_TYPE_INVALID (it's not an error). */
 g_print(" result: ");
 printOssoValue(retVal);
 g_print("/n");
 
 /* Tell the main loop to terminate. */
 g_main_loop_quit(state->mainloop);
 
 g_print("rpcCompletedCallback done/n");
}
 
下面是例子的代码:
int main(int argc, char** argv) {
 
 /* Keep the application state in main's stack. */
 ApplicationState state = {};
 /* Keeps the results from LibOSSO functions for decoding. */
 osso_return_t result;
 /* Default timeout for RPC calls in LibOSSO. */
 gint rpcTimeout;
 
 g_print("Initializing LibOSSO/n");
 state.ossoContext = osso_initialize(ProgName, "1.0", FALSE, NULL);
 if (state.ossoContext == NULL) {
    g_error("Failed to initialize LibOSSO/n");
 }
 
 /* Print out the default timeout value (which we don't change, but
     could, with osso_rpc_set_timeout()). */
 result = osso_rpc_get_timeout(state.ossoContext, &rpcTimeout);
 if (result != OSSO_OK) {
    g_error("Error getting default RPC timeout (%s)/n",
            ossoErrorStr(result));
 }
 /* Interestingly the timeout seems to be -1, but is something else
     (by default). -1 probably then means that "no timeout has been
     set". */
 g_print("Default RPC timeout is %d (units)/n", rpcTimeout);
 
 g_print("Creating a mainloop object/n");
 /* Create a GMainLoop with default context and initial condition of
     not running (FALSE). */
 state.mainloop = g_main_loop_new(NULL, FALSE);
 if (state.mainloop == NULL) {
    g_error("Failed to create a GMainLoop/n");
 }
 
 g_print("Adding timeout to launch the RPC in one second/n");
 /* This could be replaced by g_idle_add(cb, &state), in order to
     guarantee that the RPC would be launched only after the mainloop
     has started. We opt for a timeout here (for no particular
     reason). */
 g_timeout_add(1000, (GSourceFunc)launchRPC, &state);
 
 g_print("Starting mainloop processing/n");
 g_main_loop_run(state.mainloop);
 
 g_print("Out of mainloop, shutting down LibOSSO/n");
 /* Deinitialize LibOSSO. */
 osso_deinitialize(state.ossoContext);
 state.ossoContext = NULL;
 
 /* Free GMainLoop as well. */
 g_main_loop_unref(state.mainloop);
 state.mainloop = NULL;
 
 g_print("Quitting/n");
 return EXIT_SUCCESS;
}
测试的结果可能有点意外:
[sbox-CHINOOK_X86: ~/libosso-example-async] > run-standalone.sh ./libosso-rpc-async
Initializing LibOSSO
Default RPC timeout is -1 (units)
Creating a mainloop object
Adding timeout to launch the RPC in one second
Starting mainloop processing
launchRPC called
RPC launched successfully
launchRPC ending
rpcCompletedCallback called
 interface: org.freedesktop.Notifications
 method: SystemNoteDialog
 result: uint32:10
rpcCompletedCallback done
Out of mainloop, shutting down LibOSSO
Quitting
/dev/dsp: No such file or directory
你可能已经注意到了,声音设备的错误,在最下面才打印出来,为什么?看起来好像是对话框运行很久后,才开始播放声音。这和前面的同步调用有明显的区别。这再次说明了:你不能依赖D-Bus的远程方法调用的时间精确性;
 
设备状态与模式的通知:
既然Internet Tablets是移动设备,你当然希望人们在移动过程中使用它(或者您开发的软件)。另外,在飞机上或者其他地方可能无法连接网络。所以你需要知道如何处理这种状态切换
为了演示如何处理设备的重要状态,下面我们用一个小工具程序演示一下。比如说:飞行模式。用户切换设备到“掉线”模式,就会激活飞行模式。
这个程序是用来跟踪手机的背光情况,通过定期的向系统轮询,是否推迟关闭背光。一般情况下,屏幕如果一段时间没有使用,则背光关闭,这主要为了省电,对于待机时间来说是非常重要的。当然,用户可以通过手机设置来完成背光的配置,不过我们不这么做。我们用这个程序来自动推迟背光的关闭. 这里我们使用45秒的定时器来控制。
我们同时也跟踪手机的模式,一旦手机进入了飞行模式,这个程序将会被关闭,因此,如果手机已经处于飞行模式,是不能启动这个程序的。
由于这个程序是在后台运行的,没有自己的用户界面,因此我们使用通知对话框来显示一些信息给用户,提醒用户。
下面是主要的流程:
/**
 * Main program:
 *
 * 1) Setup application state // 设置程序的状态
 * 2) Start mainloop         // 启动主循环
 * 3) Release application state & terminate // 释放程序状态和退出
 */
int main(int argc, char** argv) {
 
 /* We'll keep one application state in our program and allocate
     space for it from the stack. */
 ApplicationState state = {};
 
 g_print(PROGNAME ":main Starting/n");
 /* Attempt to setup the application state and if something goes
     wrong, do cleanup here and exit. */
 if (setupAppState(&state) == FALSE) {
    g_print(PROGNAME ":main Setup failed, doing cleanup/n");
    releaseAppState(&state);
    g_print(PROGNAME ":main Terminating with failure/n");
    return EXIT_FAILURE;
 }
 
 g_print(PROGNAME ":main Starting mainloop processing/n");
 g_main_loop_run(state.mainloop);
 g_print(PROGNAME ":main Out of main loop (shutting down)/n");
 /* We come here when the application state has the running flag set
     to FALSE and the device state changed callback has decided to
     terminate the program. Display a message to the user about
     termination next. */
 displayExitMessage(&state, ProgName " exiting");
 
 /* Release the state and exit with success. */
 releaseAppState(&state);
 
 g_print(PROGNAME ":main Quitting/n");
 return EXIT_SUCCESS;
}
为了让设备状态的回调函数能强制让程序退出,我们需要传递LibOSSO的上下文给这个回调函数,同时也要让回调函数能访问主循环对象以及用一个标记量来通知定时器去退出(因为定时器是不能在Glib外部被删除的)。
/* Application state.
 
   Contains the necessary state to control the application lifetime
   and use LibOSSO. */
typedef struct {
 /* The GMainLoop that will run our code. */
 GMainLoop* mainloop;
 /* LibOSSO context that is necessary to use LibOSSO functions. */
 osso_context_t* ossoContext;
 /* Flag to tell the timer that it should stop running. Also utilized
     to tell the main program that the device is already in Flight-
     mode and the program shouldn't continue startup. */
 gboolean running;
} ApplicationState;
所有的设置和启动操作都是在函数setupAppState中完成的, 同时也包含了一些非常重要的步骤:
/**
 * Utility to setup the application state.
 *
 * 1) 初始化LibOSSO (链接到D-Bus)
 * 2) 创建一个主循环对象
 * 3) 注册回调函数
 *    这个回调函数只会在注册时调用一次.
 *    当程序需要结束时,这个回调函数把state->running复位,通过这个*    变量我们可以知道是否要运行程序。否则,显示一个错误对话框。
* 4) 注册定时器回调函数(用于保持空白屏幕)
 * 5) Un-blank the screen.
 * 6) 当电池不够时,显示告警提示框.
 * 7) 发送第一个“推迟关闭背光”的命令
 *
 * 如果这个函数返回TRUE, 一切正常,否则,出差错了。
*/
static gboolean setupAppState(ApplicationState* state) {
 
 osso_return_t result;
 
 g_assert(state != NULL);
 
 g_print(PROGNAME ":setupAppState starting/n");
 
 /* Zero out the state. Has the benefit of setting all pointers to
     NULLs and all gbooleans to FALSE. This is useful when we'll need
     to determine what to release later. */
 memset(state, 0, sizeof(ApplicationState));
 
 g_print(PROGNAME ":setupAppState Initializing LibOSSO/n");
 
 /*... Listing cut for brevity ...*/
 
 state->ossoContext = osso_initialize(ProgName, "1.0", FALSE, NULL);
 if (state->ossoContext == NULL) {
    g_printerr(PROGNAME ": Failed to initialize LibOSSO/n");
    return FALSE;
 }
 
 g_print(PROGNAME ":setupAppState Creating a GMainLoop object/n");
 /* Create a new GMainLoop object, with default context (NULL) and
     initial "running"-state set to FALSE. */
 state->mainloop = g_main_loop_new(NULL, FALSE);
 if (state->mainloop == NULL) {
    g_printerr(PROGNAME ": Failed to create a GMainLoop/n");
    return FALSE;
 }
 
 g_print(PROGNAME
          ":setupAddState Adding hw-state change callback./n");
 /* The callback will be called immediately with the state, so we
     need to know whether we're in offline mode to start with. If so,
     the callback will set the running-member to FALSE (and we'll
     check it below). */
 state->running = TRUE;
 /* In order to receive information about device state and changes
     in it, we register our callback here.
 
     Parameters for the osso_hw_set_event_cb():
       osso_context_t* : LibOSSO context object to use.
       osso_hw_state_t* : Pointer to a device state type that we're
                          interested in. NULL for "all states".
       osso_hw_cb_f* :    Function to call on state changes.
       gpointer :         User-data passed to callback. */
 result = osso_hw_set_event_cb(state->ossoContext,
                                NULL, /* We're interested in all. */
                                deviceStateChanged,
                                state);
 if (result != OSSO_OK) {
    g_printerr(PROGNAME
               ":setupAppState Failed to get state change CB/n");
    /* Since we cannot reliably know when to terminate later on
       without state information, we will refuse to run because of the
       error. */
    return FALSE;
 }
 /* We're in "Flight" mode? */
 if (state->running == FALSE) {
    g_print(PROGNAME ":setupAppState In offline, not continuing./n");
    displayExitMessage(state, ProgName " not available in Offline mode");
    return FALSE;
 }
 
 g_print(PROGNAME ":setupAppState Adding blanking delay timer./n");
 if (g_timeout_add(45000,
                    (GSourceFunc)delayBlankingCallback,
                    state) == 0) {
    /* If g_timeout_add returns 0, it signifies an invalid event
       source id. This means that adding the timer failed. */
    g_printerr(PROGNAME ": Failed to create a new timer callback/n");
    return FALSE;
 }
 
 /* Un-blank the display (will always succeed in the SDK). */
 g_print(PROGNAME ":setupAppState Unblanking the display/n");
 result = osso_display_state_on(state->ossoContext);
 if (result != OSSO_OK) {
    g_printerr(PROGNAME ": Failed in osso_display_state_on (%s)/n",
               ossoErrorStr(result));
    /* If the RPC call fails, odds are that nothing else will work
       either, so we decide to quit instead. */
    return FALSE;
 }
 
 /* Display a "Note"-dialog with a WARNING icon.
     The Dialog is MODAL, so user cannot do anything with the stylus
     until the Ok is selected, or the Back-key is pressed. */
 
 /*... Listing cut for brevity ...*/
 
 /* Other icons available:
      OSSO_GN_NOTICE: For general notices.
     OSSO_GN_WARNING: For warning messages.
       OSSO_GN_ERROR: For error messages.
        OSSO_GN_WAIT: For messages about "delaying" for something (an
                      hourglass icon is displayed).
                   5: Animated progress indicator. */
 
 /*... Listing cut for brevity ...*/
 
 g_print(PROGNAME ":setupAppState Displaying Note dialog/n");
 result = osso_system_note_dialog(state->ossoContext,
                                   /* UTF-8 text into the dialog */
                                   "Started " ProgName "./n"
                       "Please remember to stop it when you're done, "
                                "in order to conserve battery power.",
                                   /* Icon to use */
                                   OSSO_GN_WARNING,
                                   /* We're not interested in the RPC
                                      return value. */
                                   NULL);
 if (result != OSSO_OK) {
    g_error(PROGNAME ": Error displaying Note dialog (%s)/n",
            ossoErrorStr(result));
 }
 g_print(PROGNAME ":setupAppState Requested for the dialog/n");
 
 /* Then delay the blanking timeout so that our timer callback has a
     chance to run before that. */
 delayDisplayBlanking(state);
 
 g_print(PROGNAME ":setupAppState Completed/n");
 
 /* State set up. */
 return TRUE;
}
 
处理设备状态改变的回调是有函数osso_hw_set_event_cb注册的,同时我们也知道了如何强制打开背光。与此同时,我们注册了定时器的回调,这个回调在45秒后被调用。
处理设备状态的回调将接收新的“硬件状态”和用户传入的自定义数据。在注册时,它就被调用了一次。这次调用讲通知应用程序当前设备的最初状态。我们就利用这个来判断当前手机是否处于飞行状态。另外,由于我们不知道这个主循环是否处于激活状态,所以我们使用了一个额外的标志量来通知定时器回调函数去关闭这个主循环。
/**
 *
* 这个回调会在两种情况下被调用:1 注册时; 2 设备状态改变时
 *
 * The device state structure contains flags telling about conditions
 * that might affect applications, as well as the mode of the device
 * (for example telling whether the device is in "in-flight"-mode).
 */
static void deviceStateChanged(osso_hw_state_t* hwState,
                               gpointer data) {
 ApplicationState* state = (ApplicationState*)data;
 
 g_print(PROGNAME ":deviceStateChanged Starting/n");
 
 printDeviceState(hwState);
 
 /* If device is in/going into "flight-mode" (called "Offline" on
     some devices), we stop our operation automatically. Obviously
     this makes flashlight useless (as an application) if someone gets
     stuck in a dark cargo bay of a plane with snakes.. But we still
     need a way to shut down the application and react to device
     changes, and this is the easiest state to test with.
 
     Note that since offline mode will terminate network connections,
     you will need to test this on the device itself, not over ssh. */
 if (hwState->sig_device_mode_ind == OSSO_DEVMODE_FLIGHT) {
    g_print(PROGNAME ":deviceStateChanged In/going into offline./n");
 
    /* Terminate the mainloop.
       NOTE: Since this callback is executed immediately on
             registration, the mainloop object is not yet "running",
             hence calling quit on it will be ineffective! _quit only
             works when the mainloop is running. */
    g_main_loop_quit(state->mainloop);
    /* We also set the running to correct state to fix the above
       problem. */
    state->running = FALSE;
 }
}
函数printDeviceState主要是把手机的状态给打印出来。
/* Small macro to return "YES" or "no" based on given parameter.
   Used in printDeviceState below. YES is in capital letters in order
   for it to "stand out" in the program output (since it's much
   rarer). */
#define BOOLSTR(p) ((p)?"YES":"no")
 
/**
 * Utility to decode the hwstate structure and print it out in human
 * readable format. Mainly useful for debugging on the device.
 *
 * The mode constants unfortunately are not documented in LibOSSO.
 */
static void printDeviceState(osso_hw_state_t* hwState) {
 
 gchar* modeStr = "Unknown";
 
 g_assert(hwState != NULL);
 
 switch(hwState->sig_device_mode_ind) {
    case OSSO_DEVMODE_NORMAL:
      /* Non-flight-mode. */
      modeStr = "Normal";
      break;
    case OSSO_DEVMODE_FLIGHT:
      /* Power button -> "Offline mode". */
      modeStr = "Flight";
      break;
    case OSSO_DEVMODE_OFFLINE:
      /* Unknown. Even if all connections are severed, this mode will
         not be triggered. */
      modeStr = "Offline";
      break;
    case OSSO_DEVMODE_INVALID:
      /* Unknown. */
      modeStr = "Invalid(?)";
      break;
    default:
      /* Leave at "Unknown". */
      break;
 }
 g_print(
    "Mode: %s, Shutdown: %s, Save: %s, MemLow: %s, RedAct: %s/n",
    modeStr,
    /* Set to TRUE if the device is shutting down. */
    BOOLSTR(hwState->shutdown_ind),
    /* Set to TRUE if our program has registered for autosave and
       now is the moment to save user data. */
    BOOLSTR(hwState->save_unsaved_data_ind),
    /* Set to TRUE when device is running low on memory. If possible,
       memory should be freed by our program. */
    BOOLSTR(hwState->memory_low_ind),
    /* Set to TRUE when system wants us to be less active. */
    BOOLSTR(hwState->system_inactivity_ind));
}
 
如何延迟关闭屏幕呢?调用LibOSSO的一个函数即可以完成这个功能: (osso_display_blanking_pause) ,这个函数在很多地方被用到。
/**
 * Utility to ask the device to pause the screen blanking timeout.
 * Does not return success/status.
 */
static void delayDisplayBlanking(ApplicationState* state) {
 
 osso_return_t result;
 
 g_assert(state != NULL);
 
 result = osso_display_blanking_pause(state->ossoContext);
 if (result != OSSO_OK) {
    g_printerr(PROGNAME ":delayDisplayBlanking. Failed (%s)/n",
               ossoErrorStr(result));
    /* But continue anyway. */
 } else {
    g_print(PROGNAME ":delayDisplayBlanking RPC succeeded/n");
 }
}
定时器回调一般情况下用作,告诉系统推迟关屏,同时也可以检查该程序释放已经关闭。如果程序已经关闭,在定时器销毁自己(通过返回FALSE):
/**
 * Timer callback that will be called within 45 seconds after
 * installing the callback and will ask the platform to defer any
 * display blanking for another 60 seconds.
 *
 * This will also prevent the device from going into suspend
 * (according to LibOSSO documentation).
 *
 * It will continue doing this until the program is terminated.
 *
 * NOTE: Normally timers shouldn't be abused like this since they
 *       bring the CPU out from power saving state. Because the screen
 *       backlight dimming might be activated again after 60 seconds
 *       of receiving the "pause" message, we need to keep sending the
 *       "pause" messages more often than every 60 seconds. 45 seconds
 *       seems like a safe choice.
 */
static gboolean delayBlankingCallback(gpointer data) {
 ApplicationState* state = (ApplicationState*)data;
 
 g_print(PROGNAME ":delayBlankingCallback Starting/n");
 
 g_assert(state != NULL);
 /* If we're not supposed to be running anymore, return immediately
     and ask caller to remove the timeout. */
 if (state->running == FALSE) {
    g_print(PROGNAME ":delayBlankingCallback Removing/n");
    return FALSE;
 }
 
 /* Delay the blanking for a while still (60 seconds). */
 delayDisplayBlanking(state);
 
 g_print(PROGNAME ":delayBlankingCallback Done/n");
 
 /* We want the same callback to be invoked from the timer
     launch again, so we return TRUE. */
 return TRUE;
}
 
做些释放工作:
/**
 * Release all resources allocated by setupAppState in reverse order.
 */
static void releaseAppState(ApplicationState* state) {
 
 g_print(PROGNAME ":releaseAppState starting/n");
 
 g_assert(state != NULL);
 
 /* First set the running state to FALSE so that if the timer will
     (for some reason) be launched, it will remove itself from the
     timer call list. This shouldn't be possible since we are running
     only with one thread. */
 state->running = FALSE;
 
 /* Normally we would also release the timer, but since the only way
     to do that is from the timer callback itself, there's not much we
     can do about it here. */
 
 /* Remove the device state change callback. It is possible that we
     run this even if the callback was never installed, but it is not
     harmful. */
 if (state->ossoContext != NULL) {
    osso_hw_unset_event_cb(state->ossoContext, NULL);
 }
 
 /* Release the mainloop object. */
 if (state->mainloop != NULL) {
    g_print(PROGNAME ":releaseAppState Releasing mainloop object./n");
    g_main_loop_unref(state->mainloop);
    state->mainloop = NULL;
 }
 
 /* Lastly, free up the LibOSSO context. */
 if (state->ossoContext != NULL) {
    g_print(PROGNAME ":releaseAppState De-init LibOSSO./n");
    osso_deinitialize(state->ossoContext);
    state->ossoContext = NULL;
 }
 /* All resources released. */
}
 
编译运行的结果:
[sbox-CHINOOK_X86: ~/libosso-flashlight] > run-standalone.sh ./flashlight
flashlight:main Starting
flashlight:setupAppState starting
flashlight:setupAppState Initializing LibOSSO
flashlight:setupAppState Creating a GMainLoop object
flashlight:setupAddState Adding hw-state change callback.
flashlight:deviceStateChanged Starting
Mode: Normal, Shutdown: no, Save: no, MemLow: no, RedAct: no
flashlight:setupAppState Adding blanking delay timer.
flashlight:setupAppState Unblanking the display
flashlight:setupAppState Displaying Note dialog
flashlight:setupAppState Requested for the dialog
flashlight:delayDisplayBlanking RPC succeeded
flashlight:setupAppState Completed
flashlight:main Starting mainloop processing
/dev/dsp: No such file or directory
flashlight:delayBlankingCallback Starting
flashlight:delayDisplayBlanking RPC succeeded
flashlight:delayBlankingCallback Done
...
实际的运行结果:
 
 
如何高效率的使用DBUS作client/server架构 在嵌入式系统中使用dbus主要有两个方面的用途:1:进程间通信2:实现client/server模式;2也是1的具体表现形式;包括dbus自带的例子,都是采用dbus对数据的封装,实现client/server模式的,缺点有二:1 一个API要定义一个xml接口描述2 数据封装非常复杂,非常不利于以后接口的扩展;为了客服上面的缺点,提高可扩展性和效率,可以这样做:如果一个应用分为cli 阅读详情

相关推荐

DirectFB作为GDK后端时,gtk_widget_show_all()的内部机制。

   下载一个gtk,directfb源码,http://www.gtk.org/http://www.directfb.org/ 就可以分析出其复杂的饶人的重绘过程。 不少用GTK做程序的人,知道用gtk_widget_show_all来显示,内部的现实过程如果比较清楚,分析问题的能力应该会好点。   程序都是调用这个接口: void

Linux智能手机--cuijpus的专栏 6303

用dbus-send查看当前system bus或者session bus上面挂载了多少service.

 在Linux PC/手机启动后,dbus-daemo就启动了。这是如果一个程序启动了,会有一个connection挂载到dbus-daemon上面的,同时维护了这个程序的service.可以采用dbus-send命令来查看system bus或者session bus上面到底挂载了哪些service, 即,当前有哪些程序是和dbus-daemon有关联的: 

Linux智能手机--cuijpus的专栏 1万+

Maemo Linux手机平台系列分析:6 Maemo平台开发之D-Bus

    在Maemo平台中,D-Bus是一个非常重要的中间件(middleware)解决方案,主要用于进程之间的通信。已经有很多服务使用了D-Bus,接下来将介绍不同的方法去实现。D-Bus是贯穿于Maemo平台的,离不开D-Bus。  这部分的内容: 介绍一下D-Bus D-Bus的架构 D-Bus的地址和名字 在Maemo中D-Bus的作用

Linux智能手机--cuijpus的专栏 6057

GDK事件与GTK signal的前世今生

   GDK是gtk的下面一层的东西,平常都用GTK的函数,很少直接调用GDK的函数。但是GTK里面的事件、信号、回调、绘制等都和GDK有直接的关系,所以需要把GDK的绘图与事件相关的内容再理一理。   我原本打算自己去分析的,baidu了几下后,我放弃了,有分析的很好的文章有助于理解GDK的事件和绘图,下面几个是不错的分析,你们可以点击链接去看。后面我也放了几个汇总,方便些。

Linux智能手机--cuijpus的专栏 9681

import-im6.q16: attempt to perform an operation not allowed by the security policy `PS‘ @ error/cons

这六个 policy 是使用 XML 格式描述的安全策略。要将其中的限制注释掉,在每个 policy 开始和结束的标记之间添加注释标记“

m0_60657960的博客 1908

产品经理必备知识——API接口

在古代,我们的传输信息的方式有很多,比如写信、飞鸽传书,以及在战争中使用的烽烟,才有了著名的烽火戏诸侯,但这些方式传输信息的效率终究还是无法满足高速发展的社会需要。如果你选择允许,app就会根据你的当前位置为你提供更加个性化的一些服务,当然也有一些app拿到你的位置信息做出损害用户利益的行为,所以还是需要谨慎授权。首先,看接口文档的场景一般是自身业务模块需要获取外部的数据,但又不想自己重新开发,寻找外部已经实现的有开放能力的供应商(包含企业内部的)。通过发送请求和响应消息的方式实现程序间的通信。

WBKJ_Noah_的博客 3455

Maemo Linux手机平台分析系列:3 安装Maemo平台宿主Linux系统

 我们大多数单个主机都用的是Windows, 如果为了研究Maemo,还要把Windows的某个分区格式化,然后安装Linux,好像动静大了点。而且我们看文档一般习惯于在windows下面。用vmware可以解决这问题:在windows上安装vmware, 然后在vmware中安装Linux. 这样就不必离开windows了,而且可以在windows和Linux之前方便的切换。

Linux智能手机--cuijpus的专栏 6410

第五节_PySide6基本窗口控件_主窗口和标签

本文介绍了PySide6中主窗口和标签控件的使用。主要内容包括: 窗口控件分类: QWidget是基础窗口部件,可作为独立窗口或子部件 QMainWindow提供标准应用程序框架,包含菜单栏、工具栏等 QDialog用于对话框,支持模态交互 主窗口创建: 演示了如何创建QMainWindow子类 实现了窗口居中、设置图标、状态栏等功能 提供了窗口几何信息的获取方法 QLabel标签控件: 继承自QFrame类 用于显示文本或图像 文章通过代码示例详细说明了主窗口的创建和使用方法,包括位置控制、图标设置等常见

su桥木的博客 1022

Doxygen + Graphviz + Htmlhelp, 成为文档好手。

doxygen 在Linux下面开发,在代码中一般注释doxygen格式的注释,这是帮助我们生成文档的一个好方法。对于doxygen的主要是语法,网上有很多的说明,有个工程:GNOME Power Manager里面的doxygen注释写的非常好,你们可以下载下来看看,并且可以借鉴到自己的实际开发中。 这里我想说的是:如何从source code 总提取开源软件的文档。

Linux智能手机--cuijpus的专栏 6148

PCL Fast Global Registration 快速全局配准(源码版)

Fast Global Registration(FGR)是一种经典的点云粗配准算法,已集成到Open3D和CloudCompare等软件中。本文介绍了该算法的源码实现及优化方法,包括如何通过修改源码直接读取点云进行配准,而不依赖文件中读取特征描述子。文章还提供了关键参数设置(如最大迭代次数、匹配距离等)。算法实现简单高效,未来计划发布基于纯PCL的版本。源码和论文链接已附上,供开发者参考。

点云侠的博客 383

Open-AutoGLM 实战:手把手教你用 AI 操作手机「喂饭教程」

Open-AutoGLM 是一个由智谱AI开源的手机操作智能体框架,由手机端智能助手框架Phone Agent和9B大小的模型AutoGLM-Phone-9B组成,借助ADB自动执行点击、滑动、输入等操作——用户只需用自然语言描述任务,系统便能自动规划并完成整个操作流程。

blues_C的博客 1267

D-Bus新的调试工具:D-Feet.

大家在使用D-Bus的过程中,对于D-Bus出现的各种异常往往束手无策,很大一部分原因就是D-Bus没有很好的调试工具,仅仅是几个dbus-send, dbus-monitor等,调试监测效果并不好。 现在,有新的D-Bus调试工具发布出来了:Red Hat公司的John Palmieri目前正在开发一个新的D-Bus调试工具: D-Feet. 大家知道,D-Bus是GNOME

Linux智能手机--cuijpus的专栏 5961

AUTOSAR从入门到精通-【应用篇】基于AUTOSAR架构的混合动力电池 ECU 软件开发

由于严峻的环境污染和能源短缺问题,各国都在致力于发展新能源车,以达到节能排放的目的。在此背景下,12V启停系统由于成本较低廉、匹配方便,得到广泛应用。但是12V系统作为启停系统后存在许多问题,比如节能和减排效果有限,并且轻度混合动力系统的功率需求通常在10~15KW,在此电压条件下运行时,电池的电流会达到1000A,因此该方案行不通。高压混合动力系统(>110V)的节油效果好,但是成本很高,并且需要大功率的电机。48V混合动力系统比高压混合动力系统成本。

getusushu的博客 1488

嵌入式Linux研发,非常值得研究的几个开源项目

我认为作为嵌入式Linux开发者,要非常熟悉的几个开源项目:  1 d-bus 2 gstreamer3 gconf4 GNOME Power manager5 mesa6 libxml7 evolution8 gimp9 GNOME VFS花几个月乃至一年的时间去分析,理解,运用这里面的开源项目,相信你会在嵌入式Linux产品开发过程中会非常得心应

Linux智能手机--cuijpus的专栏 5180

Spring AI 项目实战(五):Spring Boot + AI + DeepSeek + Redis 实现聊天应用上下文记忆功能(附完整源码)

本文介绍了如何基于Spring Boot 3.2、Spring AI 1.0.0-M4、DeepSeek API和Redis构建具备上下文记忆功能的智能聊天应用。项目采用现代化技术栈,包括Java 17、Maven、Lombok等,实现了智能对话、会话管理、异常处理等核心功能。文章详细讲解了环境搭建、配置管理(含Redis和AI服务集成)、核心组件设计(如消息实体、控制器和服务层实现),以及完整的项目结构。该项目提供了美观的Web界面和REST API,支持对话上下文存储(通过Redis实现)和系统监控,可

博客 829

昇腾AI原生创新算子挑战赛(S1赛季)复盘-LessEqual算子

【代码】昇腾AI原生创新算子挑战赛(S1赛季)复盘-LessEqual算子。

william_myq的博客 507

三星推出的第一款Android操作系统手机

 三星Galaxy i7500作为三星首款Android手机,一经推出便深受好评,在欧洲市场销售更是表现不俗。如今三星Galaxy i7500白色版现身网络,相信会引来不少网友的关注。   三星Galaxy i7500白色版推出除了带来新的颜色外,最重要的是手机较之黑色版本将有所改变,据传闻称,三星i7500白色版将添加WiFi无线局域传输功能。也就是说,三星Galaxy i750

Linux智能手机--cuijpus的专栏 5146

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

UML建模: StarUML VS Telelogic TAU VS Rational Rose

starUML VS Telelogic TAU VS Rational Rose UML建模软件目前用的主要有3种:商业版本:Telelogic TAU 和 Rational Rose 开源版本:StarUML Telelogic TAU与Rational Rose的功能很强,但是需要买License。StarUML就是希望能提供和TAU/Rose一样功能的开源版本。

Linux智能手机--cuijpus的专栏 5011

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

D-Bus daemon在系统启动时启动,如果我们装两个不同版本的D-Bus呢?

 一般情况下,Ubuntu本身会带一个dbus daemon, 安装在/usr/bin下面。我们编译的新版本可能为了不影响Ubuntu本身的,我们一般会修改一个安装路径,比如:/usr/local/bin 这样就带来一个问题:Ubuntu系统重启后,如何启动我们新安装的dbus daemon呢? 其实修改一个地方就可以了:/etc/init.d/dbus, 我们把这个脚

Linux智能手机--cuijpus的专栏 4347

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

Maemo Linux手机平台系列分析:1 技术概览

QA: Q:为什么去分析Maemo平台呢?A:分析一个平台是为了掌握它,吸收有用的东西为我所用。 Q:为什么选择Maemo平台呢?A:Linux手机平台目前主要有ALP,Maemo, LiMo, Android, etc. (欢迎大家补充J)目前不少都是打着开源的旗号的,但是公开的力度不同:ALP目前仅仅公开了其Hilker部分;Maemo全部公开;Li

Linux智能手机--cuijpus的专栏 4233

freedesktop git repository

http://cgit.freedesktop.org/ freedesktop.org git repository browsera fast webinterface for the git dscmindex NameDescriptionOwnerIdleLinksf

Linux智能手机--cuijpus的专栏 3770

理解 Linux 动态库加载:LD_LIBRARY_PATH

flyfish

二分掌柜的 347

Linux-iostat命令详解

Linux命令学习记录

m0xin的博客 118

USB 技术系列 11 · USB Linux 驱动框架

本文系统解析Linux USB驱动框架,涵盖USB Core、HCD(xhci-hcd/dwc3)、类驱动(CDC/HID/Mass Storage)分层架构,详解usb_device_id匹配、probe/disconnect生命周期及Device Tree配置。结合RISC-V N300实战,揭示Host/Device双模式驱动开发核心逻辑,助力嵌入式BSP开发者掌握USB子系统全栈能力。

peter_pan_study的博客 251

Linux 服务器性能排查手册(2026):CPU、内存、磁盘IO、网络四大瓶颈定位

iptables 四表五链模型、firewalld zone 信任级别、云安全组与主机防火墙的关系与优先级,避坑改了防火墙把自己挡在服务器外面的翻车事故。

2502_91473995的博客 318

Linux rm 误删文件恢复实操教程

Linux使用rm删除文件时,并不会直接抹除磁盘上的数据,只是移除文件索引,让系统不再识别这块空间。只要没有写入新数据,原有扇区内容就会保留。新文件写入才有可能覆盖这些区域,一旦覆盖就很难找回。恢复的本质就是扫描磁盘,找到这些还存在、但索引丢失的数据条目,再把它们导出保存到其他分区。越早停止写入,恢复成功的概率越高。

海天数据恢复-winhex数据恢复教程 230
上一篇: Maemo Linux手机平台系列分析:6 Maemo平台开发之D-Bus
下一篇: Maemo Linux手机平台系列分析:8 Maemo平台开发之 使用Glib绑定的D-Bus
testhw
博客等级 码龄19年 172粉丝 183原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值