@@ -1355,6 +1355,7 @@ static void binder_free_ref(struct binder_ref *ref)
1355
1355
if (ref -> node )
1356
1356
binder_free_node (ref -> node );
1357
1357
kfree (ref -> death );
1358
+ kfree (ref -> freeze );
1358
1359
kfree (ref );
1359
1360
}
1360
1361
@@ -3844,6 +3845,155 @@ static void binder_transaction(struct binder_proc *proc,
3844
3845
}
3845
3846
}
3846
3847
3848
+ static int
3849
+ binder_request_freeze_notification (struct binder_proc * proc ,
3850
+ struct binder_thread * thread ,
3851
+ struct binder_handle_cookie * handle_cookie )
3852
+ {
3853
+ struct binder_ref_freeze * freeze ;
3854
+ struct binder_ref * ref ;
3855
+ bool is_frozen ;
3856
+
3857
+ freeze = kzalloc (sizeof (* freeze ), GFP_KERNEL );
3858
+ if (!freeze )
3859
+ return - ENOMEM ;
3860
+ binder_proc_lock (proc );
3861
+ ref = binder_get_ref_olocked (proc , handle_cookie -> handle , false);
3862
+ if (!ref ) {
3863
+ binder_user_error ("%d:%d BC_REQUEST_FREEZE_NOTIFICATION invalid ref %d\n" ,
3864
+ proc -> pid , thread -> pid , handle_cookie -> handle );
3865
+ binder_proc_unlock (proc );
3866
+ kfree (freeze );
3867
+ return - EINVAL ;
3868
+ }
3869
+
3870
+ binder_node_lock (ref -> node );
3871
+
3872
+ if (ref -> freeze || !ref -> node -> proc ) {
3873
+ binder_user_error ("%d:%d invalid BC_REQUEST_FREEZE_NOTIFICATION %s\n" ,
3874
+ proc -> pid , thread -> pid ,
3875
+ ref -> freeze ? "already set" : "dead node" );
3876
+ binder_node_unlock (ref -> node );
3877
+ binder_proc_unlock (proc );
3878
+ kfree (freeze );
3879
+ return - EINVAL ;
3880
+ }
3881
+ binder_inner_proc_lock (ref -> node -> proc );
3882
+ is_frozen = ref -> node -> proc -> is_frozen ;
3883
+ binder_inner_proc_unlock (ref -> node -> proc );
3884
+
3885
+ binder_stats_created (BINDER_STAT_FREEZE );
3886
+ INIT_LIST_HEAD (& freeze -> work .entry );
3887
+ freeze -> cookie = handle_cookie -> cookie ;
3888
+ freeze -> work .type = BINDER_WORK_FROZEN_BINDER ;
3889
+ freeze -> is_frozen = is_frozen ;
3890
+
3891
+ ref -> freeze = freeze ;
3892
+
3893
+ binder_inner_proc_lock (proc );
3894
+ binder_enqueue_work_ilocked (& ref -> freeze -> work , & proc -> todo );
3895
+ binder_wakeup_proc_ilocked (proc );
3896
+ binder_inner_proc_unlock (proc );
3897
+
3898
+ binder_node_unlock (ref -> node );
3899
+ binder_proc_unlock (proc );
3900
+ return 0 ;
3901
+ }
3902
+
3903
+ static int
3904
+ binder_clear_freeze_notification (struct binder_proc * proc ,
3905
+ struct binder_thread * thread ,
3906
+ struct binder_handle_cookie * handle_cookie )
3907
+ {
3908
+ struct binder_ref_freeze * freeze ;
3909
+ struct binder_ref * ref ;
3910
+
3911
+ binder_proc_lock (proc );
3912
+ ref = binder_get_ref_olocked (proc , handle_cookie -> handle , false);
3913
+ if (!ref ) {
3914
+ binder_user_error ("%d:%d BC_CLEAR_FREEZE_NOTIFICATION invalid ref %d\n" ,
3915
+ proc -> pid , thread -> pid , handle_cookie -> handle );
3916
+ binder_proc_unlock (proc );
3917
+ return - EINVAL ;
3918
+ }
3919
+
3920
+ binder_node_lock (ref -> node );
3921
+
3922
+ if (!ref -> freeze ) {
3923
+ binder_user_error ("%d:%d BC_CLEAR_FREEZE_NOTIFICATION freeze notification not active\n" ,
3924
+ proc -> pid , thread -> pid );
3925
+ binder_node_unlock (ref -> node );
3926
+ binder_proc_unlock (proc );
3927
+ return - EINVAL ;
3928
+ }
3929
+ freeze = ref -> freeze ;
3930
+ binder_inner_proc_lock (proc );
3931
+ if (freeze -> cookie != handle_cookie -> cookie ) {
3932
+ binder_user_error ("%d:%d BC_CLEAR_FREEZE_NOTIFICATION freeze notification cookie mismatch %016llx != %016llx\n" ,
3933
+ proc -> pid , thread -> pid , (u64 )freeze -> cookie ,
3934
+ (u64 )handle_cookie -> cookie );
3935
+ binder_inner_proc_unlock (proc );
3936
+ binder_node_unlock (ref -> node );
3937
+ binder_proc_unlock (proc );
3938
+ return - EINVAL ;
3939
+ }
3940
+ ref -> freeze = NULL ;
3941
+ /*
3942
+ * Take the existing freeze object and overwrite its work type. There are three cases here:
3943
+ * 1. No pending notification. In this case just add the work to the queue.
3944
+ * 2. A notification was sent and is pending an ack from userspace. Once an ack arrives, we
3945
+ * should resend with the new work type.
3946
+ * 3. A notification is pending to be sent. Since the work is already in the queue, nothing
3947
+ * needs to be done here.
3948
+ */
3949
+ freeze -> work .type = BINDER_WORK_CLEAR_FREEZE_NOTIFICATION ;
3950
+ if (list_empty (& freeze -> work .entry )) {
3951
+ binder_enqueue_work_ilocked (& freeze -> work , & proc -> todo );
3952
+ binder_wakeup_proc_ilocked (proc );
3953
+ } else if (freeze -> sent ) {
3954
+ freeze -> resend = true;
3955
+ }
3956
+ binder_inner_proc_unlock (proc );
3957
+ binder_node_unlock (ref -> node );
3958
+ binder_proc_unlock (proc );
3959
+ return 0 ;
3960
+ }
3961
+
3962
+ static int
3963
+ binder_freeze_notification_done (struct binder_proc * proc ,
3964
+ struct binder_thread * thread ,
3965
+ binder_uintptr_t cookie )
3966
+ {
3967
+ struct binder_ref_freeze * freeze = NULL ;
3968
+ struct binder_work * w ;
3969
+
3970
+ binder_inner_proc_lock (proc );
3971
+ list_for_each_entry (w , & proc -> delivered_freeze , entry ) {
3972
+ struct binder_ref_freeze * tmp_freeze =
3973
+ container_of (w , struct binder_ref_freeze , work );
3974
+
3975
+ if (tmp_freeze -> cookie == cookie ) {
3976
+ freeze = tmp_freeze ;
3977
+ break ;
3978
+ }
3979
+ }
3980
+ if (!freeze ) {
3981
+ binder_user_error ("%d:%d BC_FREEZE_NOTIFICATION_DONE %016llx not found\n" ,
3982
+ proc -> pid , thread -> pid , (u64 )cookie );
3983
+ binder_inner_proc_unlock (proc );
3984
+ return - EINVAL ;
3985
+ }
3986
+ binder_dequeue_work_ilocked (& freeze -> work );
3987
+ freeze -> sent = false;
3988
+ if (freeze -> resend ) {
3989
+ freeze -> resend = false;
3990
+ binder_enqueue_work_ilocked (& freeze -> work , & proc -> todo );
3991
+ binder_wakeup_proc_ilocked (proc );
3992
+ }
3993
+ binder_inner_proc_unlock (proc );
3994
+ return 0 ;
3995
+ }
3996
+
3847
3997
/**
3848
3998
* binder_free_buf() - free the specified buffer
3849
3999
* @proc: binder proc that owns buffer
@@ -4327,6 +4477,44 @@ static int binder_thread_write(struct binder_proc *proc,
4327
4477
binder_inner_proc_unlock (proc );
4328
4478
} break ;
4329
4479
4480
+ case BC_REQUEST_FREEZE_NOTIFICATION : {
4481
+ struct binder_handle_cookie handle_cookie ;
4482
+ int error ;
4483
+
4484
+ if (copy_from_user (& handle_cookie , ptr , sizeof (handle_cookie )))
4485
+ return - EFAULT ;
4486
+ ptr += sizeof (handle_cookie );
4487
+ error = binder_request_freeze_notification (proc , thread ,
4488
+ & handle_cookie );
4489
+ if (error )
4490
+ return error ;
4491
+ } break ;
4492
+
4493
+ case BC_CLEAR_FREEZE_NOTIFICATION : {
4494
+ struct binder_handle_cookie handle_cookie ;
4495
+ int error ;
4496
+
4497
+ if (copy_from_user (& handle_cookie , ptr , sizeof (handle_cookie )))
4498
+ return - EFAULT ;
4499
+ ptr += sizeof (handle_cookie );
4500
+ error = binder_clear_freeze_notification (proc , thread , & handle_cookie );
4501
+ if (error )
4502
+ return error ;
4503
+ } break ;
4504
+
4505
+ case BC_FREEZE_NOTIFICATION_DONE : {
4506
+ binder_uintptr_t cookie ;
4507
+ int error ;
4508
+
4509
+ if (get_user (cookie , (binder_uintptr_t __user * )ptr ))
4510
+ return - EFAULT ;
4511
+
4512
+ ptr += sizeof (cookie );
4513
+ error = binder_freeze_notification_done (proc , thread , cookie );
4514
+ if (error )
4515
+ return error ;
4516
+ } break ;
4517
+
4330
4518
default :
4331
4519
pr_err ("%d:%d unknown command %u\n" ,
4332
4520
proc -> pid , thread -> pid , cmd );
@@ -4716,6 +4904,46 @@ static int binder_thread_read(struct binder_proc *proc,
4716
4904
if (cmd == BR_DEAD_BINDER )
4717
4905
goto done ; /* DEAD_BINDER notifications can cause transactions */
4718
4906
} break ;
4907
+
4908
+ case BINDER_WORK_FROZEN_BINDER : {
4909
+ struct binder_ref_freeze * freeze ;
4910
+ struct binder_frozen_state_info info ;
4911
+
4912
+ memset (& info , 0 , sizeof (info ));
4913
+ freeze = container_of (w , struct binder_ref_freeze , work );
4914
+ info .is_frozen = freeze -> is_frozen ;
4915
+ info .cookie = freeze -> cookie ;
4916
+ freeze -> sent = true;
4917
+ binder_enqueue_work_ilocked (w , & proc -> delivered_freeze );
4918
+ binder_inner_proc_unlock (proc );
4919
+
4920
+ if (put_user (BR_FROZEN_BINDER , (uint32_t __user * )ptr ))
4921
+ return - EFAULT ;
4922
+ ptr += sizeof (uint32_t );
4923
+ if (copy_to_user (ptr , & info , sizeof (info )))
4924
+ return - EFAULT ;
4925
+ ptr += sizeof (info );
4926
+ binder_stat_br (proc , thread , BR_FROZEN_BINDER );
4927
+ goto done ; /* BR_FROZEN_BINDER notifications can cause transactions */
4928
+ } break ;
4929
+
4930
+ case BINDER_WORK_CLEAR_FREEZE_NOTIFICATION : {
4931
+ struct binder_ref_freeze * freeze =
4932
+ container_of (w , struct binder_ref_freeze , work );
4933
+ binder_uintptr_t cookie = freeze -> cookie ;
4934
+
4935
+ binder_inner_proc_unlock (proc );
4936
+ kfree (freeze );
4937
+ binder_stats_deleted (BINDER_STAT_FREEZE );
4938
+ if (put_user (BR_CLEAR_FREEZE_NOTIFICATION_DONE , (uint32_t __user * )ptr ))
4939
+ return - EFAULT ;
4940
+ ptr += sizeof (uint32_t );
4941
+ if (put_user (cookie , (binder_uintptr_t __user * )ptr ))
4942
+ return - EFAULT ;
4943
+ ptr += sizeof (binder_uintptr_t );
4944
+ binder_stat_br (proc , thread , BR_CLEAR_FREEZE_NOTIFICATION_DONE );
4945
+ } break ;
4946
+
4719
4947
default :
4720
4948
binder_inner_proc_unlock (proc );
4721
4949
pr_err ("%d:%d: bad work type %d\n" ,
@@ -5324,6 +5552,48 @@ static bool binder_txns_pending_ilocked(struct binder_proc *proc)
5324
5552
return false;
5325
5553
}
5326
5554
5555
+ static void binder_add_freeze_work (struct binder_proc * proc , bool is_frozen )
5556
+ {
5557
+ struct rb_node * n ;
5558
+ struct binder_ref * ref ;
5559
+
5560
+ binder_inner_proc_lock (proc );
5561
+ for (n = rb_first (& proc -> nodes ); n ; n = rb_next (n )) {
5562
+ struct binder_node * node ;
5563
+
5564
+ node = rb_entry (n , struct binder_node , rb_node );
5565
+ binder_inner_proc_unlock (proc );
5566
+ binder_node_lock (node );
5567
+ hlist_for_each_entry (ref , & node -> refs , node_entry ) {
5568
+ /*
5569
+ * Need the node lock to synchronize
5570
+ * with new notification requests and the
5571
+ * inner lock to synchronize with queued
5572
+ * freeze notifications.
5573
+ */
5574
+ binder_inner_proc_lock (ref -> proc );
5575
+ if (!ref -> freeze ) {
5576
+ binder_inner_proc_unlock (ref -> proc );
5577
+ continue ;
5578
+ }
5579
+ ref -> freeze -> work .type = BINDER_WORK_FROZEN_BINDER ;
5580
+ if (list_empty (& ref -> freeze -> work .entry )) {
5581
+ ref -> freeze -> is_frozen = is_frozen ;
5582
+ binder_enqueue_work_ilocked (& ref -> freeze -> work , & ref -> proc -> todo );
5583
+ binder_wakeup_proc_ilocked (ref -> proc );
5584
+ } else {
5585
+ if (ref -> freeze -> sent && ref -> freeze -> is_frozen != is_frozen )
5586
+ ref -> freeze -> resend = true;
5587
+ ref -> freeze -> is_frozen = is_frozen ;
5588
+ }
5589
+ binder_inner_proc_unlock (ref -> proc );
5590
+ }
5591
+ binder_node_unlock (node );
5592
+ binder_inner_proc_lock (proc );
5593
+ }
5594
+ binder_inner_proc_unlock (proc );
5595
+ }
5596
+
5327
5597
static int binder_ioctl_freeze (struct binder_freeze_info * info ,
5328
5598
struct binder_proc * target_proc )
5329
5599
{
@@ -5335,6 +5605,7 @@ static int binder_ioctl_freeze(struct binder_freeze_info *info,
5335
5605
target_proc -> async_recv = false;
5336
5606
target_proc -> is_frozen = false;
5337
5607
binder_inner_proc_unlock (target_proc );
5608
+ binder_add_freeze_work (target_proc , false);
5338
5609
return 0 ;
5339
5610
}
5340
5611
@@ -5367,6 +5638,8 @@ static int binder_ioctl_freeze(struct binder_freeze_info *info,
5367
5638
binder_inner_proc_lock (target_proc );
5368
5639
target_proc -> is_frozen = false;
5369
5640
binder_inner_proc_unlock (target_proc );
5641
+ } else {
5642
+ binder_add_freeze_work (target_proc , true);
5370
5643
}
5371
5644
5372
5645
return ret ;
@@ -5742,6 +6015,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
5742
6015
binder_stats_created (BINDER_STAT_PROC );
5743
6016
proc -> pid = current -> group_leader -> pid ;
5744
6017
INIT_LIST_HEAD (& proc -> delivered_death );
6018
+ INIT_LIST_HEAD (& proc -> delivered_freeze );
5745
6019
INIT_LIST_HEAD (& proc -> waiting_threads );
5746
6020
filp -> private_data = proc ;
5747
6021
@@ -6293,7 +6567,9 @@ static const char * const binder_return_strings[] = {
6293
6567
"BR_FAILED_REPLY" ,
6294
6568
"BR_FROZEN_REPLY" ,
6295
6569
"BR_ONEWAY_SPAM_SUSPECT" ,
6296
- "BR_TRANSACTION_PENDING_FROZEN"
6570
+ "BR_TRANSACTION_PENDING_FROZEN" ,
6571
+ "BR_FROZEN_BINDER" ,
6572
+ "BR_CLEAR_FREEZE_NOTIFICATION_DONE" ,
6297
6573
};
6298
6574
6299
6575
static const char * const binder_command_strings [] = {
@@ -6316,6 +6592,9 @@ static const char * const binder_command_strings[] = {
6316
6592
"BC_DEAD_BINDER_DONE" ,
6317
6593
"BC_TRANSACTION_SG" ,
6318
6594
"BC_REPLY_SG" ,
6595
+ "BC_REQUEST_FREEZE_NOTIFICATION" ,
6596
+ "BC_CLEAR_FREEZE_NOTIFICATION" ,
6597
+ "BC_FREEZE_NOTIFICATION_DONE" ,
6319
6598
};
6320
6599
6321
6600
static const char * const binder_objstat_strings [] = {
@@ -6325,7 +6604,8 @@ static const char * const binder_objstat_strings[] = {
6325
6604
"ref" ,
6326
6605
"death" ,
6327
6606
"transaction" ,
6328
- "transaction_complete"
6607
+ "transaction_complete" ,
6608
+ "freeze" ,
6329
6609
};
6330
6610
6331
6611
static void print_binder_stats (struct seq_file * m , const char * prefix ,
0 commit comments