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();
Related
I wrote a program in which a pdf file should be opened on an Action Event (you can have a look at my code below).
menuElementHilfe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
File hilfe = new File ("src\\resources\\Hilfe.pdf");
try {
java.awt.Desktop.getDesktop().open(hilfe);
} catch (IOException e) {
e.printStackTrace();
}
}
});
If I execute the program via Eclipse everything works, but after exporting as a runnable jar I get following Exception:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: The file: src\resources\Hilfe.pdf doesn't exist.
Any Feedback is appreciated
The way you're retrieving resources may be the problem. try this :
menuElementHilfe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
File hilfe = new File(getClass().getResource("/resources/Hilfe.pdf").getFile());
try {
java.awt.Desktop.getDesktop().open(hilfe);
} catch (IOException e) {
e.printStackTrace();
}
}
});
When running in Eclipse, you are targeting a file in your build path.
When running from JAR/WAR, the URL is different and look like "jar:file:/your-path/your-jar.jar!/Hilfe.pdf" which is not what you set when calling new File(...) So to get the right URL for internal resources, you have to use methods like getResource or getResourceAsStream depending on your needs.
Check out following explanations for more information :)
https://docs.oracle.com/javase/8/docs/technotes/guides/lang/resources.html
[EDIT]
I assume you're working on some Swing app, but I dont know if you're aware that doing some task like that in your AWT-EventQueue thread will freeze your UI.
To prevent that you have to run UI-unrelated stuff in another thread.
This is made using SwingUtilities.invokeLater (Java 5 and prior) method and/or the SwingWorker class (since Java 6).
as mentionned in this answer
You should put the previous solution in something like that :
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Your UI unrelated code here
}
});
The resource can be packed in the application jar, hence File (physical disk file)
is not possible. Copy it to a temporary file, so that the desktop can open it.
menuElementHilfe.addActionListener(evt -> {
Path tmp = Files.createTempFile("hilfe-", ".pdf");
Files.copy(getClass().getResourceAsStream("/Hilfe.pdf"), tmp);
try {
Desktop.getDesktop().open(tmp.toFile());
tmp.toFile().deleteOnExit();
} catch (IOException e) {
e.printStackTrace();
}
});
An other difference is the forward slash, and that the path is case-sensitive, opposed to Windows File.
After problems
menuElementHilfe.addActionListener(evt ->
SwingUtilities.invokeLater(() -> {
Path tmp = Files.createTempFile("hilfe-", ".pdf");
Logger.getLogger(getClass().getName()).log(Level.INFO, "actionPerformed "
+ tmp + "; event: " + evt);
Files.copy(getClass().getResourceAsStream("/resources/Hilfe.pdf"), tmp);
try {
Desktop.getDesktop().open(tmp.toFile());
//tmp.toFile().deleteOnExit();
} catch (IOException e) {
Logger.getLogger(getClass().getName()).log(Level.WARN, "Error with " + tmp,
e);
}
}));
I did not delete, so the Desktop access can live longer than the java app.
I did an invokeLater in order to have no frozen GUI on the actionPerformed.
I added logging to see every call to actionPerformed
I have the following simple code written in java-ME embedded:
public class JavaMEApplication2 extends MIDlet {
#Override
public void startApp() {
GPIOPinConfig config1 = new GPIOPinConfig(DeviceConfig.DEFAULT, 4, GPIOPinConfig.DIR_OUTPUT_ONLY,
DeviceConfig.DEFAULT , GPIOPinConfig.TRIGGER_NONE, true);
try {
GPIOPin pin = (GPIOPin) DeviceManager.open(config1);
Thread.sleep(2000);
pin.setValue(false);
pin.setDirection(GPIOPinConfig.MODE_INPUT_PULL_UP);
} catch (IOException ex) {
Logger.getLogger(JavaMEApplication2.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(JavaMEApplication2.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void destroyApp(boolean unconditional) {
}
}
The previous code run just fine (My LED is turned ON and OFF) until the execution reach this statement:
pin.setDirection(GPIOPinConfig.MODE_INPUT_PULL_UP);
The following exception occurs:
TRACE: <at java.security.AccessControlException: >, startApp threw an Exception java.security.AccessControlException:
My API permissions Configuration:
Can any one please tell me why this exception occurs? and if there's another way to toggle the same pin between OUTPUT Mode and INPUT Mode in java-Me embedded?
I am running into the same problem when i try and use the ADSONG AM2302 temp and humidity sensor, What I have done to avoid that is connect another pin with a pull up resistor to the current pin that is initially input/output and set one pin to output and one to input, it gets rid of the permission problem at least. The sensor is still not responding to my start signal though so this may have cause unforeseen problems
I think it may be failing because you had this parameter in the call to the GPIOPinConfig constructor:
GPIOPinConfig.DIR_OUTPUT_ONLY
Maybe try GPIOPinConfig.DIR_BOTH_INIT_OUTPUT instead.
Look here for the different values and their meanings:
https://docs.oracle.com/javame/8.0/api/dio/api/index.html
open your jwc_properties.ini file from /home/pi/javame8/bin directory inside raspberry pi and add:
authentication.provider = com.oracle.meep.security.NullAuthenticationProvider
under [internal] section
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!
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?
I'm getting the dreaded...
Exception in thread "Controller Thread" org.eclipse.swt.SWTException: Invalid thread access
Quick overview of what I am trying to accomplish:
I have a listener on the Submit button, I would like to start a new thread due to the amount of processing the app will do with various url's.
This is part of my code in the Submit button listener...
submitButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent arg0) {
try {
// Check to see if http field is valid
httpValid = checkHttp(http);
if (httpValid) {
Thread t = new Thread(new UIMain(), "Controller Thread");
t.start();
} else {
System.out.println("Not a Valid http");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Here is my run method...
public void run() {
options = new Options();
setOptions(options);
Controller run = new Controller(options);
}
The error points to line "setOptions(options)"
options is a object, holding some data from the SWF fields that the user will input. setOptions is fairly straight forward, in that function, I gather the data from the SWF fields, and set them in the object.
Let me know if I need to post any more code...
Example of some code I'm doing in setOptions(options)...
String url = http.getText();
options.addUrl(url);
Thanks,
You can not access the SWT UI straightly from a separate thread. What you should rather do is perform an async invocation from that separate thread using the Display API.
Example:
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
// access the SWT UI
}
});