└── README.md /README.md: -------------------------------------------------------------------------------- 1 | *(c) 2014-2018 Paul Sokolovsky. Portions of content (c) by their respective authors.* 2 | 3 | ## Linux 4 | 5 | ### How to find out version of kernel running 6 | 7 | If that kernel is booted and you have access to console: 8 | ``` 9 | uname -a 10 | ``` 11 | 12 | Alternatively: 13 | 14 | ``` 15 | cat /proc/version 16 | ``` 17 | 18 | 19 | If you have only kernel image file ... (tba). 20 | 21 | ### How to see what devices/partitions are mounted and their filesystem, types 22 | ``` 23 | mount 24 | ``` 25 | 26 | Alternatively: 27 | 28 | ``` 29 | cat /proc/mounts 30 | ``` 31 | 32 | ### How to read kernel message log (including boot log) 33 | 34 | ``` 35 | dmesg 36 | ``` 37 | 38 | Kernel log contains all messages from the beginning of kernel boot, 39 | but it is implemented as a circular buffer (of configurable size), so 40 | newer messages may replace older. 41 | 42 | ### Is it possible to read kernel log if dmesg is not available? 43 | 44 | `cat /proc/kmsg` will block and dump ''new'' kernel messages. This 45 | will work reliably only if there are no other consumer(s) of 46 | `/proc/kmsg` (note: on typical fully booted Linux system there's - 47 | syslogd, etc.), otherwise the output may be garbled. 48 | 49 | 50 | ### How to read system log 51 | 52 | On a full-fledged Linux system, system log is usually accessible as 53 | `/var/log/messages`. Recently, some particular distributions started 54 | to play original, for example, in Ubuntu 12.04 `/var/log/messages` is 55 | empty and instead `/var/log/syslog` may contain some, or all, of 56 | system log messages. 57 | 58 | On an embedded system, a busybox syslogs may be used, providing 59 | circular buffer without file backing storage. It can be accessed using 60 | `logread` command. 61 | 62 | ### How to write to system log 63 | `logger` command does that. 64 | 65 | ### How to find out config of a kernel? 66 | 67 | With a running kernel, if it was built with CONFIG_IKCONFIG_PROC, the 68 | config can be read as `/proc/config.gz`. For a zImage file, 69 | `scripts/extract-ikconfig` can be used to extract it (just 70 | CONFIG_IKCONFIG is required for this). 71 | 72 | ### How to list loaded kernel modules? 73 | ``` 74 | lsmod 75 | ``` 76 | 77 | Alternatively: 78 | ``` 79 | cat /proc/modules 80 | ``` 81 | 82 | ### How to load kernel modules? 83 | Low-level command to load a specific filename is: 84 | ``` 85 | insmod /path/.ko 86 | ``` 87 | 88 | Higher level command is: 89 | ``` 90 | modprobe 91 | ``` 92 | 93 | This will look for modules located in `/lib/modules/` 94 | and requires support files generated by `depmod`. 95 | 96 | ### How to force loading of kernel module? 97 | Module loading is subject to many checks (see below), so and kernel 98 | may refuse to load improper one. If CONFIG_MODULE_FORCE_LOAD is 99 | defined, it is possible to force-load module nonetheless. 100 | Unfortunately, it's not possible to force load with (recent) `insmod`. 101 | It can be done with `modprobe -f` (`modprobe ---help` for other force 102 | options). 103 | 104 | ### How to unload kernel modules? 105 | ``` 106 | rmmod 107 | ``` 108 | 109 | Module unloading usually available, but still depends on 110 | CONFIG_MODULE_UNLOAD. Module may refuse to unload if other modules 111 | depend on it, or if it's in particular state (which also includes 112 | states like "hanged" and "gone awry"), in which case it's possible to 113 | force unload (`rmmod -f`), if CONFIG_MODULE_FORCE_UNLOAD was defined. 114 | 115 | ### Can kernel modules built for one version be used with another kernel version? 116 | In general, this is not possible. With Linux kernel's "stable API is 117 | nonsense" attitude, anything in the kernel can be changed at any time 118 | - this includes APIs which can be called by a module, module format 119 | and layout itself, etc. Not only that, same kernel version built with 120 | different configuration options may have differences in these aspects 121 | (it's possible to #ifdef some fields in structures and even parameters 122 | to function calls). 123 | 124 | That said, for close kernel versions and small differences in 125 | configuration, chances of fatal incompatibilities of modules are low. 126 | However, kernel itself has "helpful guards" to preclude usage of 127 | modules with different kernel version. By default (CONFIG_MODVERSIONS 128 | is not defined), kernel's and module's vermagic strings are compared, 129 | which are of the form: "3.2.0-32-generic SMP mod_unload modversions 130 | 686", i.e. include kernel version, extraversion, then tags for most 131 | important configuration params. If vermagics don't match, module 132 | loading fails. 133 | 134 | Even more annoying "protection" is employed if CONFIG_MODVERSIONS is 135 | defined. In this case, each kernel exported symbol gets hash (CRC) 136 | signature based on the parameter signature on the underlying C 137 | function, stored both in kernel and module. These signatures are 138 | compared, and on any mismatch, loading fails. The only easing with 139 | this is that when vermagics comparison is done, kernel versions are 140 | ignored, i.e. if different kernel versions don't have param signature 141 | changes and have same core config params, a module will work across 142 | such versions. 143 | 144 | There's also support for forced module load, but that will work only 145 | if enabled in kernel config (CONFIG_MODULE_FORCE_LOAD). 146 | 147 | ### How to get detailed information about a kernel module 148 | ``` 149 | modinfo 150 | ``` 151 | 152 | This will dump main module properties and vermagic string. As a 153 | parameter, both a filename and system module name (as available in 154 | /lib/modules) can be given. 155 | 156 | To dump modversions hashes: 157 | ``` 158 | modprobe --dump-modversions .ko 159 | ``` 160 | 161 | ### How to build out of tree kernel module 162 | 163 | From official kernel docs: 164 | [Documentation/kbuild/modules.txt](http://www.kernel.org/doc/Documentation/kbuild/modules.txt), 165 | for a module source in current dir: 166 | 167 | ``` 168 | make -C M=$PWD 169 | ``` 170 | 171 | Build against currently running kernel (requires linux-headers package 172 | installed): 173 | 174 | ``` 175 | make -C /lib/modules/$(uname -r)/build M=$PWD 176 | ``` 177 | 178 | ### How to install built kernel modules to a specific location 179 | Useful when cross-compiling, etc. 180 | ``` 181 | make modules_install INSTALL_MOD_PATH=/path/where 182 | ``` 183 | 184 | More details: 185 | [Documentation/kbuild/modules.txt](http://www.kernel.org/doc/Documentation/kbuild/modules.txt). 186 | 187 | 188 | ### How to setup NAT (masquerading) 189 | 190 | If you have another host/embedded device/QEMU connected to a local host interface, 191 | and you would like to let that device connect to the Internet, masquerading should 192 | be set up for device's IP address: 193 | 194 | ``` 195 | iptables -t nat -A POSTROUTING -j MASQUERADE -s 192.168.2.2 196 | ``` 197 | 198 | (This assumes that the host has Internet connection and has IP forwarding enabled). 199 | 200 | 201 | ### How to connect to WiFi network from bare command-line (using wpa_supplicant & wpa_cli) 202 | If you're not on bare command-line, make sure you killed already running 203 | wpa_supplicant as well as other daemons which may respawn it (e.g. 204 | NetworkManager on Ubuntu). 205 | 206 | Make sure that WiFi interface is up. It otherwise doesn't need to have any 207 | special configuration: 208 | ``` 209 | ifconfig wlan0 up 210 | ``` 211 | 212 | Run: 213 | ``` 214 | wpa_supplicant -i wlan0 -g /tmp/wpa -C /tmp 215 | ``` 216 | 217 | `-g` specifies "global control socket". The caveat about is that many 218 | commands are not supported via it, issuing them via it leads to obfuscated 219 | "UNKNOWN COMMAND" reply. So, it's important to specify `-C` switch, which 220 | takes *directory* path under which individual control sockets for each 221 | WiFi interface will be stored. 222 | 223 | In another window, run: 224 | ``` 225 | wpa_cli -p /tmp 226 | ``` 227 | 228 | `-p` option gives path to per-WiFi-interface control socket dir (`-C` of 229 | wpa_supplicant). Issue following commands in wpa_cli interactive session 230 | (ignore # lines): 231 | 232 | ``` 233 | # Scan for available APs 234 | > scan 235 | OK 236 | # Wait a bit, then view results 237 | <3>CTRL-EVENT-SCAN-STARTED 238 | <3>CTRL-EVENT-SCAN-RESULTS 239 | > scan_results 240 | ... 241 | # Create new AP entry, returned is ID of new entry 242 | > add_network 243 | 0 244 | # Start setting AP parameters 245 | > set_network 0 ssid "MY_AP" 246 | OK 247 | > set_network 0 psk "password" 248 | OK 249 | # These should be all params requires for WPA 250 | # Activate network 251 | > select_network 0 252 | OK 253 | # Trigger connection 254 | > reconnect 255 | OK 256 | <3>SME: Trying to authenticate with xx:xx:xx:xx:xx:xx (SSID='MY_AP' freq=2462 MHz) 257 | <3>Trying to associate with xx:xx:xx:xx:xx:xx (SSID='MY_AP' freq=2462 MHz) 258 | <3>Associated with xx:xx:xx:xx:xx:xx 259 | ``` 260 | 261 | This will have wlan0 connected to AP. Then get IP address via DHCP: 262 | ``` 263 | dhclient wlan0 264 | ``` 265 | 266 | And configure /etc/resolv.conf to suitable DNS address (e.g. 8.8.8.8 to 267 | be monitored by Google): 268 | ``` 269 | nameserver 8.8.8.8 270 | ``` 271 | 272 | The instructions above show how to run wpa_supplicant without any stored 273 | configuration, and instead configure it dynamically (e.g., programmatically). 274 | Alternatively, using config: 275 | ``` 276 | # Create simple config file 277 | wpa_passphrase MY_AP >wpa.conf 278 | # Enter password 279 | ... 280 | wpa_supplicant -i wlan0 -c wpa.conf 281 | 282 | ``` 283 | 284 | ### How to test network multicasting 285 | Multicasting is basis of many usability protocols and services (e.g. mDNS, 286 | UPNP, DLNA, etc.), and yet means to query/test/diagnose it are not widely 287 | known, if not to say obfuscated. At the same time, multicasting has known 288 | andregular issues, when used on network interfaces differing from Ethernet, 289 | for which it was initially conceived (these other networking types include 290 | WiFi/other wireless, loopback, etc.) 291 | 292 | Multicast is similar to broadcast, except individual hosts don't receive 293 | datagrams unconditionally, but need to join "multicast group" (other way 294 | to think about it is a PubSub pattern). Multicast groups are represented 295 | by special IP addresses, e.g. for IPv4 it's 224.0.0.0 to 239.255.255.255. 296 | Some multicast IPs have predefined (STD/RFC) meaning, other are supposedly 297 | can be (dynamically) allocated per purpose. 298 | 299 | 224.0.0.1 is a "local network" predefined address. All hosts on current 300 | subnetwork are supposed to (auto)join it. In this regard, that address is 301 | similar to local network broadcast, 255.255.255.255. The basic means to 302 | test multicasting is ping this address: 303 | ``` 304 | ping 224.0.0.1 305 | ``` 306 | 307 | The expected outcome is that each host which is member of multicast group 308 | will respond (ping thus will receive duplicate responses and will report so). 309 | 310 | However: 311 | * A firewall will likely interfere. Note that broadcast/multicast pings are 312 | especially not firewall friendly, as replies are not received from 313 | destination of packet (ping packets are sent to 224.0.0.1, but received from 314 | individual host IPs). The easiest way to deal with this is usually to disable 315 | firewall during testing. 316 | * Besides firewall, modern Linux kernels ignore broadcast/multicast pings 317 | by default. To enable responses to such pings use: 318 | ``` 319 | echo "0" >/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts 320 | ``` 321 | (needs to be done on each machine from which you want to receive responses 322 | of course). 323 | * The network interface used should have multicast support enabled, and 324 | e.g. loopback (lo) is notoriously known to not have it enabled by distros 325 | by default. 326 | 327 | If you have a normal Ethernet/WiFi interface, following first 2 suggestions 328 | should lead to `ping 224.0.0.1` to get responses at least from the host 329 | you run it on. 330 | 331 | For other multicast groups, they should be pingable as long as a socket 332 | bound to that group is active on a host. 333 | 334 | To further diagnose multicast settings, refer to following /proc files: 335 | * `/proc/net/igmp` (IP-level multicast) 336 | * `/proc/net/dev_mcast` (Physical-level multicast) 337 | 338 | Few other points: 339 | * It's not required to be a member of multicast group to send a datagram 340 | to it. 341 | * To send a datagram to multicast address, sendto() call should be used, 342 | if reply is expected to be received on the same socket. connect() + 343 | send() won't work, because reply won't come from a multicast address, but 344 | reather from a real host address. 345 | 346 | ## Android 347 | 348 | ### How to enable ADB connection on device 349 | 350 | This is called "USB debugging" and is available in Settings -> Developer 351 | options. Developer options themselves are concealed by default in 352 | Android 4.2 and higher. From https://developer.android.com/studio/debug/dev-options: 353 | 354 | > On Android 4.1 and lower, the Developer options screen is available by 355 | > default. On Android 4.2 and higher, you must enable this screen. To 356 | > enable developer options, tap the Build Number option 7 times. You 357 | > can find this option in one of the following locations, depending on 358 | > your Android version: 359 | > 360 | > * Android 9 (API level 28) and higher: Settings > About Phone > Build Number 361 | > * Android 8.0.0 (API level 26) and Android 8.1.0 (API level 26): Settings > System > About Phone > Build Number 362 | > * Android 7.1 (API level 25) and lower: Settings > About Phone > Build Number 363 | 364 | ### How to configure udev rules for using adb over USB 365 | 366 | Create `/etc/udev/rules.d/99-android.rules` with content: 367 | ``` 368 | SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0660", GROUP="plugdev" 369 | ``` 370 | 371 | Here, ``0bb4`` is a USB vendor ID, you may need to adjust it for your device; 372 | ``plugdev`` - is typical pluggable device access group on most modern Linux 373 | distros. 374 | 375 | Based on: http://developer.android.com/tools/device.html 376 | 377 | ### How to connect adb over WiFi (or TCP/IP in general) 378 | On Android command line: 379 | ``` 380 | su 381 | stop adbd 382 | setprop service.adb.tcp.port 6565 383 | start adbd 384 | ``` 385 | 386 | Use `netcfg` to check device IP. (In newer Android versions, standard 387 | `ifconfig` or `ip addr` may work.) 388 | 389 | Per above (`su`), this requires a rooted device. An alternative is to 390 | connect device using USB first, and run `adb tcpip 6565`, after which 391 | USB cable can be disconnected. 392 | 393 | After that, on host: 394 | ``` 395 | adb connect :6565 396 | adb shell 397 | ``` 398 | 399 | ### How secure is ADB connection? 400 | 401 | ADB protocol does not seem to support encryption (protocol description: 402 | https://android.googlesource.com/platform/system/core/+/master/adb/protocol.txt). 403 | This means that using it over broadcasting non-encrypted physical medium (like 404 | Ethernet or public WiFi) is insecure. 405 | 406 | Until Android 4.2.2, protocol did not support authentication, which made it 407 | highly insecure. There are known exploits of trojan "charging stations" used 408 | to break into devices. 409 | 410 | In Android 4.2.1_r1, public key authentication was added to adb protocol: 411 | https://github.com/android/platform_system_core/commit/d5fcafaf41f8ec90986c813f75ec78402096af2d 412 | This requires ADB version 1.0.31 (available in SDK Platform-tools r16.0.1 or 413 | higher). User is required to confirm connection to a new ADB host on a device 414 | itself, for one time connection or to remember the approval. In the latter 415 | case, host key(s) are saved in `/data/misc/adb/adb_keys`. There can be 416 | pre-installed keys in `/adb_keys`. 417 | 418 | 419 | ### How to verify ADB host fingerprint 420 | 421 | When connecting to a new ADB host, an Android device shows an RSA fingerprint, 422 | however, it takes some effort to check that this fingerprint actually belongs 423 | to a host. 424 | 425 | On a host, ADB public key is in $HOME/.android/adb_key.pub. To get its 426 | fingerprint: 427 | 428 | awk '{print $1}' < adbkey.pub|openssl base64 -A -d -a | openssl md5 -c 429 | 430 | 431 | Based on: http://nelenkov.blogspot.de/2013/02/secure-usb-debugging-in-android-422.html 432 | 433 | 434 | ### How to read Android logs 435 | On Android command line: 436 | ``` 437 | logcat 438 | ``` 439 | See `logcat --help` 440 | 441 | From host: 442 | ``` 443 | adb logcat 444 | ``` 445 | 446 | ### How to list installed Android packages? 447 | On device: 448 | ``` 449 | pm list packages 450 | ``` 451 | 452 | ### How to install Android package (.apk)? 453 | On device: 454 | ``` 455 | pm install app.apk 456 | ``` 457 | 458 | ### How to install .apk using adb (from host command line) 459 | From host: 460 | ``` 461 | adb install app.apk 462 | ``` 463 | 464 | To force install even if already exists: 465 | ``` 466 | adb install -r app.apk 467 | ``` 468 | 469 | `adb --help` for more. 470 | 471 | ### How to remove installed Android package? 472 | On device: 473 | ``` 474 | pm uninstall 475 | ``` 476 | 477 | This won't work for system packages located in `/system/app`, see 478 | question below on how to remove them. 479 | 480 | ### How to get around lack of `cp` in default Android `toolbox` 481 | 482 | Try: 483 | ``` 484 | cat /path/from >/path/to 485 | ``` 486 | 487 | ### Is there a writable location on the main filesystems on non-rooted device? 488 | 489 | First of all, there's `/mnt/sdcard`, which is accessible to default 490 | `adb` user. However, that filesystem is mounted `noexec`, so it's not 491 | possible to run any executables from there. However, there's 492 | `/data/local` which is both writable and executable. On newer Android 493 | versions (checked with Android 7), only `/data/local/tmp` is such. 494 | 495 | ### How to get temporary root access on ro.secure=1 devices 496 | 497 | An exploit executable is needed. For Android 2.x, 498 | [zergRush](https://github.com/revolutionary/zergRush) is a well-known 499 | app. 500 | On host: 501 | ``` 502 | unzip zergRush.zip 503 | adb push zergRush /data/local 504 | adb shell 505 | cd /data/local 506 | chmod 770 zergRush 507 | ./zergRush 508 | ``` 509 | 510 | If you get error like `[-] Cannot copy boomsh.: Permission denied`, 511 | it's likely zergRush was already run previously and left some cruft, 512 | remove it and retry (on device): 513 | ``` 514 | rm tmp/sh 515 | rm tmp/boomsh 516 | ./zergRush 517 | ``` 518 | 519 | ### How to install Android su with frontend (permanent root) 520 | 521 | Get root shell as described above. Then (you [can get newer 522 | versions](http://androidsu.com/superuser/) than 3.0.7, but they're 523 | kinda bloat): 524 | ``` 525 | http://downloads.noshufou.netdna-cdn.com/superuser/Superuser-3.0.7-efghi-signed.zip 526 | unzip Superuser-3.0.7-efghi-signed.zip 527 | adb push system/bin/su /system/bin/ 528 | adb push system/app/Superuser.apk /system/app/ 529 | adb shell chmod 06755 /system/bin/su 530 | ``` 531 | 532 | ### Where vendor-provided software is located in filesystem? 533 | Preinstalled application are in `/system/app`, unlike user-installed 534 | applications, which are in `/data/app` . 535 | 536 | ### How to remove bloatware from /system/app 537 | This requires root. 538 | 539 | On host: 540 | ``` 541 | adb remount 542 | adb shell 543 | ``` 544 | Then on device: 545 | ``` 546 | cd /system/app 547 | rm bloatware.apk 548 | sync 549 | ``` 550 | 551 | You may want to reboot to clear app cache, though apps should be gone 552 | immediately. 553 | 554 | ### What are user and group ids used by Android? 555 | 556 | These are defined in 557 | [system/core/include/private/android_filesystem_config.h](http://code.metager.de/source/xref/android/2.3.7/system/core/include/private/android_filesystem_config.h) 558 | 559 | ### Is it possible to use stdout/stderr/printf/System.out.println/etc. in Android? 560 | 561 | Reference: http://developer.android.com/tools/debugging/debugging-log.html#viewingStd 562 | 563 | By default, Android redirects stdout, etc. to /dev/null. However, 564 | `log.redirect-stdio` system property can be set to `true` to redirect 565 | to system log (logcat) instead. This takes effect after system restart 566 | (and has effect during current system session), so the complete command 567 | sequence to enable stdout logging is: 568 | 569 | ``` 570 | stop 571 | setprop log.redirect-stdio true 572 | start 573 | ``` 574 | 575 | ### How to list Android services? 576 | ``` 577 | service list 578 | ``` 579 | 580 | ### How to call Android services from command line? 581 | 582 | Based on http://www.slideshare.net/jserv/android-ipc-mechanism 583 | 584 | Getting Java class implementing service: 585 | ``` 586 | service call activity 1598968902 587 | ``` 588 | 589 | 1598968902 (0x5f4e5446) is [INTERFACE_TRANSACTION](http://developer.android.com/reference/android/os/IBinder.html#INTERFACE_TRANSACTION). 590 | 591 | Prepare to dial number "123": 592 | ``` 593 | service call phone 1 s16 123 594 | ``` 595 | 596 | "1" is a method #1 per 597 | [ITelephony.aidl](https://github.com/android/platform_frameworks_base/blob/master/telephony/java/com/android/internal/telephony/ITelephony.aidl), 598 | i.e. `dial()`. 599 | 600 | ### How to start/stop Android daemons 601 | `start` & `stop` commands do that. E.g.: 602 | ``` 603 | stop vold 604 | ``` 605 | 606 | Alternatively, this can be done by setting system properties: 607 | ``` 608 | setprop ctl.stop vold 609 | setprop ctl.start vold 610 | ``` 611 | 612 | ### How to start/stop complete Android environment 613 | For this, `zygote` daemon should be stopped: 614 | ``` 615 | stop zygote 616 | ``` 617 | 618 | zygote is also a default argument for `start`/`stop`, so following 619 | will work too: 620 | ``` 621 | stop 622 | ``` 623 | 624 | ### How to dump detailed service state? 625 | `dumpsys ` dumps loadsome of information about internal 626 | service state. Omit service name to dump state of all services. 627 | 628 | ### How to Allow Apps To Write Files to USB Mass Storage Devices in Android 629 | 630 | [Based 631 | on](http://www.cnx-software.com/2012/08/26/how-to-allow-apps-to-write-files-to-usb-mass-storage-devices-in-android/): 632 | 633 | Edit `/system/etc/permissions/platform.xml` to add `` to WRITE_EXTERNALS_STORAGE permission: 635 | 636 | ``` 637 | 638 | 639 | 640 | 641 | ``` 642 | 643 | Reboot required. Tested with Android 4. 644 | 645 | ### How to list all modules available in Android platform source tree? 646 | ``` 647 | make modules 648 | ``` 649 | 650 | ### Is it possible to write console Dalvik apps? 651 | Yes, actually "am", "pm" and few other standard Android tools are actually 652 | such, and are run via shell wrapper: 653 | https://android.googlesource.com/platform/frameworks/base/+/gingerbread/cmds/am/ 654 | 655 | [hello-world.html](https://android.googlesource.com/platform/dalvik/+/gingerbread/docs/hello-world.html) 656 | from platform/dalvik/docs/ explains how: 657 | 658 | ``` 659 | # Create file Foo.java 660 | class Foo { 661 | public static void main(String[] args) { 662 | System.out.println("Hello, world"); 663 | } 664 | } 665 | ``` 666 | 667 | ``` 668 | javac Foo.java 669 | dx --dex --output=foo.jar Foo.class 670 | adb push foo.jar /sdcard 671 | adb shell dalvikvm -cp /sdcard/foo.jar Foo 672 | ``` 673 | 674 | ### I tried to flash a custom image to recovery partition (Android 4.x), however it doesn't boot and instead "red triangle of doom" is shown 675 | Assuming the image is correct for your type of device and flashed into 676 | right place for it, known "feature" which causes this behavior is 677 | Android 4.x "recovery from boot". The idea is following: Recovery 678 | allows you to restore main Android install if something goes wrong. 679 | But what if recovery itself gets corrupted? Then if main image gets 680 | corrupted too, the device is bricked. So, main image and recovery were 681 | made to "watch after another". In particular, during boot of main 682 | image, recovery partition is checked, and if it doesn't contain "know 683 | good" image, it gets silently reflashed with copy of such image kept 684 | in main partition. 685 | 686 | The backup of recovery image is commonly held in 687 | /system/recovery-from-boot.p . Actual boot-time checking and 688 | reflashing is handled by /system/etc/install-recovery.sh . Thus, to 689 | disable this behavior which gets into way of advanced Android usage, 690 | do following: 691 | ``` 692 | mv /system/recovery-from-boot.p /system/recovery-from-boot.p.old 693 | ``` 694 | or: 695 | ``` 696 | chmod 644 /system/etc/install-recovery.sh 697 | ``` 698 | 699 | Also, "red triangle of doom" is actually how a stock recovery of 700 | Android 4.x looks - while previous versions offered interactive means 701 | to investigate and fix your device, that's what to it was reduced in 702 | Android 4.x. 703 | 704 | Based on: 705 | http://android.stackexchange.com/questions/18932/why-isnt-clockworkmod-recovery-sticking 706 | , http://androtab.info/clockworkmod/rockchip/install/ 707 | --------------------------------------------------------------------------------