Home | History | Annotate | Download | only in rild
      1 /* //device/system/rild/rild.c
      2 **
      3 ** Copyright 2006, The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 #include <stdio.h>
     19 #include <stdlib.h>
     20 #include <dlfcn.h>
     21 #include <string.h>
     22 #include <stdint.h>
     23 #include <unistd.h>
     24 #include <fcntl.h>
     25 #include <errno.h>
     26 
     27 #include <telephony/ril.h>
     28 #define LOG_TAG "RILD"
     29 #include <utils/Log.h>
     30 #include <cutils/properties.h>
     31 #include <cutils/sockets.h>
     32 #include <sys/capability.h>
     33 #include <linux/prctl.h>
     34 
     35 #include <private/android_filesystem_config.h>
     36 #include "hardware/qemu_pipe.h"
     37 
     38 #define LIB_PATH_PROPERTY   "rild.libpath"
     39 #define LIB_ARGS_PROPERTY   "rild.libargs"
     40 #define MAX_LIB_ARGS        16
     41 
     42 static void usage(const char *argv0)
     43 {
     44     fprintf(stderr, "Usage: %s -l <ril impl library> [-- <args for impl library>]\n", argv0);
     45     exit(-1);
     46 }
     47 
     48 extern void RIL_register (const RIL_RadioFunctions *callbacks);
     49 
     50 extern void RIL_onRequestComplete(RIL_Token t, RIL_Errno e,
     51                            void *response, size_t responselen);
     52 
     53 extern void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
     54                                 size_t datalen);
     55 
     56 extern void RIL_requestTimedCallback (RIL_TimedCallback callback,
     57                                void *param, const struct timeval *relativeTime);
     58 
     59 
     60 static struct RIL_Env s_rilEnv = {
     61     RIL_onRequestComplete,
     62     RIL_onUnsolicitedResponse,
     63     RIL_requestTimedCallback
     64 };
     65 
     66 extern void RIL_startEventLoop();
     67 
     68 static int make_argv(char * args, char ** argv)
     69 {
     70     // Note: reserve argv[0]
     71     int count = 1;
     72     char * tok;
     73     char * s = args;
     74 
     75     while ((tok = strtok(s, " \0"))) {
     76         argv[count] = tok;
     77         s = NULL;
     78         count++;
     79     }
     80     return count;
     81 }
     82 
     83 /*
     84  * switchUser - Switches UID to radio, preserving CAP_NET_ADMIN capabilities.
     85  * Our group, cache, was set by init.
     86  */
     87 void switchUser() {
     88     prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
     89     setuid(AID_RADIO);
     90 
     91     struct __user_cap_header_struct header;
     92     struct __user_cap_data_struct cap;
     93     header.version = _LINUX_CAPABILITY_VERSION;
     94     header.pid = 0;
     95     cap.effective = cap.permitted = (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
     96     cap.inheritable = 0;
     97     capset(&header, &cap);
     98 }
     99 
    100 int main(int argc, char **argv)
    101 {
    102     const char * rilLibPath = NULL;
    103     char **rilArgv;
    104     void *dlHandle;
    105     const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
    106     const RIL_RadioFunctions *funcs;
    107     char libPath[PROPERTY_VALUE_MAX];
    108     unsigned char hasLibArgs = 0;
    109 
    110     int i;
    111 
    112     umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    113     for (i = 1; i < argc ;) {
    114         if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
    115             rilLibPath = argv[i + 1];
    116             i += 2;
    117         } else if (0 == strcmp(argv[i], "--")) {
    118             i++;
    119             hasLibArgs = 1;
    120             break;
    121         } else {
    122             usage(argv[0]);
    123         }
    124     }
    125 
    126     if (rilLibPath == NULL) {
    127         if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
    128             // No lib sepcified on the command line, and nothing set in props.
    129             // Assume "no-ril" case.
    130             goto done;
    131         } else {
    132             rilLibPath = libPath;
    133         }
    134     }
    135 
    136     /* special override when in the emulator */
    137 #if 1
    138     {
    139         static char*  arg_overrides[3];
    140         static char   arg_device[32];
    141         int           done = 0;
    142 
    143 #define  REFERENCE_RIL_PATH  "/system/lib/libreference-ril.so"
    144 
    145         /* first, read /proc/cmdline into memory */
    146         char          buffer[1024], *p, *q;
    147         int           len;
    148         int           fd = open("/proc/cmdline",O_RDONLY);
    149 
    150         if (fd < 0) {
    151             RLOGD("could not open /proc/cmdline:%s", strerror(errno));
    152             goto OpenLib;
    153         }
    154 
    155         do {
    156             len = read(fd,buffer,sizeof(buffer)); }
    157         while (len == -1 && errno == EINTR);
    158 
    159         if (len < 0) {
    160             RLOGD("could not read /proc/cmdline:%s", strerror(errno));
    161             close(fd);
    162             goto OpenLib;
    163         }
    164         close(fd);
    165 
    166         if (strstr(buffer, "android.qemud=") != NULL)
    167         {
    168             /* the qemud daemon is launched after rild, so
    169             * give it some time to create its GSM socket
    170             */
    171             int  tries = 5;
    172 #define  QEMUD_SOCKET_NAME    "qemud"
    173 
    174             while (1) {
    175                 int  fd;
    176 
    177                 sleep(1);
    178 
    179                 fd = qemu_pipe_open("qemud:gsm");
    180                 if (fd < 0) {
    181                     fd = socket_local_client(
    182                                 QEMUD_SOCKET_NAME,
    183                                 ANDROID_SOCKET_NAMESPACE_RESERVED,
    184                                 SOCK_STREAM );
    185                 }
    186                 if (fd >= 0) {
    187                     close(fd);
    188                     snprintf( arg_device, sizeof(arg_device), "%s/%s",
    189                                 ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
    190 
    191                     arg_overrides[1] = "-s";
    192                     arg_overrides[2] = arg_device;
    193                     done = 1;
    194                     break;
    195                 }
    196                 RLOGD("could not connect to %s socket: %s",
    197                     QEMUD_SOCKET_NAME, strerror(errno));
    198                 if (--tries == 0)
    199                     break;
    200             }
    201             if (!done) {
    202                 RLOGE("could not connect to %s socket (giving up): %s",
    203                     QEMUD_SOCKET_NAME, strerror(errno));
    204                 while(1)
    205                     sleep(0x00ffffff);
    206             }
    207         }
    208 
    209         /* otherwise, try to see if we passed a device name from the kernel */
    210         if (!done) do {
    211 #define  KERNEL_OPTION  "android.ril="
    212 #define  DEV_PREFIX     "/dev/"
    213 
    214             p = strstr( buffer, KERNEL_OPTION );
    215             if (p == NULL)
    216                 break;
    217 
    218             p += sizeof(KERNEL_OPTION)-1;
    219             q  = strpbrk( p, " \t\n\r" );
    220             if (q != NULL)
    221                 *q = 0;
    222 
    223             snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
    224             arg_device[sizeof(arg_device)-1] = 0;
    225             arg_overrides[1] = "-d";
    226             arg_overrides[2] = arg_device;
    227             done = 1;
    228 
    229         } while (0);
    230 
    231         if (done) {
    232             argv = arg_overrides;
    233             argc = 3;
    234             i    = 1;
    235             hasLibArgs = 1;
    236             rilLibPath = REFERENCE_RIL_PATH;
    237 
    238             RLOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
    239         }
    240     }
    241 OpenLib:
    242 #endif
    243     switchUser();
    244 
    245     dlHandle = dlopen(rilLibPath, RTLD_NOW);
    246 
    247     if (dlHandle == NULL) {
    248         RLOGE("dlopen failed: %s", dlerror());
    249         exit(-1);
    250     }
    251 
    252     RIL_startEventLoop();
    253 
    254     rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
    255 
    256     if (rilInit == NULL) {
    257         RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);
    258         exit(-1);
    259     }
    260 
    261     if (hasLibArgs) {
    262         rilArgv = argv + i - 1;
    263         argc = argc -i + 1;
    264     } else {
    265         static char * newArgv[MAX_LIB_ARGS];
    266         static char args[PROPERTY_VALUE_MAX];
    267         rilArgv = newArgv;
    268         property_get(LIB_ARGS_PROPERTY, args, "");
    269         argc = make_argv(args, rilArgv);
    270     }
    271 
    272     // Make sure there's a reasonable argv[0]
    273     rilArgv[0] = argv[0];
    274 
    275     funcs = rilInit(&s_rilEnv, argc, rilArgv);
    276 
    277     RIL_register(funcs);
    278 
    279 done:
    280 
    281     while(1) {
    282         // sleep(UINT32_MAX) seems to return immediately on bionic
    283         sleep(0x00ffffff);
    284     }
    285 }
    286 
    287