Just An Application

August 21, 2014

And Another One: Part Twenty — Abstraction Failure Or Why Does The Class android.content.pm.Signature Exist ?

I have already quoted the class documentation comment for the android.content.pm.Signature class before but here it is again.

Opaque, immutable representation of a signature associated with an application package.

It is the comment which appeared in the first version of the class and despite subsequent changes it has never been updated.

Even in the original version it was not true as the class defined this method

    ...
    
    /**
     * @return the contents of this signature as a byte array.
     */
    public byte[] toByteArray() {
        byte[] bytes = new byte[mSignature.length];
        System.arraycopy(mSignature, 0, bytes, 0, mSignature.length);
        return bytes;
    }
    
    ...

Why should it be possible to turn the contents of something supposedly opaque into a byte array ?

It looks fairly innocuous but its a major abstraction failure all on its own so lets take the documentation at its word and get rid of it, and while we are at it we will get rid of

    public char[] toChars()

as well as

    public char[] toChars(char[] existingArray, int[] outLen)

not to mention

    public String toCharsString()

just to be on the safe side.

For an opaque object it defines a remarkable number of ways of finding out whats in it, and we’re not finished yet because its

    Parcelable

and you never know, if somebody got really desperate they might write it to a Parcel then go and read it out themselves as a byte array or something.

Best not to put temptation in their way, so we’ll get rid of all of that as well.

Now what can you do with a Signature as originally defined which is genuinely opaque and immutable ?

Not much to be honest.

What’s left are the equals and hashCode methods and as we have already seen all they do is sub-contract the heavy-lifting to the java.util.Arrays class.

To be fair in its modified form it hides the fact that its really just a wrapper around byte array pretty well but nothing about it realls shouts out Signature ! does it ?

Still its an improvement on its original form where it completely fails to hide the fact that its really just a wrapper around a byte array by giving you access to it.

So, to return to the original question, why does it exist at all in its current form, or to put it another why isn’t just a wrapper a Set of encoded certificates ?

The Past Is A Foreign Country, They Do Things Differently There

One possible explanation is that once upon a time Application signatures used to be defined in a different way and that the Signature class has been re-purposed or something.

Looking for the contemporary version of the PackageManegerService class we discover it in the package.

    com.android.server

That’s right, there was a time when the PackageManegerService class was not sufficiently important to warrant its own package ! Hard to believe isn’t it ?

Now lets see how they used to compare Signatures in those days.

Well they didn’t use compareSignatures thats for sure because its not defined.

So how did grantSignaturePermission work if there was no compareSignatures method ? Answer it didn’t because its not defined.

So where are signature permissions granted then ?

A ha, grantPermissionsLP and its calling checkSignaturesLP, should have guessed, and here it is

    ...
    
    int checkSignaturesLP(PackageParser.Package p1, PackageParser.Package p2) {
        if (p1.mSignatures == null) {
            return p2.mSignatures == null
                    ? PackageManager.SIGNATURE_NEITHER_SIGNED
                    : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
        }
        if (p2.mSignatures == null) {
            return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
        }
        final int N1 = p1.mSignatures.length;
        final int N2 = p2.mSignatures.length;
        for (int i=0; i<N1; i++) {
            boolean match = false;
            for (int j=0; j<N2; j++) {
                if (p1.mSignatures[i].equals(p2.mSignatures[j])) {
                    match = true;
                    break;
                }
            }
            if (!match) {
                return PackageManager.SIGNATURE_NO_MATCH;
            }
        }
        return PackageManager.SIGNATURE_MATCH;
    }

    ...

This looks familiar.

Thats all almost exactly the code structure same as the definition of the compareSignatures method now except that the semantics of Application signatures are completely different !

No Sets there, that’s a ‘member in common’ test !

Whoah, scary ! To be honest I wasn’t expecting that !

(Enough with the exclamation marks.)

Presumably Android Application Signature arrays were constructed somewhat differently in those days or that test does not make a whole lot of sense.

Nope, PackageParser.loadCertificates looks to be nigh on identical.

OK, so at least they used to verify the certificate chains properly surely. No they didn’t do that either. JarUtils.createChain is identical.

Oh dear.

The full implications of that are left as an exercise for the reader but bear in mind that quite possibly there is something somewhere doing something which means it is not as bad as it looks.

Code Rot

Given the way it seems Signature instances were used originally it turns out that the Signature class is not quite as pointless as it appears to be now.

It doesn’t explain why the abstraction was completely broken from day one but it does explain why, for example, the class represents a single encoded certificate rather than a set of them.

The combination of the class being public and the abstraction failure presumably meant that it was felt that it was not possible to substantially modify its behaviour and what it represented.

However, given the major change in semantics that occurred, changing the class substantively so that any code that relied on it broke would have had the benefit of revealing what if anything was relying on the assumption that it contained a certificate and that that certificate could be accessed.

Having said that it does not explain why at least internally a class could not have been defined that simply encapulated all the details of what constitutes an Application’s signature, how one is constructed and how they are compared.

Afterword

When I started writing this although I thought it possible that something about how Android Application signatures worked might have changed between the point at which the Signature class was originally defined and now I didn’t really didn’t know one way or another. It was just a possible explanation for the existence of a fairly pointless class.

The earliest version of the Android source I have immediately accessible is the version I changed to get running standalone, that is, on a standard JVM rather than Dalvik, which dates from late 2008.

Although I clearly changed the PackageManagerService class for some reason at that time I have no recollection of looking at this area at all, so I was genuinely surprised to discover

  1. that it really had changed a lot, and

  2. that at that point it seems it was completely broken

The earliest version of the PackageManagerService class I have locally that constructs sets of Signatures in order to perform a comparison is from March 2011 where it is being done by the checkSignaturesLP method.

At that point there is still no compareSignatures method defined.


Copyright (c) 2014 By Simon Lewis. All Rights Reserved.

Unauthorized use and/or duplication of this material without express and written permission from this blog’s author and owner Simon Lewis is strictly prohibited.

Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.

Blog at WordPress.com.

%d bloggers like this: