usb_moded 0.86.0+mer64
usb_moded-android.c
Go to the documentation of this file.
1
24
25#include "usb_moded-android.h"
26
28#include "usb_moded-log.h"
29#include "usb_moded-mac.h"
31
32#include <unistd.h>
33#include <stdio.h>
34
35/* ========================================================================= *
36 * Prototypes
37 * ========================================================================= */
38
39/* ------------------------------------------------------------------------- *
40 * ANDROID
41 * ------------------------------------------------------------------------- */
42
43static bool android_write_file (const char *path, const char *text);
44bool android_in_use (void);
45static bool android_probe (void);
46gchar *android_get_serial (void);
47bool android_init (void);
48void android_quit (void);
49bool android_set_enabled (bool enable);
50bool android_set_charging_mode(void);
51bool android_set_function (const char *function);
52bool android_set_productid (const char *id);
53bool android_set_vendorid (const char *id);
54bool android_set_attr (const char *function, const char *attr, const char *value);
55
56/* ========================================================================= *
57 * Data
58 * ========================================================================= */
59
60static int android_probed = -1;
61
62/* ========================================================================= *
63 * Functions
64 * ========================================================================= */
65
66static bool
67android_write_file(const char *path, const char *text)
68{
69 LOG_REGISTER_CONTEXT;
70
71 bool ack = false;
72
73 if( !path || !text )
74 goto EXIT;
75
76 log_debug("WRITE %s '%s'", path, text);
77
78 char buff[64];
79 snprintf(buff, sizeof buff, "%s\n", text);
80
81 if( write_to_file(path, buff) == -1 )
82 goto EXIT;
83
84 ack = true;
85
86EXIT:
87
88 return ack;
89}
90
91bool
92android_in_use(void)
93{
94 LOG_REGISTER_CONTEXT;
95
96 if( android_probed < 0 )
97 log_debug("android_in_use() called before android_probe()");
98
99 return android_probed > 0;
100}
101
102static bool
103android_probe(void)
104{
105 LOG_REGISTER_CONTEXT;
106
107 if( android_probed <= 0 ) {
108 android_probed = access(ANDROID0_ENABLE, F_OK) == 0;
109 log_warning("ANDROID0 %sdetected", android_probed ? "" : "not ");
110 }
111
112 return android_in_use();
113}
114
117gchar *
119{
120 LOG_REGISTER_CONTEXT;
121
122 static const char path[] = "/proc/cmdline";
123 static const char find[] = "androidboot.serialno=";
124 static const char pbrk[] = " \t\r\n,";
125
126 char *res = 0;
127 FILE *file = 0;
128 size_t size = 0;
129 char *data = 0;
130
131 if( !(file = fopen(path, "r")) ) {
132 log_warning("%s: %s: %m", path, "can't open");
133 goto EXIT;
134 }
135
136 if( getline(&data, &size, file) < 0 ) {
137 log_warning("%s: %s: %m", path, "can't read");
138 goto EXIT;
139 }
140
141 char *beg = strstr(data, find);
142 if( !beg ) {
143 log_warning("%s: no serial found", path);
144 goto EXIT;
145 }
146
147 beg += sizeof find - 1;
148 size_t len = strcspn(beg, pbrk);
149 if( len < 1 ) {
150 log_warning("%s: empty serial found", path);
151 goto EXIT;
152 }
153
154 res = g_strndup(beg, len);
155
156EXIT:
157
158 free(data);
159
160 if( file )
161 fclose(file);
162
163 return res;
164}
165
170bool
172{
173 LOG_REGISTER_CONTEXT;
174
175 gchar *text;
176
177 if( !android_probe() )
178 goto EXIT;
179
180 /* Disable */
181 android_set_enabled(false);
182
183 /* Configure */
184 if( (text = android_get_serial()) )
185 {
186 android_write_file(ANDROID0_SERIAL, text);
187 g_free(text);
188 }
189
190 text = config_get_android_manufacturer();
191 if(text)
192 {
193 android_write_file(ANDROID0_MANUFACTURER, text);
194 g_free(text);
195 }
196 text = config_get_android_vendor_id();
197 if(text)
198 {
199 android_set_vendorid(text);
200 g_free(text);
201 }
202 text = config_get_android_product();
203 if(text)
204 {
205 android_write_file(ANDROID0_PRODUCT, text);
206 g_free(text);
207 }
208 text = config_get_android_product_id();
209 if(text)
210 {
211 android_set_productid(text);
212 g_free(text);
213 }
214 text = mac_read_mac();
215 if(text)
216 {
217 android_set_attr("f_rndis", "ethaddr", text);
218 g_free(text);
219 }
220 /* For rndis to be discovered correctly in M$ Windows (vista and later) */
221 android_set_attr("f_rndis", "wceis", "1");
222
223 /* Make sure remnants off mass-storage mode do not cause
224 * issues for charging_fallback & co */
225 android_set_attr("f_mass_storage", "lun/nofua", "0");
226 android_set_attr("f_mass_storage", "lun/file", "");
227
228EXIT:
229 return android_in_use();
230}
231
234void
236{
237 /* For now this exists for symmetry with other backends only */
238}
239
240bool
241android_set_enabled(bool enable)
242{
243 LOG_REGISTER_CONTEXT;
244
245 bool ack = false;
246 if( android_in_use() ) {
247 const char *val = enable ? "1" : "0";
248 ack = android_write_file(ANDROID0_ENABLE, val);
249 }
250 log_debug("ANDROID %s(%d) -> %d", __func__, enable, ack);
251 return ack;
252}
253
254/* Set a charging mode for the android gadget
255 *
256 * @return true if successful, false on failure
257 */
258bool
259android_set_charging_mode(void)
260{
261 LOG_REGISTER_CONTEXT;
262
263 bool ack = false;
264
265 if( !android_in_use() )
266 goto EXIT;
267
268 if( !android_set_function("mass_storage") )
269 goto EXIT;
270
271 /* TODO: make configurable */
272 if( !android_set_productid("0AFE") )
273 goto EXIT;
274
275 if( !android_set_enabled(true) )
276 goto EXIT;
277
278 ack = true;
279
280EXIT:
281 log_debug("ANDROID %s() -> %d", __func__, ack);
282 return ack;
283}
284
285/* Set a function for the android gadget
286 *
287 * @return true if successful, false on failure
288 */
289bool
290android_set_function(const char *function)
291{
292 LOG_REGISTER_CONTEXT;
293
294 bool ack = false;
295
296 if( !function )
297 goto EXIT;
298
299 if( !android_in_use() )
300 goto EXIT;
301
302 if( !android_set_enabled(false) )
303 goto EXIT;
304
305 if( !android_write_file(ANDROID0_FUNCTIONS, function) )
306 goto EXIT;
307
308 /* Leave disabled, so that caller can adjust attributes
309 * etc before enabling */
310
311 ack = true;
312EXIT:
313
314 log_debug("ANDROID %s(%s) -> %d", __func__, function, ack);
315 return ack;
316}
317
318/* Set a product id for the android gadget
319 *
320 * @return true if successful, false on failure
321 */
322bool
323android_set_productid(const char *id)
324{
325 LOG_REGISTER_CONTEXT;
326
327 bool ack = false;
328
329 if( id && android_in_use() ) {
330 char str[16];
331 char *end = 0;
332 unsigned num = strtol(id, &end, 16);
333 if( end > id && *end == 0 ) {
334 snprintf(str, sizeof str, "%04x", num);
335 id = str;
336 }
337 ack = android_write_file(ANDROID0_ID_PRODUCT, id);
338 }
339 log_debug("ANDROID %s(%s) -> %d", __func__, id, ack);
340 return ack;
341}
342
343/* Set a vendor id for the android gadget
344 *
345 * @return true if successful, false on failure
346 */
347bool
348android_set_vendorid(const char *id)
349{
350 LOG_REGISTER_CONTEXT;
351
352 bool ack = false;
353 if( id && android_in_use() ) {
354 char str[16];
355 char *end = 0;
356 unsigned num = strtol(id, &end, 16);
357 if( end > id && *end == 0 ) {
358 snprintf(str, sizeof str, "%04x", num);
359 id = str;
360 }
361 ack = android_write_file(ANDROID0_ID_VENDOR, id);
362 }
363 log_debug("ANDROID %s(%s) -> %d", __func__, id, ack);
364 return ack;
365}
366
371bool
372android_set_attr(const char *function, const char *attr, const char *value)
373{
374 LOG_REGISTER_CONTEXT;
375
376 bool ack = false;
377
378 if( function && attr && value && android_in_use() ) {
379 char path[256];
380 snprintf(path, sizeof path, "%s/%s/%s",
381 ANDROID0_DIRECTORY, function, attr);
382 ack = android_write_file(path, value);
383 }
384 log_debug("ANDROID %s(%s, %s, %s) -> %d", __func__,
385 function, attr, value, ack);
386 return ack;
387}
gchar * android_get_serial(void)
bool android_set_attr(const char *function, const char *attr, const char *value)
bool android_init(void)
void android_quit(void)