@@ -11,6 +11,7 @@ const kEndianTag = 0x12345678;
11
11
12
12
const kClassDefSize = 32 ;
13
13
const kProtoIdSize = 12 ;
14
+ const kFieldIdSize = 8 ;
14
15
const kMethodIdSize = 8 ;
15
16
const kTypeIdSize = 4 ;
16
17
const kStringIdSize = 4 ;
@@ -20,6 +21,7 @@ const TYPE_HEADER_ITEM = 0;
20
21
const TYPE_STRING_ID_ITEM = 1 ;
21
22
const TYPE_TYPE_ID_ITEM = 2 ;
22
23
const TYPE_PROTO_ID_ITEM = 3 ;
24
+ const TYPE_FIELD_ID_ITEM = 4 ;
23
25
const TYPE_METHOD_ID_ITEM = 5 ;
24
26
const TYPE_CLASS_DEF_ITEM = 6 ;
25
27
const TYPE_MAP_LIST = 0x1000 ;
@@ -69,6 +71,7 @@ class DexBuilder {
69
71
const {
70
72
classes,
71
73
interfaces,
74
+ fields,
72
75
methods,
73
76
protos,
74
77
parameters,
@@ -100,8 +103,9 @@ class DexBuilder {
100
103
const protoIdsSize = protos . length * kProtoIdSize ;
101
104
offset += protoIdsSize ;
102
105
103
- const fieldIdsOffset = 0 ;
104
- const fieldIdsCount = 0 ;
106
+ const fieldIdsOffset = offset ;
107
+ const fieldIdsSize = fields . length * kFieldIdSize ;
108
+ offset += fieldIdsSize ;
105
109
106
110
const methodIdsOffset = offset ;
107
111
const methodIdsSize = methods . length * kMethodIdSize ;
@@ -203,7 +207,7 @@ class DexBuilder {
203
207
offset = align ( offset , 4 ) ;
204
208
const mapOffset = offset ;
205
209
const typeListLength = interfaces . length + parameters . length ;
206
- const mapNumItems = 8 + ( 3 * classes . length ) + ( ( typeListLength > 0 ) ? 1 : 0 ) +
210
+ const mapNumItems = 8 + ( 3 * classes . length ) + ( ( typeListLength > 0 ) ? 1 : 0 ) + ( ( fields . length > 0 ) ? 1 : 0 ) +
207
211
annotationDirectories . length + annotationSets . length + throwsAnnotations . length ;
208
212
const mapSize = 4 + ( mapNumItems * kMapItemSize ) ;
209
213
offset += mapSize ;
@@ -228,8 +232,8 @@ class DexBuilder {
228
232
dex . writeUInt32LE ( typeIdsOffset , 0x44 ) ;
229
233
dex . writeUInt32LE ( protos . length , 0x48 ) ;
230
234
dex . writeUInt32LE ( protoIdsOffset , 0x4c ) ;
231
- dex . writeUInt32LE ( fieldIdsCount , 0x50 ) ;
232
- dex . writeUInt32LE ( fieldIdsOffset , 0x54 ) ;
235
+ dex . writeUInt32LE ( fields . length , 0x50 ) ;
236
+ dex . writeUInt32LE ( fields . length > 0 ? fieldIdsOffset : 0 , 0x54 ) ;
233
237
dex . writeUInt32LE ( methods . length , 0x58 ) ;
234
238
dex . writeUInt32LE ( methodIdsOffset , 0x5c ) ;
235
239
dex . writeUInt32LE ( classes . length , 0x60 ) ;
@@ -254,6 +258,15 @@ class DexBuilder {
254
258
dex . writeUInt32LE ( ( params !== null ) ? params . offset : 0 , protoOffset + 8 ) ;
255
259
} ) ;
256
260
261
+ fields . forEach ( ( field , index ) => {
262
+ const [ classIndex , typeIndex , nameIndex ] = field ;
263
+
264
+ const fieldOffset = fieldIdsOffset + ( index * kFieldIdSize ) ;
265
+ dex . writeUInt16LE ( classIndex , fieldOffset ) ;
266
+ dex . writeUInt16LE ( typeIndex , fieldOffset + 2 ) ;
267
+ dex . writeUInt32LE ( nameIndex , fieldOffset + 4 ) ;
268
+ } ) ;
269
+
257
270
methods . forEach ( ( method , index ) => {
258
271
const [ classIndex , protoIndex , nameIndex ] = method ;
259
272
@@ -373,9 +386,12 @@ class DexBuilder {
373
386
[ TYPE_STRING_ID_ITEM , strings . length , stringIdsOffset ] ,
374
387
[ TYPE_TYPE_ID_ITEM , types . length , typeIdsOffset ] ,
375
388
[ TYPE_PROTO_ID_ITEM , protos . length , protoIdsOffset ] ,
376
- [ TYPE_METHOD_ID_ITEM , methods . length , methodIdsOffset ] ,
377
- [ TYPE_CLASS_DEF_ITEM , classes . length , classDefsOffset ] ,
378
389
] ;
390
+ if ( fields . length > 0 ) {
391
+ mapItems . push ( [ TYPE_FIELD_ID_ITEM , fields . length , fieldIdsOffset ] ) ;
392
+ }
393
+ mapItems . push ( [ TYPE_METHOD_ID_ITEM , methods . length , methodIdsOffset ] ) ;
394
+ mapItems . push ( [ TYPE_CLASS_DEF_ITEM , classes . length , classDefsOffset ] ) ;
379
395
annotationSets . forEach ( ( set , index ) => {
380
396
mapItems . push ( [ TYPE_ANNOTATION_SET_ITEM , set . items . length , annotationSetOffsets [ index ] ] ) ;
381
397
} ) ;
@@ -419,10 +435,10 @@ class DexBuilder {
419
435
}
420
436
421
437
function makeClassData ( klass , constructorCodeOffset ) {
422
- const { constructorMethod, virtualMethods} = klass . classData ;
438
+ const { instanceFields , constructorMethod, virtualMethods} = klass . classData ;
423
439
424
440
const staticFieldsSize = 0 ;
425
- const instanceFieldsSize = 0 ;
441
+ const instanceFieldsSize = instanceFields . length ;
426
442
const directMethodsSize = 1 ;
427
443
428
444
const [ constructorIndex , constructorAccessFlags ] = constructorMethod ;
@@ -433,6 +449,11 @@ function makeClassData (klass, constructorCodeOffset) {
433
449
directMethodsSize ,
434
450
]
435
451
. concat ( createUleb128 ( virtualMethods . length ) )
452
+ . concat ( instanceFields . reduce ( ( result , [ indexDiff , accessFlags ] ) => {
453
+ return result
454
+ . concat ( createUleb128 ( indexDiff ) )
455
+ . concat ( createUleb128 ( accessFlags ) ) ;
456
+ } , [ ] ) )
436
457
. concat ( createUleb128 ( constructorIndex ) )
437
458
. concat ( createUleb128 ( constructorAccessFlags ) )
438
459
. concat ( createUleb128 ( constructorCodeOffset ) )
@@ -466,6 +487,7 @@ function computeModel (classes) {
466
487
const strings = new Set ( ) ;
467
488
const types = new Set ( ) ;
468
489
const protos = { } ;
490
+ const fields = [ ] ;
469
491
const methods = [ ] ;
470
492
const throwsAnnotations = { } ;
471
493
const superConstructors = new Set ( ) ;
@@ -488,6 +510,14 @@ function computeModel (classes) {
488
510
types . add ( iface ) ;
489
511
} ) ;
490
512
513
+ klass . fields . forEach ( field => {
514
+ const [ fieldName , fieldType ] = field ;
515
+ strings . add ( fieldName ) ;
516
+ strings . add ( fieldType ) ;
517
+ types . add ( fieldType ) ;
518
+ fields . push ( [ klass . name , fieldType , fieldName ] ) ;
519
+ } ) ;
520
+
491
521
klass . methods . forEach ( method => {
492
522
const [ methodName , retType , argTypes , thrownTypes = [ ] ] = method ;
493
523
@@ -605,6 +635,15 @@ function computeModel (classes) {
605
635
} , { } ) ;
606
636
const parameterItems = Object . keys ( parameters ) . map ( id => parameters [ id ] ) ;
607
637
638
+ const fieldItems = fields . map ( field => {
639
+ const [ klass , fieldType , fieldName ] = field ;
640
+ return [
641
+ typeToIndex [ klass ] ,
642
+ typeToIndex [ fieldType ] ,
643
+ stringToIndex [ fieldName ]
644
+ ] ;
645
+ } ) ;
646
+
608
647
const methodItems = methods . map ( method => {
609
648
const [ klass , protoId , name , annotationsId ] = method ;
610
649
return [
@@ -694,6 +733,8 @@ function computeModel (classes) {
694
733
annotationDirectories . push ( annotationsDirectory ) ;
695
734
}
696
735
736
+ const instanceFields = fieldItems . map ( ( field , index ) => [ index , kAccPublic ] ) ;
737
+
697
738
const constructorNameIndex = stringToIndex [ '<init>' ] ;
698
739
const constructorMethod = classMethods
699
740
. filter ( ( [ , name ] ) => name === constructorNameIndex )
@@ -715,6 +756,7 @@ function computeModel (classes) {
715
756
} ) ) ;
716
757
717
758
const classData = {
759
+ instanceFields,
718
760
constructorMethod,
719
761
superConstructorMethod,
720
762
virtualMethods,
@@ -736,6 +778,7 @@ function computeModel (classes) {
736
778
return {
737
779
classes : classItems ,
738
780
interfaces : interfaceItems ,
781
+ fields : fieldItems ,
739
782
methods : methodItems ,
740
783
protos : protoItems ,
741
784
parameters : parameterItems ,
0 commit comments