Measure Android app startup time - android

What is the most precise way to measure startup time of an Android app?
By startup time I mean the difference between 2. and 3. :
The app process is not running
User clicks on app icon in the launcher
Main Activity is fully initialized
So I basically need to somehow get time elapsed since JVM started and log it.

I understand I am too late to answer, nonetheless, this precisely answers the question.
This information gets logged on Logcat by default for API version 19 or higher.
From Android 4.4 (API level 19), logcat includes an output line containing a value called Displayed. This value represents the amount of time elapsed between launching the process and finishing drawing the corresponding activity on the screen.
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
The key is looking for it in the right place -
If you’re tracking logcat output from the command line, or in a terminal, finding the elapsed time is straightforward. To find elapsed time in Android Studio, you must disable filters in your logcat view. Disabling the filters is necessary because the system server, not the app itself, serves this log.
The extracts are from the documentation.

I'm going to interpret your question as 'Is my app startup time fast enough. How can I check I have done everything I can do?'
The startup time is largely a false metric as it will vary across devices and ROMs. I guess what you're most likely to be interested in is how much of your code is taking a long time to execute and what is potentially blocking the main thread.
I've found the most effective way of doing this is to use Traceview on the app start and then reviewing how long it takes the method to execute and if there are any gaps on the main thread.
Start tracing:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("startup");
}
}
Stop tracing:
#Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Debug.stopMethodTracing();
}
Once the trace has been collected, you should be able to see anything that is having a major impact on startup time. In my case, seen below, there was a big gap on the UI thread where is was being blocked.
It transpired that both Crashlytics and Coremetrics were requiring a call to randomUUID() which was then being synchronized across threads and blocking the main thread. The solution was just to spin up a new thread to initialise the Coremetrics code.
This is something I would not have otherwise picked up with just measuring the startup time, but it actually sped up the app 'startup time' by a few hundred milliseconds.
Here's another snapshot after spinning off a separate thread for Coremetrics initialisation:

Check in adb shell in below manner.
adb shell
adb logcat -b events | grep am_activity_launch_time
[Output]
01-01 12:32:53.469 1236 1262 I am_activity_launch_time:
[0,205360373,com.sec.android.app.clockpackage/.ClockPackage,378,**378**,0]
Remarks:
Launch time for Clock is 378ms.

Wrap the entire onCreate() method in a TimingLogger. Just put this at the beginning:
TimingLogger timings = new TimingLogger(TAG, "methodA");
and this at the end:
timings.dumpToLog();
If you want to drop times at some intermediate step, you can do timings.addSplit("name"); to get the time it took to get to that step.

A simple way to display startup time in android.
Sometimes the Displayed line in the logcat output contains an additional field for total time. For example:
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
In this case, the first time measurement is only for the activity that was first drawn
Source: Time to initial display

It is possible to implement time tracking using the next code:
Override your Application:
public class CustomApplication extends Application {
public final static long APP_START_TIME = System.currentTimeMillis();
/**
* Do all other application stuff
*/
}
And add few rows to your main Activity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final View contentView = findViewById(android.R.id.content);
contentView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= 16) {
contentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
contentView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
long launchTime = System.currentTimeMillis() - CustomApplication.APP_START_TIME;
Log.e("TEST", "App launch time = " + launchTime);
}
});
}
}
And don't forget to define your custom application in Manifest:
<application
android:label="#string/app_name"
android:name=".CustomApplication" >
</application>
Important: You have to kill your application before launch, because Application stores static variable which tracks initial time.

Use SysTrace
Also the Trace class can be used to measure sections using
Trace.beginSection("name");
Trace.endSection();
This YouTube video is a quick primer as well.

I think this has been built into Firebase Console, under performance now

One possibility would be is to save the time at the beginning of the onCreate() method and at the end of the onCreate() method and then subtract those times from each other to get the time taken to initialize the app.

Related

How to disable ANR Watchdog when generating Trace Logs for Profiling after instrumenting my App?

Currently trying to obtain profile trace logs files for a huge Android app, that we have instrumented on MyApplication class, following the documentation about instrumenting my app to get trace logs.
We are trying to dig into what happens when our app is initialized and Dagger2 creates the object graph when the app is started.
A cold startup can take a few seconds normally, the issue I have is that when I add the Debug traces, it dramatically slows down the initialization of the app, making it crash with an ANR message.
com.github.anrwatchdog.ANRError: Application Not Responding
Caused by: com.github.anrwatchdog.ANRError$$$_Thread: main (state = RUNNABLE)
I would like to know if there is a way to prevent the Android OS from crashing my app when it blocks for a long period of time, or to at least increase the ANR threshold.
Any help or tips are welcome. Thanks!
For further context, this is roughly what I am doing in my MyApplication.class:
public void onCreate() {
super.onCreate();
Debug.startMethodTracing("MyApp_onCreate()");
injectSelf();
AppInit.initApp(this);
Debug.stopMethodTracing();
}
Actually, it turns out we have our own ANRWatchDogManager which I wasn't aware of, where I can extend the limit.
public class ANRWatchDogManager implements ANRWatchDog.ANRListener {
Somewhere in that class:
public void startANRWatchDog() {
final int timeoutInterval = isDebugBuild() && isEmulator()
? ANR_INCREASED_TIMEOUT
: ANR_DEFAULT_TIMEOUT;
new ANRWatchDog(timeoutInterval).setANRListener(this).start();
}

How many mayLaunchUrl we can run at a time?

I am trying to utilize ChromeCustomTabs into our project. I ran into several issue when I used mayLaunchUrl. I checked the code Google has on the github. I simply set up an button to test the mayLaunchURL (prerender feature), when I looked up the traffic using chrome dev tool. I did the the traffic and tab got trigger and the url got loaded ( it is simply a GET call with params). However, when I click it multiple times, (after 8-10times, with different params everytime), it STOP working. I stop seeing the requests sent out. (Not seen on chrome dev tool, nor the Proxy I set up).
I wonder if there is a limit times ( restriction) for mayLaunchURL feature, in other words, how many pages we can pre-render in this case? Is there a way to manually cancel the pre-render page and free the resource?
is there a restriction in terms of times to bindCustomTabsService? The way I did to call mayLaunchURL is to have an activity and kill the activity once I finish the tab. Can I bind the service each time even I “kill (finish)” the activtiy every time?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customTabActivityHelper = new CustomTabActivityHelper();
customTabActivityHelper.setConnectionCallback(this);
}
#Override
protected void onStart() {
super.onStart();
customTabActivityHelper.bindCustomTabsService(this);
}
#Override
public void onCustomTabsConnected() {
Boolean mayLaunchUrlAccepted = customTabActivityHelper.mayLaunchUrl(Uri.parse(“the URL?f=“+params), null, null);
// the mayLaunchUrlAccepted always return true in my case. Even when there is no request sent.
}
Yes, mayLaunchURL() are very expensive in terms of battery/RAM/network, so it is throttled on app UID level. But limits get dropped after some time.
Best strategy is to use mayLaunchURL() if the confidence that the user will navigate to the URL is very high.
There is the "low confidence" mayLaunchURL() which is not throttled, but performs a more limited set of actions (currently preconnect, not specified which, may change). The low confidence mayLaunchURL is triggered by providing null as the uri and a list of URLs in otherLikelyBundles.

App using Mobile Android GNSK crashes when identifyAlbumAsync() is called before audioProcessStart()

I have being upgrading an application to use the new Mobile Android GNSK but I have noticed that using the new MusicID-Stream is a little bit tricky. If the "identifyAlbumAsync" method get executed before the "audioProcessStart" method(since this need to be executed in a different thread), the application just crashes. In the Gracenote Demo application, the "audioProcessStart" method is continuously running so there is no need to synchronize its execution with the "identifyAlbumAsync" method call. Is it the way it is supposed to be used? It will be convenient if the application didn't crashed at least when the methods are not executed in order. Also in our application, we don't want to have the "audioProcessStart" method continuously like it is done in the demo application. We only want to run the "audioProcessStart" method when the user request identification and when the song playing gets identified , we want to stop the audio processing by calling "audioProcessStop". Is there an easy way to do this? Right now, we are getting the Thread where "identifyAlbumAsync" is running to sleep for 2 seconds in order to make sure that the Thread where the "audioProcessStart" method is supposed to run has time to get executed. Thank you in advance for your prompt response
In the upcoming 1.2 release, IGnMusicIdStreamEvents includes a callback that signals audio-processing has started, and an ID can be synced with this, e.g.:
#Override
public void musicIdStreamProcessingStatusEvent( GnMusicIdStreamProcessingStatus status, IGnCancellable canceller ) {
if (GnMusicIdStreamProcessingStatus.kStatusProcessingAudioStarted.compareTo(status) == 0) {
try {
gnMusicIdStream.identifyAlbumAsync();
} catch (GnException e) { }
}
}
Thanks for the feedback, you're right about this issue. Unfortunately right now sleeping is the best solution. But we are adding support for an explicit sync event in an upcoming release, please stay tuned.

Java - Android : Thread being called (run) twice

I would like some help regarding Java - Android MultiThreading
While learning to develop my app in a multi-threading way in order to take advantage of the ever-growing multi-core devices market share (most devices are quad core now, some even octo-core), I ran in a situation where my threads are either being calling twice or running twice.
I just don't why and how.
[EDIT 3]
Alright, I narrowed down the issue : I called the AsyncTask from the onResume() method. Although my app did not lost focus (which would mean a call to onPause() then back to onResume() upon return of focus in which case my threads would be run twice) during the tests, I solved the issue by moving away the call to FetchFriendsList to another place.
So far so good, but since in my tests the app did not loose focus or perhaps it did but I could not witness it (!), I think there is another reason behind so I'd say my problem is not entirely solved ... at least for the moment. It does work though. Perhaps I did solve the issue but I do not know how :(
[end of EDIT 3]
I am implementing last Facebook SDK and I am using it to fetch the end-user friends list, which seems to do the work.
Since I am running this operation in an AsyncTask, I am not using request.executeAsync().
Instead I am using request.executeAndWait(). Facebook JavaDoc does state that this method must only be used if I am not in a the Main UI Thread which is my case otherwise I would get a NetworkOnMainThreadException.
Anyway, this is where the weird behavior is happening.
private final ArrayList<GraphUser> userFriendsList = new ArrayList<GraphUser>();
public final void fetchFriendsList() {
if (this.session != null && this.session.isOpened()) {
final Request requestUserFriendsList = Request.newMyFriendsRequest(
this.session, new Request.GraphUserListCallback()
public final void onCompleted(final List<GraphUser> users, final Response response) {
if (users != null && users.size() > 0) {
Log.v("Retrieved Friends List -> ", String.valueOf(users.size()));
userFriendsList.addAll(users);
}
}
}
);
if (this.asyncFlag)
requestUserFriendsList.executeAsync();
else
requestUserFriendsList.executeAndWait();
}
}
In my case, asyncFlag is set to false because I need to do stuff synchronously in that specific order :
Fetch User Friends List (not on the Main (UI) Thread)
Save friends list on device (separate new thread)
Save friends list on a server (separate new thread)
Following this pattern, the line userFriendsList.addAll(users); is called twice.
In the logcat, the Log.vis showed twice as well, and finally looking with the debugger, the content of the user friends list is made of duplicates.
But that's not all ... step 2 and 3 are indeed two separate threads which are both created and spawned within the same method : public final void asyncSaveFacebookFriendsList().
And guess what, this method is even called twice !
just why ?
At the beginning I was calling the method for step 2 and 3 like this :
[...]
userFriendsList.addAll(users);
asyncSaveFacebookFriendsList(); // it was private before
[...]
This is where the issue started as both line were running twice.
So I thought, alright, I'll call it later like this :
[...]
fetchFriendsList();
asyncSaveFacebookFriendsList(); // it is now public
[...]
But the issue remains still.
If I don't call public final void asyncSaveFacebookFriendsList(), then nothing is run twice.
Why does this issue happen ? Is there something I did not get in Java Threads ?
I do not think this is somehow related to the Facebook SDK because following the same pattern (and doing it also at the same time), I have the same issues when fetching and storing the end-user Twitter friends list.
So I do believe I am doing something wrong. Does someone have any idea in what possible case a thread is called twice ?
Note : all threads are started this way : thread.start(). I am not using any ThreadPool nor the ExecutorService.
In case you need more background context :
Content of AsyncTask : (no need to wonder why Void and Long, I remove the irrelevant code related to it)
private final class FetchFriendsLists extends AsyncTask<Long, Integer, Void> {
protected final Void doInBackground(final Long... params) {
if (params[0] != Long.valueOf(-1)) {
[...]
twitterAPI.fetchUserFriendsList();
publishProgress(1, -1);
}
if (params[1] == Long.valueOf(0)) {
[...]
facebookAPI.fetchFriendsList();
publishProgress(-1, 0);
}
return null;
}
protected final void onProgressUpdate(Integer... flags) {
super.onProgressUpdate(flags);
if (flags[0] != -1)
twitterAPI.asyncSaveFacebookFriendsList();
if (flags[1] == 0)
facebookAPI.asyncSaveFacebookFriendsList();
}
}
As you can see, I start step 2 and 3 in onPublishProgress() which runs on the Main UI Thread. Brefore it was in the doInBackground() method : the issue happens in both cases!
[EDIT]
After further test, it would seem any kind of code is in fact running twice.
I created a simple method called test in which in print a counter. The counter incremente twice as well !
Why you use onProgressUpdate?¿?
onProgressUpdate(Progress...), [...]. This method is used to display any form of progress in the
user interface while the background computation is still executing.
For instance, it can be used to animate a progress bar or show logs in
a text field.
This is used not at the finish of the petition, but when progress increased.
Read this:
http://developer.android.com/reference/android/os/AsyncTask.html
You need to use:
protected void onPostExecute(Long result) {

Android debug traces do not contain application specific method calls

I am trying to generate trace files for applications using the Debug.startMethodTracing (on the activity onCreate) and Debug.stopMethodTracing (on the activity onDestroy) according to the following documentation http://developer.android.com/tools/debugging/debugging-tracing.html#creatingtracefiles.
I run the application on a physical device and it successfully creates the trace file. Later I run dmtracedump on them to generate a call-stack diagram, but it does not contain any of my application method calls.
To test this, I created a simple Android application, added debbuggable to the manifest:
<application
...
android:debuggable="true">
Created two test classes A and B. Class A has two methods b() and c():
public class A {
private int _i;
public A(){_i=0;}
public void b(){c();}
public void c(){for(int k=0;k<20;k++)_i++;}}
Class B has a single method c():
public class B {
public void c(){
(new A()).b();
A d = new A();
d.c();
}}
Finally in the main activity on the onCreate and onDestroy methods I started the tracing:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Debug.startMethodTracing("debugtest");
A a;
for (int i = 0; i < 20; i++) {
a = new A();
a.b();
a.c();
}
(new B()).c();
}
#Override
public void onDestroy() {
super.onDestroy();
Debug.stopMethodTracing();
}
I was hoping to get at least A.b() and A.c() method calls in the call stack diagram but after running:
adb pull sdcard/debugtest.trace . ; dmtracedump debugtest.trace -g tree.png
The generated call graph is as follows:
Is this how it is supposed to work, i.e. just show android calls and not application method calls, or am I missing something?
Please note that i am mostly interested in retrieving the exclusive and inclusive times of method execution.
It might be because (by default) the -t option of traceview is set to 20%. From AndroidStudio dmtracedump
-t : Minimum threshold for including child nodes in the graph (child's inclusive time as a percentage of parent inclusive time). If
this option is not used, the default threshold is 20%.
If you open your trace file with traceview you'll see that your graph is something like:
the first node of your graph is the first method call
the second of your graph is the first child of the first call in traceview
the third of your graph is the first child of the child of the first method call
and so on...
Run dmtracedump with -t 0 (as follows) and you should see all the methods.
dmtracedump -t 0 debugtest.trace -g tree.png
You can get more information by placing e.getStacktrace() or using a Log in your classes. I find it's easier to explicitly ask for the errors than hoping the code will just come to you. Of course there is probably a much better way but that is how I've been doing it for a while and I've been able to get a really consistent and easy to pinpoint result.

Categories

Resources