[Nook Touch Android Development] Renate:
This post addresses the developer side of things.

It is possible to patch Smali by hand.

For quick and dirty, this is not a bad solution.

The problem is that one must be aware of how many registers are used and for what.

In the first instance, if I need another register for my mod, that can push register references on other instructions out of the 4 bit range.

Also, if the stock code is revised later that can also change register references.

Even the simple addition of a debug print statement (Log.d) can affect things.

The solution is to always replace entire methods.

That way you are not fighting with conflicting code.

The logical place to keep your patches is in Java.

Obviously you can't have a standalone method, there has to be a class.

For instance, the stock Reader.apk has a place where it validates EAN (ISBN).

It checks for all digits, which bombs on sequences with dashes.

We want to replace that, easy enough, but we have to wrap it in the class.

package com.bn.nook.model.product;

public class Products
{
public static boolean isValidEan(String ean)
{
return(true);
}
}

Obviously this does not fully implement the class, but it has enough for our little method.

We do a normal compile of this, then apktool d it to the smali.

mergesmali can then scan through this smali and edit the stock smali from the apktool d'ed stock app.

A final apktool b, jarsigning and zipaligning puts it all back together.

But what if the method that we want to replace called some other method?

We would have to put something in our class to prevent compilation errors and to ensure that the smali code for our method did the correct invocation.

We end up writing stubs for these methods that do nothing.

If it's a void method, the body of the method is simply {}, for boolean types {return(false);}, etc.

But how do we make sure that mergesmali does not substitute these stub methods for the good methods already in stock?

Annotations.

By putting Annotations before each method, we can tell mergesmali what to do.

These annotations are preserved in the decoded smali.

They are subsequently deleted when mergesmali merges the smali.

Expanding our original example (this is just an example, not realistic):

package com.bn.nook.model.product;

import com.whoever.MergeSmali.*;

public class Products
{
@Ignore
public Products() {}

@Ignore
public static double complicatedOtherMethod(String ean, String msg)
{ return(0.0); }

@Replace
public static boolean isValidEan(String ean)
{
if (complicatedOtherMethod(ean, "Hello")<2.3) return(false);
return(true);
}
}

The @Replace tells mergesmali to replace this method.

The @Ignore tells mergesmali not to replace this method.

We need to have the stub for complicatedOtherMethod in the source.

Well, why is the constructor in there?

The compiler will generate a default constructor if we don't write one and it would have no annotation.

mergesmali prints an error if any method does not have an annotation;

There is also @Append for new methods that are not in the stock.

There is also @Delete to delete methods (that either have a super or not being used at all with the rewritten methods).

What's in com.whoever.MergeSmali.* ?

package com.whoever;

public class MergeSmali
{
public @interface Ignore {}
public @interface Replace {}
public @interface Append {}
public @interface Delete {}
}

The package is not important as long as it's an Annotation and the class/subclasses are as indicated.