@@ -1355,6 +1355,7 @@ static void binder_free_ref(struct binder_ref *ref)
13551355 if (ref -> node )
13561356 binder_free_node (ref -> node );
13571357 kfree (ref -> death );
1358+ kfree (ref -> freeze );
13581359 kfree (ref );
13591360}
13601361
@@ -3844,6 +3845,155 @@ static void binder_transaction(struct binder_proc *proc,
38443845 }
38453846}
38463847
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+
38473997/**
38483998 * binder_free_buf() - free the specified buffer
38493999 * @proc: binder proc that owns buffer
@@ -4327,6 +4477,44 @@ static int binder_thread_write(struct binder_proc *proc,
43274477 binder_inner_proc_unlock (proc );
43284478 } break ;
43294479
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+
43304518 default :
43314519 pr_err ("%d:%d unknown command %u\n" ,
43324520 proc -> pid , thread -> pid , cmd );
@@ -4716,6 +4904,46 @@ static int binder_thread_read(struct binder_proc *proc,
47164904 if (cmd == BR_DEAD_BINDER )
47174905 goto done ; /* DEAD_BINDER notifications can cause transactions */
47184906 } 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+
47194947 default :
47204948 binder_inner_proc_unlock (proc );
47214949 pr_err ("%d:%d: bad work type %d\n" ,
@@ -5324,6 +5552,48 @@ static bool binder_txns_pending_ilocked(struct binder_proc *proc)
53245552 return false;
53255553}
53265554
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+
53275597static int binder_ioctl_freeze (struct binder_freeze_info * info ,
53285598 struct binder_proc * target_proc )
53295599{
@@ -5335,6 +5605,7 @@ static int binder_ioctl_freeze(struct binder_freeze_info *info,
53355605 target_proc -> async_recv = false;
53365606 target_proc -> is_frozen = false;
53375607 binder_inner_proc_unlock (target_proc );
5608+ binder_add_freeze_work (target_proc , false);
53385609 return 0 ;
53395610 }
53405611
@@ -5367,6 +5638,8 @@ static int binder_ioctl_freeze(struct binder_freeze_info *info,
53675638 binder_inner_proc_lock (target_proc );
53685639 target_proc -> is_frozen = false;
53695640 binder_inner_proc_unlock (target_proc );
5641+ } else {
5642+ binder_add_freeze_work (target_proc , true);
53705643 }
53715644
53725645 return ret ;
@@ -5742,6 +6015,7 @@ static int binder_open(struct inode *nodp, struct file *filp)
57426015 binder_stats_created (BINDER_STAT_PROC );
57436016 proc -> pid = current -> group_leader -> pid ;
57446017 INIT_LIST_HEAD (& proc -> delivered_death );
6018+ INIT_LIST_HEAD (& proc -> delivered_freeze );
57456019 INIT_LIST_HEAD (& proc -> waiting_threads );
57466020 filp -> private_data = proc ;
57476021
@@ -6293,7 +6567,9 @@ static const char * const binder_return_strings[] = {
62936567 "BR_FAILED_REPLY" ,
62946568 "BR_FROZEN_REPLY" ,
62956569 "BR_ONEWAY_SPAM_SUSPECT" ,
6296- "BR_TRANSACTION_PENDING_FROZEN"
6570+ "BR_TRANSACTION_PENDING_FROZEN" ,
6571+ "BR_FROZEN_BINDER" ,
6572+ "BR_CLEAR_FREEZE_NOTIFICATION_DONE" ,
62976573};
62986574
62996575static const char * const binder_command_strings [] = {
@@ -6316,6 +6592,9 @@ static const char * const binder_command_strings[] = {
63166592 "BC_DEAD_BINDER_DONE" ,
63176593 "BC_TRANSACTION_SG" ,
63186594 "BC_REPLY_SG" ,
6595+ "BC_REQUEST_FREEZE_NOTIFICATION" ,
6596+ "BC_CLEAR_FREEZE_NOTIFICATION" ,
6597+ "BC_FREEZE_NOTIFICATION_DONE" ,
63196598};
63206599
63216600static const char * const binder_objstat_strings [] = {
@@ -6325,7 +6604,8 @@ static const char * const binder_objstat_strings[] = {
63256604 "ref" ,
63266605 "death" ,
63276606 "transaction" ,
6328- "transaction_complete"
6607+ "transaction_complete" ,
6608+ "freeze" ,
63296609};
63306610
63316611static void print_binder_stats (struct seq_file * m , const char * prefix ,
0 commit comments