throwIndexOutOfBoundsException in updateOomAdjLocked() - android

In my tests I see the following exception in updateOomAdjLocked() of ActivityManagerService:
// java.lang.IndexOutOfBoundsException: Invalid index 27, size is 27
// at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
// at java.util.ArrayList.get(ArrayList.java:304)
// at com.android.server.am.ActivityManagerService.updateOomAdjLocked(ActivityManagerService.java:13880)
// at com.android.server.am.ActivityManagerService.updateLruProcessLocked(ActivityManagerService.java:1904)
// at com.android.server.am.ActivityStack.realStartActivityLocked(ActivityStack.java:647)
// at com.android.server.am.ActivityStack.startSpecificActivityLocked(ActivityStack.java:803)
Problematic code seems is the following (line 13850 for Android 4.2.2 r1.2):
final ArrayList<ProcessRecord> mLruProcesses
= new ArrayList<ProcessRecord>();
{...}
final void updateOomAdjLocked() {
{...}
final int N = mLruProcesses.size();
for (i=0; i<N; i++) {
ProcessRecord app = mLruProcesses.get(i);
{...}
}
If mLruProcesses.remove was called while in the loop, then mLruProcesses.get(i) for i=N accessed a non-existing index, triggering an exception.
I know very little about Android services so far, so my question is if this code needs to be reenterable, perhaps by making some of the operations thread-safe?

You could verify that the size of mLruProcess.size() is still equal to N within your loop.
final boolean updateOomAdjLocked() {
{...}
final int N = mLruProcess.size();
for(int i = 0; i < N; i++) {
if(N != mLruProcess.size()) {
//Do something accordingly, in this case return false
return false;
}
ProcessRecord app = mLruProcess.get(i);
{...}
}
{...}
return true;
}
Add some logic where you call this function, if it returns false try to have it call the function again. Otherwise, you could put mLruProcess in a Synchronized block which means that it can be accessed in only one concurrent thread. The Synchronized keyword is blocking, which means any code that tries to access mLruProcess in another thread will be blocked until the current thread is done with mLruProcess.
If you don't like to, or can't use blocking code, try using an AtomicBoolean as shown here:
When to use synchronized in Java
Set the AtomicBoolean whenever you change the object stored in mLruProcess and then check that AtomicBoolean everywhere you need to access the objects stored in mLruProcess.

Related

Read value returned in CompletableFuture

A function from some SDK is returning me a CompletableFuture. How can I read the value properly once it's reached.
My Code:
CompletableFuture<Web3ClientVersion> web3clientCompletableFuture;
web3clientCompletableFuture = web3jNode.web3ClientVersion().sendAsync();
sendAsync() Code (In SDK):
public CompletableFuture<T> sendAsync() {
return web3jService.sendAsync(this, responseType);
}
I can access the returned data using get(), but that would make the whole process syncronus and block UI.
I've checked the functions signatures on Android API Reference, like:
thenApply(Function<? super T, ? extends U> fn)
handle(BiFunction<? super T, Throwable, ? extends U> fn)
But seems I require some code examples.
[Note: I'm not so familiar with lambda]
Here is a tutorial that has examples that show you how to use these powerful methods of CompletableFuture. You are right you want to use thenApply() if you have to return value after you process the future. But if you simply want to process the future and not return anything, you should use thenAccept() and thenRun(). There are other methods listed with examples as well.
Here is an example that simply returns a CompletableFuture of type integer:
CompletableFuture<Integer> mynumber = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
mynumber = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return 4 * 4;
});
}
Here arg is the result(CompletableFuture) from the above step, and in your case the data you are receiving from the SDK. You are attaching a callback method(thenApply()) and do what ever you would like to do with it. Depending on your implementation, you can attach multiple thenApply(). Here I am calling a method that will take the result and do some computation with it.
CompletableFuture<Integer> willdoStuff = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
willdoStuff = mynumber.thenApply(arg -> {
compute(arg);
return arg / 2;
});
}
public void compute(int someInt){
Toast.makeText(getApplicationContext(), "The result of the computation is" + someInt, Toast.LENGTH_LONG).show();
}
Just comment out the sleep code to execute this code in the main thread.
The Lambda function is simply input and output, the arguments before {} being the input and the statement within the {}, which is actually a function that does something with the arguments(input). You might want to ask different question in regards to that.

odata4j requests metadata too many times

I use the odata4j library to access a WCF Data Service.
This is how I call a Service Method from my Android code:
OQueryRequest<OEntity> l = consumer.getEntities("GetDataList")
.custom("dataId", String.format("'%s'", actualData.ID))
.orderBy("Name").skip(0).top(200);
I checked it with WireShark, and I see that every method call is preceded with 2 calls of metadata information request:
Why? Are they essential? The metadata information is quite heavy, it shouldn't request is every time (not to mention 2 times).
What should I do to prevent odata4j from requesting metadata information so many times?
I found in the source code where the 'extra' request happens (in odata4j/odata4j-core/src/main/java/org/odata4j/consumer/AbstractODataConsumer.java ):
#Override
public EdmEntitySet findEdmEntitySet(String entitySetName) {
EdmEntitySet rt = super.findEdmEntitySet(entitySetName);
if (rt == null && delegate != EdmDataServices.EMPTY) {
refreshDelegate();
rt = super.findEdmEntitySet(entitySetName);
}
return rt;
}
It seems that if the entity set can't be found, the consumer creates an extra roundtrip to the server to get the metadata again (by calling refreshDelegate()):
private void refreshDelegate() {
ODataClientRequest request = ODataClientRequest.get(AbstractODataConsumer.this.getServiceRootUri() + "$metadata");
try {
delegate = AbstractODataConsumer.this.getClient().getMetadata(request);
} catch (ODataProducerException e) {
// to support services that do not expose metadata information
delegate = EdmDataServices.EMPTY;
}
}
I don't quite understand why: maybe it assumes that the server has changed and a new version of the metadata is available so it tries again.
If it fails then it tries to find a function with the given name.
Personally I don't consider this very effective unless the server side is so volatile that it changes between calls.
So, if you have no changing metadata on the server, it is safe to remove the check for the entitySet and let it return as a null:
#Override
public EdmEntitySet findEdmEntitySet(String entitySetName) {
EdmEntitySet rt = super.findEdmEntitySet(entitySetName);
//if (rt == null && delegate != EdmDataServices.EMPTY) {
// refreshDelegate();
// rt = super.findEdmEntitySet(entitySetName);
//}
return rt; //if it is null, then the search for a function will commence
}

coco2d-x call function with multiple arguments?

I'm working on a cocos2d-x project and got stuck. I want to call a function, delay and than call the same function again. I'm using cocos2d-x 2.2.5. and developing for Android.
This is what I got so far:
CCArray *arr = CCArray::create();
arr->addObject(pSprite);
arr->addObject(pGetal);
CCFiniteTimeAction *fun1 = CCCallFuncO::create(this, callfuncO_selector(GameLayer::animateFlip), arr);
CCDelayTime *delay = CCDelayTime::create(1.0);
pSprite->runAction(CCSequence::create(fun1, delay, fun1, NULL));
The method I want to call:
void GameLayer::animateFlip(CCObject *pSObj, CCObject *pGObj){
CCSprite *pSprite = (CCSprite *) pSObj;
CCLabelTTF *pGetal = (CCLabelTTF *) pSObj;
...
...
}
The function is in the same class and requires two arguments. I've tried putting both arguments (CCSprite and CCLabelTTF) in an array, but it crashes on runtime...
When I call the function just like this no errors occur:
this->animateFlip(sprite1, getal1);
Anyone any idea?
Thanks for your answers, I've created a struct for my buttons like Joachim suggested, which has the sprite and the label in it. All the buttons are put in an array. I also added the functions animateFlip and showFlip to it. AnimateFlip works fine and I'm able to call the function from the gamelayer for each indevidial button.
void GameLayer::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent)
{
CCTouch *touch = (CCTouch *)pTouches->anyObject();
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
for(int i = 0; i < 12; i++){
if(butArr[i].sprite->boundingBox().containsPoint(location)){
butArr[i].animateFlip();
break;
}
}
}
The struct:
struct Button
{
cocos2d::CCSprite *sprite;
cocos2d::CCLabelTTF *getal;
int getalINT;
void showFlip();
void animateFlip();
};
But as rule number one in programming tells us, where one problem is solved, two shall arise, I've stumbled upon a new problem:
void Button::showFlip()
{
CCFiniteTimeAction *fun1 = CCCallFunc::create(this, callfunc_selector(Button::animateFlip));
CCFiniteTimeAction *fun1 = CCCallFunc::create(this, callfunc_selector(Button::animateFlip));
CCDelayTime *delay = CCDelayTime::create(1.0f);
this->runAction(CCSequence::create(fun1, delay, fun2, NULL));
}
The CCCallFunc::create() request a context (I guess?), which is usually 'this', but 'this' in my struct point to Button. How can I get the context of the gamelayer?
Thanks again!

android emulator restarts itself (ADT)

When i invoke a function which is described below, android emulator restarts from beginning.
The function is like that
int index = 0;
Position myPostion;
Position destPosition = roadInstruction.getInstructionAt(index).getEndAddr();
while(index<roadInstruction.getNumInstruction())
{
myPostion = getMyPosition();
while(!hasArrivedToDestination(myPostion, destPosition ))
{
myPostion = getMyPosition();
}
++index;
}
What is the reason?
It maybe because of the inner while loop, but i am not sure.

Nexus S: Writing MifareClassic NFC Tags fails when not in debug mode

I've got a weird problem. When I debug my program and put a breakpoint before the "writeBlock" command to write my MifareClassic card, everything is going fine. The card is written and my program continues.
If I remove the breakpoint, I get an "IO Exception : transceived failed"! I put the breakpoint back without changing my code, it works again!
I'm lost... Could it be possible that the problem comes from the speed of the program execution? Having a breakpoint makes the execution slower...
Here's my code (the authentication is done before this function):
private static boolean WriteMfcBlock(MifareClassic mfc, int blockNumber, byte[] value) {
try {
byte[] toWrite = new byte[MifareClassic.BLOCK_SIZE];
//if the value is less than 16 bytes, fill it with '0'
for (int i=0; i<MifareClassic.BLOCK_SIZE; i++) {
if (i < value.length) toWrite[i] = value[i];
else toWrite[i] = 0;
}
if (!mfc.isConnected()) mfc.connect();
mfc.writeBlock(blockNumber, toWrite);
//Check if the writing is well done
byte[] read = mfc.readBlock(blockNumber);
for (int i = 0; i < MifareClassic.BLOCK_SIZE; i++ ) {
if (toWrite[i] != read[i]) return false;
}
return true;
}
catch (IOException e) {
textViewInfo.setText("IO EXCEPTION");
return false;
}
}
Thanks for your help
Sylvain
I go a step forward. It seems that it can come from a thread issue.
The "writeblock" command of the MifareClassic has to be triggered by the main process of the activity.
In my app, it's a button (implementing OnClickListener) that triggered the "writeblock".
When in debugging mode, the debug thread can hide this behavior because it's the main thread and make the app running well.
So from now, what I did is just to ask the user to remove the tag from the rf field and put it back. So I get the intent that a tag has been discovered again and then I can do the "writeblock" command without any problem.
Finally I thing the best way to handle read and write on tags is the create 2 activities, one for readings and one for writings.
If you have any comment or other way to do it .. please, answer this thread.
Sylvain

Categories

Resources