Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use assert on Android devices?

Tags:

android

assert

I want to use the Assert keyword in my android apps to destroy my app in some cases on the emulator, or my device during testing. Is this possible?

It seems that the emulator just ignores my asserts.

like image 909
Janusz Avatar asked Mar 02 '10 16:03

Janusz


People also ask

What is assert in Android?

assert is a Java keyword used to define an assert statement. An assert statement is used to declare an expected boolean condition in a program. If the program is running with assertions enabled, then the condition is checked at runtime. If the condition is false, the Java runtime system throws an AssertionError .

Is it good practice to use assert?

Yes it is a very good practice to assert your assumptions. Read Design By Contract. assert can be used to verify pre conditions, invariants and post conditions during integration and testing phases. This helps to catch the errors while in development and testing phases.

When should I use assert?

You can use an assert to check if your logical assumption is correct. You can also use assert statements to check if the control flow is correct or not. For example, if you have a function that returns a value, you may want to put an assert statement. However, you may get a 'non-reachable' code error.

How do I enable asserts in Java?

To configure assertion options one must use either the -ea or -da command line flags to enable or disable assertions with the command line tool: “java”. For example, “java -ea Assert” where Assert is a java class file. You may also specify a specific class or package as follows.


2 Answers

See the Embedded VM Control document (raw HTML from the source tree, or a nicely formatted copy).

Basically, the Dalvik VM is set to ignore assertion checks by default, even though the .dex byte code includes the code to perform the check. Checking assertions is turned on in one of two ways:

(1) by setting the system property "debug.assert" via:

adb shell setprop debug.assert 1 

which I verified works as intended as long as you reinstall your app after doing this, or

(2) by sending the command line argument "--enable-assert" to the dalvik VM which might not be something app developers are likely to be able to do (somebody correct me if I'm wrong here).

Basically, there is a flag that can be set either globally, at a package level, or at a class level which enables assertions at that respective level. The flag is off by default, as a result of which the assertion checks are skipped.

I wrote the following code in my sample Activity:

 public class AssertActivity extends Activity {   @Override   protected void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);     setContentView(R.layout.main);     int x = 2 + 3;     assert x == 4;   } } 

For this code, the dalvik byte code that is generated is (for Android 2.3.3):

 // Static constructor for the class 000318:                                        |[000318] com.example.asserttest.AssertActivity.:()V 000328: 1c00 0300                              |0000: const-class v0, Lcom/example/asserttest/AssertActivity; // class@0003 00032c: 6e10 0c00 0000                         |0002: invoke-virtual {v0}, Ljava/lang/Class;.desiredAssertionStatus:()Z // method@000c 000332: 0a00                                   |0005: move-result v0 000334: 3900 0600                              |0006: if-nez v0, 000c // +0006 000338: 1210                                   |0008: const/4 v0, #int 1 // #1 00033a: 6a00 0000                              |0009: sput-boolean v0, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000 00033e: 0e00                                   |000b: return-void 000340: 1200                                   |000c: const/4 v0, #int 0 // #0 000342: 28fc                                   |000d: goto 0009 // -0004  

: :

// onCreate() 00035c: |[00035c] com.example.asserttest.AssertActivity.onCreate:(Landroid/os/Bundle;)V 00036c: 6f20 0100 3200 |0000: invoke-super {v2, v3}, Landroid/app/Activity;.onCreate:(Landroid/os/Bundle;)V // method@0001 000372: 1501 037f |0003: const/high16 v1, #int 2130903040 // #7f03 000376: 6e20 0500 1200 |0005: invoke-virtual {v2, v1}, Lcom/example/asserttest/AssertActivity;.setContentView:(I)V // method@0005 00037c: 1250 |0008: const/4 v0, #int 5 // #5 00037e: 6301 0000 |0009: sget-boolean v1, Lcom/example/asserttest/AssertActivity;.$assertionsDisabled:Z // field@0000 000382: 3901 0b00 |000b: if-nez v1, 0016 // +000b 000386: 1251 |000d: const/4 v1, #int 5 // #5 000388: 3210 0800 |000e: if-eq v0, v1, 0016 // +0008 00038c: 2201 0c00 |0010: new-instance v1, Ljava/lang/AssertionError; // class@000c 000390: 7010 0b00 0100 |0012: invoke-direct {v1}, Ljava/lang/AssertionError;.:()V // method@000b 000396: 2701 |0015: throw v1 000398: 0e00 |0016: return-void

Notice how the static constructor invokes the method desiredAssertionStatus on the Class object and sets the class-wide variable $assertionsDisabled; also notice that in onCreate(), all of the code to throw java.lang.AssertionError is compiled in, but its execution is contingent upon the value of $assertionsDisabled which is set for the Class object in the static constructor.

It appears that JUnit's Assert class is what is used predominantly, so it is likely a safe bet to use that. The flexibility of the assert keyword is the ability to turn on assertions at development time and turn them off for shipping bits and instead fail gracefully.

Hope this helps.

like image 54
3 revs, 3 users 96% Avatar answered Oct 14 '22 16:10

3 revs, 3 users 96%


When assertions are enabled, the assert keyword simply throws an AssertionError when the boolean expression is false.

So IMO, the best alternative, esp. if you're averse to depend on junit, is to throw an AssertionError explicitly as shown below:

assert x == 0 : "x = " + x; 

An alternative to the above statement is:

Utils._assert(x == 0, "x = " + x); 

Where the method is defined as:

public static void _assert(boolean condition, String message) {     if (!condition) {         throw new AssertionError(message);     } } 

The Oracle java docs recommend throwing an AssertionError as an acceptable alternative.

I guess you can configure Proguard to strip out these calls for production code.

like image 43
Dheeraj Vepakomma Avatar answered Oct 14 '22 18:10

Dheeraj Vepakomma