Android Concurrency, App dying after about 3 uses - java

I'm developing an app with different views populated with data acquired from a Server API. As of right now, I've come up with a 'solution' as to how to make the most out of the multicore Android devices that are currently available. I thought that a Producer/Consumer strategy was the right choice for this problem. However I'm using as many consumers as the Phone has cores and when executing the application everything works fine. But in some cases the application dies and doesn't do anything when I launch it, if I clear the RAM on my device I can launch the application again.
Consumer run method:
while(true) {
lock.lock();
while(queuedOperations.isEmpty()) {
ma.debug("Slave " + slaveId + " is waiting for requests.");
try {
slaveCondition.await();
if(doTerminate) { return; }
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ma.debug("Executing Request... " + slaveId);
JSONRequestParam[] params = queuedOperations.poll();
ma.debug("Polled an item. " + slaveId);
lock.unlock();
ma.debug(request.execute(params)); // returns a String.
}
Using the following shutdown method:
public void destroy() {
ma.debug("Terminating all external resources...");
lock.lock();
this.doTerminate = true;
slaveCondition.signalAll();
lock.unlock();
try {
service.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
service.shutdown();
}
The way I trigger the Consumers is by a signal from the Condition class. Here's the code:
public void submitRequest(JSONRequestParam... params) {
lock.lock();
queuedOperations.add(params);
slaveCondition.signal();
lock.unlock();
}
I overrided the onBackPressed method in the main activity as well;
#Override
public void onBackPressed() {
try {
JSONRequestManager.getInstance(this).destroy();
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onBackPressed();
}
but to no avail. The application is very buggy and unstable. I have tried to find a replicate of this problem here and on numerous of different sites, couldn't find anything that helped. I'm almost sure there's no deadlocks in this application, I have a reasonable amount of experience working with concurrent applications, however Android is a tad bit different when it comes to threading...
Is there any hints or practices that I'm missing out? Why is the application working when the RAM is cleared and on first launch? Is there something jamming in the background? I really do not know. I hope you can tell!
Any help is greatly appreciated!

Related

What is the reason of making try catch OutOfMemoryError and printStackTrace()?

I undesrstand the try-catch statement, it means that it will try a piece of code and if it fails the catch section will be executed. What I don´t undesrtand is to use printStackTrace of an error in the catch section. I mean, why it would be useful to make the following code:
try{
}
catch (OutOfMemoryError e) {
e.printStackTrace();
}
If the code that is in the try section fails, an out of memory error will be printed according to the above code. What is the reason of making that? Won`t an error automatically be printed on the Google Play Console if the app crashes (the code of the try function)? I don´t understand the reason of printing an error if the Google Play Console is actually printing the stack trace of errors without need of using the try catch function...
Real example of code that I don't understand why the try catch is used:
public void playMediaPlayer(int id) {
try {
if (mediaPlayer != null || mediaPlayer.isPlaying()) {
mediaPlayer.release();
mediaPlayer = new MediaPlayer();
}
if (id == 1) {
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.sound1);
} else if (id == 2) {
mediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.sound2);
}
if (PreferenceData.getSound(getApplicationContext())) {
mediaPlayer.start();
}
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
}
Nothing will automatically go to the Google Play Console because this will never crash. The catch will prevent the exception from crashing you and continue on. Which makes this dangerous code, unless you know what you're doing. Generally something like this would only be seen in code working with caches, where a failed allocation would cause you to kick data out of a cache and retry.
As for why you may want to do this- for debugging purposes. You may want to see when it happens and information about the allocation (such as how big it was) while debugging. It will only be for your personal use, as you'll never see the logcat of other devices.

Android permission denied when reading /proc/self/exe from non-main thread

I'm trying to get the canonical path of /proc/self/exe. When I do this on the Main Thread it works, when I do this on an different thread it crashes with an IOException: "Permission denied":
DBG E Thread: main
E Path: /system/bin/app_process32
E Thread: Thread-21656
System.err W java.io.IOException: Permission denied
W at java.io.File.canonicalizePath(Native Method)
W at java.io.File.getCanonicalPath(File.java:414)
W at java.io.File.getCanonicalFile(File.java:428)
W at com.quanturium.testbugprocselfexe.MyActivity.getPathOfExecutable(MyActivity.java:36)
W at com.quanturium.testbugprocselfexe.MyActivity.access$000(MyActivity.java:12)
W at com.quanturium.testbugprocselfexe.MyActivity$1.run(MyActivity.java:26)
W at java.lang.Thread.run(Thread.java:818)
Code:
#Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getPathOfExecutable(); // Works as expected
new Thread(new Runnable() {
#Override
public void run ()
{
getPathOfExecutable(); // Trigger the IOException: Permission denied
}
}).start();
}
private void getPathOfExecutable()
{
try
{
Log.e("DBG", "Thread: " + Thread.currentThread().getName());
Log.e("DBG", "Path: " + new File("/proc/self/exe").getCanonicalFile().getPath());
}
catch (IOException e)
{
e.printStackTrace();
}
}
This error only happens when debuggable is configured to false in the build.gradle file
Code to try it out: https://github.com/quanturium/TestBugProcSelfExe
Is this a bug or an intended behavior? What would be a workaround to get the path of the current executable?
Does the code block? If it doesn't, there should be no ramifications of running it in the main thread. You can, however, do that from another thread, with:
Context.runOnUiThread(new Runnable() {
getPathOfExecutable();
});
This is the cleanest work around I can think of, short of editing the permissions of your file (that you can't get the path of without running your code on the main thread anyways) because you have r/w privileges on /proc/self/exe.
This is very weird, and I am still researching the permission differences in different threads on android.
If you can get it working in the main thread, my opinion would be to just do it in the main thread, and not worry much about optimization, as the performance is no different on different threads.
What would be a workaround to get the path of the current executable?
Since every Android app is forked from Zygote, which is the first Java vm process when the virtual machine created by /system/bin/app_process at system booting.
If you try to read the /proc/self/exe from your Android app, the actual executable will be /system/bin/app_process. Even if you read this outside of your app's main thread, the result is the same and it wouldn't have the permission error in theory.
The question you asked is a kind of weird problem, I have tested with the following code on Android 2.3.3 and worked fine.
new Thread() {
/* (non-Javadoc)
* #see java.lang.Thread#run()
*/
#Override
public void run() {
// TODO Auto-generated method stub
super.run();
try {
Log.d(TAG, new File("/proc/self/exe").getCanonicalFile().getPath());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();

Creating Multiple AsyncTask

I am using an external library for my android project. With that library i am getting the ID3 tags from stream Mp3 url. The code uses URLConnection to reach the link and then gets the tag informations.But the problem is its a very slow procedure.
while doing it on a main thread it takes more than 2 minutes to get ID3 tags of 25 songs from their URLs. So i decided to use multiple AsyncTasks to make the process faster and i used this code below. It became faster a bit, but still few seconds below 2 minute mark. When i checked the Threads tab from DDMS and i saw that during the runtime, there is only 6 AsyncTask is created and running.
My question is , how can i increase the number of AsyncTask running , in this loop.
counter=0;
for (final SongDetail e : songs) {
new AsyncTask<Void , Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
try {
MP3 mp3 = new MP3(e.getLink());
e.setTitle(mp3.getTitle());
e.setArtist(mp3.getBand());
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e2) {
e2.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(Void result) {
counter++;
if(counter==songs.size()) {
Log.d("KA","loop finished");
}
}
}.execute();
}
The Android OS will decide how many parallel threads can be running at any given time. Just because you start 20 of them doesn't mean they'll all run. Android OS will queue them up and will run some of them at a time.
See this answer for more details:
Running multiple AsyncTasks at the same time -- not possible?

Stop a JADE system (Java agents)

I run JADE embedded in a Java program, i.e. not with java jade.Boot ....
Now I wanted to stop the JADE system, but I have found no nice way to do that.
I can exit the whole program using System.exit(), but that's not what I want to do.
I tried several different things, and I succeeded stopping my agent behaviours,
but a couple of Threads continue running: the AMS, the DF, a web server, the JADE Timer dispatcher, several Deliverer threads, etc.
This is how my current shutdown method looks like:
#Override
public void shutdown() {
// TODO This does not work yet..
try {
for (WeakReference<AgentController> acr : agents) {
AgentController ac = acr.get(); // jade.wrapper.AgentController
if ( ac != null ) ac.kill();
}
container.kill(); // jade.wrapper.AgentContainer
Runtime.instance().shutDown(); // jade.core.Runtime
} catch ( StaleProxyException e ) {
e.printStackTrace();
}
}
The reason I want to do that is that I have some JUnit tests for my
agent system.
Any ideas how to accomplish that?
You can request AMS to stop the platform in such way:
Codec codec = new SLCodec();
Ontology jmo = JADEManagementOntology.getInstance();
getContentManager().registerLanguage(codec);
getContentManager().registerOntology(jmo);
ACLMessage msg = new ACLMessage(ACLMessage.REQUEST);
msg.addReceiver(getAMS());
msg.setLanguage(codec.getName());
msg.setOntology(jmo.getName());
try {
getContentManager().fillContent(msg, new Action(getAID(), new ShutdownPlatform()));
send(msg);
}
catch (Exception e) {}
You can shutdown the whole JADE platform with:
try {
this.getContainerController().getPlatformController().kill();
}
catch (final ControllerException e) {
System.out.println("Failed to end simulation.");
}
"this" refers to an Agent class object.

How to Change Screen Resolution Programmatically?

Let me tell you my problem. I want to change my screen resolution.
I can change it in an application but it changes only application's
screen. I wanna set system's resolution so it won't be important which
application is running on front. My device's resolution is set as 1280
* 720 p. Can I make it 1260 * 680? If it requires to make changes in
Android source code, I can. Just tell me where to change. Waiting for
your help.
This thread on xda-developers should set you on the right track.
Searching too a valid answer to this, but I have a lead to the solution :
WARNING Experimental buggy stuff :
/*
Requires android.permission.WRITE_SETTINGS
and android.permission.WRITE_SECURE_SETTINGS, thus it requires the app to be a system app.
*/
public void changeResolution(int x, int y){
try { Class c = Class.forName("android.os.ServiceManager");
try { Method method = c.getDeclaredMethod("checkService", String.class);
try {
IWindowManager mWindowManager = IWindowManager.Stub.asInterface((IBinder) method.invoke(null,Context.WINDOW_SERVICE));
try { mWindowManager.setForcedDisplaySize(Display.DEFAULT_DISPLAY,x,y);
} catch (RemoteException e) {e.printStackTrace();}
} catch (IllegalAccessException e) {e.printStackTrace();}
catch (InvocationTargetException e) {e.printStackTrace();}
} catch (NoSuchMethodException e) {e.printStackTrace();}
} catch (ClassNotFoundException e) {e.printStackTrace();}
}
Add a reduced AIDL version of IWindowManager to your project :
/app/src/main/aidl/android/view/IWindowManager.aidl
package android.view;
interface IWindowManager
{
boolean startViewServer(int port); // Transaction #1
boolean stopViewServer(); // Transaction #2
boolean isViewServerRunning(); // Transaction #3
void setForcedDisplaySize(int displayId, int width, int height);
void clearForcedDisplaySize(int displayId);
void setForcedDisplayDensity(int displayId, int density);
void clearForcedDisplayDensity(int displayId);
}
The app will require to be in the system apps folder.
It does something for sure, but right now it also lead to severe bugs.
Rebooting seems to cancel changes.
Waiting for feedback on this.
If you are using Windows and know how to use JNI, Microsoft provides C++ Win32 function calls to do this: ChangeDisplaySettingsEx() and EnumDisplaySettings().

Categories