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 <sys/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(EXIT_FAILURE);
     46 }
     47 
     48 extern char rild[MAX_SOCKET_NAME_LENGTH];
     49 
     50 extern void RIL_register (const RIL_RadioFunctions *callbacks);
     51 
     52 extern void RIL_onRequestComplete(RIL_Token t, RIL_Errno e,
     53                            void *response, size_t responselen);
     54 
     55 
     56 #if defined(ANDROID_MULTI_SIM)
     57 extern void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
     58                                 size_t datalen, RIL_SOCKET_ID socket_id);
     59 #else
     60 extern void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
     61                                 size_t datalen);
     62 #endif
     63 
     64 extern void RIL_requestTimedCallback (RIL_TimedCallback callback,
     65                                void *param, const struct timeval *relativeTime);
     66 
     67 
     68 static struct RIL_Env s_rilEnv = {
     69     RIL_onRequestComplete,
     70     RIL_onUnsolicitedResponse,
     71     RIL_requestTimedCallback
     72 };
     73 
     74 extern void RIL_startEventLoop();
     75 
     76 static int make_argv(char * args, char ** argv)
     77 {
     78     // Note: reserve argv[0]
     79     int count = 1;
     80     char * tok;
     81     char * s = args;
     82 
     83     while ((tok = strtok(s, " \0"))) {
     84         argv[count] = tok;
     85         s = NULL;
     86         count++;
     87     }
     88     return count;
     89 }
     90 
     91 /*
     92  * switchUser - Switches UID to radio, preserving CAP_NET_ADMIN capabilities.
     93  * Our group, cache, was set by init.
     94  */
     95 void switchUser() {
     96     prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
     97     setuid(AID_RADIO);
     98 
     99     struct __user_cap_header_struct header;
    100     memset(&header, 0, sizeof(header));
    101     header.version = _LINUX_CAPABILITY_VERSION_3;
    102     header.pid = 0;
    103 
    104     struct __user_cap_data_struct data[2];
    105     memset(&data, 0, sizeof(data));
    106 
    107     data[CAP_TO_INDEX(CAP_NET_ADMIN)].effective |= CAP_TO_MASK(CAP_NET_ADMIN);
    108     data[CAP_TO_INDEX(CAP_NET_ADMIN)].permitted |= CAP_TO_MASK(CAP_NET_ADMIN);
    109 
    110     data[CAP_TO_INDEX(CAP_NET_RAW)].effective |= CAP_TO_MASK(CAP_NET_RAW);
    111     data[CAP_TO_INDEX(CAP_NET_RAW)].permitted |= CAP_TO_MASK(CAP_NET_RAW);
    112 
    113     if (capset(&header, &data[0]) == -1) {
    114         RLOGE("capset failed: %s", strerror(errno));
    115         exit(EXIT_FAILURE);
    116     }
    117 }
    118 
    119 int main(int argc, char **argv)
    120 {
    121     const char * rilLibPath = NULL;
    122     char **rilArgv;
    123     void *dlHandle;
    124     const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
    125     const RIL_RadioFunctions *funcs;
    126     char libPath[PROPERTY_VALUE_MAX];
    127     unsigned char hasLibArgs = 0;
    128 
    129     int i;
    130     const char *clientId = NULL;
    131     RLOGD("**RIL Daemon Started**");
    132     RLOGD("**RILd param count=%d**", argc);
    133 
    134     umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
    135     for (i = 1; i < argc ;) {
    136         if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
    137             rilLibPath = argv[i + 1];
    138             i += 2;
    139         } else if (0 == strcmp(argv[i], "--")) {
    140             i++;
    141             hasLibArgs = 1;
    142             break;
    143         } else if (0 == strcmp(argv[i], "-c") &&  (argc - i > 1)) {
    144             clientId = argv[i+1];
    145             i += 2;
    146         } else {
    147             usage(argv[0]);
    148         }
    149     }
    150 
    151     if (clientId == NULL) {
    152         clientId = "0";
    153     } else if (atoi(clientId) >= MAX_RILDS) {
    154         RLOGE("Max Number of rild's supported is: %d", MAX_RILDS);
    155         exit(0);
    156     }
    157     if (strncmp(clientId, "0", MAX_CLIENT_ID_LENGTH)) {
    158         RIL_setRilSocketName(strncat(rild, clientId, MAX_SOCKET_NAME_LENGTH));
    159     }
    160 
    161     if (rilLibPath == NULL) {
    162         if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
    163             // No lib sepcified on the command line, and nothing set in props.
    164             // Assume "no-ril" case.
    165             goto done;
    166         } else {
    167             rilLibPath = libPath;
    168         }
    169     }
    170 
    171     /* special override when in the emulator */
    172 #if 1
    173     {
    174         static char*  arg_overrides[5];
    175         static char   arg_device[32];
    176         int           done = 0;
    177 
    178 #define  REFERENCE_RIL_PATH  "libreference-ril.so"
    179 
    180         /* first, read /proc/cmdline into memory */
    181         char          buffer[1024], *p, *q;
    182         int           len;
    183         int           fd = open("/proc/cmdline",O_RDONLY);
    184 
    185         if (fd < 0) {
    186             RLOGD("could not open /proc/cmdline:%s", strerror(errno));
    187             goto OpenLib;
    188         }
    189 
    190         do {
    191             len = read(fd,buffer,sizeof(buffer)); }
    192         while (len == -1 && errno == EINTR);
    193 
    194         if (len < 0) {
    195             RLOGD("could not read /proc/cmdline:%s", strerror(errno));
    196             close(fd);
    197             goto OpenLib;
    198         }
    199         close(fd);
    200 
    201         if (strstr(buffer, "android.qemud=") != NULL)
    202         {
    203             /* the qemud daemon is launched after rild, so
    204             * give it some time to create its GSM socket
    205             */
    206             int  tries = 5;
    207 #define  QEMUD_SOCKET_NAME    "qemud"
    208 
    209             while (1) {
    210                 int  fd;
    211 
    212                 sleep(1);
    213 
    214                 fd = qemu_pipe_open("qemud:gsm");
    215                 if (fd < 0) {
    216                     fd = socket_local_client(
    217                                 QEMUD_SOCKET_NAME,
    218                                 ANDROID_SOCKET_NAMESPACE_RESERVED,
    219                                 SOCK_STREAM );
    220                 }
    221                 if (fd >= 0) {
    222                     close(fd);
    223                     snprintf( arg_device, sizeof(arg_device), "%s/%s",
    224                                 ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
    225 
    226                     arg_overrides[1] = "-s";
    227                     arg_overrides[2] = arg_device;
    228                     done = 1;
    229                     break;
    230                 }
    231                 RLOGD("could not connect to %s socket: %s",
    232                     QEMUD_SOCKET_NAME, strerror(errno));
    233                 if (--tries == 0)
    234                     break;
    235             }
    236             if (!done) {
    237                 RLOGE("could not connect to %s socket (giving up): %s",
    238                     QEMUD_SOCKET_NAME, strerror(errno));
    239                 while(1)
    240                     sleep(0x00ffffff);
    241             }
    242         }
    243 
    244         /* otherwise, try to see if we passed a device name from the kernel */
    245         if (!done) do {
    246 #define  KERNEL_OPTION  "android.ril="
    247 #define  DEV_PREFIX     "/dev/"
    248 
    249             p = strstr( buffer, KERNEL_OPTION );
    250             if (p == NULL)
    251                 break;
    252 
    253             p += sizeof(KERNEL_OPTION)-1;
    254             q  = strpbrk( p, " \t\n\r" );
    255             if (q != NULL)
    256                 *q = 0;
    257 
    258             snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
    259             arg_device[sizeof(arg_device)-1] = 0;
    260             arg_overrides[1] = "-d";
    261             arg_overrides[2] = arg_device;
    262             done = 1;
    263 
    264         } while (0);
    265 
    266         if (done) {
    267             argv = arg_overrides;
    268             argc = 3;
    269             i    = 1;
    270             hasLibArgs = 1;
    271             rilLibPath = REFERENCE_RIL_PATH;
    272 
    273             RLOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
    274         }
    275     }
    276 OpenLib:
    277 #endif
    278     switchUser();
    279 
    280     dlHandle = dlopen(rilLibPath, RTLD_NOW);
    281 
    282     if (dlHandle == NULL) {
    283         RLOGE("dlopen failed: %s", dlerror());
    284         exit(EXIT_FAILURE);
    285     }
    286 
    287     RIL_startEventLoop();
    288 
    289     rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
    290 
    291     if (rilInit == NULL) {
    292         RLOGE("RIL_Init not defined or exported in %s\n", rilLibPath);
    293         exit(EXIT_FAILURE);
    294     }
    295 
    296     if (hasLibArgs) {
    297         rilArgv = argv + i - 1;
    298         argc = argc -i + 1;
    299     } else {
    300         static char * newArgv[MAX_LIB_ARGS];
    301         static char args[PROPERTY_VALUE_MAX];
    302         rilArgv = newArgv;
    303         property_get(LIB_ARGS_PROPERTY, args, "");
    304         argc = make_argv(args, rilArgv);
    305     }
    306 
    307     rilArgv[argc++] = "-c";
    308     rilArgv[argc++] = clientId;
    309     RLOGD("RIL_Init argc = %d clientId = %s", argc, rilArgv[argc-1]);
    310 
    311     // Make sure there's a reasonable argv[0]
    312     rilArgv[0] = argv[0];
    313 
    314     funcs = rilInit(&s_rilEnv, argc, rilArgv);
    315     RLOGD("RIL_Init rilInit completed");
    316 
    317     RIL_register(funcs);
    318 
    319     RLOGD("RIL_Init RIL_register completed");
    320 
    321 done:
    322 
    323     RLOGD("RIL_Init starting sleep loop");
    324     while (true) {
    325         sleep(UINT32_MAX);
    326     }
    327 }
    328