On my android app for root user, I perform a shutdown with
su reboot -p
It works ok, but I noticed that the phone is shutdown almost instantly (as opposed from showing the shutdown animation, and probably doing other stuff).
Is this the correct way to shutdown an android phone programmatically? Are there some critical code that requires to be executed before shutdown?
On Android 4.3 or later, there's probably a better way to shut the device down.
Your app doesn't need to be installed as a system app, but it must have root privileges. You can simply run this one command as root in order to shut the device down:
svc power shutdown
I thank Firelord for his answer elsewhere which inspired me to discover the existence of this shell command.
I think this will do a graceful shutdown, but I'm not sure. Maybe it will do an abrupt shutdown. Please test, and then edit this answer to clarify.
Also, the above shell command does not work in Android 4.2.2 or earlier. The help text doesn't mention it. svc rejects the command as invalid and shows some help text in order to try to be helpful.
If your app is rooted, then run the following as root:
am start -a android.intent.action.ACTION_REQUEST_SHUTDOWN
In the Android source code, you can find the following:
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use
* {#link android.internal.app.ShutdownThread} for a clean shutdown.
*
* #deprecated
* #hide
*/
#Deprecated
public static native void shutdown();
I think that this native function corresponds to your su reboot -p. Moreover, you can see from the quoted code comment that you should use ShutdownThread to do a clean shutdown.
In ShutdownThread, Android does a bunch of things.
It shuts down ActivityManager. I think shutting down ActivityManager means that all activities will pass necessary lifecycle and, thus, the states of activities will be stored. But I'm not sure. I did not check.
Then, Android turns off the cellular radio interface.
After that, it turns off Bluetooth.
Finally, it tries to shut MountService down.
Thus, you can see that it's wrong to do su reboot -p.
See here:
http://developer.android.com/reference/android/os/PowerManager.html
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
pm.reboot("Because I want you to reboot!")
This should work.
Related
I'm trying to detect the successful bootup of an emulated android OS (Google's Android Emulator, sys version 12.0, running on Linux inside Docker) over adb in order to install an app right after boot. I tried the methods mentioned in this thread, but none of them seem to work.
I tried checking for all these props in a loop:
sys.boot_completed
dev.bootcomplete
init.svc.bootanim
service.bootanim.exit
They continue returning 0 even after the device is fully booted up and never return 1.
I also tried adb wait-for-device, but that finished immediately, even though I'm using the "-delay-adb" flag on my emulator (and if I don't use it, the behavior is still the same).
Attempting to install the APK before the boot is finished (right after wait-for-device exits) results in an installation error:
adb: failed to install app.apk: Exception occurred while executing 'install': java.lang.NullPointerException: Attempt to invoke virtual method 'void android.content.pm.PackageManagerInternal.freeStorage(..) on a null object reference'
It I wait for the device to boot and then manually trigger the installation, or if I add a long enough wait time before the installation is attempted, it works without any problems. But I don't want to add an arbitrarily long sleep because this may run on different devices which take different amounts of time to boot up.
Did anybody encounter this behavior?
Do you have any suggestions on how to detect bootup without having to write my own app with a BOOT_COMPLETE listener?
More abstractly, does anybody have a different suggestion on how to install an app in the Android emulator right after boot?
It's a quite an ugly solution, but you could always just attempt to install the application in a loop with some small delay and wait until it succeeds. It's not pretty, but should do the job.
You said that you receive a specific exception when you attempt to install an app during booting. Assuming the same exception is unlikely to happen after booting the phone for some unrelated reason, it should be mostly safe approach to use.
Another thing that comes up to my mind is looking at network traffic, I'd expect android to call home right after booting the system, but that seems much more complicated, and maybe even less reliable, than the "install in a loop" idea.
I'm building some general testing tool for Android apps and trying to get the activity name (e.g. com.android.calculator/.Calculator, the com.android.calculator can be obtained through UiDevice.currentPackageName, the pain is from the second part) during the testing. This is to say that my tool may test other apps that are not in the same package as mine. For example, testing the stock calculator app.
Here is a list of attempts I have made:
the UiDevice.currentActivityName is deprecated and it does not provide the accurate information
InstrumentationRegistry.getInstrumentation().targetContext.getSystemService<ActivityManager>(), then access the ActivityManager.getRunningTasks(1).get(0).topActivity, which always returns the same value even though the view has switched (and this is deprecated too)
Similar to 2, I tried ActivityManager.getAppTasks().get(0).getTaskInfo().topActivity, but this keeps giving me null
ActivityLifecycleMonitorRegistry.getInstance().getActivitiesInStage(RESUMED). This gives me an empty collection
Application.ActivityLifecycleCallbacks. I registered it with the application, but no callback is received.
(Kinda works, but not perfect) using adb dumpsys activity then find it there. But this way I have to wait for some arbitrary time until the view is updated, otherwise the result is still inaccurate
So I am currently in a cul-de-sac now, and I appreciate any help on this issue. I try to avoid reflection, because as I know it does not work on newer devices. So any clue will be appreciated.
As there is no answer posted, I wanna share my current strategy, which is not perfect, but somewhat helpful.
So first of all, as UiDevice.getActivityName is deprecated, I can only obtain the activity name through adb. Specifically, I use adb shell dumpsys activity top for API lower than 28 and adb shell dumpsys activity activities otherwise.
Then I subscribed to AccessibilityEventListener callbacks. Specifically, I run the adb command whenever I receive callbacks with type AccessibilityEvent.TYPE_WINDOWS_CHANGED. You can set up AccessibilityEventListener using this method: setOnAccessibilityEventListener
So android studio has this really nice tool that can help you monitor and track GPU work, the problem is i cant get it to work on my live wallpaper app.
I would like to see the stats when i debug my live wallpaper(All other debugging options work just fine, including memory, CPU and network monitoring).
Is there a way to make it work? if not is there an android API that will let me access this data so that i can log it by myself?
Thanks
Edit:
To clarify: I am not using an activity, i am in a context base app no activity is present while i draw. I have used > adb shell dumpsys gfxinfo and it only updates the data if an activity is running. What i need is gfxinfo for non activity drawings.
Been testing the new Android 6 auto backup/restore function, and run into a problem with my app crashing immediately after a restore. Further investigation revealed that the Application.onCreate() initialization method was not being called before the main Activity.onCreate() method. This strikes me as a likely bug in the new autorestore logic. But I thought I would ask for advice here before reporting it as an official bug.
The sequence of events I go through is
Run the app, always open a main activity window.
Force a backup of app data by entering
adb shell bmgr fullbackup net.anei.cadpage
Use the app manager to force close the app and to clear all app and cache data
Restore app information with
adb shell bmgr restore
Manually launch the app
Resulting logs show that the Activity.onCreate() method is called before the Application.onCreate() is. The app crashes because some critical initialization was not performed by the Application.onCreate() method.
Is there something obvious that I am missing???
FWIW, launching the app a second time after the crash works perfectly.
It's actually intentional, though intrusive.
For full-data backup and restore operations, the package is launched with a base class Application instance, not your manifest-declared subclass. This is because, unfortunately, many apps open files or databases via Application subclasses, and this blocks the ability of the backup machinery to correctly read/write the underlying files. Similarly, your app's content providers are not automatically instantiated for full-data backup/restore operations. The app process is then destroyed following the operation, because of course your app cannot continue to run normally without its expected Application subclass or content providers.
You also don't say exactly what command you're using to perform a test restore, but I suspect you're using the bmgr command with this syntax:
adb shell bmgr restore PACKAGE
This doesn't do what you expect. In particular, it invokes the code path that happens when your app calls BackupManager.requestRestore(observer). In this specific code path, the app is NOT shut down following the restore operation, because the app has asked to observe the operation itself. This means that you're left with the app process still running but with a base class Application. It's a power-user API that is pretty much only safe when the app uses the original key/value backup API. You need to test instead using the other bmgr syntax:
adb shell bmgr restore TOKEN PACKAGE
where TOKEN is the identifier for which dataset should be used. At least on the most recent versions of the OS you can see the current and ancestral dataset tokens in the output of adb shell dumpsys backup.
This all needs to be better documented and made less surprising.
Subclassing Application is generally discouraged; this is one reason. Try to use your own lazy-init statics instead of subclassing Application.
I'm working on an app that can answer phone calls programmatically. Iv'e read much about it, and tried many methods to get it to work.
The only true solution that works for me in versions 5.0 and up is as followed -
Runtime.getRuntime().exec("input keyevent " + Integer.toString(KeyEvent.KEYCODE_HEADSETHOOK));
Although this method works, the actual answering time is delayed by 1.5 to 5 seconds. This delay is a real deal breaker, since my app needs to intercept all incoming calls, and I can't have it delaying the answering process.
Is there any other method that works faster?
Thanks
According to another answer[1] this depends on the Super user client used. Chainfire's SuperSU[2] is said to be faster than Superuser
[1] Need root to execute shell command "input keyevent <#>" through an app at runtime?
[2] https://play.google.com/store/apps/details?id=eu.chainfire.supersu
Depending on your situation, if only the root method works for you, one way is to keep the root shell open with your background service, and pipe the input keyevent command to it when needed. This would save the startup time of the process and the shell every time the call comes in. You can do this easily with libraries such as RootShell.